關於android webview讀取js全局變量或者函數返回值

背景:藉助現有接口技術,js可以執行原生Java代碼中的方法,可以得到方法的返回值,可以讓原生java代碼在主線程中動態的操作UI;但是藉助該接口,原生java代碼,採用webview.loadUrl("javascript: JsFunctionName"),只能做到執行js中的方法,如果想獲取js中定義的全局變量,或者獲取某個js函數的返回值,這種方式無法做到,webview也沒有提供別的函數來可供使用。

分析:爲了實現該功能,我們分析application framework的源代碼發現,從webviewloadurl()方法一路追蹤,最終在WebViewCore.java中找到如下代碼:

private native voidpassToJs(int frame, int node, int x, int y, int gen,

            String currentText, int keyCode, intkeyValue, boolean down,

            boolean cap, boolean fn, boolean sym);

BrowserFrame中,追蹤到:

private native voidnativeAddJavascriptInterface(int nativeFramePointer,

            Object obj, String interfaceName);

至此我們知道Androidwebview實現,使用的是開源的webkit瀏覽器內核,該內核是用c語言(webcore)c++語言(jscore)實現的,androidwebview底層實現最終是調用的webkit內核代碼,如果該內核提供了直接讀取js全局變量或者函數返回值的方法,那麼我們可以使用JNI(JavaNative Interface)的方式來讀取出來。

方案:

1)反射讀取方式

android.webkit包中有個BrowserFrame私有類,該類中有個Native方法:

public native StringstringByEvaluatingJavaScriptFromString(String script);

這個和蘋果中的類似:

Public NSStringstringByEvaluatingJavaScriptFromString(NSString script);

雖然該類是私有的,但是我們可以利用反射技術來執行這個方法,從而取得js全局變量和函數返回值;

步驟:

1擴展WebView,派生出MyWebView類,添加

public String stringByEvaluatingJavaScriptFromString(Stringscript)方法,該方法體中最終利用反射技術實現;

2修改佈局中的WebViewcom.appeon.test.MyWebView類型;

3  在頁面load完成的情況下,編碼取得JS變量或函數返回值;

2)JNI讀取方式

除了採用反射方式能訪問到私有類BrowserFrame中的stringByEvaluatingJavaScriptFromString方法之外,採用JNI技術,也能做到;下面我們採用JNI技術來實現20.4.1中的MyWebView類。

原理:java->C->java,具體到這裏就是mywebview.java調用bridge.cbridge.c再調用BrowserFrame.java

3)擴展webkit方式

直接擴展WebCore,擴展JSBridge,實現JS的數據類型到JAVA數據類型的轉換,確切的說是相互轉換,這裏面JAVA部分可以用反射機制來做到。

4Plu方式

採用插件的方式實現。

5)使用android調用js後,通過js調用android本地方法,從而傳入值的方式。
代碼如下:
webView.loadUrl("javascript:androidGetInfo()");//android調用當前頁面的androidGetInfo()方法。
頁面的js

<script>

      var title = '${article.title}';

      var articleId = '${article.id}';

      var articleType = '${article.type}';

      function androidGetInfo(){

          window.tlsj.getInfo(title,articleType);//調用android 中的getInfo方法。

      }

</script>

android手機端代碼如下:

webView.addJavascriptInterface(newObject() {

          public void getInfo(String _title,String _articleType) {

             title = _title;

             articleType = _articleType;

             Message msg = new Message();

             handler.sendMessage(msg);

          }

   }, "tlsj")
由此即可將js中的全局變量或者函數返回值傳入android手機端

分析:

反射讀取方式存在一定的不穩定性,如當內部不開放函數或變量名發生變化時,反射就會出現問題。

JNI讀取方式需要程序員對c++有一定了解。

使用android調用js後,通過js調用android本地方法不夠靈活。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章