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

  • WebViewExtras_v1_42.zip
    7.8 KB · Views: 7,801
Last edited by a moderator:

LordZenzo

Well-Known Member
Licensed User
Longtime User
Hello everyone
I'm creating a simple app
I need to login
I use "WebExtra.PostUrl (" https://www.robedacartoon.it/login "," [email protected]&passwd=xxxpassword ".GetBytes (" UTF8 "))"
the email used as userName is entered in the field, the password no! I checked the INPUT field names and they are right
a suggestion?
 

Lello1964

Well-Known Member
Licensed User
Longtime User
Hello,
i'm tryning to open xml file with xls scheme using WebViewExtras lib,
whius is my code :
B4X:
Sub Globals
    Dim WebView1 As WebView
   Dim WebViewExtras1 As WebViewExtras
   Dim WebViewSetting As WebViewSettings
   Dim DBFileDir As String                   : DBFileDir =RP1.GetSafeDirDefaultExternal("") 
End Sub

Sub Activity_Create(FirstTime As Boolean)
   WebView1.Initialize("WebView1")
   
   WebViewExtras1.addWebChromeClient(WebView1, "")
   Activity.AddView(WebView1, 0, 0, 100%x, 100%y)
   
   Dim url="file:///" & File.Combine(DBFileDir, "IT00430310672_0001N.xml")
   Log("Loading " & url)
   WebView1.LoadUrl(url)
   
End Sub
[code/]

both file xls and xlm are ... /Android/data/xmkl.test/files/

i have this error :

Logger connesso a:  Xiaomi Redmi Note 3
--------- beginning of system
--------- beginning of main
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
Loading file:////storage/emulated/0/Android/data/xmkl.test/files/IT00430310672_0001N.xml
Unsafe attempt to load URL file:///storage/emulated/0/Android/data/xmkl.test/files/fatturapa_v1.2.xsl from frame with URL file:///storage/emulated/0/Android/data/xmkl.test/files/IT00430310672_0001N.xml. 'file:' URLs are treated as unique security origins.
 in file:///storage/emulated/0/Android/data/xmkl.test/files/IT00430310672_0001N.xml (Line: 2)
** Activity (main) Resume **

how can i solve ?
 

Devv

Active Member
Licensed User
Longtime User
hello


i am using webview extras 1.42
we used these funtions in our app
AddJavascriptInterface
addWebChromeClient
executeJavascript
Sub WebView_Main_ProgressChanged(NewProgress As Int)

we need to use also flingable webview

we need LongPress (X As Float, Y As Float)

can we use the two libraries together ?
 

DonManfred

Expert
Licensed User
Longtime User
can we use the two libraries together ?
1. ALWAYS create a new thread in the questionsforum for any issue you have. Posting to existing threads is a mistake.
2. Did you tried it and you got any error? 'Which one?
 

Amin.D

New Member
Hi
how to use xpath code in WebViewExtras
for example

JavaScript:
document.evaluate( xpathExpression, contextNode, namespaceResolver, resultType, result );

document.evaluate('count(//p)', document, null, XPathResult.ANY_TYPE, null )

i try
B4X:
wbx.executeJavascript(wb,"test.CallSub('print',true,document.evaluate('//h2', document, null, XPathResult.ANY_TYPE, null ))")
and
output error :

undefined
 
Last edited:

drgottjr

Well-Known Member
Licensed User
Longtime User
this is an xpath error. you need to correct it. it's not the fault of webviewextras, which simply facilitates your executing javascript in a webview. (note: webview is not a full browser, so its support of javascript may not be the same as that of chrome. in any case, that, too, is not webviewextras' fault.) the error is clear enough; you need to define documentNode.
 

Amin.D

New Member
the error is clear enough; you need to define documentNode.
Tnx
Yes
I edit code to :

B4X:
wbx.executeJavascript(wb,"test.CallSub('print',true,document.evaluate('//h2', document, null, XPathResult.ANY_TYPE, null ))")

and output log :

undefined

(note: webview is not a full browser, so its support of javascript may not be the same as that of chrome. in any case, that, too, is not webviewextras' fault.)
What do you suggest?
 
Last edited:

JohnC

Expert
Licensed User
Longtime User
Adding the ChromeClient to webview (as explained in tip #1 in my signature below) will help make webview more like a chrome browser.
 

Amin.D

New Member
Tnx johnC

But I Added

My Code :
B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    Dim wb As WebView
    Dim wbx As WebViewExtras
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Activity.LoadLayout("Layout")
    wb.Initialize("wb1")
    wbx.addJavascriptInterface(wb,"test")
    wbx.addWebChromeClient(wb,"wbx")
    ProgressDialogShow("  Please Wait  ")
  
'    wb.LoadUrl("http://127.0.0.1")
    wb.LoadUrl("https://www..........org")
'    wb.LoadHtml("'file:///android_asset/index.html")
  
'    If File.Exists(File.DirAssets, "index.html") Then  Log("yes") Else Log("not found")
  
    End Sub


Sub      wb1_PageFinished (Url As String)
    ProgressDialogHide
    wbx.executeJavascript(wb,"test.CallSub('print',true,document.getElementById('ctl00_cphTop_Sampa_Web_View_TimeUI_ShowDate00cphTop_3734_lblGregorianNumeral').innerText)")
'    wbx.executeJavascript(wb,"test.CallSub('print',true,document.evaluate('html/body', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ))")
    '###########################################
    '    wbx.executeJavascript(wb,"test.CallSub('print',true,document.getElementById('ctl00_cphTop_Sampa_Web_View_TimeUI_ShowDate00cphTop_3734_lblHijriTitle').innerText)")

    wbx.executeJavascript(wb,"test.CallSub('print',true,document.evaluate('//h2', document, null, XPathResult.SRING_TYPE, null ))")
    wbx.executeJavascript(wb,"test.CallSub('print',true,document.evaluate('.//*', document, null, XPathResult.ANY_TYPE, null ))")
    End Sub

Sub print (txt As String)
    Log(txt)
End Sub
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
Hi,

A WebChromeClient handles many things, the WebChromeClient that WebViewExtras adds to your WebView enables:

-- Logging of javascript console messages and errors to the B4A log.

How I can capture this to create a Javascript log in a EditText ?

Actually the log show a strange syntax, in File:/// but without name. Is this because I load a Javascript as string inside a page?
I explain better, I read a file .js from DirAssets with File.ReadString() method to a String variable. Attached the log output.

Many thanks

Logger connesso a: asus ASUS_Z00LD
--------- beginning of main
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
Text size: 9
** Activity (main) Resume **
Page changed: 1
THREE.WebGLProgram: Program Info Log: --From Vertex Shader:
--From Fragment Shader:
Link was successful.
�� in file:/// (Line: 14237)
THREE.WebGLProgram: Program Info Log: --From Vertex Shader:
--From Fragment Shader:
Link was successful.
�� in file:/// (Line: 14237)
THREE.WebGLProgram: Program Info Log: --From Vertex Shader:
--From Fragment Shader:
Link was successful.
�� in file:/// (Line: 14237)
THREE.WebGLProgram: Program Info Log: --From Vertex Shader:
--From Fragment Shader:
Link was successful.
�� in file:/// (Line: 14237)
THREE.WebGLProgram: Program Info Log: --From Vertex Shader:
--From Fragment Shader:
Link was successful.
�� in file:/// (Line: 14237)
PageFinished (file:///)
 

drgottjr

Well-Known Member
Licensed User
Longtime User
you are asking about 2 different things:
1) how to capture output from the log and show it in an edittext view. actually, this alone involves 2 different questions.
2) why does the output itself show strange characters and missing (expected) text?


to assign log output to some variable you need to override the
behavior of the webchromeclient's onConsoleMessage() method. if you do that, you
can raise an event in your b4a app and assign the output from the event to some variable.
once you have that, you can keep simply adding that value to any previous text value of the
edittext view. (or you could use a stringbuilder - my recommendation).

if you only use webviewextras' chromeclient to send console messages to the log, then it it's
easy to extend the chromeclient with a javaobject and a few lines of java. if you use the
chromeclient for other things, then you would have to implement them all yourself. you can't have
webviewextras' client and your own at the same time. there is another webview library
(ultimatewebview) available. it may or may not allow you to capture log output as a b4a variable.
in any case, extending a webchromeclient for the purpose of capturing the log and assigning
the output to a variable is not difficult.

as to why the output you show is strange and/or missing something you're expecting, it's difficult to
say without seeing what you're doing. i can tell you that the "?"'s inside a black diamond are
indicative of character set issues. the log is attempting to print a character for which its character
code has no appropriate character. this usually involves issues between utf8 and ansi. without seeing
your code and knowing the url of the website, there isn't much more to say beyond what is often said
in the forum (and in android's documentation): a webview is not meant to be used as a substitute for a browser.
 

max123

Well-Known Member
Licensed User
Longtime User
Many thanks @drgottjr for your detailed explanation, I need to study it better because my english is not so good.
Because you asked me I went to explain better what I do from begin, if it is a too long story for you, please, just past next where I explain what I do now and because I need to redirect JS console to a TextField.

I managed with threejs these days, because I wrote an app to control 3D printers, CNC machines, laser cutter machines and next I will add foam cutter machines.

The app can simulate work of these machines by loading gcode files created with various cad/cams, for printing are slicers like eg. slic3r, Cura, PrusaSlicer, Simplify3D, for CNC CAD/CAM like RhinoCam, ArtCam and others, and for laser various software like LaserGRBL, LaserWeb and others.

My app can load all these gcode files, in the Settings need to set what machine to use and after restart it load the selected layout for that machine.
All layouts are same, just have small needed changes for any different machine.

The app not only simulate, can control manually (with phone or tablet, touch) that machines over USB OTG cable or over local WiFi network or over Internet, this worked even without use WiFi on a Smartphone, just a Data Line (SIM).

I tried it many times with various Facebook litalian users and worked well, but for now only tested 3D printing part, these users with my app controlled my Creality Ender3 3D printer to my home from anyware, tested even 1000 Km, this not change, can be even from Sidney to NewYork, maybe just increase a bit the latency.

As server part ESP8266, ESP32, Rasperry Zero W, for ESPs I wrote a dedicated sketch capable ti receive commands and data, for Raspberry I used B4J.

On phone the user open a gcode file, just press PLAY button, the app want confirmation to send a file, by clicking OK B4 send a file in chunks and the server side save it on microsd card. I initially used PrefixMode with RPI but to adapt my app ti both ESPESP8266, ESP32 and RPI now I use TCP on Normal mode. Because this is a very big work I'm unable to port it to B4R and use Prefix.

After this the server side autonomaically start a print and read line by line all gcode file, it even send a log to my app any line by line, same lines that send to a printer, but over network and my app draw these.

At this point the app can even control some things over network and receive data like temperatures, that I draw in a graph and more more.
The app has PAUSE and RESUME buttons, dedicated page where show an IP Cam, receive over network photos, in 3D orint, one photo every layer, a layer is 0.2 0.4 mm hight, then at end of printing process have a page to create a timelapse video with various oarameters like resolution, FPS, Codec. The final video is MP4.

I can close the app, the Server side occupies to control all printing proces... even hours. It is connected just over USB, ESP or RPI can print on printer LCD, do beeps on beeper, move all axes.

This way I have even managed with long prints like 8-10 hours, but some days ago I touched the file transfer part on sebder and receiver, or better Client (my app) and Server (ESPs abd RPI) and I cannot send the file... but this is another question next I will post here requesting help.
---------------------------------------------------------
Returning on redirect console, as I said I managed with threejs because I want substitute a Canvas on my app with a full 3D view. I do not know OpenGL API, so searched some object oriented, threejs is very good.... so I managed with WebViewExtras, yes even managed initially with good @Ivica Golubovic UltimateWebView that have a lots of great functionalities, but I had the problem that is not possible create istance of JSInterface on a Class. Ivica supposes it work only on Activity, I've used it in a Custom View Class. Ivica told me that check and try to fix it. iI tried with WebViewExtras that not require Me callback and it worked. Next I will use UltimateWebView library if Ivica fix the problem, just I commented for now.

Because I'm very new on threejs, I created a simple B4A app with 3 TABS to test inline:
- on first tab just a long scrollable vertical ScrollView, inside it a long TextField, here I print Javascript code
- by pressing second tab, there is a fullscreen WebView that render what i wrote in Javascript
- in last tab just there is another long scrollable TextField where next I want show a full HTML text and put a COPY, LOAD and SAVE buttons. This way it can manage with files, maybe load full HTML, extract JS and put in first TAB etc...

,- It has not colored syntax, just an EditText.
- It is like a sort of very simple jsFiddle but only for threejs.
- It permits to create 3D scenes live, add lights, put 3D objects, import 3D files (for this need to be tested, need path where load a file), rotate with touch, zoom with pinch, tranlate with 2 fingers, permits to set separate parameters for these eg dampingFactor, panSpeed, rotateSpeed, all floats, what uou write it render. Because imports are directly imported from DurAssets, it is not extensible, I only imported some JS, three.js, OrbitControl.js, Stats.js, more can be added, but by code.

Because I not yet managed to Load and Save files, for now I've created some Javascript templates that draw some scenes with some geometries, even I created a relatively long JS code that acts as small tutorial (introduction, I'm not expert) for threejs, in this code I've added some parst of threejs, geometries, lights, materials constructors with commented examples, to add to the scene just need to be uncommented.

The problem is that execute JS without a console is not a right way, if I just miss a semicolon, if I do some errors on code, by pressing the WebView is just Black, I cannot see where error is, WebView Extras show in the B4A log, but as you discussed need to be managed
I see that there are some consoles on github as Javascript that can be integrated, maybe this is a best option? What do you think on tools like Eruda or similars? I've no experience on this, tried Eruda on web and in one app from PlayStore and looks good.... maybe using code I can iteract and integrate it ?

For colored syntax I still provided to this by searching to port @stevel05 CodeMirror Classes. It after more resolved issues worked on Android as CustomView, it is excellent on my Nexus 7, even on a phone, support 100+ language hilights Thanks to stevel even B4X, it support about 30 themes, lights and dark.

The problem is that this only works in Debug mode. For some strange reasons crash in Release mode, return an exception that a class cannot cast another class type. I suppose what is the problem, I initialize a CustomView Class inside another CustomView class, stevel do this on B4J, B4A maybe don't like it.

Next days I will post the project on the Forum, maybe someone can help to solve this.
 
Last edited:

drgottjr

Well-Known Member
Licensed User
Longtime User
my understanding of your problem is that you wish to communicate between a webview and a b4a app.
i have no interest in any of the other things you talked about (sorry, no offense intended). if i understand the
problem correctly, just say yes. if yes, then i or a number of other people can tell you how to do it.

you communicate between a webview and a b4a app is by raising an event with the javascript interface or
executejavascript command. the event returns a string to b4a. you can do what you want with that string.
it can contain 1 value or as many values as you like (eg, "value1~value2~value3~value4~etc").

extending webchromeclient is 1 way. but it isn't the only way. you only have to know or be able to know
the value of some variable in the webview that you want b4a to know. you can then pass that value to b4a.
there are a couple ways to do this. they use webviewextras and are simple in theory.

if this is what you are talking about, say it clearly, and we can move forward.
 

max123

Well-Known Member
Licensed User
Longtime User
my understanding of your problem is that you wish to communicate between a webview and a b4a app.
i have no interest in any of the other things you talked about (sorry, no offense intended). if i understand the
problem correctly, just say yes. if yes, then i or a number of other people can tell you how to do it.

you communicate between a webview and a b4a app is by raising an event with the javascript interface or
executejavascript command. the event returns a string to b4a. you can do what you want with that string.
it can contain 1 value or as many values as you like (eg, "value1~value2~value3~value4~etc").

extending webchromeclient is 1 way. but it isn't the only way. you only have to know or be able to know
the value of some variable in the webview that you want b4a to know. you can then pass that value to b4a.
there are a couple ways to do this. they use webviewextras and are simple in theory.

if this is what you are talking about, say it clearly, and we can move forward.
Yes I want comunicate with a WebView from BA4 and viceversa....

Sorry, but I not a novice, I already doing this things on 10+ projects with WebViewExtras and even with UltimateWebView, so no problem at all for this
WebViewExtras to JS:
WebViewExtras1.addWebChromeClient(WebView1, "WebViewExtras1")
WebViewExtras1.addJavascriptInterface(WebView1, "B4A")
UltimateWebView to JS:
Private JSInterface As UltimateJavascriptInterface
UltimateWebView1.Initialize(Me, "UltimateWebView1")
UltimateWebView1.SetWebChromeClient(True) ' Sets WebChromeClient and its Events.
UltimateWebView1.AddJavascriptInterface(JSInterface, "B4A")
'Eventually
UltimateWebView1.Settings.JavaScriptEnabled = True
UltimateWebView1.Settings.JavaScriptCanOpenWindowsAutomatically = True
And from JS side:
B4A.CallSub (Param1, Param2, Param3)
What you omitted is that max 3 params are supported, I even resolved this and even tried to pass up 10 parameters with just Param1 using a comma delimiter string. See this thread:
https://www.b4x.com/android/forum/t...bview-javascript-function.139554/#post-883867

My question is not how to do it on B4A, but how do accomodate all on both sides, that I have to communicate B4A-JS I think is clear now, but because I never implemented a Javascript console Inside or Outside a webview I have no Idea what is the best option and how really do it with code.

Yes is this the problem:
extending webchromeclient is 1 way. but it isn't the only way. you only have to know or be able to know
the value of some variable in the webview that you want b4a to know. you can then pass that value to b4a.
there are a couple ways to do this. they use webviewextras and are simple in theory.

if this is what you are talking about, say it clearly, and we can move forward.
How tecnically do it with code, before do this my anoter question you do not responded me and it is crucial:
I see that there are some consoles on github as Javascript that can be integrated, maybe this is a best option? What do you think on tools like Eruda or similars? I've no experience on this, tried Eruda on web and in one app from PlayStore and looks good.... maybe using code I can iteract and integrate it ?
I asked you if is more convenient use eg. Eruda or similars, this is on a WebView, or just redirect as my first question the console to have a stream and write it in a EditText.

This depends if the log show the exact line number where error occours, but in Javascript that I write, because I import <script> tags as string from DirAssets, all it's code is bundled in one single string with HTML, Scripts, styles etc..... If I do error on line 1 WebviewExtras actually show line 14000+.

So how to do it tecnically....
Suppose that I use WebViewExtras, there is a way to disable the JS log to B4A Log (not really needed if I implement in app) and from JS pass a full console stream to b4A to a EditText or multiline label? But is this the better option? Or best use already existing things like Eruda?
 
Last edited:

drgottjr

Well-Known Member
Licensed User
Longtime User
i can only tell you how to communicate between a webview and b4a. i know nothing about eruda or similars. i did
not answer before because i was trying to understand the exact nature of your problem. i now understand that you
already know how to use javascript interface and executejavascript.

the more you explain, the more it looks like you are not interested so much in variables but simply in capturing
errors and showing them in an edittext view. if this is the case, then we are back to webchromeclient. because of the
line number problem (due to the way you load the webview), i believe the most you can hope for is to capture the log
by extending the webchromeclient. once you do that, you can easily add text to the edittext view. it isn't exactly a real
console, but you will see the errors. i already do something similar, but i use a webview as the "console" since i find it
more flexible than an edittext. i override webchromeclient, it sends console messages to b4a, i take the messages and
show them in my "console".

are we getting any closer now?
 

max123

Well-Known Member
Licensed User
Longtime User
And How Override WebChromeClient ?
Please post some code example if you have. I will study it.

I even study this.... but tomorrow, now are 5.00 of night, I study go to bed.
https://jsrepos.com/lib/liriliri-eruda
 

drgottjr

Well-Known Member
Licensed User
Longtime User
console.png
 

Attachments

  • console.zip
    8.3 KB · Views: 95

max123

Well-Known Member
Licensed User
Longtime User
Top