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: 8,902
  • v2.20.zip
    41.1 KB · Views: 347
Last edited by a moderator:

JohnC

Expert
Licensed User
Longtime User
OK, I found a bug, don't know if its a WVE bug or it's another example of why you can't use MsgBox2 in an event sub.

(This bug seems like it might be related to another bug I found: https://www.b4x.com/android/forum/threads/weird-webview-and-msgbox2-conflict.83602/#post-529656)

Basically,

If I use this code on the first page of this thread:

B4X:
Sub MyEventName_GeolocationPermissionsRequest As Int
   Dim Response As Int
   Response=Msgbox2("Allow the webpage to use device geolocation features?", "Permission required:", "Allow", "", "Disallow", Null)
   If Response=DialogResponse.POSITIVE Then
      ToastMessageShow("Permission granted", True)
      Return MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW
   Else
      ToastMessageShow("Permission denied", True)
      Return MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW
   End If
End Sub

After I click "Allow", the webpage seems like it can NOT run javascript reliably on it anymore.

However, if I simply have:
B4X:
Return wve.GEOLOCATION_PERMISSION_ALLOW
In the above sub, then the webpage acts correctly after I click Allow.
 

John Woodsmall

Active Member
Licensed User
Longtime User
i have simple html page (that works in desktop crome). It saves the input varibles
and then later wants to retrieve them.

does not seem to work under /files ???

var equ = document.getElementById('Equip_Mod').value ;
window.localStorage.setItem("Equip_Mod",equ);
--
var wag = document.getElementById('Cust_name') ;
wag.value= window.localStorage.getItem("Cust_name");
 

magarcan

Active Member
Licensed User
Longtime User
Hi!!

I'm working from your example here.
The fact is WebView1_PageFinished Event is triggered before the site has been fully loaded. I've set un a Delay before executing the Javascript and it works, but don't think this is the best way.

Any idea?

Thanks!!!
 

warwound

Expert
Licensed User
Longtime User
The fact is WebView1_PageFinished Event is triggered before the site has been fully loaded. I've set un a Delay before executing the Javascript and it works, but don't think this is the best way.

Any idea?

PageFinished means that all resources on the webpage have been loaded from the server, it does not mean that those resources have been fully rendered within the WebView.

Do you have control over the webpage?
If so then you can add a javascript event listener that will execute when the webpage has been fully rendered and that javascript can call a b4a sub via a JavascriptInterface.
Look here for more info: https://www.w3schools.com/jsref/event_onload.asp

If you have no control over the webpage then the only thing i can think of is to inject some javascript into the webpage and that injected javascript creates an onload event listener and calls a b4a sub via a JavascriptInterface.
 

Derek Johnson

Active Member
Licensed User
Longtime User
hi all

The following URL open without any issue in browser but not rendering with webview

http://ambiotinfotech.com/pos

login credentials:

demo / demo

tried with webviewextras but failed

need some support, Thanks in advance.

You should probably post this as a separate question, however I changed the URL in the WebView Extras demo code and got this on my Nexus 5X. What is the issue? (It was slow to load however).
 

Attachments

  • Pos.png
    Pos.png
    19.6 KB · Views: 270

Derek Johnson

Active Member
Licensed User
Longtime User
Srikanth,

I did spot this error after I logged in and it did take 10-20 seconds to finish loading after the page finished event in WebView.

** Activity (main) Create, isFirst = true **
After 00 sec Loading URL1
** Activity (main) Resume **
After 00.009 sec Resume
After 00.026 sec Removed cookies
After 00.049 sec OverideURL http://ambiotinfotech.com/pos/
After 00.79 sec OverideURL http://ambiotinfotech.com/pos/login
After 01.219 sec Page Finished http://ambiotinfotech.com/pos/login
After 33.112 sec OverideURL http://ambiotinfotech.com/pos/pos
Uncaught TypeError: Cannot read property 'getItem' of null in http://ambiotinfotech.com/pos/themes/default/assets/dist/js/scripts.min.js (Line: 1)
After 01.476 sec Page Finished http://ambiotinfotech.com/pos/pos
 

Srikanth.pendru

Member
Licensed User
Longtime User
B4X:
WebViewExtras1.Initialize(WebView1)
    websettings.setAppCacheEnabled(WebView1,True)
    websettings.setSavePassword(WebView1,True)
    websettings.setDOMStorageEnabled(WebView1,True)
 
    Dim WebChromeClient1 As DefaultWebChromeClient
    WebChromeClient1.Initialize("WebChromeClient1")
  WebViewExtras1.SetWebChromeClient(WebChromeClient1)
WebViewExtras1.AddJavascriptInterface(WebView1, "B4A")
    WebViewExtras1.JavaScriptEnabled=True
    WebView1.Height=100%y
    WebView1.Width=100%x
    WebView1.LoadUrl("http://ambiotinfotech.com/pos")

by adding this to webview the page rendered correctly

Thank you Derek Johnson :)
 

Neojoy

Member
Licensed User
Longtime User
1. You should always create a new thread instead of posting to old threads.
2. You can add a javascript interface and inject javascript and add resposible javascript code to the page to communicate with your app.

My apologies!

Ok, so I got to change my page to talk with my app.

Is there some exemple?

Thanks!
 

JohnC

Expert
Licensed User
Longtime User
WebViewExtras2 has been updated to version 2.20

This updates adds support for the PermissionRequest object introduced in android API level 21.
If a webpage requests access to 'user media' (camera, mic etc) then the WebChromeClient raises an event:

PermissionRequest (PermissionRequest1 As PermissionRequest)

And in your code you can grant or deny permission to the webpage to access the 'user media'.

WebViewExtras2 version 2.20 can be found here: http://b4a.martinpearman.co.uk/webviewextras/WebViewExtras2-v2.20.zip
An example project showing the use of PermissionRequest is attached to this post.

An up to date reference for WebViewExtras2 can be found here: http://b4a.martinpearman.co.uk/webviewextras/WebViewExtras2.html

Just a suggestion....I think it would be very helpful to include the newer webviewsextras2 lib download and reference documentation links in the first post of this thread because doing a search for "Webviewextras2" did not return a "Library" thread for v2. It did return a download link thread for v2 that first had a broken link, then a good link. But I could not figure out who wrote or was supporting the never version 2 because the first post of this thread only mentioned v1. And because I have become use to library threads on this forum to at least have a link to a more recent version of a lib in the first post of an older lib, it gave me the impression v2 was written by someone else and I had no idea who.

It wasn't until I happen to accidently stumbled upon the above post which let me know that warwound did write version 2 and that documentation exists for the lib (wouldn't it also be helpful to have the link for the reference documentation of this lib to be on the first post too?)

Just sayin' :)
 
Last edited:

JohnC

Expert
Licensed User
Longtime User
Hi Warwound,

As you can see in this thread:

https://www.b4x.com/android/forum/t...port-a-native-file-upload.103331/#post-647863

Erel came up with a way to intercept the "Browse" button on a webpage (https://www.b4x.com/android/forum/threads/upload-files-with-webview.98623/) which allows us b4a developers to now do various things before uploading a file, and it has the benefit of not having to make any changes or add a webpage to the website in order to upload a file - it is compatible with the standard "browse" button on webpages.

But because his method is incompatible with your WVE lib and because my app uses various features of WVE, Erel being the very helpful guy that he is, is trying to help me manually implement the needed WVE features one-by-one into his implementation of the chromeclient. But this can become time consuming if I need more features from WVE and seems like it's reinventing the wheel you already wrote.

So, I was wondering what the chances were for you to implement Erel's browse/file upload ability into your lib to solve this situation.

Any thoughts?
 

Highwinder

Active Member
Licensed User
Longtime User
When I try to use this library to clear the webview cache, my app crashes. It also crashes when I use the following code without using the library:

Dim o As Reflector
o.Target = WebView1
o.RunMethod2("clearCache","True","java.lang.boolean")

Any ideas?
 

Alberto Iglesias

Well-Known Member
Licensed User
Longtime User
WebViewExtras updated to version 1.30

This updates adds no new methods or properties to the library.
It does however (internally) update the WebChromeClient that can be added to a WebView.

The WebChromeClient now handles web pages that make requests to use the device's geolocation features.

If you add a WebChromeClient to a WebView and display a web page that tries to use geolocation then an event is raised:

GeolocationPermissionsRequest As Int

If you want to handle this event then the Sub that you create must return an Int value to indicate whether permission has been granted or not.

Valid values are:

B4X:
MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW
MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW_AND_REMEMBER
MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW
MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW_AND_REMEMBER

All pretty self explanatory - allow or deny permission and remember or don't remember the permission.

This update will break existing code that uses the WebViewExtras addWebChromeClient method!

Versions of WebViewExtras prior to 1.30 did NOT require that an EventName was passed in the addWebChromeClient method.

The EventName is now required so that your B4A Activity can handle whether or not to allow a web page to use the device's geolocation features.

I don't like to create an update that breaks existing code but this is a very useful update and it cannot be implemented without requiring an EventName.

Additionally to enable geolocation you must use the Manifest Editor to add this line to your application:

B4X:
'End of default text.
AddPermission(android.permission.ACCESS_FINE_LOCATION)

I have updated the addWebChromeClient method documentation in the first post in this thread.

Here's some sample code:

B4X:
'   WebViewExtras geolocation demo Activity module
Sub Process_Globals
End Sub

Sub Globals
   Dim MyWebViewExtras As WebViewExtras
   Dim WebView1 As WebView
   Dim WebView2 As WebView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("layoutMain")
  
   WebView1.Height=100%y/2
   WebView1.Width=100%x
  
   '   add the WebChromeClient to WebView1
   '   with version 1.30 of WebViewExtras an EventName is now required when adding the WebChromeClient
   MyWebViewExtras.addWebChromeClient(WebView1, "MyEventName")
  
   WebView1.LoadUrl("http://html5demos.com/geo")
  
   WebView2.Top=(100%y/2)+1
   WebView2.Height=100%y/2
   WebView2.Width=100%x
   WebView2.LoadUrl("http://html5demos.com/geo")
   '   no WebChromeClient is added to WebView2
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

Sub MyEventName_GeolocationPermissionsRequest As Int
   Dim Response As Int
   Response=Msgbox2("Allow the webpage to use device geolocation features?", "Permission required:", "Allow", "", "Disallow", Null)
   If Response=DialogResponse.POSITIVE Then
      ToastMessageShow("Permission granted", True)
      Return MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW
   Else
      ToastMessageShow("Permission denied", True)
      Return MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW
   End If
End Sub

I create two WebViews, one has a WebChromeClient added and the other does not.

The WebView that has a WebChromeClient added causes the MyEventName_GeolocationPermissionsRequest Sub to be called when the web page asks for the user's geolocation.
The Sub grants or denies permission based on user input.

Tested and working on my ZTE Blade running CyanogenMod7 Gingerbread.
There is a possibility that newer versions of Android will require you to enable Geolocation in the WebView so i have updated WebViewSettings to enable that.

Updated demo code and library are attached to the first post in this thread.

Martin.

Hello my friend,

Is possible to get all elements of page from WebE?

mDocument = WebE.GetDocument

and how I can submit a click on a button of a page? in your example ?
 
Top