android好用的webview,Android WebView的基本使用与注意点

在Android开发中,WebView的使用频率越来越高,这里跟大家分享下WebView使用中的一些技巧或者注意点

11月21日更新:

修复Android 6.0网页title获取的bug,具体见-2.网页title的获取

11月4日更新:

新增-9.WebView视频全屏播放

1.WebView顶部展示加载进度

自定义控件,继承WebView

public class ErmWebView extends WebView {

private ProgressBar progressbar;

public ErmWebView(Context context, AttributeSet attrs) {

super(context, attrs);

progressbar = new ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal);

progressbar.setProgressDrawable(context.getResources().getDra(R.drawable.style_progressbar_web));//设置样式

progressbar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 5, 0, 0));

addView(progressbar);

setWebChromeClient(new WebChromeClient());

}

public class WebChromeClient extends android.webkit.WebChromeClient {

@Override

public void onProgressChanged(WebView view, int newProgress) {//进度

if (newProgress == 100) {

progressbar.setVisibility(GONE);

} else {

if (progressbar.getVisibility() == GONE)

progressbar.setVisibility(VISIBLE);

progressbar.setProgress(newProgress);

}

super.onProgressChanged(view, newProgress);

}

}

2.网页title的获取

需要在WebChromeClient的onReceivedTitle()中获取,其他api获取不可靠

webview控件在Android6.0上有一个bug,那就是onReceivedTitle()会调用两次,一次为网页的url,一次为网页真正的title,故这里需要做一个过滤

mWebview.setWebChromeClient(new WebChromeClient(){

@Override

public void onReceivedTitle(WebView view, String title) {

super.onReceivedTitle(view, title);

//由于webview在title在6.0上会调用两次,故这里过滤掉title为url的那次

if (!getUrl().contains(title)) mTitleBar.setTitle(title);//设置title

}

});

3.本地图片(文件)选择

web页面中经常需要用户选取手机中的图片(文件)上传,这种默认的js调用,在iOS和PC端是OK的,但是Android端需要处理,否则不会做任何操作

private ValueCallback mUploadMessage;//回调图片选择,4.4以下

private ValueCallback mUploadCallbackAboveL;//回调图片选择,5.0以上

mWebview.setWebChromeClient(new WebChromeClient(){

//由于是隐藏API,故没有@Override注解

// For Android 3.0+单参数

public void openFileChooser(ValueCallback uploadMsg) {

mUploadMessage = uploadMsg;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType("image/*");

if (getContext() instanceof Activity) {

((Activity) getContext()).startActivityForResult(Intent.createChooser(i, "File Chooser"), FILE_SELECT_CODE);

}

}

// For Android 3.0+多参数

public void openFileChooser(ValueCallback uploadMsg, String acceptType) {

mUploadMessage = uploadMsg;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType("*/*");

if (getContext() instanceof Activity) {

((Activity) getContext()).startActivityForResult(Intent.createChooser(i, "File Browser"), FILE_SELECT_CODE);

}

}

// For Android 4.1

public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {

mUploadMessage = uploadMsg;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType("image/*");

if (getContext() instanceof Activity) {

((Activity) getContext()).startActivityForResult(Intent.createChooser(i, "File Chooser"), FILE_SELECT_CODE);

}

}

// For Android 5.0+

public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {

mUploadCallbackAboveL = filePathCallback;

Intent i = new Intent(Intent.ACTION_GET_CONTENT);

i.addCategory(Intent.CATEGORY_OPENABLE);

i.setType("*/*");

if (getContext() instanceof Activity) {

((Activity) getContext()).startActivityForResult(Intent.createChooser(i, "File Browser"), FILE_SELECT_CODE);

}

return true;

}

}

//将选择结果回调给网页

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (resultCode != Activity.RESULT_OK) {

if (Build.VERSION.SDK_INT >= 21) //5.0以上版本处理

mWebview.getUploadCallbackAboveL().onReceiveValue(null);//取消选择必须回调null,否则web处于阻塞状态,无法继续操作

else

mWebview.getUploadMessage().onReceiveValue(null);

return;

}

switch (requestCode) {

case FILE_SELECT_CODE: {

if (Build.VERSION.SDK_INT >= 21) {//5.0以上版本处理

Uri uri = data.getData();

Uri[] uris = new Uri[]{uri};

mWebview.getUploadCallbackAboveL().onReceiveValue(uris);//回调给js

} else {//4.4以下处理

Uri uri = data.getData();

Logger.i(uri.toString());

mWebview.getUploadMessage().onReceiveValue(uri);

}

}

break;

}

}

以上代码在大部分手机测试通过,但不排除个别机型存在bug的可能

4.宽度自适应

如果网页比较宽,webView就可以左右滑动,用户一屏看不到所有的内容,体验会比较差,我们可以设置页面自适应

WebSettings settings = getSettings();

settings.setJavaScriptEnabled(true);//开启js

settings.setUseWideViewPort(true);//宽度自适应

settings.setLoadWithOverviewMode(true);

settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);

html中的图片需要自适应,否则可能会出现图片特别宽,导致整个页面无法自适应

5.自定义网页加载出错页面

对于客户端来说,加载出错包括 网络出错+网页Load出错.默认的出错页面比较丑,并且会直接显示URL,导致我们的url暴露.

mWebview.setWebViewClient(new WebViewClient() {

@SuppressWarnings("deprecation")

@Override

public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {//低版本

mWebview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);//去除默认的404页面

mEmpty.showErrorType("网页加载出错,请点击重试");

}

@TargetApi(android.os.Build.VERSION_CODES.M)//编译版本>23

@Override

public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {

onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());

}

});

多次测试之后,上面这样写才能捕捉到所有加载出错的回调,并且在大部分机型及API版本测试通过.

6.返回键处理

用户希望能够返回到上一个网页,而不是直接退出当前webActivity

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

mLeftTv.setVisibility(View.VISIBLE);

if (keyCode == KeyEvent.KEYCODE_BACK && mWebview.canGoBack()) {

mWebview.goBack();

return true;

}

return super.onKeyDown(keyCode, event);

}

7.退出WebView

WebView的底层调用WebKit内核,加载也会另开线程,所以当WebView所在的Activity退出时,WebView内部的组建和线程可能并没有销毁,导致持续占用资源,甚至视频或者音频还在播放

@Override

protected void onPause() {

super.onPause();

if (mWebview != null) mWebview.onPause();//退出关闭webview

}

@Override

protected void onDestroy() {

super.onDestroy();

if (mWebview != null) mWebview.destroy();//退出关闭webview

}

以上代码在大部分手机上含视频播放的web页面测试通过,视频及视频声音不会再播放.但音频web页面退出未测试

8.与JS代码互相调用

有时候JS与原生互相调用各自的方法

mWebview.addJavascriptInterface(new InfoJs(), "infojs");//增加js交互的方法

public class InfoJs {

@JavascriptInterface

public void showToast(String s) {

ToastUtils.showToast("展示toast " + s);

}

}

JS调原生也可以用URL重定向来调,这样iOS比较好实现.

9.WebView视频全屏播放

webview虽然默认支持全屏播放的事件,但是在大部分手机上都是无法全屏的,要么点击全屏是空白,要么没有任何反应,好在WebView有提供全屏及取消全屏的回调事件,所以如果需要支持WebView的全屏播放,就需要处理一下:

1.布局文件中增加一个与WebView同等级的FrameLayout,用于装载全屏的Video控件

android:id="@+id/webView"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

android:id="@+id/video"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

2.处理全屏及取消全屏事件:

private class CustomWebViewChromeClient extends WebChromeClient{

@Override

public void onShowCustomView(View view, CustomViewCallback callback) {

fullScreen();

mWebview.setVisibility(View.GONE);

mVideo.setVisibility(View.VISIBLE);

mVideo.addView(view);

mCallBack=callback;

mWebTitle.setVisibility(View.GONE);//如果有titleBar,一并隐藏

super.onShowCustomView(view, callback);

}

@Override

public void onHideCustomView() {

fullScreen();

if (mCallBack!=null){

mCallBack.onCustomViewHidden();

}

mWebview.setVisibility(View.VISIBLE);

mVideo.removeAllViews();

mVideo.setVisibility(View.GONE);

mWebTitle.setVisibility(View.VISIBLE);//如果有titleBar,一并显示出来

super.onHideCustomView();

}

}

private void fullScreen() {//强制切换屏幕方向

if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

} else {

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

}

}

关于作者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值