整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Android WebView中Java與JavaS

          Android WebView中Java與JavaScript的交互方式與安全策略

          ndroid在加載網頁H5時,會用到WebView組件,以實現服務端可配置,靈活定義Action。

          這個時候就需要Java與JavaScript進行交互,典型的應用場景就是電商類APP,如京東和淘寶。

          WebView支持JavaScript這些交互動作,那么問題來了,我們怎么實現Java編寫的安卓程序與JavaScript編寫的網頁進行交互呢?下面給大家介紹下,如何實現Java與JavaScript之間的相互調用。

          在Java層調用JavaScript的方式:

          Java中調用JavaScript有兩種方式,同步和異步:

          1. 同步阻塞UI線程的方式: webView.loadUrl("javascript:funtion()")

          2. 異步非阻塞方式: evaluateJavaScript()(在API level 19加入)

          請看下面代碼:

          java中

          // android 調用 JavaScript
          public void callJavaScript(View view) {
           if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKAT) {
           // 異步運行調用JavaScript的方式
           mWebView.evaluateJavascript("javascript:callAlert()", new ValueCallback<String>() {
           @Override
           public void onReceiveValue(String value) {
           Log.e(TAG, "onReceiveValue" + value);//打印返回的值
           }
           });
           } else {
           if (mWebView !=null) {
           // 同步阻塞UI線程式調用
           mWebView.loadUrl("javascript:callAlert()");
           }
           }
          }

          JavaScript中

          function callAlert(){
           alert("Android call html Alert function !");
           return "這是需要返回的值";
          }

          在JavaScript調用Android中Java的方式

          在JavaScript有三種方式可以調用java代碼:

          1. 使用 mWebView.addJavascriptInterface(new JavaScriptInject(this), "JavaScriptInject")

          java中

          mWebView=findViewById(R.id.webview);
          mWebView.getSettings().setAllowFileAccessFromFileURLs(true);
          mWebView.addJavascriptInterface(new JavaScriptInject(this), "JavaScriptInject");
          public class JavaScriptInject {
           private Context mContext;
           JavaScriptInject(Context context) {
           this.mContext=context;
           }
           // 被JS調用的方法必須加入@JavascriptInterface注解
           @JavascriptInterface
           public void callAndroid(String string) {
           Toast.makeText(mContext,"javascript call Android", Toast.LENGTH_LONG).show();
           Log.e("JavaScriptInject", "getAndroidInfo " + string);
           }
          }

          JavaScript中

          function callAndroid(){
           JavaScriptInject.callAndroid("javascript call android");
          }

          2. 通過重寫WebChromeClient中的回調方法攔截JS不同對話框消息:

          • onJsAlert(WebView view, String url, String message, JsResult result) 對應攔截 alert()

          • onJsConfirm(WebView view, String url, String message, JsResult result) 對應攔截 confirm()

          • onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) 對應攔截 prompt()

          java中

          mWebView.setWebChromeClient(new WebChromeClient() {
           @Override
           public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
           Log.i(TAG,"onJsAlert");
           return super.onJsAlert(view, url, message, result);
           }
           @Override
           public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
           Log.i(TAG,"onJsConfirm");
           return super.onJsConfirm(view, url, message, result);
           }
           @Override
           public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
           Log.i(TAG,"onJsPrompt:"+ message);
           return super.onJsPrompt(view, url, message, defaultValue, result);
           }
          });

          JavaScript中

          function clickPrompt(){
           prompt("傳遞給Android的值");
          }
          function clickConfirm(){
           confirm("傳遞給Android的值");
          }
          function clickAlert(){
           alert("傳遞給Android的值");
          }

          webview頁面中

          <body>
           <button type="button" id="button3" onclick="clickPrompt()">點擊調用Android onJsPrompt</button>
           <button type="button" id="button4" onclick="clickConfirm()">點擊調用Android onJsConfirm</button>
           <button type="button" id="button5" onclick="clickAlert()">點擊調用Android onJsAlert</button>
          </body>

          3. 通過 WebViewClient 的 shouldOverrideUrlLoading 回調,攔截url。

          Java中

          mWebView.setWebViewClient(new WebViewClient() {
          @Override
           public boolean shouldOverrideUrlLoading(WebView view, String url) {
           // 解析該 url 的協議,如果檢測到是預先約定好的協議,就調用相應方法
           Log.e(TAG,"call shouldOverrideUrlLoading url : " + url);
           return true;
           }
          });

          JavaScript中

          function callLoadProtocol(){
           // 在JS約定所需要的Url協議
           document.location="http://www.360.cn?p=ppp&q=qqq";
          }

          安全方面策略

          1. WebView的addJavascriptInterface方法在Android 4.2版本以下使用時可能出現的安全情況有:

          • WebView所在頁面對外暴露,即AndroidManifest.xml設置了android:exported="true",會被其他應用惡意調起

          • 網絡劫持導致代碼注入

          2. 開發者需對加載的網頁Url多加限制,禁止加載非合法url。

          3. WebView對證書錯誤的頁面會打開空白頁。如果當遇到證書錯誤時調用proceed()函數,會忽略證書錯誤繼續訪問,導致https證書校驗完全失效,存在安全隱患。

          Java中

          mWebView.setWebViewClient(new WebViewClient() {
           @Override
           public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
           handler.proceed();//使用proceed()忽略證書錯誤,會存在安全隱患
           }
          }

          4. WebView加載File協議的Url存在安全隱患,需要禁止File協議調用JavaScript,設置為false。如下即可拿到file:///sdcard/test.txt文件內容,這是很危險的情況。

          Java中

          mWebView.getSettings().setJavaScriptEnabled(true);
          mWebView.getSettings().setAllowFileAccessFromFileURLs(true);

          JavaScript中

          function getFileContent(){
           var file="file:///sdcard/test.txt";
           var xmlHttpReq=new XMLHttpRequest();
           xmlHttpReq.onreadystatechange=function(){
           if (xmlHttpReq.readyState==4) { //4: 請求已完成,且響應已就緒
           alert(xmlHttpReq.responseText);//執行上傳到遠程
           }
           }
           xmlHttpReq.open("GET",file,true);
           xmlHttpReq.send();
          }
          getFileContent();

          5. Android3.0以下,Android系統會默認通過searchBoxJavaBridge的Js接口給WebView添加一個JS映射對象:searchBoxJavaBridge對象。該接口可能被利用,實現遠程任意代碼,實現中可以進行刪除該接口。

          Java中

          super.removeJavascriptInterface("searchBoxJavaBridge_");

          6. 為了解決Android4.2中開啟了輔助模式后,LocalActivityManager控制的Activity與AccessibilityInjector不兼容導致的崩潰問題可以在mWebView.getSettings().setJavaScriptEnabled之前執行下面代碼。

          Java中

          public void fixedAccessibilityInjectorException() {
           if (Build.VERSION.SDK_INT==17) {
           try {
           Object webViewProvider=WebView.class.getMethod("getWebViewProvider").invoke(this);
           Method getAccessibilityInjector=webViewProvider.getClass().getDeclaredMethod("getAccessibilityInjector");
           getAccessibilityInjector.setAccessible(true);
           Object accessibilityInjector=getAccessibilityInjector.invoke(webViewProvider);
           getAccessibilityInjector.setAccessible(false);
           Field mAccessibilityManagerField=accessibilityInjector.getClass().getDeclaredField("mAccessibilityManager");
           mAccessibilityManagerField.setAccessible(true);
           Object mAccessibilityManager=mAccessibilityManagerField.get(accessibilityInjector);
           mAccessibilityManagerField.setAccessible(false);
           Field mIsEnabledField=mAccessibilityManager.getClass().getDeclaredField("mIsEnabled");
           mIsEnabledField.setAccessible(true);
           mIsEnabledField.set(mAccessibilityManager, false);
           mIsEnabledField.setAccessible(false);
           } catch (Exception e) {
           e.printStackTrace();
           }
           }
          }

          7. 為了防止Js拿到Android對象后,通過反射(通過getClass()方法來得到Runtime實例)獲取該對象的其他所有方法,從而導致信息泄露和惡意代碼注入,需要過濾掉繼承Object類的方法,包括getClass()方法。過濾方法包括:

          • getClass

          • hashCode

          • notify

          • notifyAll

          • equals

          • toString

          • wait

          免責聲明:轉載自網絡 不用于商業宣傳 版權歸原作者所有 侵權刪

          、javaScript介紹

          JavaScript是一種基于對象和事件驅動的、并具有安全性能的腳本語言

          (客戶端語言)

          JavaScript特點

          向HTML頁面中添加交互行為

          腳本語言,語法和Java類似

          解釋性語言,邊解釋邊執行


          JavaScript組成:ECMAScript 、DOM、BOM

          基本結構:

          <script type="text/javascript">

          <!—

          JavaScript 語句;

          —>

          </script >

          示例:

          ……

          <title>初學JavaScript</title>

          </head>

          <body>

          <script type="text/javascript">

          document.write("初學JavaScript");

          document.write("<h1>Hello,JavaScript</h1>");

          </script>

          </body>

          </html>

          注:<script>…</script>可以包含在文檔中的任何地方,只要保證這些代碼在被使用前已讀取并加載到內存即可

          執行原理:


          外部JS文件:

          <script src="export.js" type="text/javascript"></script>

          直接在HTML標簽中使用:

          <input name="btn" type="button" value="彈出消息框"

          onclick="javascript:alert('歡迎你');"/>


          二、基本常見語法:

          1、核心語法:同時聲明和賦值變量

          var catName="皮皮";

          2、數據類型:

          undefined:var width;

          變量width沒有初始值,將被賦予值undefined;

          null:表示一個空值,與undefined值相等;

          number:var iNum=23; //整數

          var iNum=23.0; //浮點數

          boolean:true 和false;

          string:一組被引號(單引號或雙引號)括起來的文本

          var string1="This is a string";

          3、typeof運算符:

          typeof檢測變量的返回值

          typeof運算符返回值如下函數

          undefined:變量被聲明后,但未被賦值

          string:用單引號或雙引號來聲明的字符串

          boolean:true或false

          number:整數或浮點數

          object:javascript中的對象、數組和nul

          4、String對象:


          5、數組:


          數組的常用屬性和方法

          類別 名稱 描述

          屬性 length 設置或返回數組中元素的數目

          方法 join( ) 把數組的所有元素放入一個字符串,通過一個的分隔符進行分隔

          sort() 對數組排序

          push() 向數組末尾添加一個或更多 元素,并返回新的長度


          6、邏輯控制語句:

          if(條件)

          {

          //JavaScript代碼;

          }

          比于 Native App 和 Web App,Hybrid App 憑借其迭代靈活、控制自如、多端同步的優勢在應用市場上越發顯得優勝,主要得力于,其將變更頻繁的部分產品功能使用 H5 開發并在客戶端中借助 WebView 控件嵌入應用當中。所以,開發中我們總會遇到原生 Java 代碼與網頁中的 Js 代碼之間相互調用從而產生的交互問題。

          Java 與 Js 彼此調用的前提是設置 WebView 支持 JavaScript 功能:

          Java 調用 Js

          第一步,在網頁中使用 Js 定義提供給 Java 訪問的方法,就像普通方法定義一樣,如:

          第二步,在 Java 代碼中按照 “javascript:XXX” 的 Url 格式使用 WebView 加載訪問即可:

          注意:String 類型的參數需要使用單引號 “’” 包裹,數組類型的參數則不用,如:javascript:javaCallJs([01, 02, 03]),其他復雜類型的參數可以轉換為 Json 字符串的形式傳遞。

          Js 調用 Java

          第一步,在 Java 對象中定義 Js 訪問的方法,如:

          注意事項:提供給 Js 訪問的屬性和方法必須定義為 public 類型,并且添加注解 @JavascriptInterface。在 API 17 及更高版本的系統中,任何暴露給 Js 訪問的 Java 接口都需要添加這個注解,否則會報異常:Uncaught TypeError: Object [object Object] has no method ‘XXX’。系統這種做法也是為了降低應用的安全隱患,因為在之前的版本中,Js 可以通過反射的方式訪問注入 WebView 中的 Java 對象的 public 類型 field 和 method,從而隨意修改宿主程序。

          第二步,將提供給 Js 訪問的接口內容所屬的 Java 對象注入 WebView 中:

          addJavascriptInterface(Object object, String name) 參數說明:object 表示 Js 訪問的接口內容所在的 Java 對象;name 表示 Js 調用 Java 代碼時的接口名稱,與 Js 中的調用保持一致即可。

          第三步,Js 按照指定的接口名訪問 Java 代碼,有如下兩種寫法:

          這里簡單提供一個可供測試的 Html 網頁和 Activity 代碼:

          test.html:

          MainActivity.java:

          效果圖:

          注意:無論是 Java 調用 Js 還是 Js 調用 Java,只能通過參數傳遞數據,而無法獲取彼此方法的返回值!解決方案就是額外添加一層回調來達到這個目的。比如 Java 調用 Js 的方法,Js 計算結束所得結果不能通過 return 語句返回給 Java 調用者,而是再回調 Java 的另一個方法,通過傳參的形式傳遞給 Java。

          注意事項

          1.使用 loadUrl() 方法實現 Java 調用 Js 功能時,必須放置在主線程中,否則會發生崩潰異常。比如修改上面的代碼:

          運行時會得到如下 logcat 異常信息:

          java.lang.RuntimeException: java.lang.Throwable: A WebView method was called on thread 'Thread-18022'. All WebView methods must be called on the same thread.

          如果真的在子線程中遇到調用 Js 的功能,也要將其轉換到主線程中去:

          2.Js 調用 Java 方法時,不是在主線程 (Thread Name:main) 中運行的,而是在一個名為 JavaBridge 的線程中執行的,通過如下代碼可以測試:

          所以這里需要注意的是,當 Js 調用 Java 時,如果需要 Java 繼續回調 Js,千萬別在 JavascriptInterface 方法體中直接執行 loadUrl() 方法,而是像前面一樣進行線程切換操作。

          3.代碼混淆時,記得保持 JavascriptInterface 內容,在 proguard 文件中添加如下類似規則 (有關類名按需修改):

          Url 攔截

          除了上面這種 Java 與 Js 互調方法的方式,還可以利用 WebView 攔截 Url 的方式實現原生應用與 H5 之間的交互動作。通過 WebViewClient 提供的接口攔截網頁內諸如二級跳轉的 Url 鏈接,便可以進行業務邏輯上的判斷處理、Url 參數傳遞等功能,如:

          注意:過去常用的 shouldOverrideUrlLoading(WebView view, String url) 方法已經被廢棄。

          參考使用

          通過 Java 與 Js 之間的交互可以做很多事情,比如獲取網頁中的圖片,利用原生控件予以展示,類似響應微信公眾號文章中的圖片點擊事件。參考代碼如下:

          作者博客地址:

          http://yifeng.studio/2016/12/01/android-webview-java-js-interaction


          主站蜘蛛池模板: 性色AV一区二区三区| 欧洲精品码一区二区三区免费看| 国产传媒一区二区三区呀| 精品国产亚洲一区二区三区| 亚洲AⅤ无码一区二区三区在线| 精品一区二区三区| 国产精品电影一区| 国内自拍视频一区二区三区| 亚洲天堂一区二区三区四区| 日韩一区二区三区无码影院| 人妻AV一区二区三区精品| 亚洲午夜精品第一区二区8050| 激情综合丝袜美女一区二区| 国产一区二区在线| 无码精品一区二区三区| 亚洲电影唐人社一区二区| 国产一区二区三精品久久久无广告 | 一区二区三区AV高清免费波多| 国产一区二区三区美女 | 国产一区中文字幕| 国产一区韩国女主播| 精品女同一区二区| 国产成人欧美一区二区三区| 任你躁国语自产一区在| 高清一区二区三区日本久| 国产成人无码AV一区二区在线观看 | 成人无码AV一区二区| 成人午夜视频精品一区| 视频在线一区二区| 国产一区二区精品久久91| 四虎在线观看一区二区| 亚洲AV网一区二区三区| 亚洲综合一区无码精品| 大香伊人久久精品一区二区| 国产日韩一区二区三区| 中文乱码字幕高清一区二区| 中文字幕一区日韩精品| 无码午夜人妻一区二区不卡视频| 日韩高清一区二区| 久久综合九九亚洲一区| 久久se精品一区二区|