WebView你真的熟悉嗎?
在Android
手機中內建了一款高效能webkit
核心瀏覽器,在SDK中封裝為一個叫做WebView
元件。下面總結一下使用webview
遇到的那些事、那些坑。
一、webview的基本使用方法
1. 新增許可權:AndroidManifest.xml中設定許可權"android.permission.INTERNET",否則會出Web page not available錯誤。
2. 在要Activity中生成一個WebView元件:WebView webView = new WebView(this);或者可以在activity的layout檔案裡新增webview控制元件
3. 設定WebView基本資訊:
mWebView = (WebView) findViewById(R.id.wb);
mWebView.getSettings().setJavaScriptEnabled(true);//支援javascript
mWebView.requestFocus();//觸控焦點起作用mWebView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);//取消滾動條
mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);//設定允許js彈出alert對話方塊
//load本地
mWebView.loadUrl("file:///android_asset/hellotest.html");
//load線上
//mWebView.loadUrl("http://www.google.com");
//js訪問android,定義介面
mWebView.addJavascriptInterface(new JsInteration(), "control");
//設定了Alert才會彈出,重新onJsAlert()方法return true可以自定義處理資訊
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//return super.onJsAlert(view, url, message, result);
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
return true;
}});
4. 設定WevView要顯示的網頁:
網際網路用:webView.loadUrl("http://www.google.com");
本地檔案用:webView.loadUrl("file:///android_asset/XX.html");
本地檔案存放在:assets檔案中
5. 如果希望點選連結由自己處理,而不是新開Android的系統browser中響應該連結。給WebView新增一個事件監聽物件(WebViewClient)並重寫其中的一些方法: shouldOverrideUrlLoading
:對網頁中超連結按鈕的響應。當按下某個連線時WebViewClient會呼叫這個方法,並傳遞引數
public boolean shouldOverrideUrlLoading(WebView view,String url){
view.loadUrl(url);
return true;
}
6. 處理https請求
webView預設是不處理https請求的,頁面顯示空白,需要進行如下設定:
webView.setWebViewClient(new WebViewClient() {
@Override public void onReceivedSslError(WebView view,
SslErrorHandler handler, SslError error) {
handler.proceed();
// handler.cancel();
// handler.handleMessage(null); } });
onReceivedSslError
為webView
處理ssl證照設定
其中handler.proceed();
表示等待證照響應
handler.cancel();表示掛起連線,為預設方式
handler.handleMessage(null);可做其他處理
另外還有其他一些可重寫的方法
- 接收到Http請求的事件
onReceivedHttpAuthRequest(WebView view,HttpAuthHandler handler, String host, String realm)
- 載入頁面完成的事件
public void onPageFinished(WebView view, String url){ }
同樣道理,我們知道一個頁面載入完成,於是我們可以關閉loading條,切換程式動作。 - 載入頁面開始的事件
public void onPageStarted(WebView view, String url,Bitmap favicon) { }
這個事件就是開始載入頁面呼叫的,通常我們可以在這設定一個loading的頁面,告訴使用者程式在等待網路響應。通過這幾個事件,我們可以很輕鬆的控制程式操作,一邊用著瀏覽器顯示內容,一邊監控著使用者操作實現我們需要的各種顯示方式,同時可以防止使用者產生誤操作。 - 如果用
webview
點連結看了很多頁以後,如果不做任何處理,點選系統“Back”鍵,整個瀏覽器會呼叫finish()
而結束自身,如果希望瀏覽的網頁回退而不是退出瀏覽器,需要在當前Activity中處理並消費掉該Back事件。 覆蓋Activity
類的onKeyDown(int keyCoder,KeyEvent event)
方法。
@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
webView.goBack();// 返回前一個頁面
return true;
}
return super.onKeyDown(keyCode, event);
}
二、webview與js的互動(相互呼叫引數、傳值)
前端網頁全部程式碼,文章最後有示例專案完整原始碼
<!DOCTYPE html><html><head> <meta charset="utf-8">
<title>jaydenxiao遇上了webview</title>
<script>
function sayHello() {
alert("我是無參無返回toast")
}
function alertMessage(message) {
alert(message)
}
function toastMessage(message) {
window.control.toastMessage(message)
}
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)
}
function sumToJava2(number1, number2) {
return number1 + number2;
}
</script>
</head><body>
<button type="button" id="button" onclick="toastMessage('js呼叫了android方法')">js訪問android中方法</button>
</body>
</html>
呼叫示例:
js呼叫Java
呼叫格式為window.jsInterfaceName.methodName(parameterValues)
此例中我們使用的是control作為注入介面名稱。
function toastMessage(message) {
window.control.toastMessage(message)
}
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)
}
Java呼叫JS
webView
呼叫js的基本格式為webView.loadUrl(“javascript:methodName(parameterValues)”)
1. android呼叫js無參無返回值函式
final String call = "javascript:sayHello()";
mWebView.post(new Runnable() {
@Override
public void run() {
mWebView.loadUrl(call);
}});
2. android呼叫js有參無返回值函式
final String call = "javascript:alertMessage(\"" + "我是android傳過來的內容,hey man" + "\")";
mWebView.post(new Runnable() {
@Override
public void run() {
mWebView.loadUrl(call);
}});
3. android呼叫js有參有返回值函式(4.4之前)
Android在4.4之前並沒有提供直接呼叫js函式並獲取值的方法,所以在此之前,常用的思路是 java呼叫js方法,js方法執行完畢,再次呼叫java程式碼將值返回。
**(1).android呼叫js程式碼 **
final String call = "javascript:sumToJava(1,2)";
mWebView.post(
new Runnable() {
@Override
public void run() {
mWebView.loadUrl(call);
}});
(2).js函式處理,並將結果通過呼叫android方法返回
網頁端:
function sumToJava(number1, number2){
window.control.onSumResult(number1 + number2)
}
(3).android在回撥方法中獲取js函式返回值
@JavascriptInterfacepublic void onSumResult(int result) {
Toast.makeText(getApplicationContext(), "我是android呼叫js方法(4.4前),入參是1和2,js返回結果是" + result, Toast.LENGTH_LONG).show();
}
4. android
呼叫js有參有返回值函式(4.4以上):
Android 4.4
以上使用evaluateJavascript
即可。這裡展示一個簡單的互動示例 具有返回值的js方法
js程式碼如下:
function sumToJava2(number1, number2) {
return number1 + number2;
}
android程式碼如下:
@TargetApi(Build.VERSION_CODES.KITKAT)
public void Android2JsHaveParmHaveResult2(View view) {
mWebView.evaluateJavascript("sumToJava2(3,4)", new ValueCallback<String>() {
@Override
public void onReceiveValue(String Str) {
Toast.makeText(getApplicationContext(), "我是android呼叫js方法(4.4後),入參是3和4,js返回結果是" + Str, Toast.LENGTH_LONG).show();
}
});}
三、webview遇到的那些坑與解決方法
1. WebView的記憶體洩露。
這個問題,很難清晰描述,你在谷歌裡搜 webview lead memory 能搜到很多結果 甚至還有給谷歌提交的issue 哈哈,我也無法給出一個清晰的答案 在什麼時候 什麼版本那些手機上一定會出現記憶體洩露,
但是根據一些monkey結果來看,有時,webview記憶體洩露的情況還是很嚴重的,尤其是當你載入的頁面比較龐大的時候。解決方案參考下微信和qq的做法,試了一下是目前效果最好的,
就是 當你要用webview的時候,記得最好 另外單獨開一個程式 去使用webview 並且當這個 程式結束時,請手動呼叫System.exit(0)。
這是目前對於webview 記憶體洩露 最好的解決方案。使用此方法 所有因為webview引發的 資源無法釋放等問題 全部可以解決。
2. getSettings().setBuiltInZoomControls(true)
引發的crush
。
這個方法呼叫以後 如果你觸控螢幕 彈出那個提示框還沒消失的時候 你如果activity結束了 就會報錯了。3.0以上 4.4以下很多手機會出現這種情況
所以為了規避他,我們通常是在activity的onDestroy方法裡手動的將webiew設定成 setVisibility(View.GONE)
3.onPageFinished
函式到底有用沒有?
多數開發者都是參考的http://stackoverflow.com/questions/3149216/how-to-listen-for-a-webview-finishing-loading-a-url-in-android 這個上面的高票答案。
但其實根據我自己觀察,這個函式並沒有什麼卵用,有的時候是提前結束,有的時候就遲遲無法結束,你信這個函式 還不如信上帝,甚至於onProgressChanged
這個函式
都比onPageFinished
要準一些。如果你的產品經理堅持你一定要實現這種功能的話,我建議你 提早結束他,否則卡在那使用者遲遲動不了 這種體驗不好。
有空的同學可以跟一下原始碼,onPageFinished
在不同的核心裡 呼叫的時機都不一樣。說實話 我也很醉。。。這個問題 有完美解決方案的 請知會我一下。。。
4.後臺無法釋放js 導致耗電。
這個可能很少有人知道,你如果webview
載入的html裡 有一些js 一直在執行比如動畫之類的東西,如果此刻webview 掛在了後臺
這些資源是不會被釋放,使用者也無法感知,導致一直佔有cpu 耗電特別快,所以大家記住了,如果遇到這種情況 請在onstop
和onresume
裡分別把setJavaScriptEnabled();
給設定成false
和true
。
5.如果實在不想用開額外程式的方式解決webview
記憶體洩露的問題,那麼下面的方法很大程度上可以避免這種情況
public void releaseAllWebViewCallback() {
if (android.os.Build.VERSION.SDK_INT < 16) {
try {
Field field = WebView.class.getDeclaredField("mWebViewCore");
field = field.getType().getDeclaredField("mBrowserFrame");
field = field.getType().getDeclaredField("sConfigCallback");
field.setAccessible(true);
field.set(null, null);
} catch (NoSuchFieldException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
} else {
try {
Field sConfigCallback = Class.forName("android.webkit.BrowserFrame").getDeclaredField("sConfigCallback");
if (sConfigCallback != null) {
sConfigCallback.setAccessible(true);
sConfigCallback.set(null, null);
}
} catch (NoSuchFieldException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
}
}
在webview
的 destroy
方法裡 呼叫這個方法就行了。
相關文章
- 你真的熟悉 npm-scripts 嗎?NPM
- 作為Android開發者,你真的熟悉Activity嗎?Android
- Laravel——你真的熟悉關聯模型麼?Laravel模型
- 你真的理解this嗎
- 你真的理解setState嗎?
- 你真的理解==和===嗎
- 你真的知道JS嗎JS
- hive分割槽和分桶你熟悉嗎?Hive
- ViewStub你真的瞭解嗎View
- 你真的理解 getLocationInWindow 了嗎?
- 你真的知道跨域嗎跨域
- 你真的瞭解mongoose嗎?Go
- TCP|你真的懂 HTTP 嗎?TCPHTTP
- [譯]你真的理解grok嗎
- 你真的懂函式嗎?函式
- 你真的會用 Babel 嗎?Babel
- 你真的瞭解 WebSocket 嗎?Web
- 你真的理解 new 了嗎?
- 你真的懂C++嗎?C++
- JavaScript 你真的瞭解this指向嗎JavaScript
- 你真的會vue-router嗎?Vue
- 你真的瞭解前端路由嗎?前端路由
- 你真的熟練使用webpack嗎?Web
- 你真的理解 flex 佈局嗎?Flex
- 你真的瞭解RPC嗎?RPC
- 你真的需要新款MacBook Pro嗎?Mac
- 你真的瞭解URLEncode嗎?
- 設計模式你真的懂了嗎?設計模式
- 你真的懂Python命名嗎?Python
- 騰訊面試,你真的懂HTTP嗎?面試HTTP
- 你真的喜歡技術嗎?
- 你真的瞭解“密碼”嗎?密碼
- 你的密碼真的安全嗎?密碼
- 你真的瞭解nosql世界嗎?SQL
- 你真的需要定期重灌Windows嗎?Windows
- 三層,你真的理解了嗎?
- 熟悉 Vue ?你能解釋這個死迴圈嗎?Vue
- 你真的知道js的原型鏈嗎??JS原型