This directory


preface

This article explains how Java code and Javascript code call each other and how Javascript code is dynamically injected into a WebView in Java. Some common configurations are described in Part 1.


Java calls JS functions

1. Add permissions (here using HTML files written in the resources directory)
<uses-permission android:name="android.permission.INTERNET"/>Copy the code
2. The webView configuration
.// omit findView.. webview
mWebView.getSettings().setJavaScriptEnabled(true);Copy the code
3. The use ofwebViewtheloadUrl()Method calls a JS function

Note that the function is preceded by javascript:

. btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Call a function with no arguments in JS
        mWebView.loadUrl("javascript:javacalljs()");
        mWebView.loadUrl("Javascript: javacalljswith (\" JAVA calls the JS function refs \ ")"); }}); .Copy the code

JS calls methods in Java

1. Add the js callback interface

The first argument is the class to receive the callback, written as the current class, and then the method called by JS is added to the current class. Obj is an alias, the same as in JS.

mWebView.addJavascriptInterface(this."obj");Copy the code
2. Add methods called by JS to Java.

Note that you must not forget to add @javascriptInterface to the method here and the window.obj.localMethods(‘Incoming ‘in web.html Parameters ‘) remain consistent.

.@JavascriptInterface
public void localMethods(String arg) {
    Log.i(TAG, "This method is called!");
    Toast.makeText(this."This method is called!", Toast.LENGTH_SHORT).show();
}Copy the code

Dynamic JS injection in Java

1. Inject JS methods

Here the injection time is after onPageFinished(); The injected JS is an alert for example.

public class JsInjectionActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {... InsideWebViewClient mInsideWebViewClient =new InsideWebViewClient();  
        mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.setWebViewClient(mInsideWebViewClient);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(JsInjectionActivity.this."obj");
        mWebView.loadUrl("file:///android_asset/web.html"); . }private class InsideWebViewClient extends WebViewClient {

        @Override
        public void onPageFinished(WebView view, String url) {
            mWebView.loadUrl("javascript:" + "window.alert('Js injection success')" );
            super.onPageFinished(view, url); }}}...Copy the code

Note: the js injected above contains an alert, which may not pop up after writing. At this time to check myWebView. SetWebChromeClient (new WebChromeClient ()); Whether it is set.

2. (Emphasis) Problems caused or possible problems caused by injected JS
  1. injectionjsIt might cause a loadhtml5Pages are always loading, loading slowly or not loading at all, and this problem is not universalhtml5You may encounter this problem on some web pages;
  2. The callback function is not executed after JS injection.

Solutions:

@Override    
protected void onPause(a){    
    super.onPause();    

    mWebView.pauseTimers();    
    if(isFinishing()){    
        mWebView.loadUrl("about:blank");    
        setContentView(new FrameLayout(this)); }}@Override    
protected void onResume(a){    
    super.onResume();    
    mWebView.resumeTimers();    
}Copy the code

Call the webView. LoadUrl (” about: blank “); This method causes the webView to return only a white background, frees the resources used to load the page, and stops the javascript execution.

PauseTimers, onPause stop parsing,javascript execution, etc. The difference is that onPause only works on the WebView that calls it, while pauseTimers work on all webViews in the current application

ResumeTimers, onResume resume parsing,javascript execution and other operations. The difference is that onResume only applies to the WebView that calls it, while resumeTimers apply to all webViews in the current application.

3. When the compressed JS is injected into the webView, the injection does not take effect

My solution: inject the JS formatted or uncompressed state successfully, I don’t know if others have encountered similar problems, or other reasons, there are questions, if you have encountered the same problem, welcome to communicate with you.

Online js formatting, four Spaces indentation indentation method choice: tool.oschina.net/codeformat/…


4. Complete code

Complete code, does not contain JS injection encountered the problem part, to join.

1. web.htmlfile

File path:.. src/main/assets/web.html

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <script type="text/javascript">

    function javacalljs(a){
        document.getElementById("content").innerHTML = 

JAVA calls JS functions without arguments
; } function javacalljswith(arg){ document.getElementById("content").innerHTML = ("<br>"+arg); } </script> </head> <body> HTML content display <br/> <h1> <div id="content"</div> </h1> <br/> <input type="button" value="Click to call Java code" onclick="window.obj.localMethods('Incoming parameters')"/><br/> </body> </html>Copy the code
2. JsInjectionActivity.javafile
public class JsInjectionActivity extends Activity {
    private static final String TAG = JsInjectionActivity.class.getSimpleName();

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn_invoke_js1 = (Button) findViewById(R.id.btn_invoke_js1);
        Button btn_invoke_js2 = (Button) findViewById(R.id.btn_invoke_js2);

        mWebView = (WebView) findViewById(R.id.webview);

        InsideWebViewClient mInsideWebViewClient = new InsideWebViewClient(a); mWebView.setWebChromeClient(new WebChromeClient());
        mWebView.setWebViewClient(mInsideWebViewClient);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(JsInjectionActivity.this."obj");
        mWebView.loadUrl("file:///android_asset/web.html");

        btn_invoke_js1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mWebView.loadUrl("javascript:javacalljs()"); }}); btn_invoke_js2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mWebView.loadUrl("Javascript: javacalljswith (\" JAVA calls the JS function refs \ ")"); }}); }@JavascriptInterface
    public void localMethods(String arg) {
        Log.i(TAG."This method is called!");
        Toast.makeText(this."This method is called!".Toast.LENGTH_SHORT).show();
    }

    private class InsideWebViewClient extends WebViewClient {

        @Override
        public void onPageFinished(WebView view, String url) {
            mWebView.loadUrl("javascript:" + "window.alert('Js injection success')" );
            super.onPageFinished(view, url); }}}Copy the code

The last

If you don’t know the place, you are welcome to send me a private letter. I will reply you in the first time. If you find something wrong in your reading, you are welcome to correct it.