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

air cover

Member
Licensed User
Longtime User
ProcessHTML checks if the page is properly displaying one of two webpages, if not, it starts yet another Timer2 to try to reload the page again quickly and maybe fiddle with the wifi. My problem is that eventually _PageFinished is not called so ProcessHTML never gets called, even though Timer3 IS being called and is supposed to be reloading WebView1 every few minutes.

Sub ProcessHTML(FlingableWebView1 As FlingableWebView, Html As String)
If Html.Contains(ACTIVE_STATE_STRING) = True Then
Timer1.Enabled = False
Else If Html.Contains(INACTIVE_STATE_STRING) = True Then
If Timer1.Enabled = False Then
Timer1.Enabled = True 'this timer does a JavaScript Click() on the page in about an hour...
End If
Else
Log("PAGE ERROR")
Timer2.Enabled=True 'this timer tries to refresh the webpage in ~10 seconds and also fiddles with the wifi
End If
End Sub

Would you please post your Timer1 code for reference?
 

marcel

Active Member
Licensed User
Longtime User
I get with some URL's a exception.

B4X:
java.lang.NullPointerException
    at uk.co.martinpearman.b4a.webviewextras.WebViewExtras$1.onGeolocationPermissionsShowPrompt(WebViewExtras.java:168)
    at com.android.webview.chromium.WebViewContentsClientAdapter.onGeolocationPermissionsShowPrompt(WebViewContentsClientAdapter.java:553)
    at com.android.org.chromium.android_webview.AwContents.onGeolocationPermissionsShowPrompt(AwContents.java:1848)
    at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
    at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:24)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5139)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612)
    at dalvik.system.NativeStart.main(Native Method)
Fatal signal 6 (SIGABRT) at 0x00000fa0 (code=-6), thread 4000 (.yazula.android)

I am using from webextras:

B4X:
MyWebViewExtras.addJavascriptInterface(WebView1,"B4A")
MyWebViewExtras.addWebChromeClient(WebView1, "")

If I remove the line:
MyWebViewExtras.addWebChromeClient(WebView1, "")

Then I have no problems anymore
 

marcel

Active Member
Licensed User
Longtime User
I get with some URL's a exception.

B4X:
java.lang.NullPointerException
    at uk.co.martinpearman.b4a.webviewextras.WebViewExtras$1.onGeolocationPermissionsShowPrompt(WebViewExtras.java:168)
    at com.android.webview.chromium.WebViewContentsClientAdapter.onGeolocationPermissionsShowPrompt(WebViewContentsClientAdapter.java:553)
    at com.android.org.chromium.android_webview.AwContents.onGeolocationPermissionsShowPrompt(AwContents.java:1848)
    at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
    at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:24)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5139)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612)
    at dalvik.system.NativeStart.main(Native Method)
Fatal signal 6 (SIGABRT) at 0x00000fa0 (code=-6), thread 4000 (.yazula.android)

I am using from webextras:

B4X:
MyWebViewExtras.addJavascriptInterface(WebView1,"B4A")
MyWebViewExtras.addWebChromeClient(WebView1, "MyEventName")

If I remove the line:
MyWebViewExtras.addWebChromeClient(WebView1, "MyEventName")

Then I have no problems anymore

Add geolocation function:

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

This fixes the issue.
 

warwound

Expert
Licensed User
Longtime User
You see your 'startmarker' Marker on the map do you and it is draggable?

If you update your changeCoordPersona function to this:

B4X:
function changeCoordPersona(scoord) {
    console.log("changeCoordPersona called");
        B4A.CallSub("ChangeCoordPersona",true,scoord);
}

Now look in the b4a log when you drag your Marker - do you see 'changeCoordPersona'?
 

warwound

Expert
Licensed User
Longtime User
Are you compiling using obfuscated mode?
If so change the sub name - add an underecore somewhere in it's name.
For example: change_CoordPersona.
That'll prevent the sub name from being obfuscated - if it's obfuscated then the javascript is calling a sub that doesn't exist.
 

warwound

Expert
Licensed User
Longtime User
PS.
the code [console.log("xxxxxxxxxx")] as it works ? i don't see nothing in log.

Depends on which version of WebViewExtras you're using.
The newest version doesn't automatically log the console out whereas the older versions did.

There's a code example HERE that shows how to handle console messages in the newer versions of WebViewExtras.
 

Siam

Active Member
Licensed User
Longtime User
Hello,
I dont give up :p:D
by coincidence I found out that the file upload with Android 5.0 works!!! after several hours i have found the solution.

Add in the Manifest.xml :

B4X:
 android:targetSdkVersion="20"

z.b.
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="20"/>

With this simple modification works The FileUpload with The Samsung galaxy S5 with Android 5.0.0

B4X:
Touch event's action is 0x1 (deviceType=0) [pCnt=1, s=] when=420713087824000
Delivering touch to (30257): action: 0x1, toolType: 1
openFileChooser Jelly Bean
AcceptType: */*
Capture:


If The targetsdkVersion is bigger than 20 following Happens without Firering the FileChooser.

B4X:
Input event: value=1
Touch event's action is 0x0 (deviceType=0) [pCnt=1, s=0.19698 ] when=420716498963000
Delivering touch to (30257): action: 0x0, toolType: 1

or:

Input event: value=0
Touch event's action is 0x1 (deviceType=0) [pCnt=1, s=] when=420265132717000
Delivering touch to (30257): action: 0x1, toolType: 1

I hope that this helps a littlebit to get in Future a Library that works with android 5 and bigger. :rolleyes:

For the moment i think is ok :)



Andy
 

warwound

Expert
Licensed User
Longtime User
WebViewExtras updated to version 1.42

The WebChromeClient currently raises the event:
ProgressChanged (NewProgress As Int)

This update adds a new event:
ProgressChanged2 (WebView1 As WebView, NewProgress As Int)

Much like the existing ProcessedChanged event but the event sub is also passed a reference to the WebView.

Version 1.42 of WebViewExtras is attached to the first post of this thread.
 

warwound

Expert
Licensed User
Longtime User
How to get the webview scrolling top value? like getScrollY

The getScrollY method isn't exposed by WebViewExtras.
You should be able to use JavaObject to call this method instead:

B4X:
Dim JavaObject1 As JavaObject=MyWebView
Dim ScrollY As Int=JavaObject1.RunMethod("getScrollY", Null)
 

fash866

Member
Licensed User
Longtime User
The getScrollY method isn't exposed by WebViewExtras.
You should be able to use JavaObject to call this method instead:

B4X:
Dim JavaObject1 As JavaObject=MyWebView
Dim ScrollY As Int=JavaObject1.RunMethod("getScrollY", Null)
thanks!
 

warwound

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
 

Attachments

  • PermissionRequest.zip
    7.9 KB · Views: 400

warwound

Expert
Licensed User
Longtime User
Yes stuff like javascript work the same regardless of whether you've opened the webpage in it's mobile or desktop mode.
Obviously javascript must be enabled in your WebView settings.
 

warwound

Expert
Licensed User
Longtime User
You need to see the WebView console output to debug this.
To see that output you can use WebViewExtras2 library:
http://b4a.martinpearman.co.uk/webviewextras/WebViewExtras2-v2.20.zip

Create and add a DefaultWebChromeClient to your WebView.
The WebChromeClient will raise an event 'ConsoleMessage' whenever an error occurs in the WebView.
Code example here:
https://www.b4x.com/android/forum/t...oaded-website-into-webview.11232/#post-354156

Now try to execute some javascript and see what ConsoleMessage(s) are passed in this event.
You should hopefully see what's happening.
 

peacemaker

Expert
Licensed User
Longtime User
Hi, warwound,

Is it possible to dynamically update HTML by document.getElementById and update somehow by .innerHTML = new_string ? Without full reloading.
Any sample, please ?
 

warwound

Expert
Licensed User
Longtime User
Hi, warwound,

Is it possible to dynamically update HTML by document.getElementById and update somehow by .innerHTML = new_string ? Without full reloading.
Any sample, please ?

Hi.

That is all pretty much 'standard javascript and DOM manipulation' so all possible.
I'm afraid I'm too busy with work to put any example together for you.

Can you describe what you're hoping to achieve?

Martin.
 

peacemaker

Expert
Licensed User
Longtime User
Hi.
Can you describe what you're hoping to achieve?
Martin.
THanks for confirmation.
I hope to make dynamical table update with data, getting from a web-site XML.
 
Top