Android WebView 總結 —— Java和JavaScript交互


一、交互如何實現

交互實現的前提 —— WebView允許執行JS

WebSettings settings = myWebView.getSettings();
settings.setJavaScriptEnabled(true);

1.1 Java 調用 JS

調用方式:

/** 注意參數的傳遞需要符合JS的語法,用單引號或者反斜杠轉義 */
String js = "javascript:javaCallJS(\"Java called JS.\")";

此時注意,javascript 這個詞不能存在大寫的狀態,否則在低版本的Android手機上(Android 4.4版本以下)是無反應的,因為Android 4.4版本以下的手機的WebView內核是WebKit,Android 4.4版本以后WebView的內核為Chromium。

1.2 JS 調用 Java

實現JS調用Java也比較簡單,通常只需要以下幾步。

  • WebView開啟JavaScript腳本執行(在開頭已經說明)
  • WebView設置供JavaScript調用的交互接口。
  • 客戶端和網頁端編寫調用對方的代碼。

提供JavaScript調用的交互接口

public class MainActivity extends Activity {
  @SuppressLint("JavascriptInterface")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ....
      /** 添加交互接口 */
      myWebView.addJavascriptInterface(new JsInteration(), "control");
    .... }
/** 聲明交互接口及具體的回調方法 */ public class JsInteration { @JavascriptInterface public void toastMessage(String message) { Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); } } }

網頁端調用交互接口

function toastMessage(message) { 
    window.control.toastMessage(message)
}

二、疑問解答

2.1 Alert 無法彈出

沒有設置WebChromeClient的原因,需要在webView設置WebChromeClient().

myWebView.setWebChromeClient(new WebChromeClient() {});

2.2 Uncaught ReferenceError: functionName is not defined

網頁的js代碼沒有加載,就調用了js方法。解決方法是在網頁加載完成之后調用js方法或者限制用戶在頁面加載完成之前不允許調用JS的事件,下面的代碼是在網頁加載完成后調用JS方法的實例:

myWebView.setWebViewClient(new WebViewClient() {
  @Override
  public void onPageFinished(WebView view, String url) {
      super.onPageFinished(view, url);
      //在這里執行你想調用的js函數
  }
});

2.3 Uncaught TypeError: Object [object Object] has no method

如果只在Android 4.2版本及以上的手機存在這個問題,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.

中文大意為

警告:如果你的APP的tagSdk level是17或者是更高,你必須要在暴露給網頁可調用的方法(這個方法必須是公開的)加上@JavascriptInterface注釋。如果你不這樣做的話,在4.2以以后的平台上,網頁無法訪問到你的方法。

兩種解決方法
  • 將targetSdkVersion設置成17或更高,引入@JavascriptInterface注釋
  • 自己創建一個注釋接口名字為@JavascriptInterface,然后將其引入。注意這個接口不能混淆。鏈接:部分混淆代代碼的方案

2.4 All WebView methods must be called on the same thread

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).
    }
});

三、引申

JavaScript和Java的交互是在子線程上面進行的

因為JavaScript和Java交互是在子線程上面進行的,所以如果需要UI方面的修改操作,或者執行其他的操作,必須要考慮到線程安全的問題。這個在上面的 疑問解答4有所體現出來。

為何Android4.2版本之后需要使用@JavascriptInterface來進行注解

在JELLY_BEAN_MAR1之前JS的注入存在很大的漏洞,此漏洞會導致通過頁面可以直接操作Android Native Application。而且隨着Android版本的不斷提高,對WebView的要求也是逐漸嚴格的,這樣減少了對Android的安全存在的威脅。 

鏈接: Android 4.2版本以下使用WebView組件addJavascriptInterface方法存在JS漏洞

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM