First, Android and JS interaction – bridge WebView
(1) JS calls Android methods
There are three methods of JS calling Android, and the principles, use, advantages and disadvantages are introduced in the following sequence.
1. Object mapping via addJavascriptInterface() of WebView
Specific principles
Android and JS through webview. AddJavascriptInterface (new JSKit (), “MJS) method to form the object map, JS object of MJS can invoke in the Android JSKit methods on the object.
The specific use
Step 1: In Android, set the mapping between Android classes and JS code through WebView
public class MainActivity extends AppCompatActivity {
WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true); // Set the permission to interact with Js // Javascript object name / / through the addJavascriptInterface () AJavaScriptInterface class object is mapped to the JS object of MJS mWebView. AddJavascriptInterface (new JSKit(),"mjs"); // Load the JS code mwebview.loadURL ("file:///android_asset/javascript.html");
Copy the code
Step 2: Define an Android class: JSKit that maps to JS objects
Public class JSKit {// define the method that JS needs to call, @javascriptInterface public void hello(String MSG) {system.out.println (String MSG);"JS successfully calls Android's hello method"); }}Copy the code
Step 3: Place the javascript. HTML format of the javascript code to be called in the SRC /main/assets folder
<! DOCTYPE html> <html> <head> <meta charset="utf-8">
<title>Carson</title>
<script>
function callAndroid(){// called because of object mappingtestObject is equal to calling the Android mapped object mjs.hello("Js calls the Hello method in Android"); } </script> </head> <body> // Click the button to call callAndroid function <buttontype="button" id="button1" onclick="callAndroid()"></button>
</body>
</html>
Copy the code
The advantages and disadvantages
Advantages: simple to use, only Android objects and JS objects can be mapped;
Disadvantages:
For Android below 4.2, there are security vulnerabilities, which need to be fixed by interception Prompt ();
For Android above 4.2, you only need to annotate the function called by JS with @javascriptInterface
Intercepting urls via the WebViewClient shouldOverrideUrlLoading() method callback;
Specific principles
Android intercepts the URL through the WebViewClient callback shouldOverrideUrlLoading() and resolves the protocol for the URL. If a pre-agreed protocol is detected, the corresponding method is called, that is, JS needs to call the method in Android.
The specific use
Step 1: Place the required Url protocol JS code: javasjavascript. HTML in the SRC /main/assets folder
<! DOCTYPE html> <html> <head> <meta charset="utf-8">
<title>SoarYuan</title>
<script>
function callAndroid(){/* The convention url protocol is: js:// webView? arg1=111&arg2=222*/ document.location ="js://webview? arg1=111&arg2=222"; } </script> </head> <! -- Clicking the button calls the callAndroid() method --> <body> <buttontype="button" id="button2" onclick="callAndroid()"</button> </body> </ HTML >Copy the code
When the JS is loaded via Android’s mwebview.loadurl (“file:///android_asset/javascript.html”), it calls shouldOverrideUrlLoading().
Step 2: Override shouldOverrideUrlLoading() on Android via WebViewClient
public class MainActivity extends AppCompatActivity {
WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true); / / set with Js interaction permissions webSettings. SetJavaScriptCanOpenWindowsAutomatically (true); Step 1: load the JS code in the following format :file:///android_asset/ filenames. HTML mwebview.loadurl ("file:///android_asset/javascript.html"); / / copy the WebViewClient class mWebView shouldOverrideUrlLoading method. The setWebViewClient (newWebViewClient() {/ / the overloading method is not recommended, above 7.0 system has rejected the / / shouldOverrideUrlLoading (WebView view, String url) this method, / / if you want to intercept the url, you need to do to compatibility, Rewrite / / shouldOverrideUrlLoading (WebView view, WebResourceRequest request) method, @override public Boolean shouldOverrideUrlLoading(WebView View, String URL) {returnsuper.shouldOverrideUrlLoading(view, url); } @override public Boolean shouldOverrideUrlLoading(WebView View, WebResourceRequest Request){ // It is generally determined by scheme (protocol format) & authority (protocol name) (first two parameters) // It is assumed that the url passed in ="js://webview? arg1=111&arg2=222"Uris (which are also agreed to intercept) URIs;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
uri = request.getUrl();
} else{ uri = Uri.parse(request.toString()); } // If the url's protocol = predefined JS protocol, parse the following parsing parametersif ( uri.getScheme().equals("js")) {// if authority = pre-agreed webview in the protocol, that is, represents the convention of the protocol // so intercept the URL, the following JS starts to call the method Android needsif (uri.getAuthority().equals("webview") {// Step 3: Execute the logic system.out.println ("Js calls Android methods"); HashMap<String, String> params = new HashMap<>(); Set<String> collection = uri.getQueryParameterNames(); String result =(useid=123456);
view.loadUrl("javascript:returnResult(\"" + result + "\")");
}
return true;
}
returnsuper.shouldOverrideUrlLoading(view, request); }}); }}Copy the code
The advantages and disadvantages
Advantages: No addJavascriptInterface() vulnerability;
Disadvantages: Complex return value of JS getting Android methods. If JS wants to get the return value of the Android method, it must execute the JS method to pass the return value back via the WebView loadUrl().
// Android:MainActivity.java
mWebView.loadUrl("javascript:returnResult(" + result + ")"); / / JS: javascript. HTMLfunction returnResult(result){
alert("result is" + result);
}
Copy the code
3, through the WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt() method callback interception JS dialog box alert(), confirm(), prompt() method, message interception
Specific principles
Android intercepts JS dialogs via onJsAlert(), onJsConfirm(), and onJsPrompt (), and then parses the content of their messages.
The specific use
The common interception is JS input box prompt() method, because only prompt() can return any type of value, the operation is the most comprehensive, convenient, more flexible; The alert() dialog does not return a value; The Confirm () dialog box can only return two values in two states (confirm/cancel).
Step 1: Load the JS code, as follows: javascript. HTML into the SRC /main/assets folder
<! DOCTYPE html> <html> <head> <meta charset="utf-8">
<title>SoarYuan</title>
<script>
function clickprompt(){var result=prompt();"js://demo? arg1=111&arg2=222");
alert("demo "+ result); } </script> </head> <! Clickprompt () --> <body> <buttontype="button" id="button3" onclick="clickprompt()"</button> </body> </ HTML >Copy the code
When the above JS code is loaded using mwebview.loadurl (“file:///android_asset/javascript.html”), the callback onJsPrompt() is triggered, as follows:
If it is an interception warning box, alert(), the callback onJsAlert() is triggered; The callback onJsConfirm() is triggered if it is intercepting the confirmation box, known as Confirm();
Step 2: Copy onJsPrompt() on Android via WebChromeClient
public class MainActivity extends AppCompatActivity {
WebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true); / / set with Js interaction permissions webSettings. SetJavaScriptCanOpenWindowsAutomatically (true); Step 1: load the JS code in the following format :file:///android_asset/ filenames. HTML mwebview.loadurl ("file:///android_asset/javascript.html");
mWebView.setWebChromeClient(new WebChromeClient() {// block the input field (shouldOverrideUrlLoading) // Message: represents the content of promt() (not the URL) // result: represents the return value of the input field @override public Boolean onJsPrompt(WebView view, String URL, String Message, String defaultValue, JsPromptResult result) {// Step 2: Determine whether the url is required according to the protocol parameters (same principle as method 2) // Generally judge according to scheme (protocol format) & authority (protocol name) (first two parameters) // The url passed in ="js://webview? arg1=111&arg2=222"Uri = uri.parse (message); // If url protocol = pre-agreed js protocol, parse the following parsing parametersif ( uri.getScheme().equals("js") {// if authority = the webview in the protocol in advance, that is, the protocol that represents the convention // so intercept the URL, the JS below starts to call the method that Android needsif (uri.getAuthority().equals("webview") {// Step 3: Execute the logic system.out.println ("Js calls Android methods"); HashMap<String, String> params = new HashMap<>(); Set<String> collection = uri.getQueryParameterNames(); // Parameter result: represents the return value of the message box (input value) result.confirm((useid=123456));
}
return true;
}
returnsuper.onJsPrompt(view, url, message, defaultValue, result); } @override public Boolean onJsAlert(WebView view, String URL, String message, JsResult result) {returnsuper.onJsAlert(view, url, message, result); } @override public Boolean onJsConfirm(WebView view, String URL, String message, JsResult result) {returnsuper.onJsConfirm(view, url, message, result); }}); }}Copy the code
The advantages and disadvantages
Advantages:
There is no addJavascriptInterface() vulnerability;
Can meet most situations of interaction scenarios;
Result.confirm () is easy to call back to JS to retrieve data;
Disadvantages: Complex adaptation, need to carry on the constraints of the protocol
(2) Android calls JS methods
There are two methods for Android to call JS, which are described in turn below.
Webbview.loadurl ()
Step 1: Load the JS code, as follows: javascript. HTML into the SRC /main/assets folder
<! DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Carson_Ho</title> <scriptfunction callJS(){
alert("Android calls the callJS method");
}
</script>
</head>
</html>
Copy the code
Step 2: In Android, call JS code with WebView Settings
public class MainActivity extends AppCompatActivity {
WebView mWebView;
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mWebView =(WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true); / / set with Js interaction permissions webSettings. SetJavaScriptCanOpenWindowsAutomatically (true); // Set to allow JS popover mwebView.loadURL ("file:///android_asset/javascript.html");
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {@override public void onClick(View v) {// send a message via Handler mwebView.post (new)Runnable() {
@Override
public void run() {// call the javascript callJS() method mwebview.loadURL ()"javascript:callJS()"); }}); }}); // Set the alert popover to display the resultssetWebChromeClient mWebView.setWebChromeClient(new WebChromeClient()); }}Copy the code
2, through the WebView. EvaluateJavascript () – Android4.4 later
EvaluateJavascript () is more efficient and concise to use. But the execution of this method does not cause the page to refresh, whereas the execution of loadUrl() does.
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {@override public void onReceiveValue(String value) {// This is the result returned by js}});Copy the code
3. Suggestions for use
Use a mix of these two methods, i.e. loadUrl() for Android 4.4 below and evaluateJavascript() for Android 4.4 above.
if (Build.VERSION.SDK_INT < 18) {
mWebView.loadUrl("javascript:callJS()");
} else{mWebView. EvaluateJavascript ("javascript:callJS()", new ValueCallback<String>() {@override public void onReceiveValue(String value) {// This is the result returned by js}}); }Copy the code
Ii. Problems encountered during development
1. The Alert cannot be displayed
If WebChromeClient is not set, use the following code:
myWebView.setWebChromeClient(new WebChromeClient());
Copy the code
2. Uncaught ReferenceError: functionName is not defined
The cause of the problem is that the JS method is called before the page’s JS code is loaded. The solution is to call the JS method after the page has loaded. For example: just open the HTML page, to call the JS returnResult method
webview.loadUrl("file:///android_asset/javascript.html");
String result = (useid=123456);
webview.loadUrl("javascript:returnResult(\"" + result + "\")");
Copy the code
Set it up as follows:
webview.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
String result = (useid=123456);
webview.loadUrl("javascript:returnResult(\"" + result + "\")"); }});Copy the code
3, Uncaught TypeError: Object [Object Object] has no method
Security restriction issue, appear on Android4.2 and above machines.
Solution: Set targetSdkVersion to 17 or higher and introduce the @javascriptInterface annotation.
Code obfuscation problem. If the unobfuscated version works fine, but the obfuscated version runs incorrectly and says Uncaught TypeError: Object [Object Object] has no method, you did not do the obfuscated exception. Add a code solution like this to the obfuscation file:
Add confusion to proguard-rules.pro. -keepattributes *Annotation* -keepattributes *JavascriptInterface* -keep public class xx.xxx.JSKit{ public <methods>; } with xx, XXX.. JSKit is a class that does not need to be confusedCopy the code
4, All WebView methods must be called on the same thread
The Java callback thread after the JS call is not the main thread. To resolve the above exception, simply place the WebView operations in the main thread.
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl(YOUR_URL).
}
});
Copy the code
Three, reference thanks
www.cnblogs.com/android-blo…
www.jianshu.com/p/345f4d8a5…