B4A Library WebViewExtras

Hi all.

WebViewExtras is my latest library.
It's a much updated version of JSInterface.

WebViewExtras exposes more of the available native Android WebView methods to your B4A application:

addJavascriptInterface(webView1 As WebView, interfaceName As String)

Add a javascript interface to webView1, methods of the interface can be accessed using javascript with the interfaceName as the javascript namespace.

The interface contains just a single overloaded method CallSub().
The CallSub method signatures are:

CallSub(subName As String, callUIThread As boolean)
CallSub(subName As String, callUIThread As boolean, parameter1 As String)
CallSub(subName As String, callUIThread As boolean, parameter1 As String, parameter2 As String)
CallSub(subName As String, callUIThread As boolean, parameter1 As String, parameter2 As String, parameter3 As String)


So if you have added the interface to your webView with the interfaceName of "B4A" then you can write javascript such as:

B4X:
B4A.CallSub('MySubName', true)

The callUIThread parameter is an important update - it's not available with JSInterface.

Does the Sub called by your javascript modify your activity UI?
If the answer is yes then you need to pass boolean true as callUIThread otherwise you can pass false.
If you pass false and then the Sub tries to modify your activity UI you will get an exception.

Does your javascript require a return value from your Sub?
If the answer is yes then the Sub MUST NOT modify the activity UI.
If CallSub is excuted with callUIThread set to true then no values will be returned from your Sub to the javascript.

You will need to structure your B4A code so that Subs that return values to javascript do not modify the activity UI.

addWebChromeClient(webView1 As WebView, EventName As String)

Add a WebChromeClient to webView1.

The default B4A WebView has no WebChromeClient.
A WebChromeClient handles many things, the WebChromeClient that WebViewExtras adds to your WebView enables:

Version 1.30 of WebViewExtras requires that an additional EventName parameter is passed to the addWebChromeClient method, see this post: http://www.b4x.com/forum/additional-libraries-official-updates/12453-webviewextras-2.html#post102448

clearCache(webView1 As WebView, includeDiskFiles As boolean)

Clear the WebView cache.
Note that the cache is per-application, so this will clear the cache for all WebViews used in an application.

boolean includeDiskFiles - If false, only the RAM cache is cleared.

executeJavascript(webView1 As WebView, javascriptStatement As String)

Executes a string of one or more javascript statements in webView1.
javascriptStatement - A string of one or more (semi-colon seperated) javascript statements.

flingScroll(webView1 As WebView, vx As Int, vy As Int)

flingScroll is a poorly documented method of the WebView.
It's included in WebViewExtras as it may be useful but i can find no documentation for it or it's parameters.

vx and vy do not seem to be pixel values - i suspect they are velocity values for the kinetic/fling scroll.

pageDown(webView1 As WebView, scrollToBottom As boolean)

Scroll the contents of webView1 down by half the page size.

scrollToBottom - If true then webView1 will be scrolled to the bottom of the page.

Returns a Boolean value to indicate the success or failure of the scroll.

pageUp(webView1 As WebView, scrollToTop As boolean)

Scroll the contents of webView1 up by half the page size.

scrollToTop - If true then webView1 will be scrolled to the top of the page.

Returns a Boolean value to indicate the success or failure of the scroll.

zoomIn(webView1 As WebView)

Perform zoom in on webView1.

Returns a Boolean value to indicate the success or failure of the zoom.

zoomOut(webView1 As WebView)

Perform zoom out on webView1.

Returns a Boolean value to indicate the success or failure of the zoom.

Up to date documentation/reference for this library can be found here: http://www.b4x.com/forum/additional-libraries-official-updates/12453-webviewextras-3.html#post106486.

Library and demo code is attached to this post.

The demo is a bit brief - sorry but i don't have time to write demo code for all the new methods.
The demo displays two WebViews - the top WebView has a JavascriptInterface and WebChromeClient whereas the lower WebView has neither - it is the default B4A WebView.

Martin.

Edit by Erel:
- There is a security issue related to AddJavascriptInterface in older versions of Android. See this link: https://www.b4x.com/android/forum/t...ascriptinterface-vulnerability.85032/#content
- v2.20 is attached. This is the latest version.
 

Attachments

  • WebViewExtras_v1_42.zip
    7.8 KB · Views: 9,532
  • v2.20.zip
    41.1 KB · Views: 854
Last edited by a moderator:

Inman

Well-Known Member
Licensed User
Longtime User
Can you please add getContentHeight() and getScale() for webview? Apparently getContentHeight * getScale = height of the webview, which is essential for my current project.
 

warwound

Expert
Licensed User
Longtime User
Can you please add getContentHeight() and getScale() for webview? Apparently getContentHeight * getScale = height of the webview, which is essential for my current project.

Can you test the attached update?

I've added:

  • GetContentHeight (WebView1 As WebView) As Int
    Gets the height of the HTML content.
  • GetScale (WebView1 As WebView) As Float
    Get the WebView scale.
    This method was deprecated in API level 17.
    This method is prone to inaccuracy due to race conditions between the web rendering and UI threads; prefer onScaleChanged(WebView, float, float).

As you can see, the native getScale method is deprecated for technical reasons.

Listening for the onScaleChanged event would require an update to the WebViewClient.
The WebViewClient is part of the standard B4A WebView so i can't update that.
I could create a new WebViewClient that you could use instead of the client that is part of the standard B4A WebView - that'd take me a little while so can you test this quick update that i've made and post with your results?

If the GetScale method causes problems i'll look at an updated WebViewClient.

Martin.
 
Last edited:

Inman

Well-Known Member
Licensed User
Longtime User
Tested on Android 4.2.2 and works great. GetContentHeight x GetScale is indeed the length of the webview.
 

desof

Well-Known Member
Licensed User
Longtime User
Hola baje esta aplicacion instale la libraria y lo pruebo a travez de Bridge y la pantalla me queda en blanco por tiempo indefinido...
Que puede ser?
 

warwound

Expert
Licensed User
Longtime User
Hola baje esta aplicacion instale la libraria y lo pruebo a travez de Bridge y la pantalla me queda en blanco por tiempo indefinido...
Que puede ser?

Well Google Translate tells me you've asked:

Hello down this application install the bookstore and I try to travez Bridge and the screen goes blank me indefinitely ...
Any suggestions?

I fail to understand lol...

Martin.
 

warwound

Expert
Licensed User
Longtime User
WebViewExtras updated to version 1.36

Two new methods added:

  • GetContentHeight (WebView1 As WebView) As Int
    Gets the height of the HTML content.
  • GetScale (WebView1 As WebView) As Float
    Get the WebView scale.
    This method was deprecated in API level 17.
    This method is prone to inaccuracy due to race conditions between the web rendering and UI threads; prefer onScaleChanged(WebView, float, float).

Version 1.36 is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
WebViewExtras updated to version 1.37

This is a bug fix, fixing a bug where the WebChromeClient failed to properly handle a file upload form on a web page.

Version 1.37 is attached to the first post in this thread.

Martin.
 

ivan.tellez

Active Member
Licensed User
Longtime User
Event on page update

Hello warwound

I am using your WebViewExtras lib, its awesome. I have been programing in B4A only for a few days, so I expect this is not to much of newbie question.

I'm trying to make a program that interacts with a page made in ASP. The original idea was somenting like this:

1. User input some data (4 strings) in B4A views
2. User press a B4A validate button
3. Make a WebView1.LoadUrl("") and wait for the Webview1_PageFinished event
4. Using the WebViewExtras.executeJavascript, put data from step 1 in the web form and send it
5. Wait for Webview1_PageFinished and parse the results
6. if the data was not valid, alert the user
7. If data was valid, show it in a ListView and save it.

Thanks to your great contribution, This looks like is piece of cake, but then i got a problem in step 5, there was NO subsecuent PageFinished Events.

After looking ath the page, i discovered that it uses ASP.NET and sending the form in some XMLHttpRequest, the page is the same, just updated by Javascript with the XMLHttpRequest response.

So, there is no PageFinished Event :(


The question: Is there a way to intercept the XMLHttpRequest responses and expose them as a event in B4A? or maybe a way in Javascript an call a B4A function with the addJavascriptInterface and CallSub?

In this way i could change step 5 to

5. Wait for XMLHttpResponseArrived and parse the results


Thanks in advance
 

warwound

Expert
Licensed User
Longtime User
Hi.

The only solution i can think is to inject some javascript into the webpage after it has loaded.
You'd have to look at the webpage source code - the HTML and javascript - to establish exactly what code executes after a successful login and inject javascript that will get executed after the XMLHttpRequest has completed.

That may or may not be possible - it depends entirely on how the webpage is written.

If you'd like me to take a look then post the URL of the login webpage - if you'd rather not post the URL then send me a PM with the URL.

Martin.
 

ivan.tellez

Active Member
Licensed User
Longtime User
How to implement an event on PageUpdated

Hi.

The only solution i can think is to inject some javascript into the webpage after it has loaded.
You'd have to look at the webpage source code - the HTML and javascript - to establish exactly what code executes after a successful login and inject javascript that will get executed after the XMLHttpRequest has completed.

Martin.



Hi, thank for the help, the page its not a login page, Its a service that check the authenticity of an invoice. Just fill the form, press send, and the page updates through the XMLHttpResponse.



I use the camera to read a QR code to provide the first 3 fields, and ask the user for input the captcha manually.

The solution you provided its what im doing, when the page loads, I inject javascript to populate and send the form, at the same time Also inject a function to parse the page and get the results (Captcha is wrong, Data has errors, data is valid, etc.)

Its easy because the page adds or removes DIVs whit the result, so I just have to check if a certain element is on the page, injecting at PageFinished something like:

B4X:
sJavascript = "function GetStatus(){
  Element = document.getElementById('ctl00_MainContent_PnlNoResultados');
  if (Element != null) {
    B4A.CallSub('ShowStatus',true, 'CFDIFalso', 'The invoice is fake'); 
    return};
... Other states code ...
}"
MyWebViewExtras.executeJavascript(WebView1,sJavascript)


I just work great when I execute the injected function from a B4A Button.

B4X:
Sub CmdStatus_Click
   Dim sJavascript As String
   sJavascript = "DoFormat();"
   MyWebViewExtras.executeJavascript(WebView1,sJavascript)
End Sub

So the current aproach is to ask the user to press the "Check Status" buton after the form was sent. Each time the user preses the buton, the previously injected javascript funcion is executed giving feedback.


It Works, but its a "quick and dirty" solution :(


The ideal is to have an Event triggered when the page is modified to put in there the code in "CmdStatus_Click". Thet way the proces is automated.


Thanks for your help
 

westingenieria

Active Member
Licensed User
Longtime User
Great work! but the "FileUpload" example doesnt work with Android 4.1.2
anyone has this problem?
 

warwound

Expert
Licensed User
Longtime User
Can you try the attached update?

Look in the log when a file upload is requested, do you see any of these messages: "openFileChooser < 3.00", "openFileChooser 3.00+" or "openFileChooser Jelly Bean"?

Martin.
 
Last edited:

westingenieria

Active Member
Licensed User
Longtime User
Can you try the attached update?

Look in the log when a file upload is requested, do you see any of these messages: "openFileChooser < 3.00", "openFileChooser 3.00+" or "openFileChooser Jelly Bean"?

Martin.

Hi, thank u very much. I only see "openFileChooser Jelly Bean". In the app i see "select a file" "no application can perform this action" .
 

warwound

Expert
Licensed User
Longtime User
Looks like a problem with the MIME type being requested by the WebChromeClient.
My logs shows the requested MIME type to be "" - i've added a check to the code, if the MIME type is "" then it is changed to "*/*".

I tested the update at Sample File Upload Form using my Jelly Bean Galaxy Tab2 and it works fine.
Can you test it too - if it works for you i'll upload the new version as a bug fix.

Martin.
 

Attachments

  • WebViewExtras_v1_38_test2.zip
    7.4 KB · Views: 560

westingenieria

Active Member
Licensed User
Longtime User
Looks like a problem with the MIME type being requested by the WebChromeClient.
My logs shows the requested MIME type to be "" - i've added a check to the code, if the MIME type is "" then it is changed to "*/*".

I tested the update at Sample File Upload Form using my Jelly Bean Galaxy Tab2 and it works fine.
Can you test it too - if it works for you i'll upload the new version as a bug fix.

Martin.

Warwound, thank u very much. I tested in a Samsung Galaxy Tab 2 7" with jelly bean and it works GREAT! Nice work! :)
 

warwound

Expert
Licensed User
Longtime User
WebViewExtras updated to version 1.38

This is a bug fix.
The WebChromeClient now better handles webpages that contain a file upload form on Jelly Bean.

Version 1.38 is attached to the first post in this thread.

Martin.
 

ivan.tellez

Active Member
Licensed User
Longtime User
app broken

Hi, i made an app, and it was working ok, tested on varios phones without problems.

But, then I got a Galaxy S4, and the addJavascriptInterface just dont work.

The B4A.CallSub does nothing when calling the sub.

All the rest of the WebViewExtras.executeJavascript() works ok, and the app its fine in other devices.

Android ver. 4.2.2, until now Im clueless.

Have you any report or idea what the problem is?


Thanks
 

warwound

Expert
Licensed User
Longtime User
First thing to check is for any (javascript) errors being reported by the WebView.
To do that you need to use the addWebChromeClient(webView1 As WebView, EventName As String) method to add a WebChromeClient.
WebView errors will now be written to the log.

If the WebView cannot find the javascript interface then you'll see an error such as 'foobar is null or undefined' where foobar is the interfaceName passed in addJavascriptInterface(webView1 As WebView, interfaceName As String).

Martin.
 
Top