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:

deboerr

New Member
I know this thread is old, but I would like to add my 2cents here. Advice in this thread from Warwound, Erel and others made my life a breeze to implement accessing localstorage from javascript in a webpage. Thanks guys. The only thing to be careful of is to not put the code in the Initialize sub. Put your code it in B4XPage_Created ... as per below. My B4A app has a webview display avionic data (alt, airspeed, heading, groundspeed etc) which is collected and collated by an ESP32 microcontroller and pushed to the mobile device.
B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private WebView1 As WebView
    Dim wvx As WebViewExtras
    Dim wvs As WebViewSettings

End Sub

Public Sub Initialize
'    B4XPages.GetManager.LogEvents = True
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
    
    wvx.addWebChromeClient(WebView1, "wvx")
    wvs.setDatabaseEnabled(WebView1, True)
    wvs.setDOMStorageEnabled(WebView1, True)
    
    WebView1.LoadUrl("http://192.168.137.1:8000/")
End Sub
 

max123

Well-Known Member
Licensed User
Longtime User
Hi @deboerr , please can this help to solve my problem I've posted here ? Maybe permisson problem ?
https://www.b4x.com/android/forum/threads/download-files-from-webview-local-storage.141068/

What I need to do is click a button created by javascript and download the file that javascript pass as blog. This is done internally by threejs library, just use it to export 3D models created by code or by user, in this case it export an STL file. If I click this button on my pc or Android phone browser, it save the file in Download folder where browser store all downloads, but I cannot do the same in a B4A WebView.
 
Last edited:

deboerr

New Member
The only other change that I made to my project was to add the following 2 lines to the project manifest file. I'm not sure if this is actually needed.
B4X:
AddManifestText(<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />)
AddManifestText(<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />)
 

max123

Well-Known Member
Licensed User
Longtime User
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
I haven't seen all posts in this thread. Generally speaking you can directly access files in XUI.DefaultFolder = File.DirInternal.

Other places require the usage of SaveAs or ContentChooser or ExternalStorage.

 

max123

Well-Known Member
Licensed User
Longtime User
Many thanks Erel,

the problem for my question is that JS send a file in blob format, it do not expets user intervention and Save dialog, on normal browser it just save the file in browser downloads folder.

Anyway put a Save dialog is not a problem, but just I cannot know how to receive the file and handle it to be saved.
 

arjian

Member
Licensed User
Longtime User
hello,
when a site includes several pages like the attached pic
sc1.png

the method "B4A.CallSub('processHTML',true, document.documentElement.outerHTML)" just save the first page, but the browser save all pages in one html file
how can save all pages in one html file?
any help would be appreciated
 

max123

Well-Known Member
Licensed User
Longtime User
Sorry @arjian , I cannot help you because I've no knowledge on this.

My quetion remains open to all members.
I not yet solved it.

I've created with B4A a sort of 3D CAD with ThreeJS, I can manage complex 3D with boolean subtraction, addition, and some advanced things, but after I create a 3D object I cannot save the resulting 3D model as STL file to be sliced and printed on my 3D print. With browser it works, by default it saves the STL file as blob in Android Download folder, where Chrome save files. I can change it if it is not allowed, just to save the model.

After a lot of work (2 years) this is the last step to get all working.

Please help to know how manage it.
 
Last edited:

byz

Active Member
Licensed User
Sorry @arjian , I cannot help you because I've no knowledge on this.

My quetion remains open to all members.
I not yet solved it.

I've created with B4A a sort of 3D CAD with ThreeJS, I can manage complex 3D with boolean subtraction, addition, and some advanced things, but after I create a 3D object I cannot save the resulting 3D model as STL file to be sliced and printed on my 3D print. With browser it works, by default it saves the STL file as blob in Android Download folder, where Chrome save files. I can change it if it is not allowed, just to save the model.

After a lot of work (2 years) this is the last step to get all working.

Please help to know how manage it.
Perhaps you should try using JavaScript to create objects to save text formatted stl, and then pass it to b4a through JavaScript, which then saves it to your phone.
 

max123

Well-Known Member
Licensed User
Longtime User
Perhaps you should try using JavaScript to create objects to save text formatted stl, and then pass it to b4a through JavaScript, which then saves it to your phone.
Yes thanks @arjian this is what Isearch to do, but without success. I will try the @JohnC code posted here, may I have some success.
ThreeJS save it as 'blob' by default, I'm not sure I can change it. Here the related thread.
https://www.b4x.com/android/forum/t...from-webview-local-storage.141068/post-966871
 
Last edited:

byz

Active Member
Licensed User

max123

Well-Known Member
Licensed User
Longtime User
js can get blob
And how to do it? I'm not JS expert. I now do not have here the JS class code because it is on another PC.
May I will search it inside online threejs distribution and if I find it post here or in a new thread.

I remember that I had to use theejs 138 and changed one class to adapt it with an older theejs version to get read working, this way I can open any file like 3D models, textures etc. But only read worked, I cannot save.

The class internally works in a way similar to this.... so at the end download a blob. So may I've to extract Blob back to string or binary.
Note that there are two types of STL files, text based and binary. The binary is more suitable, it cannot textually read, but make smaller files by removing spaces and other things.
JavaScript:
var exporter = new THREE.STLExporter();
var str = exporter.parse( scene ); // Export the scene
var blob = new Blob( [str], { type : 'text/plain' } ); // Generate Blob from the string
//saveAs( blob, 'file.stl' ); //Save the Blob to file.stl

//Following code will help you to save the file without FileSaver.js
var link = document.createElement('a');
link.style.display = 'none';
document.body.appendChild(link);
link.href = URL.createObjectURL(blob);
link.download = 'Scene.stl';
link.click();

Here the relevant JS main code:
JavaScript:
            function exportASCII() {
                Log ("Export ASCII STL file");
                const result = exporter.parse( mesh );
                saveString( result, 'box.stl' );
            }

            function exportBinary() {
                Log ("Export bynary STL file");
                const result = exporter.parse( mesh, { binary: true } );
                saveArrayBuffer( result, 'box.stl' );
            }

            const link = document.createElement( 'a' );  // CREATE DOWNLOAD LINK
            link.style.display = 'none';
            document.body.appendChild( link );

            function save( blob, filename ) {
                Log ("Save the file: " + filename);
                link.href = URL.createObjectURL( blob );
                link.download = filename;
                link.click();
            }

            function saveString( text, filename ) {
                Log ("Save string: " + filename);
                save( new Blob( [ text ], { type: 'text/plain' } ), filename );
            }

            function saveArrayBuffer( buffer, filename ) {
                Log ("Save array buffer: " + filename);
                save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );
            }

Here the example I working on to test STL save:
https://threejs.org/examples/misc_exporter_stl
https://github.com/atnartur/three-STLexporter
https://threejs.org/docs/#examples/en/exporters/STLExporter
 
Last edited:

JohnC

Expert
Licensed User
Longtime User
Please start a new thread and continue this particular issue there so this thread doesn't fill with too many off-topic posts.
 

max123

Well-Known Member
Licensed User
Longtime User
I will do it, thanks fo your help @JohnC .
 
Top