概覽
- Android中打開本地的HTML
- 網(wǎng)頁打開App指定頁面,并傳遞參數(shù)
- JS調(diào)用Native
- Native調(diào)用JS
- WebView優(yōu)化
Android中打開本地的HTML
初始化WebView,加載本地的Html文件
javaMethod = new JavaMethod(this);
webView = new WebView(this);
WebSettings settings = webView.getSettings();
settings.setDomStorageEnabled(true);
settings.setJavaScriptEnabled(true);
settings.setBlockNetworkImage(false);
webView.setWebViewClient(javaMethod.getWebViewClient());
webView.setWebChromeClient(javaMethod.getWebChromeClient());
webView.addJavascriptInterface(javaMethod, "android");
frameLayout.addView(webView);
// webView加載一個網(wǎng)頁
webView.loadUrl("file:///android_asset/test_js.html");
js調(diào)用native
1. 借助WebView.addJavascriptInterface實現(xiàn)H5與Native通信
WebView的addJavascriptInterface方法允許Natvive向Web頁面注入Java對象,之后,在js中便可以直接訪問該對象南蹂,使用@JavascriptInterface注解的方法。
public class JavaMethod {
private MainActivity mainActivity;
private Handler uiHandler;
public JavaMethod(MainActivity mainActivity) {
this.mainActivity = mainActivity;
uiHandler = new Handler(Looper.getMainLooper());
}
@JavascriptInterface
public void JsToJavaInterface(final String param) {
uiHandler.post(new Runnable() {
@Override
public void run() {
mainActivity.setTextShow("from JavaInterface: " + param);
}
});
}
}
在前端的js代碼中,是可以直接通過mJsMethodApi.callNative(jsonString)通知Native的艘狭,而且通過addJavascriptInterface注入的對象在H5的任何地方都可以調(diào)用,不存在注入時機跟注入失敗的問題,在H5的head里調(diào)用都沒問題巢音。
<html>
<head>
<meta http-equiv="Content-Type" charset="UTF-8"/>
<script type="text/javascript">
</script>
</head>
<body>
<h3>Js Method</h3>
<h3 id="textshow">調(diào)用結(jié)果</h3>
<input type="button" value="JavascriptInterface" onclick="window.android.JsToJavaInterface('我來自Js')"/>
</body>
</html>
2. shouldOverrideUrlLoading
通過WebViewClient中的shouldOverrideUrlLoading攔截url遵倦,制定一個對應(yīng)協(xié)議。
在Html中增加一條
<input type="button" value="shouldOverrideUrlLoading" onclick="document.location = 'js://jstojava?arg1=1號參數(shù)&arg2=2號參數(shù)'"/><br/>
在Android代碼中攔截url
/**
* shouldOverrideUrlLoading:webViewClient加載url時候的回調(diào)
*
* @return WebViewClient
*/
public WebViewClient getWebViewClient() {
WebViewClient webViewClient = new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri uri = request.getUrl();
// 與JS端定義好協(xié)議: 一般協(xié)議格式是Scheme(協(xié)議頭)+ Authority(協(xié)議名)
if (uri != null) {
String scheme = uri.getScheme();
if (scheme != null && scheme.equals("js")) {
String authority = uri.getAuthority();
if (authority != null && authority.equals("jstojava")) {
// 獲取參數(shù)
String arg1 = uri.getQueryParameter("arg1");
String arg2 = uri.getQueryParameter("arg2");
showText(MessageFormat.format("參數(shù): {0}; {1}", arg1, arg2));
Log.e("==TAG==>", "參數(shù) -> arg1:" + arg1 + " ; arg2:" + arg2);
}
return true;
}
}
return super.shouldOverrideUrlLoading(view, request);
}
};
return webViewClient;
}
這種方式?jīng)]有版本限制和漏洞港谊,不過沒有返回值骇吭,如果Js調(diào)用后需要android返回就得使用loadUrl()或者evaluateJavascript()回傳對應(yīng)的接收方法了。值得一提的是歧寺,這種方式便于和IOS通用一套協(xié)議燥狰,簡便Js端的代碼量。
3. onJsAlert()斜筐、onJsConfirm()龙致、onJsPrompt()
通過 WebChromeClient 中的onJsAlert()、onJsConfirm()顷链、onJsPrompt()攔截Js中的alert()目代、confirm()、prompt() 消息嗤练。而alert榛了、confirm、prompt代表Js中三種常用提示框煞抬,第一種沒有返回值霜大,第二種返回布爾值,第三種可返回任意值革答。由于考慮到靈活性战坤,所以我們可以直接實現(xiàn)對prompt的攔截即可。
在Html中添加
<script type="text/javascript">
function jstojavaprompt(param){
result = prompt(param);
document.getElementById("textshow").innerHTML = (result);
}
</script>
...
<input type="button" value="onJsPrompt"
onclick="jstojavaprompt('js://jstojava?arg3=1號參數(shù)&arg4=2號參數(shù)')"/><br/>
代碼中設(shè)置setWebChromClient()残拐,攔截onJsPrompt
/**
* onJsPrompt:調(diào)用本地方法jstojavaprompt()途茫,然后回調(diào)onJsPrompt()
*
* @return WebChromeClient
*/
public WebChromeClient getWebChromeClient() {
return new WebChromeClient() {
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
Log.e("==TAG==>", "url:" + url);
Uri uri = Uri.parse(message);
// 與JS端定義好協(xié)議: 一般協(xié)議格式是Scheme(協(xié)議頭)+ Authority(協(xié)議名)
if (uri != null) {
String scheme = uri.getScheme();
if (scheme != null && scheme.equals("js")) {
String authority = uri.getAuthority();
if (authority != null && authority.equals("jstojava")) {
// 獲取參數(shù)
String arg1 = uri.getQueryParameter("arg3");
String arg2 = uri.getQueryParameter("arg4");
showText(MessageFormat.format("參數(shù): {0}; {1}", arg1, arg2));
Log.e("==TAG==>", "參數(shù) -> arg1:" + arg1 + " ; arg2:" + arg2);
result.confirm("我來自onJsPrompt");
}
return true;
}
}
return super.onJsPrompt(view, url, message, defaultValue, result);
}
};
}
Native調(diào)用JS
1. loadUrl() 方式
在Html中添加JS方法
<script type="text/javascript">
var s = '我來自Js方法';
function javatojscallback(param){
document.getElementById("textshow").innerHTML = (param);
window.android.jsCallbackParams(s)
}
</script>
window.android.JsToJavaInterface(s)是Js調(diào)用android的方法,由于loadUrl()不能從Js返回數(shù)據(jù)溪食,可以讓Js回調(diào)android的方法回傳參數(shù)囊卜。
在Android代碼中添加接收Js回調(diào)傳參的方法
// Js回調(diào)Android的方法,傳遞參數(shù)
@JavascriptInterface
public void jsCallbackParams(String params){
showText(params);
}
在Android中調(diào)用JS方法
/**
* 通過 webView.loadUrl 調(diào)用JS
*
* @param view view
*/
public void loadUrl(View view) {
webView.loadUrl("javascript:javatojscallback('我來自Java')");
}
2. evaluateJavascript()方式
在Html中定義js的方法错沃,供Java調(diào)用
var s = '我來自Js方法';
function javatojswith(param){
document.getElementById("textshow").innerHTML = (param);
return s;
}
在Android中通過webView.evaluateJavascript()調(diào)用JS中的方法
/**
* 通過 webView.evaluateJavascript 調(diào)用JS
*
* @param view
*/
public void evaluate(View view) {
webView.evaluateJavascript("javascript:javatojswith('這是來自Java的參數(shù)')",
new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
setTextShow(value);
Toast.makeText(WebActivity.this, value, Toast.LENGTH_SHORT).show();
}
});
}
WebView優(yōu)化
為什么擁有Webview的H5頁面打開這么慢边败,是因為它通常會經(jīng)歷以下幾個階段:
1)Webview初始化。
2)到達新的頁面捎废,網(wǎng)絡(luò)連接笑窜,從服務(wù)器下載html,css登疗,js排截,頁面白屏嫌蚤。
3)頁面基本框架出現(xiàn),js請求頁面數(shù)據(jù)断傲,頁面處于loading狀態(tài)脱吱。
4)出現(xiàn)所需的數(shù)據(jù),完成整個頁面的渲染认罩,用戶可交互箱蝠。
1. Webview提前初始化
提前加載WebView,進行WebView的初始化垦垂。加載Webview內(nèi)核宦搬,這是一個重量級的操作,內(nèi)核是以apk的形式存在劫拗。
App生成一個全局webview间校,并且在啟動時初始化,這樣在后面使用時通過動態(tài)獲取這個全局Webview页慷,然后添加到rootview中憔足,這樣就可以進行復(fù)用從而減少初始化的時間。
注意:如果在不同頁面使用Webview時使用不同的設(shè)置酒繁,就需要動態(tài)維護滓彰,而且在不同的頁面跳轉(zhuǎn)前要做好清理工作。
2. H5頁面拉取優(yōu)化
可以把html州袒,css找蜜,js,image等資源預(yù)置在客戶端本地稳析,并和服務(wù)端協(xié)商好前端的版本控制和增量更新策略豌拙,如此一來Webview就可以先快速加載本地緩存頁面資源甚牲,剩下的就只需要拉取那些需要更新的增量資源即可。
而針對這些需要拉取的增量資源窜觉,可以對它們進行webpack+gzip數(shù)據(jù)壓縮和CDN加速處理撰筷,以提升拉取速度陈惰。并且在建立網(wǎng)絡(luò)連接時,可以讓前端請求的域名和客戶端API接口域名一致毕籽,以減少DNS解析時間抬闯。
對于H5頁面來說,圖片資源的拉取是最為耗時的关筒,一個比較好的解決方案就是先加載并展示非圖片內(nèi)容溶握,延遲這些圖片的加載,以提升用戶體驗蒸播。
WebView有一個setBlockNetworkImage(boolean)方法睡榆,該方法的作用是是否屏蔽圖片的加載萍肆。可以利用這個方法來實現(xiàn)圖片的延遲加載:在onPageStarted時屏蔽圖片加載胀屿,在onPageFinished時開啟圖片加載塘揣。
3. H5動態(tài)數(shù)據(jù)拉取并行
正常的順序是在html,css宿崭,js拉取下來之后亲铡,才開始由js發(fā)起前端的ajax請求,獲取到數(shù)據(jù)后才開始進行填充葡兑。
其實我們可以把前端的ajax請求提前到和頁面加載同時進行奖蔓,由客戶端請求數(shù)據(jù),等到H5加載完畢铁孵,直接向客戶端索要即可锭硼,縮短了總體的頁面加載時間。
WebView中的安全漏洞
WebView與Native的通信
WebView緩存優(yōu)化
WebView的加載優(yōu)化