Detect click on HTML button through javascript in Android WebView

88,605

Solution 1

I finally got it on my own after some reading. Kind of hard when you know nothing about javascript and when the doc is quite thin on the subject.
Here is my solution, hope this will help others :

With an HTML page containing 2 buttons at the end like that :

<div>
     <button type="button" id="ok" style="font-weight: 700; margin-right: 20px;" onclick="validClick();">J'accepte</button>
     <button type="button" id="no" onclick="refuseClick();">Je refuse</button>
</div>

I send the event of the click to the javascript at the top of my HTML page :

<script language="javascript">

   function validClick()
   {
      valid.performClick();
      document.getElementById("ok").value = "J'accepte";
   }
   function refuseClick()
   {
      refuse.performClick();
      document.getElementById("no").value = "Je refuse";
   }

</script>

valid and refuse are 2 java objects that I passed through the javascript interface to use their methods. So in java, I created 2 buttons (not really displayed in the Activity, only here for their methods and are sort of shadows of the HTML buttons :

valid = new Button(ctx);
valid.setOnClickListener(this);
refuse = new Button(ctx);
refuse.setOnClickListener(this);

Then I added javascript to my WebView :

// Enablejavascript
WebSettings ws = wv.getSettings();
ws.setJavaScriptEnabled(true);
// Add the interface to record javascript events
wv.addJavascriptInterface(valid, "valid");
wv.addJavascriptInterface(refuse, "refuse");

And finally, handle the click events in the onClick method :

@Override
public void onClick(View v) {
    if (v.equals(valid)) {
        //do Something
    } else if (v.equals(refuse)) {
        //do Something else }
}

Hope this will help some people

Solution 2

Here's a simpler solution. On the Java side, create a listener for each button. It doesn't need to be any particular class, since the method will be looked up using reflection:

WebSettings ws = wv.getSettings();
ws.setJavaScriptEnabled(true);
wv.addJavascriptInterface(new Object()
{
  public void performClick()
  {
    // Deal with a click on the OK button
  }
}, "ok");

Then in the HTML, call it directly from the button tag:

<button type="button" onclick="ok.performClick();">OK</button>

Solution 3

In case you also want to retrieve button value.

Java:

WebSettings ws = wv.getSettings();
ws.setJavaScriptEnabled(true);
wv.addJavascriptInterface(new Object()
{
   @JavascriptInterface           // For API 17+
   public void performClick(String strl)
   {
      stringVariable = strl;
      Toast.makeText (YourActivity.this, stringVariable, Toast.LENGTH_SHORT).show();
   }
}, "ok");

HTML:

<button type="button" value="someValue" onclick="ok.performClick(this.value);">OK</button>

Solution 4

    WebView browser = new WebView(this);
    browser.getSettings().setJavaScriptEnabled(true);
    browser.loadUrl("file:///android_asset/page.html");
    setContentView(browser);
    WebSettings ws = browser.getSettings();
    ws.setJavaScriptEnabled(true);
    browser.addJavascriptInterface(new Object()
    {
        @JavascriptInterface           // For API 17+
        public void performClick(String strl)
        {

            Toast.makeText (MainActivity.this, strl, Toast.LENGTH_SHORT).show();

        }
    }, "ok");

page.html file

<html>
<body>

    First name: <input type="text" name="fname" id="txtfname"><br>
    Last name: <input type="text" name="lname" id="txtlname"><br>

    <script>
    function getValues() {
    document.getElementById("btnOK").value = document.getElementById("txtfname").value+" "+document.getElementById("txtlname").value;
    }
    </script>

    <button type="button" value="" id="btnOK" onclick="getValues();ok.performClick(this.value);">OK</button>
</body>
</html>

Solution 5

Use below Android code and web code also given below of android code. I am already implemented the below all code and its running perfectly fine in android version 11

 mWebView.loadUrl(outputResponse.getRedirectUserTo());
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        mWebView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Intent returnIntent = new Intent();
                        returnIntent.putExtra("result",message);
                        setResult(Activity.RESULT_OK,returnIntent);
                        finish();
                    }
                });
                return true;
            }
        });

        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return true;
            }
        });

   function validClick()
   {
      alert("Success");
   }
 
    
    {
        background:#f2f2f2;
    }

    .payment
    {
        border:2px solid #01BD9A;
        height:280px;
        border-radius:20px;
        background:#fff;
    }
   .payment_header
   {
        background:#01BD9A;
       padding:20px;
       border-radius:20px 20px 0px 0px;
       
   }

    .button_clk
   {
        background:#F55951;
       padding:10px;
       margin-top: 30;
       border-radius:20px 20px 20px 20px;
       
   }
   
   .check
   {
       margin:0px auto;
       width:50px;
       height:50px;
       border-radius:100%;
       background:#fff;
       text-align:center;
   }
   
   .check i
   {
       vertical-align:middle;
       line-height:50px;
       font-size:30px;
   }

    .content 
    {
        text-align:center;
    }

    .content  h1
    {
        font-size:25px;
        padding-top:25px;
    }

    .content a
    {
        width:200px;
        height:35px;
        color:#fff;
        border-radius:30px;
        padding:5px 10px;
        background:rgba(255,102,0,1);
        transition:all ease-in-out 0.3s;
    }

    .content a:hover
    {
        text-decoration:none;
        background:#000;
    }
   
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />

<body>

<div class="container">
   <div class="row">
      <div class="col-md-6 mx-auto mt-5">
         <div class="payment">
            <div class="payment_header">
               <div class="check"><i class="fa fa-check" aria-hidden="true"></i></div>
            </div>
            <div class="content">
               <h1>Payment Success !</h1>
               <div>
     <button class="button_clk" type="button" id="ok" onclick="validClick();">Go Back</button>
     
</div>
            </div>
            
         </div>
      </div>
   </div>
</div>

   </body>
Share:
88,605
Sephy
Author by

Sephy

Free s/Lance/Spirit Frontender with a touch of backend culture (Fullstack :D ? ) Enjoys playing with all the crazy stuff going about the web platform (React, React Native, new Web APIs, Angular, NodeJs ...)

Updated on July 09, 2022

Comments

  • Sephy
    Sephy almost 2 years

    I'm not highly familiar with javascript but I think this is the best way to accomplish my purpose. If not, please correct me.

    I have a licence text 2 buttons at the end. All of this is written in HTML in a WebView because there are some links in the licence. Now, I want that when the user clicks the "ok" button in the WebView, this triggers some javascript or listener that I can grab in Java to fire an Intent to go forward in the application. (The cancel button would do the opposite, but if I know how to do one, I can do the other. ;) )

    Does this rings any bell to someone? Any explanation or sample code is welcome.

  • Sephy
    Sephy over 12 years
    Seems to me to be quite the same as mine though with only one button. Note that I'd bind the javascript interface to a Button instead of a simple Object, this way you can benefit the whole set of methods and stuff around buttons !
  • Steve Blackwell
    Steve Blackwell about 11 years
    peastman's method is actually better, at least semantically. Binding to a Button will trick people into thinking there's a link between them, but there's not. The code doesn't care whether you bind your JavaScript to a Button or a Bitmap or a plain Object. It will call whatever function you tell it to. You don't get access to extra methods. For example, calling setText() on your Java Button object won't change the text of you HTML buttons.
  • newBie
    newBie over 10 years
    @Sephy can you please explain what is valid and refuse are they buttons or JavaWebInterface objects? And the onclick method is because you have implemented onclick listener or something of that sort? I am sorry but I am not able to run the above code. Please help. Thanks
  • Mr.India
    Mr.India over 10 years
    @Sephy this is not working in Android 2.3 . I there i any way to implement this?
  • mamba4ever
    mamba4ever over 10 years
    IMPORTANT! For devices api level 17+ Don't forget to add "@JavascriptInterface" annotation. From developer.android.com/guide/webapps/webview.html Caution: If you've set your targetSdkVersion to 17 or higher, you must add the "@JavascriptInterface" annotation to any method that you want available to your JavaScript (the method must also be public). If you do not provide the annotation, the method is not accessible by your web page when running on Android 4.2 or higher.
  • Geet taunk
    Geet taunk over 10 years
    Anyone here? its not working in 4.1 and 4.2 as well. Please help
  • iAmLearning
    iAmLearning over 10 years
    I tried but not working for me. Please see stackoverflow.com/questions/20917235/…
  • George Thomas
    George Thomas over 9 years
    what about a remote url, which is not in the assets folder, how to get click from it
  • user1530779
    user1530779 almost 9 years
    Does this name "performClick" has to be same across both java and javascript ?
  • user1530779
    user1530779 almost 9 years
    @Sephy : Im assuming here that the object should have a click listener here , Name of the function is not important Ami right ? Or to say it simply performClick can be replaced with any text ?
  • user1530779
    user1530779 almost 9 years
    Does this name "performClick" has to be same across both java and javascript ?
  • Scaraux
    Scaraux over 8 years
    @user1530779 Yes, because it's the name of the Object function
  • IntoTheDeep
    IntoTheDeep about 8 years
    Unable to add javascriptInterface
  • Bheid
    Bheid over 5 years
    I got this error: Uncaught TypeError: ok.performClick is not a function", source: file:....
  • Gemini Keith
    Gemini Keith over 3 years
    What if I do not want to change the HTML source code or the site isn't mine?
  • Denny Hsu
    Denny Hsu about 2 years
    Add "@JavascriptInterface" annotation before the line "public void performClick()" then it works.