對於android調用JS代碼的方法有2種:
1. 經過WebView的loadUrl()
2. 經過WebView的evaluateJavascript()javascript
對於JS調用Android代碼的方法有3種:
1. 經過WebView的addJavascriptInterface()進行對象映射
2. 經過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url
3. 經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息html
2.1 Android經過WebView調用 JS 代碼java
對於Android調用JS代碼的方法有2種:android
經過WebView的loadUrl()
經過WebView的evaluateJavascript()
方式1:經過WebView的loadUrl()web
實例介紹:點擊Android按鈕,即調用WebView JS(文本名爲javascript)中callJS()
具體使用:
步驟1:將須要調用的JS代碼以.html格式放到src/main/assets文件夾裏ide
爲了方便展現,本文是採用Andorid調用本地JS代碼說明;
實際狀況時,Android更多的是調用遠程JS代碼,即將加載的JS代碼路徑改爲url便可
須要加載JS代碼:JavaScript.html函數
// 文本名:javascript
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Carson_Ho</title> // JS代碼 <script> // Android須要調用的方法 function callJS(){ alert("Android調用了JS的callJS方法"); } </script> </head> </html>
步驟2:在Android裏經過WebView設置調用JS代碼
Android代碼:MainActivity.Javapost
註釋已經很是清楚
public class MainActivity extends AppCompatActivity { WebView mWebView; Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView =(WebView) findViewById(R.id.webview); WebSettings webSettings = mWebView.getSettings(); // 設置與Js交互的權限 webSettings.setJavaScriptEnabled(true); // 設置容許JS彈窗 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 先載入JS代碼 // 格式規定爲:file:///android_asset/文件名.html mWebView.loadUrl("file:///android_asset/javascript.html"); button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 必須另開線程進行JS方法調用(不然沒法調用) mWebView.post(new Runnable() { @Override public void run() { // 注意調用的JS方法名要對應上 // 調用javascript的callJS()方法 mWebView.loadUrl("javascript:callJS()"); } }); } }); // 因爲設置了彈窗檢驗調用結果,因此須要支持js對話框 // webview只是載體,內容的渲染須要使用webviewChromClient類去實現 // 經過設置WebChromeClient對象處理JavaScript的對話框 //設置響應js 的Alert()函數 mWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this); b.setTitle("Alert"); b.setMessage(message); b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { result.confirm(); } }); b.setCancelable(false); b.create().show(); return true; } }); } }
特別注意:JS代碼調用必定要在 onPageFinished() 回調以後才能調用,不然不會調用。ui
onPageFinished()屬於WebViewClient類的方法,主要在頁面加載結束時調用
方式2:經過WebView的evaluateJavascript()this
優勢:該方法比第一種方法效率更高、使用更簡潔。
由於該方法的執行不會使頁面刷新,而第一種方法(loadUrl )的執行則會。
Android 4.4 後纔可以使用
具體使用
// 只須要將第一種方法的loadUrl()換成下面該方法便可 mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此處爲 js 返回的結果 } }); }
2.1.2 方法對比
2.1.3 使用建議
兩種方法混合使用,即Android 4.4如下使用方法1,Android 4.4以上方法2
// Android版本變量 final int version = Build.VERSION.SDK_INT; // 由於該方法在 Android 4.4 版本纔可以使用,因此使用時需進行版本判斷 if (version < 18) { mWebView.loadUrl("javascript:callJS()"); } else { mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此處爲 js 返回的結果 } }); }
2.2 JS經過WebView調用 Android 代碼
對於JS調用Android代碼的方法有3種:
1. 經過WebView的addJavascriptInterface()進行對象映射
2. 經過 WebViewClient 的shouldOverrideUrlLoading ()方法回調攔截 url
3. 經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息
4. 2.2.1 方法分析
方式1:經過 WebView的addJavascriptInterface()進行對象映射
步驟1:定義一個與JS對象映射關係的Android類:AndroidtoJs
AndroidtoJs.java(註釋已經很是清楚)
// 繼承自Object類 public class AndroidtoJs extends Object { // 定義JS須要調用的方法 // 被JS調用的方法必須加入@JavascriptInterface註解 @JavascriptInterface public void hello(String msg) { System.out.println("JS調用了Android的hello方法"); } }
步驟2:將須要調用的JS代碼以.html格式放到src/main/assets文件夾裏
須要加載JS代碼:javascript.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Carson</title> <script> function callAndroid(){ // 因爲對象映射,因此調用test對象等於調用Android映射的對象 test.hello("js調用了android中的hello方法"); } </script> </head> <body> //點擊按鈕則調用callAndroid函數 <button type="button" id="button1" onclick="callAndroid()"></button> </body> </html>
步驟3:在Android裏經過WebView設置Android類與JS代碼的映射
詳細請看註釋
public class MainActivity extends AppCompatActivity { WebView mWebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = mWebView.getSettings(); // 設置與Js交互的權限 webSettings.setJavaScriptEnabled(true); // 經過addJavascriptInterface()將Java對象映射到JS對象 //參數1:Javascript對象名 //參數2:Java對象名 mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS類對象映射到js的test對象 // 加載JS代碼 // 格式規定爲:file:///android_asset/文件名.html mWebView.loadUrl("file:///android_asset/javascript.html");
特色
優勢:使用簡單
僅將Android對象和JS對象映射便可
缺點:存在嚴重的漏洞問題,具體請看文章:你不知道的 Android WebView 使用漏洞
方式2:經過 WebViewClient 的方法shouldOverrideUrlLoading ()回調攔截 url
具體原理:
Android經過 WebViewClient 的回調方法shouldOverrideUrlLoading ()攔截 url
解析該 url 的協議
若是檢測到是預先約定好的協議,就調用相應方法
即JS須要調用Android的方法
具體使用:
步驟1:在JS約定所須要的Url協議
JS代碼:javascript.html
以.html格式放到src/main/assets文件夾裏
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Carson_Ho</title> <script> function callAndroid(){ /*約定的url協議爲:js://webview?arg1=111&arg2=222*/ document.location = "js://webview?arg1=111&arg2=222"; } </script> </head> <!-- 點擊按鈕則調用callAndroid()方法 --> <body> <button type="button" id="button1" onclick="callAndroid()">點擊調用Android代碼</button> </body> </html>
當該JS經過Android的mWebView.loadUrl(「file:///android_asset/javascript.html」)加載後,就會回調shouldOverrideUrlLoading (),接下來繼續看步驟2:
步驟2:在Android經過WebViewClient複寫shouldOverrideUrlLoading ()
MainActivity.java
public class MainActivity extends AppCompatActivity { WebView mWebView; // Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = mWebView.getSettings(); // 設置與Js交互的權限 webSettings.setJavaScriptEnabled(true); // 設置容許JS彈窗 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 步驟1:加載JS代碼 // 格式規定爲:file:///android_asset/文件名.html mWebView.loadUrl("file:///android_asset/javascript.html"); // 複寫WebViewClient類的shouldOverrideUrlLoading方法 mWebView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // 步驟2:根據協議的參數,判斷是不是所須要的url // 通常根據scheme(協議格式) & authority(協議名)判斷(前兩個參數) //假定傳入進來的 url = "js://webview?arg1=111&arg2=222"(同時也是約定好的須要攔截的) Uri uri = Uri.parse(url); // 若是url的協議 = 預先約定的 js 協議 // 就解析往下解析參數 if ( uri.getScheme().equals("js")) { // 若是 authority = 預先約定協議裏的 webview,即表明都符合約定的協議 // 因此攔截url,下面JS開始調用Android須要的方法 if (uri.getAuthority().equals("webview")) { // 步驟3: // 執行JS所須要調用的邏輯 System.out.println("js調用了Android的方法"); // 能夠在協議上帶有參數並傳遞到Android上 HashMap<String, String> params = new HashMap<>(); Set<String> collection = uri.getQueryParameterNames(); } return true; } return super.shouldOverrideUrlLoading(view, url); } } ); } }
特色
優勢:不存在方式1的漏洞;
缺點:JS獲取Android方法的返回值複雜。
若是JS想要獲得Android方法的返回值,只能經過 WebView 的 loadUrl ()去執行 JS 方法把返回值傳遞回去,相關的代碼以下:
// Android:MainActivity.java mWebView.loadUrl("javascript:returnResult(" + result + ")"); // JS:javascript.html function returnResult(result){ alert("result is" + result); }
方式3:經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調攔截JS對話框alert()、confirm()、prompt() 消息
在JS中,有三個經常使用的對話框方法:
方式3的原理:Android經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調分別攔截JS對話框
(即上述三個方法),獲得他們的消息內容,而後解析便可。
下面的例子將用攔截 JS的輸入框(即prompt()方法)說明 :
經常使用的攔截是:攔截 JS的輸入框(即prompt()方法)
由於只有prompt()能夠返回任意類型的值,操做最全面方便、更加靈活;而alert()對話框沒有返回值;confirm()對話框只能返回兩種狀態(肯定 / 取消)兩個值
步驟1:加載JS代碼,以下:
javascript.html
以.html格式放到src/main/assets文件夾裏
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Carson_Ho</title> <script> function clickprompt(){ // 調用prompt() var result=prompt("js://demo?arg1=111&arg2=222"); alert("demo " + result); } </script> </head> <!-- 點擊按鈕則調用clickprompt() --> <body> <button type="button" id="button1" onclick="clickprompt()">點擊調用Android代碼</button> </body> </html>
當使用mWebView.loadUrl(「file:///android_asset/javascript.html」)加載了上述JS代碼後,就會觸發回調onJsPrompt(),具體以下:
若是是攔截警告框(即alert()),則觸發回調onJsAlert();
若是是攔截確認框(即confirm()),則觸發回調onJsConfirm();
步驟2:在Android經過WebChromeClient複寫onJsPrompt()
public class MainActivity extends AppCompatActivity { WebView mWebView; // Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = mWebView.getSettings(); // 設置與Js交互的權限 webSettings.setJavaScriptEnabled(true); // 設置容許JS彈窗 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 先加載JS代碼 // 格式規定爲:file:///android_asset/文件名.html mWebView.loadUrl("file:///android_asset/javascript.html"); mWebView.setWebChromeClient(new WebChromeClient() { // 攔截輸入框(原理同方式2) // 參數message:表明promt()的內容(不是url) // 參數result:表明輸入框的返回值 @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { // 根據協議的參數,判斷是不是所須要的url(原理同方式2) // 通常根據scheme(協議格式) & authority(協議名)判斷(前兩個參數) //假定傳入進來的 url = "js://webview?arg1=111&arg2=222"(同時也是約定好的須要攔截的) Uri uri = Uri.parse(message); // 若是url的協議 = 預先約定的 js 協議 // 就解析往下解析參數 if ( uri.getScheme().equals("js")) { // 若是 authority = 預先約定協議裏的 webview,即表明都符合約定的協議 // 因此攔截url,下面JS開始調用Android須要的方法 if (uri.getAuthority().equals("webview")) { // // 執行JS所須要調用的邏輯 System.out.println("js調用了Android的方法"); // 能夠在協議上帶有參數並傳遞到Android上 HashMap<String, String> params = new HashMap<>(); Set<String> collection = uri.getQueryParameterNames(); //參數result:表明消息框的返回值(輸入值) result.confirm("js調用了Android的方法成功啦"); } return true; } return super.onJsPrompt(view, url, message, defaultValue, result); } // 經過alert()和confirm()攔截的原理相同,此處不做過多講述 // 攔截JS的警告框 @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { return super.onJsAlert(view, url, message, result); } // 攔截JS的確認框 @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { return super.onJsConfirm(view, url, message, result); } } ); } }
2.2.2 三種方式的對比 & 使用場景