WebView與JavaScript的交互總結(jié)
1、交互總結(jié)
WebView與JS之間的交互總結(jié)可以概括為下面兩種:
- Android客戶端去調(diào)用JS代碼
- JS端去調(diào)用Android原生代碼
它們之間互相調(diào)用的橋梁是WebView。
2、交互前準備
2.1 Android客戶端代碼
Activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.web_view);
//android調(diào)用JS代碼的Button
btnAndroidCallJS = findViewById(R.id.btn_call_js);
//防止外部瀏覽器調(diào)用此鏈接
webView.setWebViewClient(new WebViewClient());
WebSettings settings = webView.getSettings();
//允許WebView使用JS
settings.setJavaScriptEnabled(true);
//支持通過JS打開新窗口(允許JS彈窗)
settings.setJavaScriptCanOpenWindowsAutomatically(true);
}
XML:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/container"
tools:context="com.zw.plugins.MainActivity">
<WebView
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/btn_call_js"
android:id="@+id/web_view"></WebView>
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:id="@+id/btn_call_js"
android:text="Android調(diào)用JS"
app:layout_constraintTop_toBottomOf="@id/web_view"
app:layout_constraintBottom_toBottomOf="parent"
/>
</android.support.constraint.ConstraintLayout>
2.2 JS端代碼
test.html:
<head>
</head>
<body>
<h1 onClick='callAndroid()'>這是JS調(diào)用原生1</h1>
<h1 onClick='callAndroid2()'>這是JS調(diào)用原生2</h1>
<h1 onClick='callAndroid3()'>這是JS調(diào)用原生3</h1>
<Script>
//Android原生調(diào)用JS方法
function callJS(){
alert("Android調(diào)用了JS的callJS方法");
return "Android調(diào)用了JS的callJS()"
}
//JS調(diào)用Android原生方法
function callAndroid(){
// 由于對象映射,所以調(diào)用android對象等于調(diào)用Android映射的對象
android.callAndroid("js調(diào)用了");
}
//JS調(diào)用通過shouldOverrideUrlLoading()調(diào)用Android原生方法
function callAndroid2(){
//document.location代表當前頁面的url
document.location = "js://webview?arg1=111&arg2=222"
}
//JS調(diào)用通過prompt()調(diào)用Android原生方法
function callAndroid3(){
var result = prompt("js://webview?arg1=111");
alert(result);
}
</Script>
</body>
3、Android端調(diào)用JS代碼
3.1 Android端調(diào)用JS代碼有2種方法:
- 通過WebView的
loadUrl() - 通過WebView的
evaluateJavascript()
這兩種方式調(diào)用JS代碼時,格式都是以javascript:開頭的,后面接JavaScript的方法名。
3.2 通過WebView的loadUrl()
//Android調(diào)用JS代碼
btnAndroidCallJS.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
webView.loadUrl("javascript:callJS()");
}
});
注意:JS代碼調(diào)用一定要在WebViewClient的onPageFinished()回調(diào)之后才能調(diào)用,否則不會調(diào)用。
3.3 通過WebView的evaluateJavascript()
//Android調(diào)用JS代碼
btnAndroidCallJS.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
//s是JS方法的返回值
Log.e("zw",s); //這里s是“Android調(diào)用了JS的callJS()”
}
});
}
});
這種方式比第一種方式效率高(執(zhí)行時不會刷新頁面),同時可以獲取返回值。缺點是只兼容到Android4.4版本以后。
4、JS端調(diào)用Android端代碼
3.1 JS端調(diào)用Android端代碼有3種方法:
- 通過WebView的
addJavascriptInterface()進行對象映射 - 通過
WebViewClient的shouldOverrideUrlLoading()方法回調(diào)攔截url - 通過
WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調(diào)攔截JS對話框alert()、confirm()、prompt()消息
3.2 通過WebView的addJavascriptInterface()進行對象映射
3.2.1 先定義一個和JS映射的對象
public class AndroidToJS {
// 定義JS需要調(diào)用的方法
// 被JS調(diào)用的方法必須加入@JavascriptInterface注解
@JavascriptInterface
public void callAndroid(String msg){
Log.e("zw","JS調(diào)用了Android的callAndroid(),msg : " + msg);
}
}
3.2.2 JavaScript內(nèi)需要有Android調(diào)用原生的方法
//JS調(diào)用Android原生方法
function callAndroid(){
// 由于對象映射,所以調(diào)用android對象等于調(diào)用Android映射的對象
android.callAndroid("js調(diào)用了");
}
3.2.3 Android原生調(diào)用JavaScript方法
// 通過addJavascriptInterface()將Java對象映射到JS對象
//參數(shù)1:Javascript對象名
//參數(shù)2:Java對象名
webView.addJavascriptInterface(new AndroidToJS(),"android");
結(jié)果:
E/zw: JS調(diào)用了Android的callAndroid(),msg : js調(diào)用了
這種方法優(yōu)點是使用簡單,缺點是存在嚴重的漏洞問題,請看文章:你不知道的 Android WebView 使用漏洞
3.3 通過WebViewClient的shouldOverrideUrlLoading()方法回調(diào)攔截url
3.3.1 先約定好調(diào)用的URL協(xié)議
比如以js://webview?arg1=111開頭。
3.3.2 在JS中定義調(diào)用方法
//JS調(diào)用通過shouldOverrideUrlLoading()調(diào)用Android原生方法
function callAndroid2(){
//document.location代表當前頁面的url
document.location = "js://webview?arg1=111&arg2=222"
}
3.3.3 Android端的WebView設(shè)置WebViewClient對URL進行攔截
最好重寫兩個shouldOverrideUrlLoading()方法,避免其中一個不生效。
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.e("ll", url );
if(url.startsWith("js")){
if(url.contains("webview")){
Toast.makeText(getApplicationContext(),"heihei",Toast.LENGTH_SHORT).show();
return true;
}
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
Log.e("ll", uri.getScheme() + " , " + uri.getAuthority() + " , ");
if("js".equals(uri.getScheme())){
if("webview".equals(uri.getAuthority())){
Toast.makeText(getApplicationContext(),"heihei",Toast.LENGTH_SHORT).show();
return true;
}
}
return super.shouldOverrideUrlLoading(view, request);
}
});
3.4 通過WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調(diào)攔截JS對話框alert()、confirm()、prompt()消息
關(guān)于WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt()方法,可以在我的 WebView全面解析 這篇文章中得到解答。
由于alert()沒有返回值,confirm()只能返回true或者false,而prompt()可以返回任意類型的值,因此更加的靈活,這里,以prompt()舉例。
3.4.1 先約定好在prompt()中顯示信息的協(xié)議
比如以js://webview?arg1=111開頭。
3.4.2 在JS中定義調(diào)用方法
//JS調(diào)用通過prompt()調(diào)用Android原生方法
function callAndroid3(){
var result = prompt("js://webview?arg1=111");
alert(result);
}
3.4.3 Android端的WebView設(shè)置WebChromeClient對傳入的參數(shù)進行解析并返回
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
Log.e("ll",message + " , " + defaultValue);
if(message.startsWith("js")){
if(message.contains("webview")){
//confirm表示確認(并返回值),cancel表示取消。
result.confirm("8848");
//返回true表示不彈出系統(tǒng)提示框
return true;
}
}
return super.onJsPrompt(view,url,message,defaultValue,result);
}
5、總結(jié)
幾種調(diào)用方式的優(yōu)缺點總結(jié)如下:

Android與JS互相調(diào)用總結(jié)