這次項目中有一個主頁面?完全是H5的頁面柿冲,要求H5調(diào)用Native茬高,js交互傳值,看起來貌似很簡單假抄,網(wǎng)上教程一大堆怎栽,但是在實際開發(fā)過程中還是遇到很多問題,在這里記錄一下宿饱。
- 首先熏瞄,設(shè)置user agent,使前端可區(qū)分請求來自APP 谬以,這里我設(shè)置的是"android_app/1.0.0"强饮,名稱加版本號,具體設(shè)置什么大家可隨意为黎。
WebSettings settings = webView.getSettings();
String ua = settings.getUserAgentString();
settings.setUserAgentString(ua + "; android_app/1.0.0");
2.H5頁面的登錄邮丰,因為我們的應(yīng)用不需要登錄也能瀏覽,H5的頁面有些也是不需要登陸的铭乾,所以點擊H5頁面需要登錄的地方剪廉,要跳轉(zhuǎn)到Native的頁面登錄,登錄成功刷新H5頁面炕檩,設(shè)置cookie妈经,使WebView頁面保持登錄狀態(tài),具體代碼如下:
注:WebSettings的一些設(shè)置一定要放到設(shè)置cookie前面執(zhí)行。
設(shè)置cookie要注意作用域的問題吹泡,以及setCookie的時候最好分步設(shè)置骤星,大家可以看下面的代碼,我setCookie()了四次爆哑,不要把所有字符串拼接起來再一次setCookie洞难,一次setCookie可能只會設(shè)置成功第一個分號前的cookie值。
public void synCookies(Context context, String host, String cookies) {
try {
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
// 5.0以上版本的webview做了較大的改動揭朝,如:同步cookie的操作已經(jīng)可以自動同步队贱、但前提是我們必須開啟第三方cookie的支持。
// cookieManager.setAcceptThirdPartyCookies(webView, true);//5.0以下的手機崩潰
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();//移除
cookieManager.removeAllCookie();
//base64加密
// String base64Cookies = Base64Utils.encodeStr(getCookies());
//根據(jù)RFC822規(guī)定潭袱,BASE64Encoder編碼每76個字符柱嫌,還需要加上一個回車換行。
//使用 commons-codec-1.10.jar 不會換行而且效率更高
//這里我使用的是sun.misc.BASE64Decoder.jar,每76個字符會換行屯换,所以下面去掉換行编丘,為什么不用上面的呢,使用commons-codec-1.10.jar彤悔,Android Studio編譯提示方法重復(fù)嘉抓,沒找到解決辦法。
// base64Cookies = base64Cookies.replace("\n", "");
// Log.i("base64Cookies:", base64Cookies);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 7);
String expiresTime = calendar.getTime().toGMTString();
Log.i("expiresTime =", expiresTime);
//分開設(shè)置晕窑,不然只會設(shè)置第一個分號之前的cookie
// cookieManager.setCookie(host, "Token=" + base64Cookies);
//不加密
cookieManager.setCookie(host, "Token=" + cookies);
//注意host的值抑片,類似于這個網(wǎng)址:http://www.reibang.com/writer#/notebooks/2498434/notes/4304102/preview,host可以妊畛唷:www.reibang.com或者.jianshu.com敞斋,注意作用域,不要把整個url都放上了疾牲。
cookieManager.setCookie(host, "Domain=" + host);
cookieManager.setCookie(host, "Path=/");
// Expires變量是一個只寫變量渺尘,它確定了Cookie有效終止日期。該屬性值DATE必須以特定的格式來書寫:
// 星期幾说敏,DD-MM-YY HH:MM:SS GMT,GMT表示這是格林尼治時間丢郊。反之盔沫,不以這樣的格式來書寫,系統(tǒng)將無法識別枫匾。
// 該變量可省架诞,如果缺省時,則Cookie的屬性值不會保存在用戶的硬盤中干茉,而僅僅保存在內(nèi)存當中谴忧,Cookie文件將隨著瀏覽器的關(guān)閉而自動消失。
cookieManager.setCookie(host, "Expires=" + expiresTime);
CookieSyncManager.getInstance().sync();
String newCookie = cookieManager.getCookie(host);
if (newCookie != null) {
Log.i("getCookie:", newCookie);
}
} catch (Exception e) {
Log.e("failedCookie=%s", e.toString());
}
}
3.自定義scheme、js交互傳值沾谓、調(diào)用js方法及document對象
例如:登錄scheme為 ?goto://just/loginref=http://www.baidu.com&callback=loginWeb
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//1.登錄scheme url = ?goto://just/login?callback=loginWeb
if (url.startsWith("goto://just/login")) {
//登錄委造,跳轉(zhuǎn)到native得LoginActivity
//成功后在onActivityResult()方法中執(zhí)行js的回調(diào)方法loginWeb傳toekn值給H5
return true;
//2.跳轉(zhuǎn)新activity scheme url = ?goto://just/newweb?ref=http://www.baidu.com
} else if (url.startsWith("goto://just/newweb")) {
//頁面加載不在本頁webview加載,而是新打開此MainActivity(標準模式均驶,為了循環(huán)復(fù)用)
String ref = "http://www.baidu.com";
Intent intent = new Intent(MainActivity.this, MainActivity.class);
intent.putExtra("webUrl", ref);
startActivity(intent);
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
//頁面錯誤
llError.setVisibility(View.VISIBLE);
}
public void onPageFinished(WebView view, String url) {
Log.d("WebView", "onPageFinished ");
//獲取整個頁面的Html
view.loadUrl("javascript:window.weixinObj.getHtml('<head>'+" +
"document.getElementsByTagName('html')[0].innerHTML+'</head>');");
//通過document.title 獲取頁面的title
view.loadUrl("javascript:window.weixinObj.getTitle(document.title)");
//此方法也可以通過document.title 獲取標題昏兆,但是需要Api19才能使用
// view.evaluateJavascript("document.title", new ValueCallback<String>() {
// @Override
// public void onReceiveValue(String title) {
//
// }
// });
super.onPageFinished(view, url);
}
});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//登錄頁返回后執(zhí)行
String callback = "loginWeb";
synCookies(this, host, cookies);
webView.loadUrl("javascript:" + callback + "('" + cookies + "')");
webView.reload();
}
private class InterfaceObject {
@JavascriptInterface
public void getHtml(String html) {
//獲取html的內(nèi)容
}
@JavascriptInterface
public void getTitle(String title) {
//獲取標題
}
}
4.以上是我在項目中使用到的一些交互,經(jīng)過測試是可用的妇穴,其實上面寫的這些網(wǎng)上有很多爬虱,但是比較分散,我就自己總結(jié)了一下腾它,例子無法運行的(沒有調(diào)試跑筝,可能有些邏輯錯誤),因為沒有網(wǎng)頁測試瞒滴,如果使用本地html的也不好模擬網(wǎng)絡(luò)上環(huán)境曲梗,所以只寫了一些邏輯,需要大家自行寫h5測試逛腿。
資源:Example下載