现在混合开发越来越火热,WebView的使用也是越来越频繁,今天详细介绍一下webview的常用属性和方法,以及开发时遇到的坑
使用
xml中定义
<WebView
android:id="@+id/main_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layerType="software"
android:fadingEdge="none"
android:fadingEdgeLength="0dp"
android:scrollbars="none"/>
android:layerType="software"
硬件加速 layerType与WebView白屏
android:fadingEdge="none"
设置拉滚动条时 ,边框渐变的放向。none(边框颜色不变),horizontal(水平方向颜色变淡),vertical(垂直方向颜色变淡)。
android:fadingEdgeLength="0dp"
用来设置边框渐变的长度
android:scrollbars="none"
去掉webview的滚动条
加载html的四种方式
- 网络url
webView.loadUrl("https://blog.csdn.net/zyw0101");
(注:如果页面加载后自动跳转默认浏览器,则需要webView.setWebViewClient(new WebViewClient());,下面会详细介绍
) - assets文件下的html
webView.loadUrl("file:///android_asset/my.html");
- sd卡中的html
webView.loadUrl("file:///" + Environment.getExternalStorageDirectory() + "/my.html");
(注:访问本地文件需要设置setAllowFileAccess为true,同时开启读取权限
) - 直接显示html代码
webView.loadDataWithBaseURL(null, "<!DOCTYPE html>\n" + "<html>\n" + "<head>\n" + "\t<title>测试网页</title>\n" + "</head>\n" + "<body>\n" + "<p>直接显示html代码</p>\n" + "</body>\n" + "</html>", "text/html", "utf-8", null);
WebSetting常用设置
WebSettings webSettings = webView.getSettings();
webSettings.setDomStorageEnabled(true);// 开启 DOM storage API 功能
webSettings.setLoadWithOverviewMode(true); // 当页面宽度大于WebView宽度时,缩小使页面宽度等于WebView宽度
webSettings.setUseWideViewPort(true);// 页面通过`<meta name="viewport" ... />`自适应手机屏幕
webSettings.setJavaScriptEnabled(true);// 支持JS
webSettings.setAllowContentAccess(true);// 是否可访问Content Provider的资源,默认值 true
webSettings.setAllowFileAccess(true);// 是否可访问本地文件 如:读取sd卡的html文件
webSettings.setAllowFileAccessFromFileURLs(false);// 是否允许通过file url加载的Javascript读取本地文件,默认值 false
webSettings.setAllowUniversalAccessFromFileURLs(false);// 是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false
webSettings.setSupportZoom(true);// 支持屏幕缩放
webSettings.setBuiltInZoomControls(true);// 支持屏幕缩放
webSettings.setDisplayZoomControls(false);// 显示隐藏缩放按钮
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);// 缓存方式
不常用
// 定位(location)
settings.setGeolocationEnabled(true);
// 是否保存表单数据
settings.setSaveFormData(true);
// 是否当webview调用requestFocus时为页面的某个元素设置焦点,默认值 true
settings.setNeedInitialFocus(true);
// 布局算法
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
// 是否支持多窗口,默认值false
settings.setSupportMultipleWindows(false);
// 是否可用Javascript(window.open)允许弹窗,默认值 false
settings.setJavaScriptCanOpenWindowsAutomatically(false);
// 资源加载
settings.setLoadsImagesAutomatically(true); // 是否自动加载图片
settings.setBlockNetworkImage(false); // 禁止加载网络图片
settings.setBlockNetworkLoads(false); // 禁止加载所有网络资源
// 默认文本编码,默认值 "UTF-8"
settings.setDefaultTextEncodingName("UTF-8");
settings.setDefaultFontSize(16); // 默认文字尺寸,默认值16,取值范围1-72
settings.setDefaultFixedFontSize(16); // 默认等宽字体尺寸,默认值16
settings.setMinimumFontSize(8); // 最小文字尺寸,默认值 8
settings.setMinimumLogicalFontSize(8); // 最小文字逻辑尺寸,默认值 8
settings.setTextZoom(100); // 文字缩放百分比,默认值 100
// 字体
settings.setStandardFontFamily("sans-serif"); // 标准字体,默认值 "sans-serif"
settings.setSerifFontFamily("serif"); // 衬线字体,默认值 "serif"
settings.setSansSerifFontFamily("sans-serif"); // 无衬线字体,默认值 "sans-serif"
settings.setFixedFontFamily("monospace"); // 等宽字体,默认值 "monospace"
settings.setCursiveFontFamily("cursive"); // 手写体(草书),默认值 "cursive"
settings.setFantasyFontFamily("fantasy"); // 幻想体,默认值 "fantasy"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 用户是否需要通过手势播放媒体(不会自动播放),默认值 true
settings.setMediaPlaybackRequiresUserGesture(true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 5.0以上允许加载http和https混合的页面(5.0以下默认允许,5.0+默认禁止)
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 是否在离开屏幕时光栅化(会增加内存消耗),默认值 false
settings.setOffscreenPreRaster(false);
}
if (isNetworkConnected(context)) {
// 根据cache-control决定是否从网络上取数据
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
} else {
// 没网,离线加载,优先加载缓存(即使已经过期)
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
// 提高渲染的优先级
settings.setRenderPriority(WebSettings.RenderPriority.HIGH);
WebView的常用方法
-
WebViewClient
-
主要帮助WebView处理各种通知、请求事件的,有以下常用方法:
- onPageFinished 页面请求完成
- onPageStarted 页面开始加载
- shouldOverrideUrlLoading 拦截url
- onReceivedError 访问错误时回调,例如访问网页时报错404,在这个方法回调的时候可以加载错误页面。
webView.setWebViewClient(new WebViewClient(){
// 拦截url
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
// 拦截页面加载,返回true表示宿主app拦截并处理了该url,否则返回false由当前WebView处理
// 该方法可以防止跳转默认浏览器
return super.shouldOverrideUrlLoading(view, request);
}
// 页面开始加载
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.e(TAG, "onPageStarted");
progressBar.setVisibility(View.VISIBLE);
}
// 页面加载完成
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.e(TAG, "onPageFinished");
progressBar.setVisibility(View.GONE);
}
// 访问错误时回调,例如访问网页时报错404,在这个方法回调的时候可以加载错误页面。
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
Log.e(TAG, "onReceivedError");
}
});
-
WebChromeClient
- 主要辅助WebView处理Javascript的对话框、网站图标、网站title、加载进度等,有以下常用方法。
- onJsAlert webview 不支持js的alert弹窗,需要自己监听然后通过dialog弹窗
- onReceivedTitle 获取网页标题
- onReceivedIcon 获取网页icon
- onProgressChanged 加载进度回调
webView.setWebChromeClient(new WebChromeClient(){
// alert弹窗如果不能弹出 需要创建一个WebChromeClient
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
AlertDialog.Builder localBuilder = new AlertDialog.Builder(webView.getContext());
localBuilder.setMessage(message).setPositiveButton("确定",null);
localBuilder.setCancelable(false);
localBuilder.create().show();
//注意:
//必须要这一句代码:result.confirm()表示:
//处理结果为确定状态同时唤醒WebCore线程
//否则不能继续点击按钮
result.confirm();
return true;
// return super.onJsAlert(view, url, message, result);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
Log.e(TAG, "onReceivedTitle = " + title);
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
progressBar.setProgress(newProgress);
}
});
-
canGoBack和goBack
判断有没有上一页和返回上一页
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// 点击返回按钮
if (keyCode == KeyEvent.KEYCODE_BACK) {
// 判断有没有上一页
if (webView.canGoBack()) {
// 返回webView的上一个页面
webView.goBack();
} else {
finish();
}
}
return super.onKeyDown(keyCode, event);
}
Android和JS相互调用
-
Android调用js方法
js代码
<script type="text/javascript">
function showAlert(){
alert("欢迎调用js方法");
}
function addText(){
var x = document.getElementById("my_text");
x.innerHTML = "调用了js方法addText";
}
</script>
Android代码
webView.loadUrl("javascript:addText()");
其中addText()就是js中定义的方法,当android当前版本大于等于19时,可以使用最新方法调用
webView.evaluateJavascript("javascript:addText()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// 回调
Log.e(TAG, "onReceiveValue = " + value);
}
});
多了一个回调方法
两个方法的区别:通过loadUrl调用没有返回值且会刷新页面,但对版本没有要求,evaluateJavascript效果比较高有返回值且不会刷新页面,但需要4.4及以上才能使用,所以开发时需要配合使用
int version = Build.VERSION.SDK_INT;
if (version < 19) {
webView.loadUrl("javascript:addText()");
} else {
webView.evaluateJavascript("javascript:addText()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
// 回调
Log.e(TAG, "onReceiveValue = " + value);
}
});
}
这里需要注意的是 如果js方法里执行的是alert(),那么需要在android中设置
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);// 设置允许JS弹窗
-
js调用Android方法
Android代码
1.直接定义方法
webView.addJavascriptInterface(this, "android");// js调用android方法
@JavascriptInterface
public void showAndroid(){
tv.setText("js调用了android方法");
}
2.新建类
webView.addJavascriptInterface(new Myjs(), "test");// js调用android方法
public class Myjs{
@JavascriptInterface
public void showToast(){
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText("js调用了android方法");
}
});
}
}
js代码
<input type="button" name="btn" value="js调用android" onclick="android.showAndroid()">
FAQ
-
为什么android调用js方法后,html不能弹窗
答:是否使用了alert(),如果是,是否设置了
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webView.setWebChromeClient(new WebChromeClient());
-
加载本地html文件不成功
答:是否设置了webSettings.setAllowFileAccess(true);
,是否开启了本地访问本地文件的读写权限,6.0以后需要动态申请 -
加载在线网页或者点击网页跳转时打开了android默认浏览器
答:是否设置了webView.setWebViewClient(new WebViewClient());
-
android调用js时多个参数如何传递
答:webView.loadUrl("javascript:addText(" + "'" + param1+ "'" + "," + "'" + param2 + "'" + ")");
需要将参数放到单引号中
参考
Android:你要的WebView与 JS 交互方式 都在这里了
Android WebView基本使用
Android:你不知道的 WebView 使用漏洞