WebView一直是安卓的一个大坑,新版本经常会废弃旧版本的api,导致在使用WevView的时候经常会遇到各种各样的问题,在此整理下WebView的用法及一些坑。
WebView(网络视图)能加载显示网页,可以将其视为一个浏览器。它使用了WebKit渲染引擎加载显示网页。iOS的UIWebView也同样使用的是WebKit内核,不知道为何渲染速度比Android快很多,坑也比Android少。
本章主要包含WebView的简单使用;WebView常用的三个类WebSettings,WebViewClient,WebChromeClient;进度条;在当前WebView中打开新连接,不跳转到系统浏览器;back键返回访问历史;js与原生互调;加载web url,插入本地js。
(1)在布局里声明WebView。
"@+id/mWebView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
(2)使用loadUrl方法加载网页。
mWebView = (WebView) findViewById(R.id.mWebView);
mWebView.loadUrl("http://wujinkui.com/");
1、WebSettings 关于WebView的一些设置,比如缓存,js等
2、WebViewClient 主要帮助WebView处理各种通知、请求事件等
3、WebChromeClient 主要辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等
获取WebSettings:WebSettings settings = mWebView.getSettings();
不是说所有的方法都列出来了,只是一些会用到的,下同
//下面三个最常用,基本都需要设置
setCacheMode 设置缓存的模式 eg: settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
setJavaSciptEnabled 设置是否支持Javascript eg: settings.setJavaScriptEnabled(true);
setDefaultTextEncodingName 设置在解码时使用的默认编码 eg: settings.setDefaultTextEncodingName(“utf-8”);
setAllowFileAccess 启用或禁止WebView访问文件数据
setBlockNetworkImage 是否显示网络图像
setBuiltInZoomControls 设置是否支持缩放
setDefaultFontSize 设置默认的字体大小
setFixedFontFamily 设置固定使用的字体
setLayoutAlgorithm 设置布局方式
setLightTouchEnabled 设置用鼠标激活被选项
setSupportZoom 设置是否支持变焦
设置WebViewClient:mWebView.setWebViewClient(new WebViewClient());
onPageStarted 网页开始加载
onReceivedError 报告错误信息
onLoadResource 加载指定地址提供的资源
shouldOverrideUrlLoading 控制新的连接在当前WebView中打开
onPageFinished 网页加载完毕,此方法并没有方法名表现的那么美好,调用时机很不确定。如需监听网页加载完成可以使用onProgressChanged,当int progress返回100时表示网页加载完毕。
doUpdate VisitedHistory 更新历史记录
onFormResubmission 应用程序重新请求网页数据
onScaleChanged WebView发生改变
onProgressChanged 加载进度条改变
onJsPrompt 用在解决4.2以下addJavascriptInterface漏洞问题
onCloseWindow 关闭WebView
onCreateWindow 创建WebView
onJsAlert 处理Javascript中的Alert对话框
onJsConfirm处理Javascript中的Confirm对话框
onJsPrompt处理Javascript中的Prompt对话框
onReceivedlcon 网页图标更改
onReceivedTitle 网页Title更改
onRequestFocus WebView显示焦点
onConsoleMessage 在Logcat中输出javascript的日志信息
在WebChromeClient里有onProgressChanged方法,利用此方法可以实现进度条。
(1)布局
"match_parent"
android:layout_height="match_parent">
"@+id/mWebView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
"@+id/mProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_gravity="center_vertical"
android:max="100"
android:progressDrawable="@drawable/progress_bar_web_view" />
(2)重写onProgressChanged方法
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress == 100) {
// 网页加载完成
mProgressBar.setVisibility(View.GONE);
} else {
// 加载中
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setProgress(newProgress);
}
}
});
重写WebViewClient的shouldOverrideUrlLoading方法
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if(你想在当前页面打开新连接){
view.loadUrl(url);
}else if(在一个新的activity中打开新连接){
Intent intent = new Intent(mContext, NewWebViewActivity.class);
intent.putputExtra("URL", url);
startActivity(intent);
}
return true;
}
});
在Android N中 shouldOverrideUrlLoading(WebView view, String url)被废弃,改为shouldOverrideUrlLoading(WebView view, WebResourceRequest request),我们可以通过request.getUrl()来获取url。
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
mWebView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
// 返回键退回
mWebView.goBack();
return true;
} else
return false;
}
});
准备工作,创建一个test.html文件,在此html中创建一个js方法alertMsg,作用为将java里传来的message弹出。
"-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
"Content-Type" content="text/xhtml; charset=utf-8"/>
"title">原生与js互调
HTML page load success!
布局文件里写一个Button,点击此Butiton,调用js方法。
findViewById(R.id.btn_call_js_method).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//调用alertMsg方法,并传递参数"来自原生的字符串"。
mWebView.loadUrl("javascript:alertMsg('" + "来自原生的字符串" + "')");
}
});
点击后页面显示对话框,内容为“来自原生的字符串”。
//stub、nativeMethod可自定义,但在java代码里和html代码里必须一致。
mWebView.addJavascriptInterface(new JSCallback(), "stub"); //stub为window.stub.nativeMethod中的stub,为自定义.
public class JSCallback {
//nativeMethod为window.stub.nativeMethod中的nativeMethod
@JavascriptInterface
public void nativeMethod(String data) {
Toast.makeText(NormalActivity.this, data, Toast.LENGTH_SHORT).show();
}
}
在assets文件夹新建一个alert.js。只有一个方法,接受一个mseesage,并将message弹出。
function aliert(message) {
alert(message)
}
在onPageFinished方法回调的时候,将此js插入到WebView中。此处有坑,尝试了网上的各种方法,均不能成功,最后在stackoverflow上找到方法。
wvContent.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
injectScriptFile(view, "alert.js");
}
//ref http://stackoverflow.com/questions/21552912/android-web-view-inject-local-javascript-file-to-remote-webpage
private void injectScriptFile(WebView view, String scriptFile) {
InputStream input;
try {
input = getAssets().open(scriptFile);
byte[] buffer = new byte[input.available()];
input.read(buffer);
input.close();
String encoded = Base64.encodeToString(buffer, Base64.NO_WRAP);
view.loadUrl("javascript:(function() {" +
"var parent = document.getElementsByTagName('head').item(0);" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
// Tell the browser to BASE64-decode the string into your script !!!
"script.innerHTML = window.atob('" + encoded + "');" +
"parent.appendChild(script)" +
"})()");
} catch (IOException e) {
e.printStackTrace();
}
}
});
接下来就和用原生调用js一样了。