Android Question Catching error messages from Webview using WebviewExtras

CidTek

Active Member
Licensed User
Longtime User
I'm loading html into a WebView that is Google Maps V3 JS (loads a map with markers) and I need to know if an error occurs so I can reload the WebView.

I've seen several references to WebviewExtras console logs but no clear example on how they used.
 

warwound

Expert
Licensed User
Longtime User
You need to add a WebChromeClient to your WebView, you'll now see all console messages from the WebView in the android log.

Take a look at this example:

B4X:
Sub Process_Globals

End Sub

Sub Globals
   Dim WebView1 As WebView
   Dim WebViewExtras1 As WebViewExtras
End Sub

Sub Activity_Create(FirstTime As Boolean)
   WebView1.Initialize("WebView1")
   WebViewExtras1.addWebChromeClient(WebView1, "")
   Activity.AddView(WebView1, 0,0, 100%x, 100%y)
   WebView1.LoadUrl("http://www.b4x.com/android/forum/threads/catching-error-messages-from-webview-using-webviewextras.33437/#content")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub WebView1_PageFinished (Url As String)
   Dim Javascript As String="alertt('Hello World');"
   WebViewExtras1.executeJavascript(WebView1, Javascript)
End Sub

The log shows:

** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
XenForo.init() %dms. jQuery %s/%s in http://www.b4x.com/android/forum/js/xenforo/xenforo.js?_v=28d42049 (Line: 191)
Uncaught ReferenceError: alertt is not defined in null (Line: 1)
Invalid App Id: Must be a number or numeric string representing the application id. in http://connect.facebook.net/en_US/all.js (Line: 56)
FB.getLoginStatus() called before calling FB.init(). in http://connect.facebook.net/en_US/all.js (Line: 56)
FB.getLoginStatus() called before calling FB.init(). in http://connect.facebook.net/en_US/all.js (Line: 56)

Not only is my deliberate javascript error reported (i used alertt instead of alert) but also some other errors.
If you are writing your own webpages you can make use of this using javascript such as:

B4X:
console.log('Hello World');

Martin.
 

Attachments

  • WebViewErrors.zip
    5.9 KB · Views: 749
Upvote 0

CidTek

Active Member
Licensed User
Longtime User
You need to add a WebChromeClient to your WebView, you'll now see all console messages from the WebView in the android log.

Not only is my deliberate javascript error reported (i used alertt instead of alert) but also some other errors.
If you are writing your own webpages you can make use of this using javascript such as:

B4X:
console.log('Hello World');

Martin.

Hi Martin,

How can you detect the presence of errors from within the app itself in real time? My situation (blank webview) is not handled by sitting at a PC looking the log in the IDE but it can be fixed by refreshing the Webview if the presence of an error is detected.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
Hi again.

Take a look at the library code which sends the WebView console messages to the android log:

B4X:
       public boolean onConsoleMessage(final ConsoleMessage consoleMessage1) {
         String logMessage = consoleMessage1.message() + " in " + consoleMessage1.sourceId() + " (Line: " + consoleMessage1.lineNumber() + ")";
         BA.Log(logMessage);
         return true;
       }

The WebChromeClient onConsoleMessage callback is passed a ConsoleMessage object, it strips the error message, source and line number from the ConsoleMessage and logs those values.

I could put a custom WebChromeClient together which instead of logging the console messages raises a b4a event and passes either the ConsoleMessage object or the error message, source and line number.
Ie the event could receive a ConsoleMessage and you could access the ConsoleMessage methods/properties, or the library could could extract the error message, source and line number from the ConsoleMessage and pass those values instead of the ConsoleMessage object.

Would that be of any use in your project?
To be honest i think that's about the best (only) solution available.

Martin.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
I decided it'd be a good update to raise an event and pass the ConsoleMessage object to b4a rather than logging the console message values to the android log.

So i've updated WebViewExtras2, which is the not yet officially uploaded updated version of WebViewExtras.
Grab the latest version of WebViewExtras2 from here: http://android.martinpearman.co.uk/b4a/temp/WebViewExtras2_20131012.zip.

Here's a sample project:

B4X:
Sub Process_Globals

End Sub

Sub Globals
   Dim WebViewExtras1 As WebViewExtras
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Dim WebView1 As WebView
   WebView1.Initialize("")
   WebViewExtras1.Initialize(WebView1)
   
   Dim WebChromeClient1 As DefaultWebChromeClient
   WebChromeClient1.Initialize("WebChromeClient1")
   
   WebViewExtras1.SetWebChromeClient(WebChromeClient1)
   
   Activity.AddView(WebViewExtras1, 0, 0, 100%x, 100%y)
   
   WebViewExtras1.LoadUrl("http://www.b4x.com/android/forum/threads/catching-error-messages-from-webview-using-webviewextras.33437/#post-195766")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub WebChromeClient1_ConsoleMessage(ConsoleMessage1 As ConsoleMessage) As Boolean
   Dim Message As StringBuilder
   
   Message.Initialize
   Message.Append("WebChromeClient1_ConsoleMessage: ")
   Select ConsoleMessage1.MessageLevel
     Case ConsoleMessage1.DEBUG
       Message.Append("DEBUG")
     Case ConsoleMessage1.ERROR
       Message.Append("ERROR")
     Case ConsoleMessage1.Log   '   the compiler insists on changing LOG to Log!
       Message.Append("LOG")
     Case ConsoleMessage1.TIP
       Message.Append("TIP")
     Case ConsoleMessage1.WARNING
       Message.Append("WARNING")
   End Select
   Log(Message.ToString)
   
   Message.Initialize
   Message.Append(ConsoleMessage1.Message)
   Message.Append(" in ")
   Message.Append(ConsoleMessage1.SourceId)
   Message.Append(" (Line: ")
   Message.Append(ConsoleMessage1.LineNumber)
   Message.Append(")")
   
   Log(Message.ToString)
   
   Return True
End Sub

You'll see the syntax for WebViewExtras2 is completely different to WebViewExtras.
WebViewExtras was a bunch of static methods that you passed an instance of a WebView to in order to execute a method.
WebViewExtras2 is a 'proper' instance of a WebView.

This is the new ConsoleMessage object reference:

ConsoleMessage
Fields:

  • DEBUG As MessageLevel
  • ERROR As MessageLevel
  • LOG As MessageLevel
  • TIP As MessageLevel
  • WARNING As MessageLevel
Methods:
  • IsInitialized As Boolean
  • LineNumber As Int
  • Message As String
  • MessageLevel As MessageLevel
  • SourceId As String

Don't try to use both WebViewExtras and WebViewExtras2 in the same b4a project, WebViewExtras2 can do all that WebViewExtras can do and a lot more.
If you need help converting from WebViewExtras to WebViewExtras2 then let me know.

The sample project is attached.

Martin.
 

Attachments

  • ConsoleMessage.zip
    6.1 KB · Views: 812
Upvote 0

CidTek

Active Member
Licensed User
Longtime User
Brilliant!!!

That fixed my issue which I guess I should explain. I ported my transit app to run on Blackberry OS10 whose versions vary from 10.0 and the soon to be released 10.2. The older versions of BB10 don't always play nice with Google maps V3 javascript in a Webview and require a refresh of the Webview until the map and markers display. This can vary from 0 to 3 refreshes depending on it's mood I guess.

The error was "Uncaught TypeError: Cannot read property 'style' of undefined in file/// (line 25)"

Now when I detect a console error I just...
WebView1.StopLoading
WebView1.LoadHtml(HTML)

which seems to work so smooth the user can't tell there was an issue.

This will be less of an issue as BB10.2 is released.

Thanks so much for this solution and I sent you a contribution in appreciation.
 
Last edited:
Upvote 0

CidTek

Active Member
Licensed User
Longtime User
What is the syntax for adding an interface name with the new library (WebViewExtras2)?

I'm getting "Uncaught ReferenceError: B4A is not defined" when I use the following js.

google.maps.event.addListener(map, 'click', function(event) {
latLon = event.latLng.lat().toFixed(6) + ' |' + event.latLng.lng().toFixed(6);
B4A.CallSub('ShowToast', true, latLon);
});
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
The B4A object your error refers to is the InterfaceName passed to the WebViewExtras AddJavascriptInterface method:

AddJavascriptInterface (JavascriptInterface As Object, InterfaceName As String)
Injects the supplied Java object into this WebView.
JavascriptInterface - The Java object to inject into this WebView's JavaScript context. Null values are ignored.
InterfaceName - The name used to expose the object in JavaScript.

Most of my examples use B4A as the InterfaceName but you can use just about any name you want.

Martin.
 
Upvote 0

CidTek

Active Member
Licensed User
Longtime User
Note I am using WebViewExtras2

I added the javascript interface

WebviewExtras1.Initialize(WebView1)
Dim WebChromeClient1 AsDefaultWebChromeClient
WebChromeClient1.Initialize("WebChromeClient1")
WebviewExtras1.SetWebChromeClient(WebChromeClient1)
WebviewExtras1.addJavascriptInterface(WebView1, "B4A")


I get this error...
Uncaught TypeError: Object android.webkit.WebView@414e1de0 has no method 'CallSub'

with this code...

google.maps.event.addListener(map, 'click', function(event) {
var LatLon = event.latLng.lat().toFixed(6) + ' |' + event.latLng.lng().toFixed(6);
B4A.CallSub('ShowToast', true, LatLon);
});
 
Last edited:
Upvote 0

warwound

Expert
Licensed User
Longtime User
You have a mix of syntax from the original WebViewExtras and WebViewExtras2.

This line (with WebViewExtras2) adds the WebView to itself as a JavascriptInterface:

B4X:
WebviewExtras1.addJavascriptInterface(WebView1, "B4A")

Hence the Uncaught TypeError.

The lower case a in addJavascriptInterface looks like it's been copied from code that used the original version of WebViewExtras.

This is an example of adding a DefaultJavascriptInterface and DefaultWebChromeClient to a WebView using WebViewExtras2:

B4X:
WebViewExtras1.Initialize(WebView1)

Dim JavascriptInterface1 As DefaultJavascriptInterface
JavascriptInterface1.Initialize
WebViewExtras1.AddJavascriptInterface(JavascriptInterface1, "B4A")

Dim WebChromeClient1 As DefaultWebChromeClient
WebChromeClient1.Initialize("WebChromeClient1")
WebViewExtras1.SetWebChromeClient(WebChromeClient1)

WebViewExtras2 has been updated a few times, my main reason not to have properly released WebViewExtras2 to the b4a forum has been a reluctance to handle the confustion between the old and new versions.

Latest version of WebViewExtras2.

Martin.
 
  • Like
Reactions: eps
Upvote 0

CidTek

Active Member
Licensed User
Longtime User
Progress but another stumbling block.

I got my toast message with your declaration changes but a java error immediately popped after the toast.

How do I set Geolocation permission and handle requests (hopefully without a popup everytime) using WebViewExtras2?

I downloaded your latest release.


java.lang.NullPointerException

at uk.co.martinpearman.b4a.webkit.DefaultWebChromeClient$1.onGeolocationPermissionsShowPrompt(DefaultWebChromeClient.java:66)
at android.webkit.CallbackProxy.handleMessage(CallbackProxy.java:558)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5041)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
 
Upvote 0

CidTek

Active Member
Licensed User
Longtime User
The syntax in your example fails with your new WebViewExtras2

Substituting B4A for the MyEventName as in
"Sub B4A_GeolocationPermissionsRequest As Int" results in the sub name underlined in red in the IDE.

Also "Return WebViewExtras1.GEOLOCATION_PERMISSION_ALLOW" results in an Unknown member error.

It would be nice to have sample projects that you have for WebViewExtras rewritten for WebViewExtras2.


Did you get my donation I sent you last week?
What I assumed to be the return page to your site after the donation was made resulted in an html error but PayPal shows the payment was sent.
 
Upvote 0

warwound

Expert
Licensed User
Longtime User
@CidTek

Take a look at this, it's a rewrite of the old WebViewExtras geolocation demo.
Works fine here on Jelly Bean:

B4X:
Sub Process_Globals

End Sub

Sub Globals
   '   WebChromeClient1 is a global so we can reference it in the Sub WebChromeClient1_GeoLocationPermissionsRequest
   Dim WebChromeClient1 As DefaultWebChromeClient
   Dim WebView1 As WebView
   Dim WebView2 As WebView
   Dim WebViewExtras1 As WebViewExtras
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("layoutMain")
  
   WebView1.Height=100%y/2
   WebView1.Width=100%x
  
   WebViewExtras1.Initialize(WebView1)
   WebChromeClient1.Initialize("WebChromeClient1")
   WebViewExtras1.SetWebChromeClient(WebChromeClient1)
  
   WebView1.LoadUrl("http://html5demos.com/geo")
  
   WebView2.Top=(100%y/2)+1
   WebView2.Height=100%y/2
   WebView2.Width=100%x
   WebView2.LoadUrl("http://html5demos.com/geo")
   '   no WebChromeClient is added to WebView2
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub WebChromeClient1_GeoLocationPermissionsRequest As Int
   '   note that the manifest has had android.permission.ACCESS_FINE_LOCATION manually added to it
   Dim Response As Int
   Response=Msgbox2("Allow WebView1 to use device geolocation features?", "Permission required:", "Allow", "", "Disallow", Null)
   If Response=DialogResponse.POSITIVE Then
     ToastMessageShow("Permission granted", True)
     Return WebChromeClient1.GEOLOCATION_PERMISSION_ALLOW
   Else
     ToastMessageShow("Permission denied", True)
     Return WebChromeClient1.GEOLOCATION_PERMISSION_DISALLOW
   End If
End Sub

See how GEOLOCATION_PERMISSION_ALLOW and GEOLOCATION_PERMISSION_DISALLOW are now fields of the DefaultWebChromeClient and not fields of the WebViewExtras object?

Maybe that error was causing your Sub to be underlined in red?

I've just uploaded an update to WebViewExtras2: http://android.martinpearman.co.uk/b4a/temp/WebViewExtras2_20131025.zip
The update now properly checks that the GeoLocationPermissionsRequest Sub has returned an integer value, the update isn't essential but you might as well download it just so you have the latest version.

Thanks for the donation - much appreciated.
I keep trying to fix that Paypal redirect that occurs when someone sends me a donation but can't find where in the Paypal settings to cancel it.

Martin.
 

Attachments

  • GeolocationDemoFixed.zip
    6.8 KB · Views: 735
Upvote 0
Top