B4A Library UltimateWebView Custom View

iz0ndg

Active Member
Licensed User
Longtime User
It would not be bad to post your solution here because it might help someone with the same or a similar problem. Thanks.
Sure...

in Globals :
B4X:
Sub Globals
    ...
    Dim jo As JavaObject
End Sub

in Activity Create :
B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    ...
    If FirstTime Then
        jo.InitializeContext
    End If
    ...   
End Sub

One sub :
B4X:
Sub StringtoHtml(Stringa As String) As String
    Dim HtmlResult As String=jo.RunMethod("jsonToHtml",Array(Stringa))
    HtmlResult = HtmlResult.Replace($"\""$,$"""$).Replace($"\n"$,Chr(13))
    ' Replace \" with one " and \n with chr(13)  (New Line)
    Return HtmlResult
End Sub

And the Java code :
B4X:
#If Java
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.lang.StringBuffer;
import java.lang.Integer;

public String jsonToHtml (String data) {
        Pattern p = Pattern.compile("\\\\u(\\p{XDigit}{4})");
        Matcher m = p.matcher(data);
        StringBuffer buf = new StringBuffer(data.length());
        while (m.find()) {
            String ch = String.valueOf((char) Integer.parseInt(m.group(1), 16));
            m.appendReplacement(buf, Matcher.quoteReplacement(ch));
        }
        m.appendTail(buf);
        return buf.toString();
    }

#End If
 

Ivica Golubovic

Active Member
Licensed User
If the address changes when the user closes the connection then it is possible to catch it via the "PageFinished" event as in the example below:
Example::
Sub UltimateWebView1_PageFinished (Url As String)
    If Url.Contains("meet.jit.si") And Url.Contains("close") Then
        'User closes connection
    End If
End Sub
 

Ivica Golubovic

Active Member
Licensed User
Version 1.6 released. Download library and documents from first post.


Changes:

1.
Added class SafeBrowsingResponse.
Added the "SafeBrowsingResponse" class required for the "SafeBrowsingHit" event that is activated when the URL has been flagged by Safe Browsing.

2. Added event SafeBrowsingHit (WebResourceRequest1 As WebResourceRequest, SafeBrowsingResponse1 As SafeBrowsingResponse).

3. Added method SetRendererPriorityPolicy(RendererRequestedPriority As Int, WaivedWhenNotVisible As Boolean) to UltimateWebView class.
Examples:
Example::
UltimateWebView1.SetRendererPriorityPolicy(UltimateWebView1.Constants.RENDERER_PRIORITY_BOUND,True)
'Or
UltimateWebView1.SetRendererPriorityPolicy(UltimateWebView1.Constants.RENDERER_PRIORITY_IMPORTANT,True)
'Or
UltimateWebView1.SetRendererPriorityPolicy(UltimateWebView1.Constants.RENDERER_PRIORITY_WAIVED,True)

4. Added property AccessibilityClassName As String to UltimateWebView class.
This property returns a String that represents the class to which the object is bound. Example: android.webkit.WebView

5. Added property View As View to UltimateWebView class.
This property converts UltimateWebView to android.view.View which allows you to programmatically add this object to an activity or panel. Before that, of course, it is necessary to initialize the object.
Example::
Dim UWebView As UltimateWebView
UWebView.Initialize(Me,"UWebView")
Activity.AddView(UWebView.View,0,20%y,100%x,80%y)
'OR
Panel1.AddView(UWebView.View,0,20%y,100%x,80%y)

6. Added property SafeBrowsingPrivacyPolicyUrl As AndroidNetURI to UltimateWebView class.
You need to download my "AndroidNetUri" library from the link below:

7. Added event CreateChildWindow (IsDialog As Boolean, IsUserGesture As Boolean) As UltimateWebView
To enable this event you first need to add the following lines to "Sub Activity_Create (FirstTime As Boolean)":
Example::
UltimateWebView1.SetWebViewClient
UltimateWebView1.SetWebChromeClient
UltimateWebView1.Settings.SupportMultipleWindows=True
Many websites require a new interface (child view) to display some additional content. If you click on a certain button or link, those sites will not display content unless the content is transferred to child view. In this case, the "CreateChildWindow" event will be activated. The return object of the event is UltimateWebView which is defined by you. The library will continue to manage this object on its own, so DON'T add it to the activity. You can also add events for the newly created child view. If you do not want to allow the website to transfer content to a child view then return Null and page will not be loaded. If you do not want this event to be activated at all and to disable this feature on all sites, set Settings.SupportMultipleWindows to False.
Example::
Private Sub UltimateWebView1_CreateChildWindow (IsDialog As Boolean, IsUserGesture As Boolean) As UltimateWebView
    Log("Added New Child Window")
    'Return Null if you do not want to create child window. Page will not be loaded!
    Dim NewUltimateView As UltimateWebView
    NewUltimateView.Initialize(Me,"NewUltimateView")
    NewUltimateView.EnableSlowWholeDocumentDraw
    NewUltimateView.Settings=UltimateWebView1.Settings 'Import settings from main UltimateWebView
    NewUltimateView.SetWebViewClient
    NewUltimateView.SetWebChromeClient
    NewUltimateView.CookieManager.AcceptCookies=True
    NewUltimateView.CookieManager.AcceptFileSchemeCookies=True
    NewUltimateView.CookieManager.AcceptThirdPartyCookies=True
    NewUltimateView.CookieManager.Flush
    Return NewUltimateView 'Return created UltimateWebView like child window. Library will do the rest. You can initialize all needed events for this child.
End Sub

Sub NewUltimateView_PageFinished (Url As String)
    Log("ChildFinishedPage: " & Url)
End Sub

Sub NewUltimateView_OverrideUrl (WebResourceRequest1 As WebResourceRequest) As Boolean
    Log("OverridenChildUrl: " & WebResourceRequest1.GetUrl)
    Return False
End Sub

8. Added event RenderProcessGone (DidCrash As Boolean, RendererPriorityAtExit As Int)
This event will be triggered the moment an error occurs in rendering the selected content to prevent the UltimateWebView and the application from crashing. By default, the library will try to prevent the UltimateWebView and application to crash. Of course, if you want, you can exit the application yourself by executing the "ExitApplication" command in this event.
Example::
Private Sub UltimateWebView1_RenderProcessGone (DidCrash As Boolean, RendererPriorityAtExit As Int)
    Log(DidCrash)
    Log(RendererPriorityAtExit)
End Sub

9. Discovered bugs fixed
 

Ivica Golubovic

Active Member
Licensed User
Version 1.7 released. Download library and documents from first post.

Changes:
  • Added class JsPromptResult
  • Added method PrintContent to UltimateWebView class
  • Added method FindFocus As View to UltimateWebView class
  • Added method ImportSettingsFrom (From As UltimateWebView) to UltimateWebViewSettings class
  • Added event JsPrompt (JsProperties1 As JsProperties, JsPromptResult1 As JsPromptResult) As Boolean
  • Added event OnFocusChange (HasFocus As Boolean)
  • Added event OnKeyEvent (KeyCode As Int, AndroidViewKeyEvent As Object) As Boolean
  • Added event OnLayoutChange (New As LayoutChangeProperties, Old As LayoutChangeProperties)
  • Added event OnScrollChange (New As ScrollChangeProperties, Old As ScrollChangeProperties)
  • Added event OnTouch (AndroidViewMotionEvent As Object) As Boolean
  • Added event OnUnhandledKeyEvent (KeyCode As Int, AndroidViewKeyEvent As Object) As Boolean
 

stevenindon

Active Member
Licensed User
Hello,

Nice!! A library that what i am waiting. Just 2 questions:

1) Is this cross platform? - Android / IOS
2) Does it have a function like in WebViewExtras - that we can call a B4A/B4i function from our web page?

B4X:
Example :  PBrowser.CallSub('Exec_App_Toastmessage',true,'This is a toast message','true');

Or even Call a B4a/B4i function from our webpage --> With a return value?

I have face a lot of problem programming in IOS having to use javascript to call functions inside B4A/B4i :

window.location='Exec[ExecReturn_http_ReqString|http://www.MyWeb.com|James|32]' and then catch the command word from
Sub WKWebView_OverrideUrl (Url As String) As Boolean

This library will be super valuable if it is cross platform (Android / IOS) as i see that you have put great great amount of work on this.
 
Last edited:

Ivica Golubovic

Active Member
Licensed User
The answer to your first question is NO. The library is made only for android. At the moment, I have no plans to work on something similar for IOS. If someone has the time and will for such a project, I will be happy to provide assistance if needed.

As for your second question, it is possible if you create JavascriptInterface through java code and insert it into UltimateWebView via the AddJavaScriptInterface method. My plan is to implement several standard JS interfaces in one of the next versions of the library, including CallSub.
 

stevenindon

Active Member
Licensed User
Thank you Ivica. Most of the projects involves IOS as well.. That is the only reason i have to switch to native instead of Webview as current Webview in IOS still cant CallSub functions in application using javascript. I have done a project using Webview in both B4A and B4i ... and it is pain staking.
 

Ivica Golubovic

Active Member
Licensed User
Okay, as you probably already know, this library is closely related to the android.webkit set of classes. Some parts have been rewritten and some have been reworked to make them easier to use. As for the iOS library, you have to know that there is a big difference between androd.webkit.WebView and WKWebView for IOS and it is very difficult to make a simple cross platform library. Besides, if you readed the first post, the main parts of this library were reworked from one of my projects (somewhere around 75%). I decided to make this library to make it easier for me to work on my future projects, and after that I decided to share it with this community as well. This library will save you hours of Java programming in your future projects for the Android platform. It's up to you to use it. Thanks.
 

Ivica Golubovic

Active Member
Licensed User
Hi
How properly use AddJavascriptInterface and CallSub from ultimatewebview?
In a few days, a new version of the library will be released, which will include the UltimateJavascriptInterface class, which will include CallSub, ShowToast, Log, StartActivity and Print methods. Wait a few days.
 

mzsoft

Member
Hi.
i just run example but on line LoadLayout this error show.

B4X:
Error occurred on line: 33 (Main)
java.lang.ClassNotFoundException: android$view$View$OnUnhandledKeyEventListener
    at anywheresoftware.b4j.object.JavaObject.getCorrectClassName(JavaObject.java:289)
    at anywheresoftware.b4j.object.JavaObject.createEvent(JavaObject.java:253)
    at anywheresoftware.b4j.object.JavaObject.CreateEvent(JavaObject.java:216)
    at com.uwebview.ultimatewebview._initialize(ultimatewebview.java:1000)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:777)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:354)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
    at anywheresoftware.b4a.objects.CustomViewWrapper.AfterDesignerScript(CustomViewWrapper.java:61)
    at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:162)
    at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:209)
    at com.test.net.main._activity_create(main.java:392)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:351)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at com.test.net.main.afterFirstLayout(main.java:105)
    at com.test.net.main.access$000(main.java:17)
    at com.test.net.main$WaitForLayout.run(main.java:83)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5530)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:734)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
 

Ivica Golubovic

Active Member
Licensed User
Hi.
i just run example but on line LoadLayout this error show.
The problem is because you are using the SDK library below version 28. Download the latest version of B4A and the latest SDK configuration file from the link below. Follow the instructions on how to configure B4A.

Are you using an emulator or a real device and which version of Android is on it?

 

mzsoft

Member
no i have sdk last version.
on android 11 it is ok.
on android 7 got error.
 

Ivica Golubovic

Active Member
Licensed User
Version 2.0 released. Download library and documents from first post.

Changes:

1.
Added class UltimateJavascriptInterface.
You can add UltimateJavascriptInterface to UltimateWebView via the AddJavascriptInterface method. Example:
Example::
Sub Globals
    Private JSInterface As UltimateJavascriptInterface
End Sub

Sub Activity_Create(FirstTime As Boolean)
    JSInterface.Initialize(Me)
    UltimateWebView1.AddJavascriptInterface(JSInterface,"B4A") '"B4A" is name of javascriptinterface. You can use different name if you want.
End Sub
UltimateJavascriptInterface methods and functions:
  • ShowToast(String message, boolean lengthLong);
  • Log(String logMessage);
  • StartActivity(String activityName);
  • Print();
  • CallSub(String subName, Boolean callUIThread);
  • CallSub(String subName, Boolean callUIThread, String parameter1);
  • CallSub(String subName, Boolean callUIThread, String parameter1, String parameter2);
  • CallSub(String subName, Boolean callUIThread, String parameter1, String parameter2, String parameter3);
  • CallSub(String subName, Boolean callUIThread, String parameter1, String parameter2, String parameter3, String parameter4)
CallSub methods are identical to WebViewExtra2 (great stuff doesn't need to be changed).
Examples of HTML javascript methods to call UltimateJavascriptInterface methods::
B4A.CallSub("[SubName]", true)
'Or
B4A.CallSub("[SubName]", true, "message1")
'Or
B4A.CallSub("[SubName]", true, "message1", "message2")
'Or
B4A.CallSub("[SubName]", true, "message1", "message2", "message3")
'Or
B4A.CallSub("[SubName]", true, "message1", "message2", "message3", "message4")
'Or
var value1 = B4A.CallSub("[SubName]", false,.....)

B4A.ShowToast("[Toast message]", true)

B4A.Log("[Log message]")

B4A.StartActivity("[Activity name]")

B4A.Print()

2. Added custom properties in Designer:
  • AcceptCookies
  • AcceptFileSchemeCookies
  • AcceptThirdPartyCookies
  • AllowContentAccess
  • AllowFileAccess
  • AppCacheEnabled
  • AppCacheMaxSize
  • AllowFileAccessFromFileURLs
  • AllowUniversalAccessFromFileURLs
  • AppCachePath
  • BlockNetworkImage
  • BlockNetworkLoads
  • BuiltInZoomControls
  • CacheMode
  • CursiveFontFamily
  • DatabaseEnabled
  • DatabasePath
  • DefaultFixedFontSize
  • DefaultFontSize
  • DefaultTextEncodingName
  • DisabledActionModeMenuItems
  • DisplayZoomControls
  • DomStorageEnabled
  • EnableSlowWholeDocumentDraw
  • EnableSmoothTransition
  • FantasyFontFamily
  • FixedFontFamily
  • ForceDark
  • GeolocationDatabasePath
  • GeolocationEnabled
  • HorizontalFadingEdgeEnabled
  • HorizontalScrollBarEnabled
  • HorizontalScrollbarThumbColor
  • HorizontalScrollbarTrackColor
  • InitialScale
  • JavaScriptCanOpenWindowsAutomatically
  • JavaScriptEnabled
  • LightTouchEnabled
  • LoadWithOverviewMode
  • LoadsImagesAutomatically
  • MediaPlaybackRequiresUserGesture
  • MinimumFontSize
  • MinimumLogicalFontSize
  • MixedContentMode
  • NeedInitialFocus
  • OffscreenPreRaster
  • RequestFocus
  • SafeBrowsingEnabled
  • SansSerifFontFamily
  • SaveFormData
  • SavePassword
  • ScrollbarFadingEnabled
  • ScrollBarDefaultDelayBeforeFade
  • ScrollBarFadeDuration
  • ScrollBarSize
  • ScrollBarStyle
  • SerifFontFamily
  • SetDownloadListener
  • SetWebChromeClient
  • SetWebViewClient
  • StandardFontFamily
  • SupportMultipleWindows
  • SupportZoom
  • TextZoom
  • UseWideViewPort
  • UserAgentString
  • VerticalFadingEdgeEnabled
  • VerticalScrollBarEnabled
  • VerticalScrollbarPosition
  • VerticalScrollbarThumbColor
  • VerticalScrollbarTrackColor
As of version 2.0, all UltimateWebView settings can be done through the Designer. It does not need to be set programmatically. Of course, the choice is yours.

3. Added methods to UltimateWebView class:
  • RequestFocus As Boolean
  • IsFocused As Boolean
  • ClearFocus

4. Added properties to UltimateWebViewSettings class:
  • HorizontalFadingEdgeEnabled As Boolean
  • HorizontalScrollBarEnabled As Boolean
  • HorizontalScrollBarThumbColor (Color As Int) 'Works from SDK29
  • HorizontalScrollBarTrackColor (Color As Int) 'Works from SDK29
  • ScrollbarFadingEnabled As Boolean
  • ScrollBarDefaultDelayBeforeFade As Int
  • ScrollBarFadeDuration As Int
  • ScrollBarSize As Int
  • VerticalFadingEdgeEnabled As Boolean
  • VerticalScrollBarEnabled As Boolean
  • VerticalScrollBarPosition (Value As Int)
  • VerticalScrollBarThumbColor (Color As Int) 'Works from SDK29
  • VerticalScrollBarTrackColor (Color As Int) 'Works from SDK29

5.
Added events:
  • OnShouldOverrideKeyEvent (KeyCode As Int, AndroidViewKeyEvent As Object) As Boolean
6. Bugs fixed.
 

mzsoft

Member
very good.
again error on load layout.
but error change.

B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
Error occurred on line: 33 (Main)
java.lang.RuntimeException: Cannot parse: null as boolean
    at anywheresoftware.b4a.BA.parseBoolean(BA.java:629)
    at anywheresoftware.b4a.BA.ObjectToBoolean(BA.java:699)
    at com.uwebview.ultimatewebview._afterloadlayout(ultimatewebview.java:302)
    at com.uwebview.ultimatewebview.callSub(ultimatewebview.java:3061)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:1066)
    at anywheresoftware.b4a.keywords.Common.CallSubNew2(Common.java:1037)
    at com.uwebview.ultimatewebview._designercreateview(ultimatewebview.java:835)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:777)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:354)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
    at anywheresoftware.b4a.objects.CustomViewWrapper.AfterDesignerScript(CustomViewWrapper.java:61)
    at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:162)
    at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:209)
    at com.test.net.main._activity_create(main.java:392)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:351)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
    at com.test.net.main.afterFirstLayout(main.java:105)
    at com.test.net.main.access$000(main.java:17)
    at com.test.net.main$WaitForLayout.run(main.java:83)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5293)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
** Activity (main) Resume **
 

Ivica Golubovic

Active Member
Licensed User
Okay, I'll try on older versions of androids. So far I have tried it on Android 9,10,11. Thank you for pointing me to the problem.
 

Ivica Golubovic

Active Member
Licensed User
Version 2.01 released. Download library and documents from first post.

Changes:
  • Bugs fixes for older versions of androids (below SDK28).
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…