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:

oceanwanderlust

Member
Licensed User
Longtime User
Does WebViewExtras work with FlingableWebview too?

(I need to inspect the contents of the webpage, and determine whenever the user changes pages)
 
Last edited:

oceanwanderlust

Member
Licensed User
Longtime User
It sounds like I should use HitTestResult to determine when the user changes pages instead of injecting javascript? However, then I single click on a button on the C# webpage I am displaying, oHit.GetExtra is null. I have one line commented out from Andrew's example, wbvWeb(tabTabs.CurrentTab), which I did not understand and did not know how do declare.

Sub MyWebview_SingleTap (X As Float, Y As Float) As Boolean
Log("FlingableWebView SINGLETAP "&X&", "&Y)
' wbv = wbvWeb(tabTabs.CurrentTab)
Dim oHit As HitTestResult
oHit = MyWebview.GetHitTestResult
msDeferURL = oHit.GetExtra
 

warwound

Expert
Licensed User
Longtime User
Try to get the HitTestResult code working on a standard HTML page - a page that contains <a> anchor links ect.
Does that work?

If so then load your C# webpage into a browser and look at the source code, locate the button in the source.
How is C# creating the button - what HTML code is in the webpage?

Martin.
 

oceanwanderlust

Member
Licensed User
Longtime User
GetExtra does correctly contain a valid URL when I use a simple webpage with a simple link. However, in my c# page, I do not have an <a> anchor link, it is just a form with a button:

<form name="form1" method="post" action="SimpleAlarmsManualAlarm.aspx" id="form1">
.....
<input type="submit" name="button1" value="I Need Assistance" id="button1" class="active_button size_and_font" />
</form>

I'm trying to get the current state of the page which I can tell from the text on the button or the class I have applied to the button. Should I stay on this course or try to inject javascript? I think one of your posts said this method was better, so I tried it first.

joe
 

warwound

Expert
Licensed User
Longtime User
Look at the android documentation for HitTestResult, only a small number of HTML elements are supported and i see no mention of support for form submit elements.

So it would seem as though javascript injection is your only option.

Martin.
 

oceanwanderlust

Member
Licensed User
Longtime User
Now, I'm trying javascript injection with AJWebKit, but my injected processHTML sub is never being called. I have a feeling that I have an incorrect first argument to AddJavascriptInterface, but I don't know what the correct one should be. The HTML says this argument is: "JavascriptInterface - The Java object to inject into this WebView's JavaScript context. Null values are ignored."

joe


Dim DoorbellWebview As FlingableWebView

DoorbellWebview.Initialize("HandleDoorbellWebview")
DoorbellWebview.LoadUrl(myurl)
DoorbellWebview.JavaScriptEnabled = True
DoorbellWebview.AddJavascriptInterface(WHAT_GOES_HERE,"B4A")
Dim jsStatement As String = "B4A.CallSub('processHTML', true, document.documentElement.outerHTML)"
DoorbellWebview.executeJavascript(jsStatement)

Sub processHTML(html As String)
Log(html)
End Sub
 
Last edited:

warwound

Expert
Licensed User
Longtime User
You need to initialize a JavascriptInterface:

B4X:
Dim JavascriptInterface1 As DefaultJavascriptInterface
JavascriptInterface1.Initialize(DoorbellWebView)
DoorbellWebView.AddJavascriptInterface(JavascriptInterface1, "B4A")

Martin.
 

oceanwanderlust

Member
Licensed User
Longtime User
You need to initialize a JavascriptInterface:

B4X:
Dim JavascriptInterface1 As DefaultJavascriptInterface
JavascriptInterface1.Initialize(DoorbellWebView)
DoorbellWebView.AddJavascriptInterface(JavascriptInterface1, "B4A")

Martin.

I'm still struggling with this. I used the functional saveHTML example from elsewhere in this forum and tried to port it to AJWebKit.

My _PageFinished is never being called. Alternatively, when I try to trigger the javascript from _SingleTap, the following error occurs
java.lang.Exception: Sub processhtml signature does not match expected signature.
 

Attachments

  • SaveHTML_ajwebkit.zip
    21.8 KB · Views: 340

warwound

Expert
Licensed User
Longtime User
I got it working!
  • The AJWebKit library raises events different to the standard b4a WebView and different to WebViewExtras.
    Many events are passed the instance of the FlingableWebView as a parameter.
    This applies to Subs called by the JavascriptInterface too:
    B4X:
    Sub ProcessHTML(FlingableWebView1 As FlingableWebView, Html As String)
    	Log("ProcessHTML: "&Html)
    End Sub
  • The PageFinished event is raised by the WebViewClient and you'd not added a WebViewClient to the WebView.
    So i created and added a WebViewClient and now the PageFinished event is raised.
    The PageFinished event is also passed he instance of the FlingableWebView as a parameter by the way.

Fixed project attached.

Martin.
 

Attachments

  • SaveHTML_ajwebkit_20140517.zip
    7.1 KB · Views: 380

warwound

Expert
Licensed User
Longtime User
Hi again.

WebView, under Events:

PageFinished (Url As String)
OverrideUrl (Url As String) As Boolean
UserAndPasswordRequired (Host As String, Realm As String) As String()

WebViewExtras, search the page for Events:.

I don't think there any event for WebView back or forward navigation.
You can listen for OverrideUrl (Url As String) As Boolean events to detect the user naviagting.

You use the WebView quite a bit, you might be interested in an enhanced version i created for another forum member.
If so have a look at this post: http://www.b4x.com/android/forum/threads/webviewextras.12453/page-8#post-240663.
The AJWebKit library wraps just about any android WebKit packages that can be wrapped.
The download for AJWebKit contains an HTML reference library - search that for Events: to see which events are available.

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin - Me again!
Have you tried running your revised lib (maybe it's time to rename AJWebKit :)) under KitKat? I'm getting reports from the field that the browser in my app doesn't work, but takes forever to load even the simplest page. I don't have a physical KitKat device, and I'm getting mixed results with emulation:
  • On the standard Google AVD emulator I can't get it running properly at all under 4.4.2
  • On an Androidx86 virtual machine it runs OK, but is definitely slower to load web pages than on my other devices (whereas generally the VM works OK, much faster than the AVDs)
It looks like this is all down to the revised WebView in KitKat. I've had a look at https://developer.android.com/guide/webapps/migrating.html and tried setting the target API level in my app to 19, but that doesn't solve the problem. I'm wondering if you need to do the same in the library?

Any ideas?
Thanks
Andrew
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,

Sorry to bother you again. Hope work is going well.

I'm still trying to get to the bottom of the problems under KitKat. Some documentation on the web seems to suggest the problem is a deadlock in the cookie handling in the KitKat webview. I'm therefore wondering whether turning cookies off might help, but I can't see how to achieve this in your new library. Can we do this readily with the library?

Thanks
Andrew
 

warwound

Expert
Licensed User
Longtime User
@andrewj

Have you seen my CookieManager?
It's method SetAcceptCookies (Accept As Boolean) might be what you need.

You didn't reply to my PM dated 5th June regarding your post dated 4th June - did you receive that PM?

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,

Thanks for the reply. Unfortunately setting .SetAcceptCookies(False) doesn't seem to do anything to solve the KitKat problem. Do I need to do anything special given that I have multiple instances active of the modified Webkit?

Andrew
 

warwound

Expert
Licensed User
Longtime User
Hi Martin,

Thanks for the reply. Unfortunately setting .SetAcceptCookies(False) doesn't seem to do anything to solve the KitKat problem. Do I need to do anything special given that I have multiple instances active of the modified Webkit?

Andrew


To be honest i don't know.
You stated "Some documentation on the web seems to suggest the problem is a deadlock in the cookie handling in the KitKat webview.", can you post a link to what you have been reading?

Martin.
 

andrewj

Active Member
Licensed User
Longtime User
Hi Martin,
I may have fixed the problem. I have code which updates a progress indicator in the wbvWeb_ProgressChanged event, which is the main processing which happens while a page is loading rather than after the event. I have disabled this for KitKat (but left it running for other versions) and suddenly it works. I guess we'll have to avoid any such intermediate processing until the KitKat webview is sorted out.

Thanks for your help
Andrew
 

ArminKH

Well-Known Member
Hi
Is there any way to catch or disable any alert or modal dialogs when username.or password is not correct on login to a site?
When my user or pass is wrong webview show me an alert but i want to show my custom message
Tnx for your response
 

warwound

Expert
Licensed User
Longtime User
@arminkh

  • If you use WebViewExtras AddWebChromeClient then you are adding support for javascript dialogs to the WebView.
  • Don't add the WebChromeClient to the WebView and i'm sure you will get no javascript dialogs.

Look at the documentation for the WebChromeClient: http://developer.android.com/reference/android/webkit/WebChromeClient.html
Look at it's onJsAlert() and onJsPrompt() callback methods.

You need a custom WebChromeClient that implements it's own callbacks for the javascript dialogs and from there you can display your own message - or take whatever action you desire.

A custom WebChromeClient would be created as a java class and then compiled into a b4a library.

HTH.
 
Top