如今純原生Android開發愈來愈少了,如今通常App都會混合開發,其餘混合的技術先不說,最經常使用就是WebView加載H5頁面,再App客戶端和Web端交互,提供一些用戶信息、客戶端Api等,本篇介紹WebView調用Js,Js調用Android方法的知識。javascript
本文使用的Html文件
<html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>WebView</title> <style type="text/css"> body { background: #caff0c; }
.btn { line-height: 40px; margin: 10px; background: #cccccc; }
#input { margin-left: 5px; }</style></head><body><h2>WebView</h2><div><span>請輸入要傳遞的數據</span><input type="text" id="input"></div><div id="btn"><span class="btn">點我</span></div><div><a href="info://info?name=wally&age=18">點我跳轉連接</a></div>
<script type="text/javascript"> //5.按鈕點擊,調用客戶端方法 var btnEle = document.getElementById("btn"); var inputEle = document.getElementById("input"); btnEle.addEventListener("click", function () { var str = inputEle.value; if (window.androidJs) { window.androidJs.setValue(str); } else { alert("window androidJs is not found!") } })
//提供給客戶端調用的有參Js方法,設置輸入文字 var remote = function (str) { inputEle.value = str; }
//帶返回值的Js方法,給客戶端得到輸入的文字 var remoteWithValue = function () { return inputEle.value; }</script></body></html>
JS調用Android方法
(方式一)css
1.容許WebView加載Js代碼html
2.編寫一個提供給Web的Js接口類(方法要加上@JavascriptInterface註解)前端
3.給WebView添加Js接口(將接口對象掛載到Web的window下)java
4.Web端調用window下的接口類對象中的Android方法android
Android客戶端,設置容許加載Js代碼,提供Js接口類,注入到Web端的Window中。web
/** * 加載的Html位置 */private static final String SETUP_HTML = "file:///android_asset/index.html";
//1.容許WebView加載Js代碼mWebView.getSettings().setJavaScriptEnabled(true);
/** * 2.編寫一個提供給Web的Js接口類 */public class JsInterface { private static final String TAG = JsInterface.class.getSimpleName(); private Callback mCallback;
public JsInterface(Callback callback) { mCallback = callback; }
@JavascriptInterface public void setValue(String value) { if (TextUtils.isEmpty(value)) { return; } Log.d(TAG, "value: " + value); if (mCallback != null) { mCallback.onSetValue(value); } }
public interface Callback { void onSetValue(String value); }}
//3.給WebView添加Js接口mWebView.addJavascriptInterface(new JsInterface(new JsInterface.Callback() { @Override public void onSetValue(final String value) { mMainHandler.post(new Runnable() { @Override public void run() { mResult.setText("value: " + value); } }); }}), "androidJs"); //4.加載HtmlmWebView.loadUrl(SETUP_HTML);
Html中按鈕點擊時,Js調用客戶端方法typescript
//5.按鈕點擊,調用客戶端方法var btnEle = document.getElementById("btn");var inputEle = document.getElementById("input");btnEle.addEventListener("click", function () { var str = inputEle.value; //判斷是否在客戶端環境 if (window.androidJs) { window.androidJs.setValue(str); } else { alert("window androidJs is not found!") }})
(方式二)微信
和客戶端協商協議,以該協議加載Url,客戶端WebView.setWebViewClient(),複寫shouldOverrideUrlLoading()進行攔截,獲取行爲和參數。架構
//和前端協商的協議前綴private static final String CALLBACK_SCHEME = "info://info";
mWebView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { //是否攔截Url boolean isIntercept = url.startsWith(CALLBACK_SCHEME); //處理攔截特定前綴Url handleUrlIntercept(url); if (isIntercept) { return true; } else { return super.shouldOverrideUrlLoading(view, url); } }}); /** * 處理攔截特定前綴Url */private void handleUrlIntercept(String text) { HashMap<String, String> paramsMap = new HashMap<>(5); String result = text.replaceFirst(CALLBACK_SCHEME.concat("\\?"), ""); String[] paramsGroup = result.split("&"); //按組拆分bold=false for (String groupStr : paramsGroup) { String[] paramsKeyValue = groupStr.split("="); //參數和值拆分 String paramsName = paramsKeyValue[0]; String paramsValue = paramsKeyValue[1]; paramsMap.put(paramsName, paramsValue); } final String name = paramsMap.get("name"); final String age = paramsMap.get("age"); toast("攔截Url,獲取參數 -> " + "name:" + name + " age:" + age);}
Web端,超連接加載自定義協議,客戶端進行攔截
//點擊超連接,加載自定義協議,客戶端進行攔截<div><a href="info://info?name=wally&age=18">點我跳轉連接</a></div>
(方式三)
使用prompt,發送數據,客戶端webView.setWebChromeClient,複寫onJsPrompt進行攔截,獲取數據。
mWebView.setWebChromeClient(new WebChromeClient() { public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { //攔截掉,回調4.4一下的Js返回值處理 OnMethodResultCallback callback = mCompatKitkatJsMethodCallbackMap.get(url); if (callback != null) { callback.onMethodResult(message); mCompatKitkatJsMethodCallbackMap.remove(url); //攔截後必須取消掉,不發送到客戶端WebView,不調用也不行,會阻塞等待結果 result.cancel(); return true; } else { return super.onJsPrompt(view, url, message, defaultValue, result); } }});
Android調用Js方法
/** * 調用JS方法獲取返回值的監聽 */interface OnMethodResultCallback { /** * 返回值返回時回調 * * @param result 函數返回值 */ void onMethodResult(String result);}
調用無返回值Js方法
1.Web提供Js方法
2.Android客戶端調用
WebView.loadUrl(「javascript:methodName(params)」);,調用Js方法。
客戶端,設置發送文字調用Js方法,設置輸入內容
//調用無返回值的Js方法mSend.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { String str = mInput.getText().toString(); mWebView.loadUrl("javascript:if(window.remote){window.remote('" + str + "')}"); }});
Web端提供的Js方法,設置輸入內容
//提供給客戶端調用,設置輸入文字var remote = function (str) { inputEle.value = str;}
調用有參Js方法
1.4.4以上,調用webView.evaluateJavascript(),提供一個ValueCallback獲取返回值。
2.4.4一下,沒有獲取返回值的Api,只能使用alert,prompt,confirm。在mWebView.setWebChromeClient()中複寫onJsAlert()、onJsConfirm()、onJsPrompt()攔截。
//調動有返回值的Js方法mCallJsParamsMethod.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { final OnMethodResultCallback onCall = new OnMethodResultCallback() { public void onMethodResult(String result) { toast("收到調用的Js方法返回值: " + result); } }; if (isOvertopKitkat()) { //4.4以上能夠直接用 mWebView.evaluateJavascript("javascript:remoteWithValue();", new ValueCallback<String>() { public void onReceiveValue(String value) { onCall.onMethodResult(value); } }); } else { mCompatKitkatJsMethodCallbackMap.put(SETUP_HTML, onCall); //4.4如下,使用prompt將信息帶出去,受到信息再攔截掉 mWebView.loadUrl("javascript:prompt(remoteWithValue());"); } }});
mWebView.setWebChromeClient(new WebChromeClient() { public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { //攔截掉,回調4.4一下的Js返回值處理 OnMethodResultCallback callback = mCompatKitkatJsMethodCallbackMap.get(url); if (callback != null) { callback.onMethodResult(message); mCompatKitkatJsMethodCallbackMap.remove(url); //攔截後必須取消掉,不發送到客戶端WebView,不調用也不行,會阻塞等待結果 result.cancel(); return true; } else { return super.onJsPrompt(view, url, message, defaultValue, result); } }});
/** * 版本號是否大於等於4.4 */protected boolean isOvertopKitkat() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;}
本文分享自微信公衆號 - Android架構師成長之路(gh_07f996f00d9b)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。