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

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
Thanks for the info. Is there a quick way to check my API version? I updated everything about a month ago, so I should be running latest versions, but if there's a flag I need to set in B4A or something I may have missed it.
Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
In the b4a IDE select menu option Tools > Configure Paths.
The path to the android.jar file defines which version of android you are compiling with.

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
If I understand right, I'm using v19:

C:\Program Files\adt-bundle-windows-x86_64\sdk\platforms\android-19\android.jar

Is this correct?
If so, should I be able to use text select functionality by default, or do I have to enable it in some way?
Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
Hi Martin,
If I understand right, I'm using v19:

C:\Program Files\adt-bundle-windows-x86_64\sdk\platforms\android-19\android.jar

Is this correct?
If so, should I be able to use text select functionality by default, or do I have to enable it in some way?
Thanks
Andrew

From what i've read the answer is yes.
But to be honest i'm not at all sure!

Does a long press on a WebView in your app cause any clipboard related stuff to appear?

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
Yes, if I disable the LongClick() event, then I get text selection functionality by default.

However, this then raises the question of how I should enable my required LongClick functionality. I don't see how I can disable my handler at runtime, so we might just need a variable in your Wrapper so the webview can be in either "select mode" (longclick disabled) or "longclick" mode, and I can toggle between them in my code.

I still can't do anything with an image in the text, but that's another issue...
Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
The java/android OnLongClickListener returns a boolean value to indicate whether it has handled the long click event or not.

If you have a sub that handles the long click event then - within the WebView - the listener is hardcoded to return True.
It'd be better if the WebView long click event returned a boolean value to indicate whether the sub has handled the long click.

This way a user could long click the WebView, a long click event would be raised.
Your sub could return False and presumably the WebView would enter clipboard selection mode - and if your sub returned True then the clipboard mode would not be enabled.

I'll have a look at whether the default b4a long click listener can be replaced with a listener that returns a boolean value when i start coding a bit later.

You didn't mention whether your app needs to support older versions of android - version before 11 (Honeycomb) or whether support for Honeycomb and later is all that's required.
If you can let me know what android versions your app needs to support i can create that custom WebView for you.

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Thanks Martin,
I don't think we need to support anything before v11. It would be ideal if it didn't crash running on an older device, but if it doesn't "work" that's no great loss.
Andrew
 

warwound

Expert
Licensed User
Longtime User
@andrewj

I have another question...
The FlingableWebView raises the event:

LongPress(X As Float, Y As Float)

If you have a sub that listens for this event, does that prevent the clipboard being enabled just as having a LongClick event sub prevents the clipboard being enabled?
(Can you add such a sub to test this if you do not already have a this sub?)

If so, do you actually use the LongPress event in your app?

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
Yes, I do use the LongPress event, and it looks like once you are listening it disables the clipboard functionality. To get the default copy behaviour working I had to comment out my handler sub altogether. Does that answer your question?
Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
Right i have attached a project for you to take a look at.

I decided that a FlingableWebView with clipboard functionality and then WebViewExtras2 used to enable GeoLocation would be best.

So far though the GeoLocation simply refuses to work in KitKat.
Works on Gingerbread (android 2.3.7) and Jelly Bean (android 4.3.1) but not KitKat (android 4.4.2).

On KitKat either the 'allow geolocation' prompt appears and the webpage requesting location fails to load.
Or the webpage requesting permission loads but no prompt for 'allow geolocation' appears which means the GeoLocationPermissionRequest event is not being raised.

Anyway i'll attach the project and library files and let you have a play and await your comments and findings.

I'll create a more detailed post about the changes to the FlingableWebView and about WebViewExtras2 tomorrow.

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
Looks hopeful. The geolocation stuff now works fine. That might have been down to an error in the permissions in my project.

Two questions:
1. How do I enable / disable LongCLick() processing, because I do need that in my project most of the time?
2. I'm trying to use your trick for returning the page title using JavaScript, but the handler no longer fires. It looks like you've changed the JavaScript calling logic from WebViewExtras1. What sub name should be doing the handling?

Thanks very much for all your effort on this,
Andrew
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,

I've made an odd discovery - I've gone back to the old versions of your libraries temporarily, and now I seem to have long click behaving almost as expected - if I long-click on a URL it triggers my code for the drop-down menu, but if I long-click on plain text it activates selection mode. I'll investigate further tomorrow, but your original code might actually work!

Regarding your new versions I wonder if there's an opportunity to create a much simpler programming model. I was hoping that you would extend the FlingableWebView with the WebViewExtras methods and events built in , so users only have to define and use a single object. Also I preferred the previous model for "AddChromeClient", and I'm not sure why you now need a separate object for this.

Anyway, very grateful for all your good work. I'll report back further tomorrow.

Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
Morning Andrew.

I've now got time to document what i've done so...

First downloaded the updated b4a project attached.
Open both FlingableWebView.html and WebViewExtras2.html in your browser.

FlingableWebView
  • Combines flingable functionality with clipboard functionality.
    The method EnableClipboardMode is used to enable clipboard mode.
    On newer devices (Honeycomb and later), a long press on the WebView may enable clipboard mode, but if your LongPress or LongClick event subs prevent that then you can enable it using this method.
  • The LongClick event handling sub must now return a Boolean value to indicate whether it has consumed the event.
    This should help you to allow your users to enable using a long press (see above) as your LongClick sub can return False and the default action to enable clipboard mode should then happen.
  • The event ClipChanged (ClipboardText As String) is raised when text is detected in the clipboard.
    I changed the event name to more logically match the underlying (java) event.
  • The FlingableWebView does not set a WebViewClient - you need to do this yourself with WebViewExtras2.
    The WebViewExtras2 DefaultWebViewClient raises many more events that the default b4a WebView's WebViewClient.
  • The FlingableWebView does not change any settings of the (android) WebView.
    The b4a WebView enables javascript, plugins and built in zoom controls by default, the FlingableWebView does not.
    Again you need WebViewExtras2 to customise these and many more WebSettings.

I could add all of the WebViewExtras2 code to the FlingableWebView but any future updates to WebViewExtras2 would require me to update and re-compile your FlingableWebView.
Better to keep them separate to make maintenance easier.

WebViewExtras2 uses a more modular and object oriented approach - you create instances of DefaultWebViewClient, DefaultJavascriptInterface etc and add or set them to the WebView.
If i or another developer created a different WebViewClient, JavascriptInterface etc with different functionality then you can use the different functionality with minimal code changes.
Whereas the original version of WebViewExtras with it's addJavascriptInterface etc methods lacks any such 'future proofing'.

Disabling/enabling LongClick processing should now be possible in your code as you can return a Boolean value to allow the default LongClick event action to be taken instead of it being hardcoded to use the b4a sub action.

FlingableWebView has been updated so overwite your existing version with the attached version, WebViewExtras2 has not been updated.

Testing the updated b4a project on my KitKat device it now works perfectly.
I suspect that adding a WebViewClient has fixed the problems i reported yesterday.

The project shows how to get the loaded webpage HTML to a b4a sub you should be able to kodify this to get the loaded webpage title instead.
WebViewExtras2 does have a method GetTitle As String which if called after the webpage has loaded should be an easier option though.
The WebChromeClient can also be updated to raise events when:
  • A new favicon has been received, see onReceivedIcon(WebView view, Bitmap icon).
  • A new document title has been received, see onReceivedTitle(WebView view, String title).

Look here to see all the possible WebChromeClient events: http://developer.android.com/reference/android/webkit/WebChromeClient.html.
You might also want to check out what all the possible WebViewClient events are: http://developer.android.com/reference/android/webkit/WebViewClient.html.

WebViewExtras2 enables many of these events but not all of them, i can add more events if required.

Have a read through the 2 HTML documents and have a look at the demo project and let me have your comments.

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
Thanks for all the work. This looks very comprehensive. I need to take time to assimilate what you've done, and I need to think through whether the programming model works with it all separate (I have a tabbed browser and I'm therefore managing arrays of components, which further complicates things...). I'll try and have a proper look at this tonight/tomorrow and come back to you.
Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
OK.

If you truly want the FlingableWebView and WebViewExtras2 libraries merged into one i can do that.
But just watch that at a possible future point in time you might regret it if there's a WebViewExtras2 update and i'm not available to also update your FlingableWebView...

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
Quick question - what does the "WebViewClient" do and why does it need to be separate?

I do think that the number of separate objects I'm going to have to work with in my browser is going to be unmanageable. I wonder if there's a compromise position: you keep two separate libraries, but when you initialise the FlingableWebView you set all these objects by default (with the same event name as the parent control) and you expose them through the FlingableWebView's interface, so I can write code like

B4X:
MyWebView.Extras.GetSettings.SetGeolocationEnabled(True)
or
B4X:
MyWebView.ChromeClient.GEOLOCATION_PERMISSION_ALLOW

However, in order to allow for future flexibility you could provide set-er methods to allow a programmer to override with different objects if he wants.
Would that be a good model?

Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
I think you have two 'elegant' options for good readable and maintainable code:
  • I combine the FlingableWebView and WebViewExtras2 libraries.
  • You create a custom Type and work with a collection or array of this Type.
    For example:
    B4X:
    Sub Process_Globals
       Type BrowserTab( _
         WebChromeClient As DefaultWebChromeClient, _
         WebView As FlingableWebView, _
         WebViewClient As DefaultWebViewClient)
    End Sub

The Type option is quick and easy to implement, is future proof if i update WebViewExtras2 and also allows you to add new properties at a future date.

Martin.
 

chrjak

Active Member
Licensed User
Longtime User
please remove the mark&copy feature like i said some posts before
 

warwound

Expert
Licensed User
Longtime User
please remove the mark&copy feature like i said some posts before

Well in all of my research over the past few days i've found no way to disable the clipboard functionality that is available with Honeycomb and later versions of android.

If you add a Sub to your Activity that listens for the WebView LongClick event that might prevent the WebView from enabling the clipboard mode.
The Sub doesn't have to do anything:

B4X:
Sub MyWebView_LongClick
    ' do nothing
End Sub

Try that.

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
I think my vote would be for combining the two libraries. I don't know how other users are positioned, but I would guess anyone using the one is probably happy using the other.

Otherwise the Type option might be an OK solution. It's bordering on what I was thinking of, writing a wrapper class for your different libraries, but is probably simpler. The disadvantage of the Type is that then I have to use an extra level of indirection even to access the basic web view properties.

I don't think you answered my question about DefaultWebViewClient. What is this? I haven't seen any reference to it elsewhere, and your sample code doesn't do anything with it as far as I can see...

Thanks
Andrew
 
Top