B4A Library WebViewExtras

warwound

Expert
Licensed User
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.basic4ppc.com/forum/addi...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.basic4ppc.com/forum/addi...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
 

Attachments

Last edited by a moderator:

warwound

Expert
Licensed User
Scrolling by page is perfect, but how do we know how many pages there are?
Hi.

I can find no method that will return how many pages are in a particular WebView.

I think you need to look at the return value from a call to pageDown() or pageUp().
If the call returns a boolean false then the scroll has failed - that might(!) indicate that there are no more pages to scroll through.

Martin.
 

Cableguy

Expert
Licensed User
Hi Martin...

I really need some kind of WebView.GetDocument alike method...So I started seaching and found these 2 webpages...

Xebra Labs: Extract HTML from Android webview

Android WebBrowser using WebView « PocketMagic

In them thay state that using JSInterface along with WeView it is possible to retrieve the pages html...
Anyway of adding this to your dll?

BTW...Why not create a WebViewAdv dll, with all these methods included as well as the "native" basic WebView methods???
 

warwound

Expert
Licensed User
Hi.

Look at this thread you started a few days back:

http://www.basic4ppc.com/forum/bugs-wishlist/12404-wish-webview-documenttext-get.html#post69709

And my related post:

http://www.basic4ppc.com/forum/basi.../9400-save-webview-html-file-2.html#post56406

With WebViewExtras or JSInterface you can execute javascript AFTER the webpage has loaded and that javascript can send the page HTML content as a string to a B4A Sub.

But the mechanism is asynchronous - i can't create a getter method that will return the webpage HTML.

Asking the webpage to send it's HTML to a B4A Sub (and then taking action) is the best option available.

As for creating a new custom WebView library instead of a library (such as WebViewExtras) that extends the default B4A WebView...

Have a read here http://www.basic4ppc.com/forum/libraries-developers-questions/11106-decompiled-webviewwrapper.html

agraham is right - it's better to leave the default views (WebView or whatever) as native B4A views that get updated as B4A develops and create libraries to increase their functionality rather than taking on the (ominous!) task of creating and updating custom B4A views.

Martin.
 

warwound

Expert
Licensed User
Hi all.

WebViewExtras is now updated to version 1.1.

No new methods to document but i have updated it's addWebChromeClient method.

This updated WebChromeClient overrides the default onExceededDatabaseQuota method.
Detailed info can be found here: WebChromeClient | Android Developers.

This means that we can now properly enable and use the HTML5 Database Storage API in a WebView.

I have updated my WebViewSettings library too with 5 new methods and you'll need both WebViewSettings and WebViewExtras to enable the database storage API:

B4X:
Sub Globals
   Dim WebView1 As WebView
   Dim WebViewExtras1 As WebViewExtras
   Dim WebViewSetting1 As WebViewSettings
End Sub

Sub Activity_Create(FirstTime As Boolean)
   WebView1.Initialize("WebView1")
   
   WebView1.JavaScriptEnabled=True
   WebViewExtras1.addJavascriptInterface(WebView1, "B4A") ' NOT ESSENTIAL
   WebViewExtras1.addWebChromeClient(WebView1)
   WebViewSetting1.setDatabaseEnabled(WebView1, True)
   '   WebViewSetting1.setDOMStorageEnabled(WebView1, True)
   
   Log("DefaultWebViewDatabasePath: "&WebViewSetting1.getDatabasePath(WebView1))
   '   the WebView will fail to create any databases if the database path is NOT set
   WebViewSetting1.setDatabasePath(WebView1, "")
   Log("NewWebViewDatabasePath: "&WebViewSetting1.getDatabasePath(WebView1))
   
   
   Activity.AddView(WebView1, 0, 0, 100%x, 100%y)
   WebView1.LoadUrl("file:///android_asset/my_webpage.htm")
   
End Sub
Version 1.1 of WebViewExtras is attached to post #1 in this thread.

I shall post a demo project using the new database storage API within the next few days.

Martin.
 

warwound

Expert
Licensed User
WebViewExtras updated to version 1.20

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 updated WebChromeClient enables web pages with file upload forms to be properly handled.
Prior to this update if your WebView displayed a page with a file upload form, the user would not be able to select a file from the device to upload.
With this update the user can now select a file to upload.

Version 1.20 of WebViewExtras is attached to the first post in this thread.
The attachment also contains a demo of the new file upload capability.

Martin.
 

bluedude

Well-Known Member
Licensed User
Could it be used like this

Hi,

I'm looking into adding new UI elements by using webviews and jQuery interface elements. Would below code work?

script>
$(function() {
$(".knob").knob(
{
'change':function(e){
console.log(e);
B4A.CallSub('changeKnob', true)
}
}
)

;
});
</script>
 

warwound

Expert
Licensed User
I see no reason why it wouldn't work.

As long as jQuery doesn't use any javascript that is not supported by the WebView there should be no problems.

WebView is quite up to date with it's level of javascript support so jQuery should be fine.

Martin.
 

bluedude

Well-Known Member
Licensed User
Got that working, now I need to change a value in the html file

Hi,

That works! Now I want to execute some javascript to change a value, that is not in your samples.

Is there a simple execute javascript sample?

Cheers,
 

warwound

Expert
Licensed User
This is the basic code structure to execute some javascript:

B4X:
Dim Javascript As String
Javascript="alert('Hello World!')"
MyWebViewExtras.executeJavascript(WebView1, Javascript)
That won't actually do anything unless you've added a WebChromeClient to your WebView as the default B4A WebView does not display modal dialogs such as alert.

Anyway search the forum for 'executeJavascript' and you'll find some posts with various examples.

Martin.
 

warwound

Expert
Licensed 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.
 

NeoTechni

Well-Known Member
Licensed User
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)
How about a Callsub that takes a list of parameters, that way you only need 1 version and it can take any number of parameters.
 

warwound

Expert
Licensed User
How about a Callsub that takes a list of parameters, that way you only need 1 version and it can take any number of parameters.
Unfortunately that's not possible.

You cannot pass a (javascript) Array to the CallSub method.

Only basic types such as strings, booleans and numbers can be used.

There's a blog HERE that you might find interesting.
It documents some of the quirks and limits of the JavascriptInterface.

Passing a single string to CallSub where that string is a JSON object containing any number of values of any valid type looks like a flexible solution.

Martin.
 

vitneum

Member
Licensed User
filedialog....

:sign0085:
Hi Everyone~
"file upload dialog" function well does it work?
In my case, "dialog" that will be displayed.
but, the files have not been able to choose.:BangHead:
 

warwound

Expert
Licensed User
:sign0085:
Hi Everyone~
"file upload dialog" function well does it work?
In my case, "dialog" that will be displayed.
but, the files have not been able to choose.:BangHead:
I've just updated the demo code in the attachment, it lacked an EventName parameter to work with the latest version of WebViewExtras:

B4X:
Sub Activity_Create(FirstTime As Boolean)
   WebView1.Initialize("WebView1")
   
   '   no EventName is used as we're not listening for the GeolocationPermissionsRequest event
   WebViewExtras1.addWebChromeClient(WebView1, "")
   
   Activity.AddView(WebView1, 0, 0, 100%x, 100%y)
   
   WebView1.LoadUrl("http://cgi-lib.berkeley.edu/ex/fup.html")
End Sub
Presumably you've added an EventName as your code compiles.

Can you zip and upload your project so i can try it myself?

And can you post what device you're running it on - is it an Android device running HoneyComb or ICS OR is it a device running a version of Android prior to Honeycomb?

Martin.
 

vitneum

Member
Licensed User
I was just run your source code to the emulator.

Select the file and return to first screen.

File is not selected.
and Click the screen also does not react.

emulator version 2.2 and 2.3.3

TT...
 
Top