android與H5交互

1 — WebView基本配置

2 —WebView和H5的交互

3 — WebView錯誤頁面處理

4 —WebView中的Cookie操作

5 —WebView漏洞

6 —WebView內(nèi)存泄漏問題

1WebView基本配置

布局設(shè)置


代碼設(shè)置

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

? ? xmlns:android="http://schemas.android.com/apk/res/android"

? ? android:layout_width="match_parent"

? ? android:layout_height="match_parent"

? ? android:orientation="vertical">

? ? <LinearLayout

? ? ? ? android:layout_width="match_parent"

? ? ? ? android:layout_height="50dp">

? ? ? ? <Button

? ? ? ? ? ? android:layout_width="0dp"

? ? ? ? ? ? android:layout_weight="1"

? ? ? ? ? ? android:layout_height="match_parent"

? ? ? ? ? ? android:id="@+id/btn1"

? ? ? ? ? ? android:text="無參調(diào)用"/>

? ? ? ? <Button

? ? ? ? ? ? android:layout_width="0dp"

? ? ? ? ? ? android:layout_weight="1"

? ? ? ? ? ? android:layout_height="match_parent"

? ? ? ? ? ? android:text="有參調(diào)用"

? ? ? ? ? ? android:id="@+id/btn2"/>

? ? </LinearLayout>

? ? <WebView

? ? ? ? android:id="@+id/wv"

? ? ? ? android:layout_width="fill_parent"

? ? ? ? android:layout_height="fill_parent"

? ? ? ? android:layout_weight="9" />

</LinearLayout>

初如化控件

? ? ? ? //初始化控件

? ? ? ? Button btn1 = (Button) findViewById(R.id.btn1);

? ? ? ? btn1.setOnClickListener(this);

? ? ? ? Button btn2 = (Button) findViewById(R.id.btn2);

? ? ? ? btn2.setOnClickListener(this);

? ? ? ? wv = (WebView) findViewById(R.id.wv);

? ? ? ? //獲取webSettings

? ? ? ? WebSettings settings = wv.getSettings();

? ? ? ? //讓webView支持JS

? ? ? ? settings.setJavaScriptEnabled(true);

? ? ? ? //加載百度網(wǎng)頁

? ? ? ? wv.loadUrl("http://www.baidu.com/");

? ? ? ? //這個時候就能顯示百度頁面了


2 WebView和H5的交互

我們自己寫一個H5頁面 放在assets目錄下

注意 : 如果html文件存于assets:則加前綴:file:///android_asset/

如果在Sdcard直接使用file:///sdcard/ or file:/sdcard也可以

  //加載本地assets目錄下的靜態(tài)網(wǎng)頁

? ? wv.loadUrl("file:///android_asset/123.html");

? ? //第一個參數(shù)把自身傳給js 第二個參數(shù)是this的一個名字

? ? //這個方法用于讓H5調(diào)用android方法

? ? wv.addJavascriptInterface(this, "android");


Android調(diào)用JS方法

//這個是button的點擊事件

@Override

? ? public void onClick(View v) {

? ? ? ? switch (v.getId()) {

? ? ? ? ? ? case R.id.btn1:

? ? ? ? ? ? ? ? //參數(shù) “javascript:”? +? js方法名

? ? ? ? ? ? ? ? wv.loadUrl("javascript:message()");

? ? ? ? ? ? ? ? break;

? ? ? ? ? ? case R.id.btn2:

? ? ? ? ? ? ? ? //在android調(diào)用js有參的函數(shù)的時候參數(shù)要加單引號

? ? ? ? ? ? ? ? wv.loadUrl("javascript:message2('" + name + "')");

? ? ? ? ? ? ? ? break;

? ? ? ? }

? ? }

JS調(diào)用Android方法

? ? //下面的兩個方法是讓網(wǎng)頁來調(diào)的

? ? //這個注解必須加 因為 兼容問題

? ? @JavascriptInterface

? ? public void setMessage() {

? ? ? ? Toast.makeText(this, "我彈", Toast.LENGTH_SHORT).show();

? ? }

? ? @JavascriptInterface

? ? public void setMessage(String name) {

? ? ? ? Toast.makeText(this, "我彈彈" + name, Toast.LENGTH_SHORT).show();

? ? }


H5代碼,如果H5看不懂請自行百度

<!DOCTYPE html>

<html>

<head>

? ? <meta charset="utf-8" />

? ? <title></title>

</head>

<body>

<button id="btn0">調(diào)用android無參參數(shù)</button>

<button id="btn1">調(diào)用android有參參數(shù)</button>

<a href='aa://atguigu/path'>點我試試</a>

<a >百度</a>

<div id="content"></div>

</body>

<script type="text/javascript">

? ? ? ? var name = "啊福老師 哇哇哇"

? ? ? ? document.getElementById("btn0").onclick = function(){

????????//android是傳過來的對象名稱,setmessage是android中的方法

? ? ? ? ? ? android.setMessage();

? ? ? ? };

? ? ? ? document.getElementById("btn1").onclick = function(){

????????//android是傳過來的對象名稱,setmessage是android中的方法

? ? ? ? ? ? ? ? android.setMessage(name);

? ? ? ? };

? ? ? ? var content = document.getElementById("content");

? ? ? ? function message(){

? ? ? ? ? ? content.innerHTML = "調(diào)用了有參的js函數(shù)"

? ? ? ? };

? ? ? ? function message2(des){

? ? ? ? ? ? content.innerHTML = "調(diào)用了"+des;

? ? ? ? };

? ? </script>

</html>


第二種交互方式 而是采用scheme + cookie的方式

--1、Java 調(diào)用 js里面的函數(shù)、效率低、估計要200ms左右

而js去調(diào)Java的方法、速度很快、50ms左右、所以盡量用js調(diào)用Java方法

--2、Java 調(diào)用 js 的函數(shù)、沒有返回值、調(diào)用了就控制不到了

--3、Js 調(diào)用 Java 的方法、返回值如果是字符串、你會發(fā)現(xiàn)這個字符串是 native 的、轉(zhuǎn)成 locale 的才能正常使用

--4、網(wǎng)頁中盡量不要使用jQuery、執(zhí)行起來需要5-6秒、最好使用原生的js寫業(yè)務(wù)腳本、以提升加載速度、改善用戶體驗

--5、Android4.2以下的系統(tǒng)存在著webview的js對象注入漏洞…Android API 16 沒有正確限制使用webview.addJavaScripteInterface方法,遠程攻擊者 使用JavaReflectionAPI利用執(zhí)行任意java對象的方法


scheme設(shè)置:對于要啟動的Activity

//這一章不詳細講解scheme的使用

<activity android:name=".SecondActivity">

? ? ? ? ? ? <intent-filter>

? ? ? ? ? ? ? ? <data android:scheme="aa"/>

? ? ? ? ? ? ? ? <action android:name="android.intent.action.VIEW"/>

? ? ? ? ? ? ? ? <category android:name="android.intent.category.DEFAULT"/>

? ? ? ? ? ? ? ? <category android:name="android.intent.category.BROWSABLE"/>

? ? ? ? ? ? </intent-filter>

? ? ? ? </activity>

看一下原來的H5代碼

<a href='aa://atguigu/path'>點我試試</a>

注意:

//Url地址? aa://atguigu/path

下面的是Activity清單文件的配置

<data android:scheme="aa" android:host="atguigu" android:path="/path"/>

上下對比其實和我們的URL地址是一樣的

aa 是 scheme

host 是主機名稱

path 是路徑

當然還可以配置端口和加參數(shù)

aa://atguigu:8080/path?id = 10

通過activity配置那么就可以跳轉(zhuǎn)到相應(yīng)的界面里,如果activity只配置scheme = aa那么只要是aa的Url都是適配的

wv.setWebViewClient(new WebViewClient() {

//當頁面開始加載的時候調(diào)用此方法

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onPageStarted(WebView view, String url, Bitmap favicon) {

? ? ? ? ? ? ? ? super.onPageStarted(view, url, favicon);

? ? ? ? ? ? ? //通過對URl的解析來決定調(diào)轉(zhuǎn)到哪個頁面

? ? ? ? ? ? ? //這邊只是簡單做一些判斷當前是否是Scheme跳轉(zhuǎn)

? ? ? ? ? ? ? ? if (url.contains("aa")) {

? ? ? ? ? ? ? ? ? ? Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));

? ? ? ? ? ? ? ? ? ? startActivity(intent);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

3WebView錯誤頁面處理

場景 : 加載webview錯誤時加載網(wǎng)頁的錯誤頁面,體驗不好,速度慢,這個時候就需要我們自行處理錯誤頁面

第一步 先做一個錯誤的H5頁面放在本地,或者加載Activity都可以

wv.setWebViewClient(new WebViewClient() {

? ? @Override

? ? ? ? ? ? public void onReceivedError(WebView view, int errorCode,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? String description, String failingUrl) {

? ? ? ? ? ? ? ? super.onReceivedError(view, errorCode, description, failingUrl);

? ? ? ? ? ? ? ? Log.i(TAG, "onReceivedError: " + errorCode + "? " + description);

? ? ? ? ? ? ? ? //判斷錯誤類型

? ? ? ? ? ? ? ? if (errorCode == ERROR_UNSUPPORTED_SCHEME) {

? ? ? ? ? ? ? ? ? ? Log.i(TAG, "onReceivedError: " + "true");

? ? ? ? ? ? ? ? ? ? //停止加載錯誤頁面,否則會顯示原來H5加載的錯誤頁面

? ? ? ? ? ? ? ? ? ? //再跳到現(xiàn)在的錯誤頁面,體驗不好,當然也可以做其它操作

? ? ? ? ? ? ? ? ? ? view.stopLoading();

? ? ? ? ? ? ? ? ? ? view.loadUrl("file:///android_asset/error.html");

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

}


4WebView中的Cookie操作

關(guān)于Cookie的介紹在這不再詳說

場景:webView需要保存從網(wǎng)頁中獲取到的Cookie 在涉及到賬戶體系的產(chǎn)品中,包含了一種登錄狀態(tài)的傳遞。比如,在Native(原生)界面的登錄操作,進入到Web界面時,涉及到賬戶信息時,需要將登錄狀態(tài)傳遞到Web里面,避免用戶二次登錄。這里就涉及到WebView加載網(wǎng)頁時的Cookie操作了。

通常我們在登錄時獲取到用戶的Cookie信息,然后將其保存到sdcard的WebView緩存文件當中,這樣在加載網(wǎng)頁時,WebView會自動將當前url的本地Cookie信息放在http請求的request中,傳遞給服務(wù)器

獲取cookie

//加載百度網(wǎng)站

wv.loadUrl("http://www.baidu.com");

wv.setWebViewClient(new WebViewClient() {

? ? @Override

? ? ? ? ? ? public void onPageStarted(WebView view, String url, Bitmap favicon) {

? ? ? ? ? ? ? ? super.onPageStarted(view, url, favicon);

? ? ? ? ? ? ? CookieManager instance = CookieManager.getInstance();

? ? ? ? ? ? ? //這樣就可以獲取到Cookie了

? ? ? ? ? ? ? String cookie = instance.getCookie(url);

? ? ? ? ? ? ? Log.i(TAG, "onPageStarted: "+cookie);

? ? ? ? ? ? }

}

設(shè)置cookie

? ? ? ? //創(chuàng)建CookieSyncManager 參數(shù)是上下文

? ? ? ? CookieSyncManager.createInstance(context);

? ? ? ? //得到CookieManager

? ? ? ? CookieManager cookieManager = CookieManager.getInstance();

? ? ? ? //得到向URL中添加的Cookie的值

? ? ? ? String cookieString;//獲取方法不再詳述,以項目要求而定

? ? ? ? //使用cookieManager..setCookie()向URL中添加Cookie

? ? ? ? cookieManager.setCookie(url, cookieString);

? ? ? ? CookieSyncManager.getInstance().sync();


5WebView漏洞和內(nèi)存泄漏

/**

* ① Android API 16 沒有正確限制使用webview.addJavaScripteInterface方法,遠程攻擊者使用 JavaReflectionAPI利用執(zhí)行任意java對象的方法

*

* ② webview在布局文件中的使用:webView寫在其它容器中時 (先銷毀webview再銷毀activity)因為 webview是獨立進程,最好創(chuàng)建個viewGroup用來放置webview,Activity創(chuàng)建時add進來,在Activity停止時remove掉

*

* ③使用 jsbridge(詳情看下面)

*

* ④ 在此方法的操作放到后者使用webviewClient.onPageFinished->WebChromeClient.onProgressChanged

*

* ⑤ 后臺耗電問題 :activity不可見時要停用webview

*

* ⑥ webview硬件加速導致頁面渲染問題-白屏展示(關(guān)閉硬件加速)

*

* ⑦動態(tài)添加webview,對傳入webview中使用的context使用弱引用,動態(tài)添加webview意思在布局

* */

JSBridge

什么是JsBridge

WebViewJavascriptBridge是移動UIView和Html交互通信的橋梁,就是實現(xiàn)java和js的互相調(diào)用的橋梁。替代了WebView的自帶的JavascriptInterface的接口,使得開發(fā)者更方便的讓js和native靈活交互,使我們的開發(fā)更加靈活和安全。

1

JSBridge的優(yōu)點

? ? Android API 4.4以前,谷歌的webview存在安全漏洞,網(wǎng)站可以通過js注入就可以隨便拿到客戶端的重要信息,甚至輕而易舉的調(diào)用本地代碼進行流氓行為,谷歌后來發(fā)現(xiàn)有此漏洞后,在API 4.4以后增加了防御措施,如果用js調(diào)用本地代碼,開發(fā)者必須在代碼申明JavascriptInterface, 列如在4.0之前我們要使得webView加載js只需如下代碼:

mWebView.addJavascriptInterface(new JsToJava(), "myjsfunction");

4.4之后使用時需要在調(diào)用Java方法加入@JavascriptInterface注解,如果代碼無此申明,那么也就無法使得js生效,也就是說這樣就可以避免惡意網(wǎng)頁利用js對客戶端的進行竊取和攻擊。 但是即使這樣,我們很多時候需要在js調(diào)用本地java代碼的時候,要做一些判斷和限制,或者有的場景也會做些過濾或者對用戶友好提示,甚至更復雜的Hybrid模式下,需要js和native之間進行交互通訊,拍照上傳,因此原生的JavascriptInterface 就比較維護了,特此有了基于JavascriptInterface 封裝的WebViewJavascriptBridge框架。

---------------------

作者:小龍哥的開發(fā)日記

來源:CSDN

原文:https://blog.csdn.net/w15321970103/article/details/75635454

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容