Android Question Interact with webview

TheRealMatze

Active Member
Licensed User
Hi,
we decide to use more functionality from webview, because the main components are already working in html. So, i try to interact between webview and b4x.
I try the example which pulls a webview function from the activity. that works. But more important is the other way, pushing from the webview to the activity.
I found a article here that says the easiest way for b4a and b4i is the "OverrideUrl" from webview. I´ve tried it - it does nothing :/

Can anyone tell me what my mistake is?

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals

End Sub

Sub Globals
    Private WebView1 As WebView
    Dim we As WebViewExtras
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    we.addJavascriptInterface(WebView1,"B4A")
    WebView1.LoadUrl(WebViewAssetFile("index.html"))
End Sub

Sub TheContentIs(content As String)
    Msgbox(content,"Content From JS")
End Sub

Sub WebViewAssetFile (FileName As String) As String
   #if B4J
     Return File.GetUri(File.DirAssets, FileName)
   #Else If B4A
    Dim jo As JavaObject
    jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File")
    If jo.GetField("virtualAssetsFolder") = Null Then
        Return "file:///android_asset/" & FileName.ToLowerCase
    Else
        Return "file://" & File.Combine(jo.GetField("virtualAssetsFolder"), _
       jo.RunMethod("getUnpackedVirtualAssetFile", Array As Object(FileName)))
    End If
   #Else If B4i
     Return $"file://${File.Combine(File.DirAssets, FileName)}"$
   #End If
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
    we.executeJavascript(WebView1,"javascript: doCallBack();")
End Sub

Sub Webview1_OverrideUrl (Url As String)
    Msgbox(Url,"Called")
    If Url.Contains ("#") Then
    Msgbox(Url,"Contains Hash")
    End If
End Sub

In the html is a button

HTML:
<button onclick="changeHash('#nice',this)">Push me</button>

</body>
<script>
function changeHash(h,t){
window.location.href=h
t.innerHTML=h;
}
</script>

Webview1_OverrideUrl will not called...

Regards
Matze
 
it's not clear what you mean by "pushing from the webview to the activity".
what are we pushing?

there is an issue with window.location.href and webviewclient's shouldoverrideurlloading().
i want to test a couple things. in the meantime, if you like, do this:
make the button an "<a href=...>" tag and point it to https://www.b4x.com. click on the
link. that should trigger webview's OverrideUrl event (at least on b4a. technically, webviews
on b4j and ios are more akin to webkit. b4a's is closer to android's interpretation of webkit.)

don't forget that OverrideUrl is expecting you to return true (to override) or false (to let continue).
it's a clever way of letting you deal with something in b4a that you would have to do in java
directly otherwise.

if OverridUrl fires (which i think it should), then the problem would seem to be window.location.href.
you can research that if you like.

also, to debug webview, you need to add chromeclient to your webviewextras.
 
Upvote 0
Ok, it needs a url...

<button onclick="changeHash('https://www.test.de#nice',this)">Push me</button>
<a href="file://index.html#test">yes!</a>

works a little bit more. But after the second msgbox the app crashes in the simulator and on the phone.

Sub Webview1_OverrideUrl (Url As String)
Msgbox(Url,"Called")
If Url.Contains ("#") Then
Msgbox(Url,"Contains Hash")
End If
Return True
End Sub

But by the way - the webview is working under b4i also, correct?
 
Upvote 0
But after the second msgbox the app crashes in the simulator and on the phone.
MsgBox is deprecated and should be replaced by async methods.
I guess it can be problmatic to use these days.
 
Last edited:
Upvote 0
Ok, it needs a url...

<button onclick="changeHash('https://www.test.de#nice',this)">Push me</button>
<a href="file://index.html#test">yes!</a>

works a little bit more. But after the second msgbox the app crashes in the simulator and on the phone.

Sub Webview1_OverrideUrl (Url As String)
Msgbox(Url,"Called")
If Url.Contains ("#") Then
Msgbox(Url,"Contains Hash")
End If
Return True
End Sub

But by the way - the webview is working under b4i also, correct?

as donmanfred says, async msgbox, especially when you've got background threads all tied up waiting for you.
also don't use msgbox(async) for debugging. use log.
and you shouldn't blindly use true, even when practicing. a little disicipline, right? if you want to override (given some condition) then return true else return false. one less thing to wonder about later.
you'll have to run your code on those other platforms to see what gives...
 
Upvote 0
Ok, no msgbox. Done. The return-value - yes, but without any condition to test...

I have tried different options. One was a success, but i don´t understand what i do with it.

I want to see an when the crash begins, so i included a sleep(1000) into overrideUrl. The compiler dont like that, because in this case the return-value is not allowed. So, i removed the return - and it stop crashing... After that the event is fired. So far so good, but i don´t think that is correct.

Sub Webview1_OverrideUrl (Url As String)
If Url.Contains ("#") Then
Button1.Text="With Hash " & Url
Else
Button1.Text="Nope, only " & Url
End If

Sleep(1)
End Sub
Only updating the hash is not working anymore...

Using webviewextras instead will solve my problems (under android). That works without any error, but i´m not sure if i can adopt it to ios.
When i add webviewextra to b4i i cant compile (webviewextra.h not found) - but even if i try to use the webview i run in trouble...
Sub Process_Globals
'These global variables will be declared once when the application starts.
'Public variables can be accessed from all modules.
Public App As Application
Public NavControl As NavigationController
Private Page1 As Page
Private xui As XUI
Private Button1 As Button
Private WebView1 As WebView
'Dim we As WebViewExtras
End Sub

Private Sub Application_Start (Nav As NavigationController)
NavControl = Nav
Page1.Initialize("Page1")
Page1.RootPanel.LoadLayout("Page1")
NavControl.ShowPage(Page1)
'we.addJavascriptInterface(WebView1,"activity")
'Url(File.Combine(File.DirAssets, "index.html"))

WebView1.LoadHtml("This is HTML")
End Sub

I see no way to load a local html-file, that´s bad bad not essential. LoadHtml is working on both plattforms, so the Html will be hardcoded into the app. But the missing WebViewExtra is a problem. In ios Webview1_OverrideUrl works on hashtag...

So for me it looks like

ios can´t load local html files
ios cant use webviewextra
android cant use overrideurl

Is this correct?

Matze
 
Upvote 0
I didn't follow the whole thread, so just a thought: Why don't you use Javascript for the interaction between your B4X app and the webview? The Javascript approach is a little different for Android and iOS but it definitely works.
I also tried Override_URL but found that it didn't fire in the speed I needed for my app.
 
Upvote 0
maybe i search for the wrong keywords, but i can´t find anything else then webviewextra or overrideurl...
Do you have a example?
 
Upvote 0
That looks good, but how can i call the sub from javascript?
It is described in the library thread
 
Upvote 0
Probably better to start a new thread for the non-B4A things.
It's in the B4I example. The B4I button demonstrates the JavaScript code (postMessage):
B4X:
WebView1.EvaluateJavaScript("window.webkit.messageHandlers.callback.postMessage('postMessage successful " & DateTime.Now & "');")
 
Upvote 0
I don't know. I just do it like this:
B4X:
        function SendMessage(ID, msg)
        {
        try{B4A.CallSub(ID, true, msg);}catch(err){}
        try{window.webkit.messageHandlers.callback.postMessage(ID + '@' + msg);}catch(err){}
        }
 
Upvote 0
i asked you early on what you were "pushing". i suspected it
was javascript injection, but my approach is to try to answer
the question(s) posed by the poster.

i don't know how you latched onto overrideurl() in the first
place (as it relates to your app), but it seems to me that
you don't understand how overrideurl works since, mainly,
you continue to use it incorrectly. it may not even be necessary,
but it's what you asked about. in any case, you should
understand how the webviewclient method shouldoverrideurlloading()
works and its relation to b4a's overrideurl().

javascript injection is a whole other matter, and, possibly what
you're after. i'm guessing you're dropping overrideurl() at this point,
but to say that it doesn't work is not accurate.
 
Upvote 0
I havn´t "say" it doesn´t work. In my test it will not, and i asked general if my determination is correct or not. What i see is, that overrideurl fires when a complete url is called, but not only a page-link (http://test.me works but #jumpthere not).
I havn´t seen shouldoverrideurlloading before, i just search for it in the b4a-webview section in the documentation, but there is no information about it. it´s difficult to understand the relationship between parts without knowing their existence.

At the end of the day i only need a way to interact both directions. And the combination of jscallback and webviewextras looking good for this task.
 
Upvote 0
Hi,
we decide to use more functionality from webview, because the main components are already working in html. So, i try to interact between webview and b4x.
I try the example which pulls a webview function from the activity. that works. But more important is the other way, pushing from the webview to the activity.
I found a article here that says the easiest way for b4a and b4i is the "OverrideUrl" from webview. I´ve tried it - it does nothing :/

Can anyone tell me what my mistake is?

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals

End Sub

Sub Globals
    Private WebView1 As WebView
    Dim we As WebViewExtras
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    we.addJavascriptInterface(WebView1,"B4A")
    WebView1.LoadUrl(WebViewAssetFile("index.html"))
End Sub

Sub TheContentIs(content As String)
    Msgbox(content,"Content From JS")
End Sub

Sub WebViewAssetFile (FileName As String) As String
   #if B4J
     Return File.GetUri(File.DirAssets, FileName)
   #Else If B4A
    Dim jo As JavaObject
    jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File")
    If jo.GetField("virtualAssetsFolder") = Null Then
        Return "file:///android_asset/" & FileName.ToLowerCase
    Else
        Return "file://" & File.Combine(jo.GetField("virtualAssetsFolder"), _
       jo.RunMethod("getUnpackedVirtualAssetFile", Array As Object(FileName)))
    End If
   #Else If B4i
     Return $"file://${File.Combine(File.DirAssets, FileName)}"$
   #End If
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
    we.executeJavascript(WebView1,"javascript: doCallBack();")
End Sub

Sub Webview1_OverrideUrl (Url As String)
    Msgbox(Url,"Called")
    If Url.Contains ("#") Then
    Msgbox(Url,"Contains Hash")
    End If
End Sub

In the html is a button

HTML:
<button onclick="changeHash('#nice',this)">Push me</button>

</body>
<script>
function changeHash(h,t){
window.location.href=h
t.innerHTML=h;
}
</script>

Webview1_OverrideUrl will not called...

Regards
Matze
If I understood you correctly, when you click on 'Button1' should the javascript be executed and the response sent by the javascript interface be captured?

Ok, I will try to help you...
First, download library from this link: https://www.b4x.com/android/forum/threads/ultimatewebview-custom-view.135666/#post-860033

Merge WebView with UltimateWebView as in the code below.
[CODE lang="b4x" title="Example:"]Sub Activity_Create(FirstTime As Boolean)
'Do not forget to load the layout file created with the visual designer. For example:
Activity.LoadLayout("Main") 'Use your activity name

UltimateWebView1.Initialize(Me, "UltimateWebView1") 'Initializes UltimateWebView
UltimateWebView1.WebView=WebView1 'Merge your WebView with UltimateWebView

UltimateWebView1.SetWebViewClient
UltimateWebView1.SetWebChromeClient
UltimateWebView1.Settings.JavaScriptEnabled=True 'Very important for JavaScripts
UltimateWebView1.Settings.AllowContentAccess=True
UltimateWebView1.Settings.AllowFileAccess=True
UltimateWebView1.Settings.AppCacheEnabled=True
UltimateWebView1.Settings.CacheMode=UltimateWebView1.Settings.Constants.CACHEMODE_LOAD_DEFAULT
UltimateWebView1.Settings.JavaScriptCanOpenWindowsAutomatically=True
UltimateWebView1.Settings.DisplayZoomControls=False
UltimateWebView1.Settings.DomStorageEnabled=True
UltimateWebView1.Settings.MediaPlaybackRequiresUserGesture=False
UltimateWebView1.Settings.AllowFileAccessFromFileURLs=True
UltimateWebView1.Settings.AllowUniversalAccessFromFileURLs=True
UltimateWebView1.Settings.GeolocationEnabled=True
UltimateWebView1.SetDownloadListener

UltimateWebView1.CookieManager.AcceptCookies=True
UltimateWebView1.CookieManager.AcceptThirdPartyCookies=True
UltimateWebView1.CookieManager.AcceptFileSchemeCookies=True
UltimateWebView1.CookieManager.Flush

UltimateWebView1.LoadUrl(WebViewAssetFile("index.html"))
End Sub[/CODE]

Second use this code in your Button1_Click Sub (For synchronized result):
[CODE lang="b4x" title="Example:"]Sub Button1_Click
UltimateWebView1.ExecuteJavaScript2([Your JavaScript Code])
Wait For UltimateWebView1_ExecuteJavaScriptResult (Result As String)
If Result<>"" Then
If Result.Contains ("#") Then
Log("Result Contains Hash")
End If
End If
End Sub[/CODE]

For Asynchronized result:
[CODE lang="b4x" title="Example:"]Sub Button1_Click
UltimateWebView1.ExecuteJavaScript2([Your JavaScript Code])
End Sub

'Result Event:
Sub UltimateWebView1_ExecuteJavaScriptResult (Result As String)
If Result<>"" Then
If Result.Contains ("#") Then
Log("Result Contains Hash")
End If
End If
End Sub[/CODE]
 
Last edited:
Upvote 0

Similar Threads

  • Locked
  • Article Article
Replies
2
Views
16K
  • Article Article
Android Code Snippet Upload files with WebView
Replies
37
Views
43K
Back
Top