Preface
- Now many Apps have built-in Web pages (Hyprid App), such as many e-commerce platforms, Taobao, Jingdong, Cost-effective, and so on, such as the following image
- These functions are implemented by Android's WebView, which involves the implementation of Android client interaction with Web pages
- Today I'll give you a full overview of how Android interacts with JS through WebView
Read this before reading: Android development: the most comprehensive and understandable Web view in detail
Catalog
1. Interactive Summary
Android Calling methods with JS through WebView is actually:
- Code for Android to invoke JS
- JS to call Android's code
The bridge between them is WebView
There are two ways for Android to call JS code:
1. loadUrl () through WebView
2. evaluateJavascript () via WebView
There are three ways for JS to call Android code:
1. Object mapping via WebView's addJavascriptInterface ()
2. Intercept URLs via the WebViewClient shouldOverrideUrlLoading () method callback
3. Intercept JS dialog alert(), confirm(), prompt() messages via WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt() method callbacks
2. Specific analysis
2.1 Android calls JS code through WebView
There are two ways for Android to call JS code:
- loadUrl () through WebView
- evaluateJavascript () via WebView
Mode 1: Load Url () through WebView
- Example description: Click the Android button to call JS () in WebView JS (text name is javascript)
- Specific use:
Step 1: Place the JS code you need to invoke in the src/main/assets folder in.html format
- For demonstration purposes, this article uses Andorid to call local JS code instructions;
- As a matter of fact, Android calls more remote JS code by changing the path of the loaded JS code to a url.
JS code needs to be loaded: javascript.html
// Text name: javascript
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson_Ho</title>
// JS Code
<script>
// Method Android needs to call
function callJS(){
alert("Android Called JS Of callJS Method");
}
</script>
</head>
</html>
Step 2: Call JS code in Android through WebView settings
Android code: MainActivity.java
The comment is already clear
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();
// Set permissions to interact with Js
webSettings.setJavaScriptEnabled(true);
// Set Allow JS Pop-up
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// Load JS code first
// The format is specified as file:///android_asset/filename.html
mWebView.loadUrl("file:///android_asset/javascript.html");
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// JS method calls must be made on a separate thread (otherwise they cannot be called)
mWebView.post(new Runnable() {
@Override
public void run() {
// Note that the JS method name called should correspond to the
// Call the callJS() method of javascript
mWebView.loadUrl("javascript:callJS()");
}
});
}
});
// The js dialog box needs to be supported because the pop-up window check call result is set
// webview is just a carrier, and the rendering of content needs to be done using the webviewChromClient class
// Processing JavaScript dialogs by setting WebChromeClient objects
//Set Alert() function in response to js
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
b.setTitle("Alert");
b.setMessage(message);
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
b.setCancelable(false);
b.create().show();
return true;
}
});
}
}
Special note: JS code calls must be made after the onPageFinished () callback, otherwise they will not be called.
onPageFinished() is a method of the WebViewClient class that is called primarily at the end of page loading
Mode 2: evaluateJavascript () through WebView
-
Advantages: This method is more efficient and concise than the first method.
- Because this method does not refresh the page, the first method (loadUrl) does.
- Android 4.4 is not available until
-
Specific use
// Simply replace the loadUrl() of the first method with the following method
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//Here is the result returned for js
}
});
}
- 8
2.1.2 Method Comparison
2.1.3 Use Recommendations
Mixed use of the two methods, that is, Android 4.4 below method 1, Android 4.4 above method 2
// Android Version Variable
final int version = Build.VERSION.SDK_INT;
// Since this method is available in Android version 4.4, version judgment is required when using it
if (version < 18) {
mWebView.loadUrl("javascript:callJS()");
} else {
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//Here is the result returned for js
}
});
}
2.2 JS calls Android code through WebView
There are three ways for JS to call Android code:
1. Object mapping via WebView's addJavascriptInterface ()
2. Intercept URLs via the WebViewClient shouldOverrideUrlLoading () method callback
3. Intercept JS dialog alert(), confirm(), prompt() messages via WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt() method callbacks
2.2.1 Method Analysis
Mode 1: Object mapping via WebView's addJavascriptInterface ()
Step 1: Define an Android class that maps to JS objects: AndroidtoJs
AndroidtoJs.java (comment is already clear)
// Inherit from Object class
public class AndroidtoJs extends Object {
// Define the method JS needs to call
// Methods invoked by JS must be annotated with @JavascriptInterface
@JavascriptInterface
public void hello(String msg) {
System.out.println("JS Called Android Of hello Method");
}
}
Step 2: Place the JS code you need to call in the src/main/assets folder in.html format
JS code needs to be loaded: javascript.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson</title>
<script>
function callAndroid(){
// Because of the object mapping, calling the test object is equal to calling the Android mapping object
test.hello("js Called android In hello Method");
}
</script>
</head>
<body>
//Click the button to call the callAndroid function
<button type="button" id="button1" onclick="callAndroid()"></button>
</body>
</html>
Step 3: Set up the mapping of Android classes to JS code in Android through WebView
See notes for more details
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();
// Set permissions to interact with Js
webSettings.setJavaScriptEnabled(true);
// Mapping Java objects to JS objects via addJavascriptInterface()
//Parameter 1: Javascript object name
//Parameter 2: Java object name
mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS class object maps to js test object
// Load JS code
// The format is specified as file:///android_asset/filename.html
mWebView.loadUrl("file:///android_asset/javascript.html");
Characteristic
-
Advantages: Easy to use
Only map Android and JS objects
-
Disadvantages: There are serious bug problems, please see the article: Unknown Android WebView usage vulnerability
Mode 2: Intercept url through WebViewClient's method shouldOverrideUrlLoading () callback
-
Specific principles:
- Android intercepts URLs via WebViewClient's callback method shouldOverrideUrlLoading ()
- Protocol for resolving the url
- If a pre-agreed protocol is detected, the corresponding method is called
That is, JS needs to call Android's method
-
Specific use:
Step 1: Url protocol required in the JS Convention
JS code: javascript.htmlPlace in the src/main/assets folder in.html format
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson_Ho</title>
<script>
function callAndroid(){
/*The agreed url protocol is: js://webview?Arg1=111&arg2=222*/
document.location = "js://webview?arg1=111&arg2=222";
}
</script>
</head>
<!-- Click the button to invoke callAndroid()Method -->
<body>
<button type="button" id="button1" onclick="callAndroid()">Click Call Android Code</button>
</body>
</html>
When the JS is loaded through Android's mWebView.loadUrl("file:///android_asset/javascript.html"), it calls back shouldOverrideUrlLoading(), and then proceeds to step 2:
Step 2: Replicate shouldOverrideUrlLoading () from WebViewClient on Android
MainActivity.java
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();
// Set permissions to interact with Js
webSettings.setJavaScriptEnabled(true);
// Set Allow JS Pop-up
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// Step 1: Load JS code
// The format is specified as file:///android_asset/filename.html
mWebView.loadUrl("file:///android_asset/javascript.html");
// Override the shouldOverrideUrlLoading method of the WebViewClient class
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Step 2: Determine if the required url is based on the parameters of the protocol
// Generally based on scheme & authority (protocol name) (first two parameters)
//Assume that the incoming url = "js://webview?Arg1=111&arg2=222" (which is also agreed to require interception)
Uri uri = Uri.parse(url);
// If the url's protocol = the pre-agreed js protocol
// Parse parameters down
if ( uri.getScheme().equals("js")) {
// If authority = webview in a pre-agreed agreement, that is, agreement that represents compliance with the agreement
// So intercept url, the JS below starts calling the methods Android needs
if (uri.getAuthority().equals("webview")) {
// Step 3:
// Logic to invoke to execute JS
System.out.println("js Called Android Method");
// Can take parameters on the protocol and pass them to Android
HashMap<String, String> params = new HashMap<>();
Set<String> collection = uri.getQueryParameterNames();
}
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}
);
}
}
Characteristic
- Advantages: There is no vulnerability in Mode 1;
- Disadvantage: The return value of the JS Get Android method is complex. If the JS wants to get the return value of the Android method, it can only pass the return value back through the loadUrl() of WebView, as follows:
// Android: MainActivity.java
mWebView.loadUrl("javascript:returnResult(" + result + ")");
// JS: javascript.html
function returnResult(result){
alert("result is" + result);
}
Mode 3: Intercept JS dialog alert(), confirm(), prompt () messages via WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt () method callbacks
There are three common dialog box methods in JS:
Principle of Mode 3: Android intercepts JS dialog boxes through WebChromeClient onJsAlert(), onJsConfirm(), and onJsPrompt () method callbacks, respectively
(that is, the three methods above), get their message content, and then parse it.
The following example illustrates using an input box (prompt() method) that intercepts JS:
- The common interception is to intercept the JS input box (prompt() method)
- Because only prompt () can return any type of value, it is the most comprehensive and flexible operation; the alert () dialog does not return a value; the confirm () dialog can only return two states (OK/Cancel) with two values.
Step 1: Load the JS code as follows:
javascript.html
Place in the src/main/assets folder in.html format
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson_Ho</title>
<script>
function clickprompt(){
// Call prompt()
var result=prompt("js://demo?arg1=111&arg2=222");
alert("demo " + result);
}
</script>
</head>
<!-- Click the button to invoke clickprompt() -->
<body>
<button type="button" id="button1" onclick="clickprompt()">Click Call Android Code</button>
</body>
</html>
When the above JS code is loaded using mWebView.loadUrl("file:///android_asset/javascript.html"), the callback onJsPrompt() is triggered as follows:
- If the warning box is intercepted (alert()), the callback onJsAlert() is triggered;
- If the confirmation box is intercepted (confirm()), the callback onJsConfirm () is triggered;
Step 2: Replicate onJsPrompt() via WebChromeClient on Android
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();
// Set permissions to interact with Js
webSettings.setJavaScriptEnabled(true);
// Set Allow JS Pop-up
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
// Load JS code first
// The format is specified as file:///android_asset/filename.html
mWebView.loadUrl("file:///android_asset/javascript.html");
mWebView.setWebChromeClient(new WebChromeClient() {
// Intercept Input Box (same way 2)
// Parameter message: Content representing promt() (not url)
// Parameter result: Represents the return value of the input box
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
// Determine if the required URL is based on the parameters of the protocol (same principle as mode 2)
// Generally based on scheme & authority (protocol name) (first two parameters)
//Assume that the incoming url = "js://webview?Arg1=111&arg2=222" (which is also agreed to require interception)
Uri uri = Uri.parse(message);
// If the url's protocol = the pre-agreed js protocol
// Parse parameters down
if ( uri.getScheme().equals("js")) {
// If authority = webview in a pre-agreed agreement, that is, agreement that represents compliance with the agreement
// So intercept url, the JS below starts calling the methods Android needs
if (uri.getAuthority().equals("webview")) {
//
// Logic to invoke to execute JS
System.out.println("js Called Android Method");
// Can take parameters on the protocol and pass them to Android
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("js Called Android The method succeeded");
}
return true;
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
// Interception by alert() and confirm() works the same way, but we won't go into much detail here
// Warning box to intercept JS
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
// Confirmation box to intercept JS
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
}
);
}
}
2.2.2 Comparison of three modes - using scenes
3. Summary
- This article gives an overview of how Android interacts with JS through WebView.
- Next, I'll continue with other Android developments, and I'm interested in continuing to focus on them Carson_Ho's Android Development Notes!!!!