發佈時間:2014-12-12 瀏覽次數:8566javascript
Android提供了一個很強大的WebView控件用來處理Web網頁,而在網頁中,JavaScript又是一個很舉足輕重的腳本。本文將介紹如何實現Java代碼和Javascript代碼的相互調用。html
實現Java和js交互十分便捷。一般只須要如下幾步。前端
爲了便於講解,先貼出所有代碼java
Java代碼android
package com.example.javajsinteractiondemo; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.webkit.JavascriptInterface; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; public class MainActivity extends Activity { private static final String LOGTAG = "MainActivity"; @SuppressLint("JavascriptInterface") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final WebView myWebView = (WebView) findViewById(R.id.myWebView); WebSettings settings = myWebView.getSettings(); settings.setJavaScriptEnabled(true); myWebView.addJavascriptInterface(new JsInteration(), "control"); myWebView.setWebChromeClient(new WebChromeClient() {}); myWebView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); testMethod(myWebView); } }); myWebView.loadUrl("file:///android_asset/js_java_interaction.html"); } private void testMethod(WebView webView) { String call = "javascript:sayHello()"; call = "javascript:alertMessage(\"" + "content" + "\")"; call = "javascript:toastMessage(\"" + "content" + "\")"; call = "javascript:sumToJava(1,2)"; webView.loadUrl(call); } public class JsInteration { @JavascriptInterface public void toastMessage(String message) { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); } @JavascriptInterface public void onSumResult(int result) { Log.i(LOGTAG, "onSumResult result=" + result); } } }
前端網頁代碼web
<html> <script type="text/javascript"> function sayHello() { alert("Hello") } function alertMessage(message) { alert(message) } function toastMessage(message) { window.control.toastMessage(message) } function sumToJava(number1, number2){ window.control.onSumResult(number1 + number2) } </script> Java-Javascript Interaction In Android </html>
調用格式爲window.jsInterfaceName.methodName(parameterValues) 此例中咱們使用的是control做爲注入接口名稱。json
function toastMessage(message) { window.control.toastMessage(message) } function sumToJava(number1, number2){ window.control.onSumResult(number1 + number2) }
webView調用js的基本格式爲webView.loadUrl(「javascript:methodName(parameterValues)」)安全
String call = "javascript:sayHello()"; webView.loadUrl(call);
注意對於字符串做爲參數值須要進行轉義雙引號。bash
String call = "javascript:alertMessage(\"" + "content" + "\")"; webView.loadUrl(call);
Android在4.4以前並無提供直接調用js函數並獲取值的方法,因此在此以前,經常使用的思路是 java調用js方法,js方法執行完畢,再次調用java代碼將值返回。app
1.Java調用js代碼
String call = "javascript:sumToJava(1,2)"; webView.loadUrl(call);
2.js函數處理,並將結果經過調用java方法返回
function sumToJava(number1, number2){ window.control.onSumResult(number1 + number2) }
3.Java在回調方法中獲取js函數返回值
@JavascriptInterface public void onSumResult(int result) { Log.i(LOGTAG, "onSumResult result=" + result); }
Android 4.4以後使用evaluateJavascript便可。這裏展現一個簡單的交互示例 具備返回值的js方法
function getGreetings() { return 1; }
java代碼時用evaluateJavascript方法調用
private void testEvaluateJavascript(WebView webView) { webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { Log.i(LOGTAG, "onReceiveValue value=" + value); }}); }
輸出結果
I/MainActivity( 1432): onReceiveValue value=1
注意
你應該是沒有設置WebChromeClient,按照如下代碼設置
myWebView.setWebChromeClient(new WebChromeClient() {});
問題出現緣由,網頁的js代碼沒有加載完成,就調用了js方法。解決方法是在網頁加載完成以後調用js方法
myWebView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //在這裏執行你想調用的js函數 } });
若是隻在4.2版本以上的機器出問題,那麼就是系統處於安全限制的問題了。Android文檔這樣說的
Caution: If you’ve set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.
中文大意爲
警告:若是你的程序目標平臺是17或者是更高,你必需要在暴露給網頁可調用的方法(這個方法必須是公開的)加上@JavascriptInterface註釋。若是你不這樣作的話,在4.2以之後的平臺上,網頁沒法訪問到你的方法。
注,建立@JavascriptInterface代碼
public @interface JavascriptInterface { }
若是在沒有混淆的版本運行正常,在混淆後的版本的代碼運行錯誤,並提示Uncaught TypeError: Object [object Object] has no method,那就是你沒有作混淆例外處理。 在混淆文件加入相似這樣的代碼
-keep class com.example.javajsinteractiondemo$JsInteration { *; }
過濾日誌曾發現過這個問題。
E/StrictMode( 1546): java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {528712d4} called on Looper (JavaBridge, tid 121) {52b6678c}, FYI main Looper is Looper (main, tid 1) {528712d4}) E/StrictMode( 1546): at android.webkit.WebView.checkThread(WebView.java:2063) E/StrictMode( 1546): at android.webkit.WebView.loadUrl(WebView.java:794) E/StrictMode( 1546): at com.xxx.xxxx.xxxx.xxxx.xxxxxxx$JavaScriptInterface.onCanGoBackResult(xxxx.java:96) E/StrictMode( 1546): at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method) E/StrictMode( 1546): at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27) E/StrictMode( 1546): at android.os.Handler.dispatchMessage(Handler.java:102) E/StrictMode( 1546): at android.os.Looper.loop(Looper.java:136) E/StrictMode( 1546): at android.os.HandlerThread.run(HandlerThread.java:61)
在js調用後的Java回調線程並非主線程。如打印日誌可驗證
ThreadInfo=Thread[WebViewCoreThread,5,main]
解決上述的異常,將webview操做放在主線程中便可。
webView.post(new Runnable() { @Override public void run() { webView.loadUrl(YOUR_URL). } });