Android Question How to Pass Command from Javascript Function to Webview in B4A

omo

Active Member
Licensed User
Hello, honorable members, referring to this link earlier raized: https://www.b4x.com/android/forum/t...ont-and-back-camera-on-webrtc-webview.119962/

I have carried out more intense research by dwelling only on javascript based on @ Erel's suggestion. I have used webviewextras and webviewextras2 (not together) just to make sure i execute javascript function that can pass command to webrtc to change phone camera from front to back and verse-versa. I have tried several examples on this forum, but many focuses were just on (1) loading javascript/html resource into webview i.e webview1.loadURL(....) (2) Passing data (values) from javascript to webview i.e WebViewExtras1.ExecuteJavascript(WebView1, "',true)};"). I only succeeded in loading asset javascript/html file into webview, which did not change the camera,but affected current display by loading itself into webview. Now, my question is: Can i send command from javascript function to webview in b4a without loading into webview or send data from javascript? However, if loading URl or passing data will solve my problem, i don't care so far it works. Please, help me
 

drgottjr

Well-Known Member
Licensed User
the answer to your question is yes.

the javascript interface in webviewextras can run functions, set values, query values, etc. in the webview.

the interface is a 2-way street: you can run javascript from b4a, and the webview can raise an event in b4a.

without knowing exactly what it is you want to do (or have tried to do), there is no way to know if you're doing it correctly.
 
Upvote 0

omo

Active Member
Licensed User
the answer to your question is yes.

the javascript interface in webviewextras can run functions, set values, query values, etc. in the webview.

the interface is a 2-way street: you can run javascript from b4a, and the webview can raise an event in b4a.

without knowing exactly what it is you want to do (or have tried to do), there is no way to know if you're doing it correctly.

Hello, drgottjr,
What I want to acheive is continuation of what is raised in refrenced link above. But let me put it like this:
I need example or clarification on how I can pass JavaScript like this below to reach webview using webviewextras or any other method:
var front = false; document.getElementById('flip-button').onclick = function() { front =` !front; }; var constraints = { video: { facingMode: (front? "user" : "environment") } };
Hope the message is clearer now? Otherwise, I will have to explain better when I am with my computer
Regards
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
does the javascript snippet you provide above appear in the file you have in dirassets (and which is loaded into the webview)?
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
here's a simple example for you.
it shows 2 different ways to control some element on a webview.
the example loads a simple webview from dirassets.
there is a sleep command for 10 seconds so you can settle down and look at the webview (i don't want you to miss the show :).)

the first example executes a javascript command to change the text color of an element directly. comment that one and uncomment the second one.
the second example executes a javascript function which does the same thing.
i believe either case could work for you.
if you leave both uncommented, you will only see the result of the second example.

note: there is a button on the webview. if you tap it, the color changes. understand that the webviewextras executejavascript command that runs a function (the second example) is clicking the button programatically, as if you had tapped the button.
 

Attachments

  • omo.zip
    8.5 KB · Views: 154
Upvote 0

omo

Active Member
Licensed User
does the javascript snippet you provide above appear in the file you have in dirassets (and which is loaded into the webview)?

Yes, the JavaScript was put in html tags with <script>tags and saved in dirasset before loading it with: webview1.loadURL(....). JavaScript page was displaying in webrtc webview and displacing current webrtc video streaming session instead. What I want is for JavaScript to send command that will force webrtc to change front camera to back camera instead of loading the page inside webview. Although, I am not the writer of that JavaScript, I only got it from stack overflow as solution
Thanks
 
Upvote 0

omo

Active Member
Licensed User
here's a simple example for you.
it shows 2 different ways to control some element on a webview.
the example loads a simple webview from dirassets.
there is a sleep command for 10 seconds so you can settle down and look at the webview (i don't want you to miss the show :).)

the first example executes a javascript command to change the text color of an element directly. comment that one and uncomment the second one.
the second example executes a javascript function which does the same thing.
i believe either case could work for you.
if you leave both uncommented, you will only see the result of the second example.

note: there is a button on the webview. if you tap it, the color changes. understand that the webviewextras executejavascript command that runs a function (the second example) is clicking the button programatically, as if you had tapped the button.
Ok, thank you, I will try it, sorry for my late response. I wasn't within the vicinity where I could get access to my system at moment. I will check and get back to you tomorrow by God's grace. Is already to 11pm night here, much thanks
Regards
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
i do not believe the snippet you showed will cause the camera to change. it will cause the "front" variable to change, yes, but the code which actually controls which camera to show (based on the "front" constraint) is, presumably, elsewhere in the html file. that function is the one you need to call.

it's like changing the size of an image for your camera. you can change the size all you like, but if you don't take the picture, the size is irrelevant. you can change "front" all you like, but without the missing function to activate a change, you have nothing. in my opinion.
 
Upvote 0

omo

Active Member
Licensed User
here's a simple example for you.
it shows 2 different ways to control some element on a webview.
the example loads a simple webview from dirassets.
there is a sleep command for 10 seconds so you can settle down and look at the webview (i don't want you to miss the show :).)

the first example executes a javascript command to change the text color of an element directly. comment that one and uncomment the second one.
the second example executes a javascript function which does the same thing.
i believe either case could work for you.
if you leave both uncommented, you will only see the result of the second example.

note: there is a button on the webview. if you tap it, the color changes. understand that the webviewextras executejavascript command that runs a function (the second example) is clicking the button programatically, as if you had tapped the button.

Sorry for my late response, i was trying to do everything by twisting your code to solve problem at hand. Thank you for that your code; it was so simple and better than the one i was using to achieve the same result discussed in previous posts. Even the dullest can understand your own, i have learnt from your own. In this your code, html is still being loaded into webrtc webview like i pointed out before. In my own case, the html is already loaded from https://appr.tc/r/009 via WebView1.LoadUrl("https://appr.tc/r/009") and not stored in dirasset through code below.

Full source code is here posted by Erel

Webrtc Html that shows on B4A webview:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    Private rp As RuntimePermissions
End Sub

Sub Globals
    Private WebView1 As WebView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    rp.CheckAndRequest(rp.PERMISSION_CAMERA)
    Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
    If Result Then
        rp.CheckAndRequest(rp.PERMISSION_RECORD_AUDIO)
        Wait For Activity_PermissionResult (Permission As String, Result As Boolean)
        If Result Then
            Dim client As JavaObject
            client.InitializeNewInstance(Application.PackageName & ".main$MyChromeClient", Null)
            Dim jo As JavaObject = WebView1
            jo.RunMethod("setWebChromeClient", Array(client))
            
            WebView1.LoadUrl("https://appr.tc/r/009")
        End If
    End If
End Sub


#if Java
import android.webkit.*;
public static class MyChromeClient extends WebChromeClient {
[USER=69643]@override[/USER]
     public void onPermissionRequest(PermissionRequest request) {
        request.grant(request.getResources());
    }
}
#End If

When the code above is run on phone, it displays a streaming session using default front camera, but i have read online and based on what Erel said that javascript function can be used to change the camera from front to back camera. . Now, i have been able to search for javascript like this below that i assumed can change the camera to back camera:

Unverified Javascript functions for changing front to back camera in webrtc webview:
// camera stream video element
let videoElm = document.querySelector('#camera-stream');
// flip button element
let flipBtn = document.querySelector('#flip-btn');

// default user media options
let defaultsOpts = { audio: false, video: true }
let shouldFaceUser = true;

// check whether we can use facingMode
let supports = navigator.mediaDevices.getSupportedConstraints();
if( supports['facingMode'] === true ) {
  flipBtn.disabled = false;
}

let stream = null;

function capture() {
  defaultsOpts.video = { facingMode: shouldFaceUser ? 'user' : 'environment' }
  navigator.mediaDevices.getUserMedia(defaultsOpts)
    .then(function(_stream) {
      stream  = _stream;
      videoElm.srcObject = stream;
      videoElm.play();
    })
    .catch(function(err) {
      console.log(err)
    });
}

flipBtn.addEventListener('click', function(){
  if( stream == null ) return
  // we need to flip, stop everything
  stream.getTracks().forEach(t => {
    t.stop();
  });
  // toggle / flip
  shouldFaceUser = !shouldFaceUser;
  capture();
})

capture();

Now, my question is this, how can i pass this javascript function to already displaying webrtc webview (not the one i will load from dirasset) to cause my phone to change its camera to back camera from B4A?
Note: I am open to any other solution like java or otherwise that can solve problem at hand. Hope is clearer now? Thank you for your time,
Regards
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
you still don't get how executeJavascript works; it doesn't matter where the source running in the webview comes from. you're inside the webview.

technically, you can inject the javascript you show. without some modification, it probably won't work. but i can tell you it is essentially doing what is required to change the camera. if you understand webrtc and javascript, you will see that. basically, all you need is the code that's inside the capture() function. a couple other steps are necessary, but they are in the code you posted. you would have to modify them a little. i don't know what you know about webrtc and javascript. somebody is going to have to spend some time with this. it's unclear whether that's you or not. based on what i've seen about webrtc and what's in the javascript you posted, i'd say you were only a few steps away. but they are tricky. the webviewextras aspect is the least of your problems (my example showed how easily it works). once you figure out the javascript, injecting it is simple.
 
Upvote 0

omo

Active Member
Licensed User
you still don't get how executeJavascript works; it doesn't matter where the source running in the webview comes from. you're inside the webview.

technically, you can inject the javascript you show. without some modification, it probably won't work. but i can tell you it is essentially doing what is required to change the camera. if you understand webrtc and javascript, you will see that. basically, all you need is the code that's inside the capture() function. a couple other steps are necessary, but they are in the code you posted. you would have to modify them a little. i don't know what you know about webrtc and javascript. somebody is going to have to spend some time with this. it's unclear whether that's you or not. based on what i've seen about webrtc and what's in the javascript you posted, i'd say you were only a few steps away. but they are tricky. the webviewextras aspect is the least of your problems (my example showed how easily it works). once you figure out the javascript, injecting it is simple.
Ok, that's good! Now, it means if only I can see sample that demonstrates how to send function to running webview from any url, then, I should be able to keep trying looking for JavaScript that will solve current problem. Please, I wouldn't mind at your leisure time before end of next week, if you can modify that your example you sent to me to inject JavaScript to any running webview like I demonstrated; from there I believe I should be able to solve the problem through 'try and error' approach
Thank you,
Regards
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
injecting a function is different from injecting a command. if the function is already in the webpage, you can call it with webviewextras. inserting a function and running it may or may not work. you'd have to try. with closure it might work. in the example i sent you, you can see how i ran a function with webviewextras.

if you want to create a webpage and make it available on the internet, i'd be happy to "manipulate" it with webviewextras. for the purposes of showing you, the page would have to be simple but with a function or 2 and some addressable elements (preferably identifiable by id). if the function does something visible and if the elements have properties that can be queried or changed, i'll do it. i'm not going to spend days trying to get the camera to change in a webrtc page. that's your job ;)
 
Upvote 0

omo

Active Member
Licensed User
...i'm not going to spend days trying to get the camera to change in a webrtc page. that's your job ;)
Yes, you are right, I will surely keep doing that once I get the basis I need. You have even tried for me, I really appreciate. What about opening this page for the link below from browser and right click to view source code and see if one I'd can be picked to inject the command:
https://appr.tc/r/009
009 can be random number 1 to 10, so that changes can be view
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
i'll take a look. but, here, look at these i just took from my device:
i ran the webrtc test from erel's link. everything ok.
i inject some javascript to send you a message using a function which already exists in the webpage. you can see it on your device. so, clearly, webviewextras can inject javascript into the webrtc page which causes something to happen in the webrtc page. that the command to change the camera failed just means there are some missing steps.

anyway, i'll take a look at your link above and see if there is a candidate suitable for injection. i'll revert later
 

Attachments

  • before-omo.png
    before-omo.png
    67.2 KB · Views: 82
  • after-omo.png
    after-omo.png
    53.8 KB · Views: 87
  • Like
Reactions: omo
Upvote 0

drgottjr

Well-Known Member
Licensed User
i just looked at your link. it is exactly what i told you i'm not going to deal with. i don't know enough about webrtc to spend the time 1) to learn and then 2) to keep testing until i figure out how to change the camera. i'm sorry.
 
Upvote 0

omo

Active Member
Licensed User
Wh
i'll take a look. but, here, look at these i just took from my device:
i ran the webrtc test from erel's link. everything ok.
i inject some javascript to send you a message using a function which already exists in the webpage. you can see it on your device. so, clearly, webviewextras can inject javascript into the webrtc page which causes something to happen in the webrtc page. that the command to change the camera failed just means there are some missing steps.

anyway, i'll take a look at your link above and see if there is a candidate suitable for injection. i'll revert later
Whaoo, my standing ovation for you! You are too much!
 
Upvote 0

omo

Active Member
Licensed User
i just looked at your link. it is exactly what i told you i'm not going to deal with. i don't know enough about webrtc to spend the time 1) to learn and then 2) to keep testing until i figure out how to change the camera. i'm sorry.
Kindly, send me the code demo you used that you screenshot. I will follow that to keep solving the problem.
 
Upvote 0

omo

Active Member
Licensed User
How you did that inject button and without html in asset affecting display is amazing to me. Whaoo! That should be enough to keep trying to acheive what I want. You are too much! !! !!!
 
Upvote 0

drgottjr

Well-Known Member
Licensed User
the button is in b4a. you need some way to run executejavascript with webviewextras. initially i did a sleep() and then had executejavascript run by itself.
this time i put a button. you tap, it runs executejavascript.

i looked at the source for the webrtc demo (erel's link) and saw a function that the page used to put messages on the screen. i simply take that function, added my own message, and had webviewextras execute the function.

the point was to show you that the source does not have to be loaded from dirassets. once a page has been loaded into webview, you can access it if you know what to look for. in this case, i saw something that i was sure would let me make the webview display change. in your case, you have to find out exactly which function to call to do what you want. from the javascript snippet you sent earlier, you can clearly see capture() is called. if you look at capture(), you can see what it does. that's the function. but you have to first stop the broadcasting and set the appropriate constraint to "environment" before you call capture(). that's the part that's going to be the hardest and will require a lot of testing.

although i find webrtc interesting, it's just too hot to spend the time needed to learn about it. plus there are all kinds of other considerations (servers, peer-to-peer, cross-browser co-operation, etc). it's a big project.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------
CORRECTION:
it's not capture() that does what you want, it's Flipbtn.click(). you would set shouldFaceUser to false and then call flipBtn.click(). Flibtn.click() calls capture() after stopping broadcasting. you would need to identify Flipbtn by id or class. i couldn't. that leads me to believe the snippet isn't even from the link posted by erel.
i'm guessing it's just something you found out there. you need the javascript that applies to the page you're dealing with. you can't just inject some random code.
 

Attachments

  • omo2.zip
    9.1 KB · Views: 95
  • Like
Reactions: omo
Upvote 0

omo

Active Member
Licensed User
the button is in b4a. you need some way to run executejavascript with webviewextras. initially i did a sleep() and then had executejavascript run by itself.
this time i put a button. you tap, it runs executejavascript.

i looked at the source for the webrtc demo (erel's link) and saw a function that the page used to put messages on the screen. i simply take that function, added my own message, and had webviewextras execute the function.

the point was to show you that the source does not have to be loaded from dirassets. once a page has been loaded into webview, you can access it if you know what to look for. in this case, i saw something that i was sure would let me make the webview display change. in your case, you have to find out exactly which function to call to do what you want. from the javascript snippet you sent earlier, you can clearly see capture() is called. if you look at capture(), you can see what it does. that's the function. but you have to first stop the broadcasting and set the appropriate constraint to "environment" before you call capture(). that's the part that's going to be the hardest and will require a lot of testing.

although i find webrtc interesting, it's just too hot to spend the time needed to learn about it. plus there are all kinds of other considerations (servers, peer-to-peer, cross-browser co-operation, etc). it's a big project.

----------------------------------------------------------------------------------------------------------------------------------------------------------------------
CORRECTION:
it's not capture() that does what you want, it's Flipbtn.click(). you would set shouldFaceUser to false and then call flipBtn.click(). Flibtn.click() calls capture() after stopping broadcasting. you would need to identify Flipbtn by id or class. i couldn't. that leads me to believe the snippet isn't even from the link posted by erel.
i'm guessing it's just something you found out there. you need the javascript that applies to the page you're dealing with. you can't just inject some random code.
Hello, thank you so much! I tried your second program sent to me, once again, I saw your simplicity at display; and I was able to get the message. You have shown me how it is easy to pass command to webview without necessarily loading it from dirasset. Having tested it, it works fine with link in Erel's posted snippet, but couldn't just work with Google link. It seems Google has locked the webview internally. At least, I have gotten the message, I will keep managing only front camera, while I keep working on better option. Thank, you so much for your time and for more things I have learnt from you. I appreciate!
Regards
 
Upvote 0
Top