B4A Library WebViewExtras

Discussion in 'Additional libraries, classes and official updates' started by warwound, Nov 7, 2011.

  1. warwound

    warwound Expert Licensed User

    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:

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

    Attached Files:

    Last edited: Jan 6, 2015
  2. NeoTechni

    NeoTechni Well-Known Member Licensed User

    Scrolling by page is perfect, but how do we know how many pages there are?
     
  3. warwound

    warwound Expert Licensed User

    Hi.

    I can find no method that will return how many pages are in a particular WebView.

    I think you need to look at the return value from a call to pageDown() or pageUp().
    If the call returns a boolean false then the scroll has failed - that might(!) indicate that there are no more pages to scroll through.

    Martin.
     
    sk_9999 likes this.
  4. Cableguy

    Cableguy Expert Licensed User

    Hi Martin...

    I really need some kind of WebView.GetDocument alike method...So I started seaching and found these 2 webpages...

    Xebra Labs: Extract HTML from Android webview

    Android WebBrowser using WebView « PocketMagic

    In them thay state that using JSInterface along with WeView it is possible to retrieve the pages html...
    Anyway of adding this to your dll?

    BTW...Why not create a WebViewAdv dll, with all these methods included as well as the "native" basic WebView methods???
     
    manuaaa and KY Leng like this.
  5. warwound

    warwound Expert Licensed User

    Hi.

    Look at this thread you started a few days back:

    http://www.basic4ppc.com/forum/bugs-wishlist/12404-wish-webview-documenttext-get.html#post69709

    And my related post:

    http://www.basic4ppc.com/forum/basi.../9400-save-webview-html-file-2.html#post56406

    With WebViewExtras or JSInterface you can execute javascript AFTER the webpage has loaded and that javascript can send the page HTML content as a string to a B4A Sub.

    But the mechanism is asynchronous - i can't create a getter method that will return the webpage HTML.

    Asking the webpage to send it's HTML to a B4A Sub (and then taking action) is the best option available.

    As for creating a new custom WebView library instead of a library (such as WebViewExtras) that extends the default B4A WebView...

    Have a read here http://www.basic4ppc.com/forum/libraries-developers-questions/11106-decompiled-webviewwrapper.html

    agraham is right - it's better to leave the default views (WebView or whatever) as native B4A views that get updated as B4A develops and create libraries to increase their functionality rather than taking on the (ominous!) task of creating and updating custom B4A views.

    Martin.
     
  6. agraham

    agraham Expert Licensed User

    Oh doom! Onerous maybe? :)
     
  7. warwound

    warwound Expert Licensed User

    LOL it's Friday night and my syntax is going going gone - just like me.

    Martin.
     
  8. Cableguy

    Cableguy Expert Licensed User

  9. warwound

    warwound Expert Licensed User

    Hi all.

    WebViewExtras is now updated to version 1.1.

    No new methods to document but i have updated it's addWebChromeClient method.

    This updated WebChromeClient overrides the default onExceededDatabaseQuota method.
    Detailed info can be found here: WebChromeClient | Android Developers.

    This means that we can now properly enable and use the HTML5 Database Storage API in a WebView.

    I have updated my WebViewSettings library too with 5 new methods and you'll need both WebViewSettings and WebViewExtras to enable the database storage API:

    Code:
    Sub Globals
       
    Dim WebView1 As WebView
       
    Dim WebViewExtras1 As WebViewExtras
       
    Dim WebViewSetting1 As WebViewSettings
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       WebView1.Initialize(
    "WebView1")
       
       WebView1.JavaScriptEnabled=
    True
       WebViewExtras1.addJavascriptInterface(WebView1, 
    "B4A"' NOT ESSENTIAL
       WebViewExtras1.addWebChromeClient(WebView1)
       WebViewSetting1.setDatabaseEnabled(WebView1, 
    True)
       
    '   WebViewSetting1.setDOMStorageEnabled(WebView1, True)
       
       
    Log("DefaultWebViewDatabasePath: "&WebViewSetting1.getDatabasePath(WebView1))
       
    '   the WebView will fail to create any databases if the database path is NOT set
       WebViewSetting1.setDatabasePath(WebView1, "")
       
    Log("NewWebViewDatabasePath: "&WebViewSetting1.getDatabasePath(WebView1))
       
       
       
    Activity.AddView(WebView1, 00100%x100%y)
       WebView1.LoadUrl(
    "file:///android_asset/my_webpage.htm")
       
    End Sub
    Version 1.1 of WebViewExtras is attached to post #1 in this thread.

    I shall post a demo project using the new database storage API within the next few days.

    Martin.
     
  10. warwound

    warwound Expert Licensed User

    WebViewExtras updated to version 1.20

    This updates adds no new methods or properties to the library.
    It does however (internally) update the WebChromeClient that can be added to a WebView.

    The updated WebChromeClient enables web pages with file upload forms to be properly handled.
    Prior to this update if your WebView displayed a page with a file upload form, the user would not be able to select a file from the device to upload.
    With this update the user can now select a file to upload.

    Version 1.20 of WebViewExtras is attached to the first post in this thread.
    The attachment also contains a demo of the new file upload capability.

    Martin.
     
  11. bluedude

    bluedude Well-Known Member Licensed User

    Could it be used like this

    Hi,

    I'm looking into adding new UI elements by using webviews and jQuery interface elements. Would below code work?

    script>
    $(function() {
    $(".knob").knob(
    {
    'change':function(e){
    console.log(e);
    B4A.CallSub('changeKnob', true)
    }
    }
    )

    ;
    });
    </script>
     
  12. warwound

    warwound Expert Licensed User

    I see no reason why it wouldn't work.

    As long as jQuery doesn't use any javascript that is not supported by the WebView there should be no problems.

    WebView is quite up to date with it's level of javascript support so jQuery should be fine.

    Martin.
     
  13. bluedude

    bluedude Well-Known Member Licensed User

    Got that working, now I need to change a value in the html file

    Hi,

    That works! Now I want to execute some javascript to change a value, that is not in your samples.

    Is there a simple execute javascript sample?

    Cheers,
     
  14. warwound

    warwound Expert Licensed User

    This is the basic code structure to execute some javascript:

    Code:
    Dim Javascript As String
    Javascript=
    "alert('Hello World!')"
    MyWebViewExtras.executeJavascript(WebView1, Javascript)
    That won't actually do anything unless you've added a WebChromeClient to your WebView as the default B4A WebView does not display modal dialogs such as alert.

    Anyway search the forum for 'executeJavascript' and you'll find some posts with various examples.

    Martin.
     
  15. warwound

    warwound Expert Licensed User

    WebViewExtras updated to version 1.30

    This updates adds no new methods or properties to the library.
    It does however (internally) update the WebChromeClient that can be added to a WebView.

    The WebChromeClient now handles web pages that make requests to use the device's geolocation features.

    If you add a WebChromeClient to a WebView and display a web page that tries to use geolocation then an event is raised:

    GeolocationPermissionsRequest As Int

    If you want to handle this event then the Sub that you create must return an Int value to indicate whether permission has been granted or not.

    Valid values are:

    Code:
    MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW
    MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW_AND_REMEMBER
    MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW
    MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW_AND_REMEMBER
    All pretty self explanatory - allow or deny permission and remember or don't remember the permission.

    This update will break existing code that uses the WebViewExtras addWebChromeClient method!

    Versions of WebViewExtras prior to 1.30 did NOT require that an EventName was passed in the addWebChromeClient method.

    The EventName is now required so that your B4A Activity can handle whether or not to allow a web page to use the device's geolocation features.

    I don't like to create an update that breaks existing code but this is a very useful update and it cannot be implemented without requiring an EventName.

    Additionally to enable geolocation you must use the Manifest Editor to add this line to your application:

    Code:
    'End of default text.
    AddPermission(android.permission.ACCESS_FINE_LOCATION)
    I have updated the addWebChromeClient method documentation in the first post in this thread.

    Here's some sample code:

    Code:
    '   WebViewExtras geolocation demo Activity module
    Sub Process_Globals
    End Sub

    Sub Globals
       
    Dim MyWebViewExtras As WebViewExtras
       
    Dim WebView1 As WebView
       
    Dim WebView2 As WebView
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("layoutMain")
       
       WebView1.Height=
    100%y/2
       WebView1.Width=
    100%x
       
       
    '   add the WebChromeClient to WebView1
       '   with version 1.30 of WebViewExtras an EventName is now required when adding the WebChromeClient
       MyWebViewExtras.addWebChromeClient(WebView1, "MyEventName")
       
       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 MyEventName_GeolocationPermissionsRequest As Int
       
    Dim Response As Int
       Response=
    Msgbox2("Allow the webpage to use device geolocation features?""Permission required:""Allow""""Disallow"Null)
       
    If Response=DialogResponse.POSITIVE Then
          
    ToastMessageShow("Permission granted"True)
          
    Return MyWebViewExtras.GEOLOCATION_PERMISSION_ALLOW
       
    Else
          
    ToastMessageShow("Permission denied"True)
          
    Return MyWebViewExtras.GEOLOCATION_PERMISSION_DISALLOW
       
    End If
    End Sub
    I create two WebViews, one has a WebChromeClient added and the other does not.

    The WebView that has a WebChromeClient added causes the MyEventName_GeolocationPermissionsRequest Sub to be called when the web page asks for the user's geolocation.
    The Sub grants or denies permission based on user input.

    Tested and working on my ZTE Blade running CyanogenMod7 Gingerbread.
    There is a possibility that newer versions of Android will require you to enable Geolocation in the WebView so i have updated WebViewSettings to enable that.

    Updated demo code and library are attached to the first post in this thread.

    Martin.
     
  16. NeoTechni

    NeoTechni Well-Known Member Licensed User

    How about a Callsub that takes a list of parameters, that way you only need 1 version and it can take any number of parameters.
     
  17. warwound

    warwound Expert Licensed User

    Unfortunately that's not possible.

    You cannot pass a (javascript) Array to the CallSub method.

    Only basic types such as strings, booleans and numbers can be used.

    There's a blog HERE that you might find interesting.
    It documents some of the quirks and limits of the JavascriptInterface.

    Passing a single string to CallSub where that string is a JSON object containing any number of values of any valid type looks like a flexible solution.

    Martin.
     
  18. vitneum

    vitneum Member Licensed User

    filedialog....

    :sign0085:
    Hi Everyone~
    "file upload dialog" function well does it work?
    In my case, "dialog" that will be displayed.
    but, the files have not been able to choose.:BangHead:
     
  19. warwound

    warwound Expert Licensed User

    I've just updated the demo code in the attachment, it lacked an EventName parameter to work with the latest version of WebViewExtras:

    Code:
    Sub Activity_Create(FirstTime As Boolean)
       WebView1.Initialize(
    "WebView1")
       
       
    '   no EventName is used as we're not listening for the GeolocationPermissionsRequest event
       WebViewExtras1.addWebChromeClient(WebView1, "")
       
       
    Activity.AddView(WebView1, 00100%x100%y)
       
       WebView1.LoadUrl(
    "http://cgi-lib.berkeley.edu/ex/fup.html")
    End Sub
    Presumably you've added an EventName as your code compiles.

    Can you zip and upload your project so i can try it myself?

    And can you post what device you're running it on - is it an Android device running HoneyComb or ICS OR is it a device running a version of Android prior to Honeycomb?

    Martin.
     
  20. vitneum

    vitneum Member Licensed User

    I was just run your source code to the emulator.

    Select the file and return to first screen.

    File is not selected.
    and Click the screen also does not react.

    emulator version 2.2 and 2.3.3

    TT...
     
Loading...