Android WebView 的使用
WebView 是 Android 中一个非常实用的组件,它内置了WebKit引擎,WebKit是一个开源的浏览器引擎,Chrome浏览器也是基于它,所以我们可以把WebView当做一个轻量级的浏览器使用。 WebView 可以使得网页轻松的内嵌到 app 里,还可以直接跟 js 相互调用。
1、添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
2、WebSettings 对访问页面进行设置。
WebView mWebView = new WebView(this);
WebSettings webSettings = mWebView .getSettings(); // 支持获取手势焦点,输入用户名、密码或其他
mWebView.requestFocusFromTouch();
webSettings.setJavaScriptEnabled(true); // 支持js
webSettings.setUseWideViewPort(true); // 将图片调整到适合 webview 的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
webSettings.setSupportZoom(true); // 支持缩放,默认为 true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); // 设置内置的缩放控件。
webSettings.setDisplayZoomControls(false); // 隐藏原生的缩放控件
webSettings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); // 支持内容重新布局
webSettings.supportMultipleWindows(); // 多窗口
webSettings.setAllowFileAccess(true); // 设置可以访问文件
webSettings.setNeedInitialFocus(true); // 当 webview 调用 requestFocus 时为 webview 设置节点
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 支持通过 JS 打开新窗口
webSettings.setLoadsImagesAutomatically(true); // 支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8"); // 设置编码格式
webSettings.setDatabaseEnabled(true); // 设置支持本地存储
String path = getActivity().getApplicationContext().getDir("cache", Context.MODE_PRIVATE).getPath(); // 取得缓存路径
webSettings.setDatabasePath(path); // 设置缓存路径
webSettings.setDomStorageEnabled(true); // 设置支持DomStorage
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); // 设置存储模式
//webSettings。setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK) ;//关闭webview中缓存
webSettings.setAppCacheEnabled(true); // 设置支持缓存
mWebView.requestFocus();
3、页面加载方式
// 加载一个网页:
mWebView.loadUrl("https://www.baidu.com/");
// 加载 apk assets目录文件中的一个 html 页面
mWebView.loadUrl("file:///android_asset/test.html");
// 加载手机本地的一个 html 页面的方法:
mWebView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
4、WebView 的两个重要方法 WebViewClient 和 WebChromeClient
WebViewClient 就是帮助 WebView 处理各种通知、请求事件的。
// 打开网页时不调用系统浏览器,而是在本 WebView 中显示:
mWebView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
// 将上面定义的 webviewclinet 设置给 webview
mWebView.setWebViewClient(webViewClient);
下面介绍 WebView 的一些事件:
WebViewClient mWebViewClient = new WebViewClient()
{
//在网页上的所有加载都经过这个方法,这个函数我们可以做很多操作。
//比如获取url,查看url.contains(“add”),进行添加操作
shouldOverrideUrlLoading(WebView view, String url);
//重写此方法才能够处理在浏览器中的按键事件。
shouldOverrideKeyEvent(WebView view, KeyEvent event);
//这个事件就是开始载入页面调用的,我们可以设定一个loading的页面,告诉用户程序在等待网络响应。
onPageStarted(WebView view, String url, Bitmap favicon) ;
//在页面加载结束时调用。同样道理,我们可以关闭loading 条,切换程序动作。
onPageFinished(WebView view, String url);
// 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
onLoadResource(WebView view, String url) ;
// (报告错误信息)
onReceivedError(WebView view, int errorCode, String description, String failingUrl);
//(更新历史记录)
doUpdateVisitedHistory(WebView view, String url, boolean isReload);
//(应用程序重新请求网页数据)
onFormResubmission(WebView view, Message dontResend, Message resend);
//(获取返回信息授权请求)
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,String realm);
//重写此方法可以让webview处理https请求。
onReceivedSslError(WebView view, SslErrorHandler handler, SslError error);
// (WebView发生改变时调用)
onScaleChanged(WebView view, float oldScale, float newScale);
//(Key事件未被加载时调用)
onUnhandledKeyEvent(WebView view, KeyEvent event);
}
WebChromeClient 是辅助 WebView 处理 Javascript 的对话框,网站图标,网站 title,加载进度等。
WebChromeClient mWebChromeClient = new WebChromeClient() {
// 获得网页的加载进度,显示在右上角的 TextView 控件中
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress < 100) {
String progress = newProgress + "%";
} else {
}
}
// 获取 Web 页中的 title 用来设置自己界面中的 title
// 当加载出错的时候,比如无网络,这时 onReceiveTitle 中获取的标题为 找不到该网页,
// 因此建议当触发 onReceiveError 时,不要使用获取到的 title
@Override
public void onReceivedTitle(WebView view, String title) {
MainActivity.this.setTitle(title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
//
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
//
return true;
}
@Override
public void onCloseWindow(WebView window) {
}
// 处理 alert 弹出框,html 弹框的一种方式
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
//
return true;
}
// 处理 confirm 弹出框
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult
result) {
//
return true;
}
// 处理 prompt 弹出框
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
//
return true;
}
};
// 同样,将上面定义的 WebChromeClient 设置给 WebView :
webView.setWebChromeClient(mWebChromeClient);
WebChromeClient 调用 Android 相机和相册
private int CAMERA_CODE_REQUEST = 0;
private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadCallbackAboveL;
public static final int FILECHOOSER_RESULTCODE = 5173;
public static final int FILECHOOSER_RESULTCODE_FOR_ANDROID_5 = 5174;
/**
* 申请拍照权限
*/
public static final int REQUEST_ACCESS_COARSE_CAMERA = 00002;
/**
* 拍照裁剪
*/
private Uri imageUri;
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onReceivedTitle(WebView view, String webtitle) {
super.onReceivedTitle(view, webtitle);
}
@Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
// For Android < 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
this.openFileChooser(uploadMsg, "*/*");
}
// For Android >= 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg,String acceptType) {
Log.e("acceptType", acceptType);
this.openFileChooser(uploadMsg, acceptType, null);
}
// For Android >= 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
Log.e("acceptType", acceptType + "capture" + capture);
CAMERA_CODE_REQUEST = FILECHOOSER_RESULTCODE;
mUploadMessage = uploadMsg;
openCamera();
}
@Override
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView mWebView,ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
CAMERA_CODE_REQUEST = FILECHOOSER_RESULTCODE_FOR_ANDROID_5;
mUploadCallbackAboveL = filePathCallback;
openCamera();
return true;
}
});
/**
* 这里是权限处理,大家可以使用各自的方法进行处理
*/
public void openCamera() {
//
PermissionHelper.with(this)
.requestCode(REQUEST_ACCESS_COARSE_CAMERA)
.requestPermission(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.request();
}
/**
* 拍照权限申请成功BLUETOOTH
*/
@PermissionSucceed(requestCode = REQUEST_ACCESS_COARSE_CAMERA)
public void onSuccess() {
showCameraAction();
}
/**
* 拍照权限申请失败
*/
@PermissionFail(requestCode = REQUEST_ACCESS_COARSE_CAMERA)
private void onFail() {
UIHelper.getSystemHintToast(this, "您拒绝了拍照权限,将不能正常拍照");
}
/**
* 调用摄像头和相册添加图片
*/
protected void showCameraAction() {
File file = FileUtils.getNewFile();
imageUri = getUriForFile(this, file);
final List<Intent> cameraIntents = new ArrayList<>();
final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
final List<ResolveInfo> listCam = getPackageManager().queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
final String packageName = res.activityInfo.packageName;
final Intent i = new Intent(captureIntent);
i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
i.setPackage(packageName);
i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
cameraIntents.add(i);
}
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
Intent chooserIntent = Intent.createChooser(i, "图片上传");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
startActivityForResult(chooserIntent, CAMERA_CODE_REQUEST);
}
protected Uri getUriForFile(Context context, File file) {
if (context == null || file == null) {
throw new NullPointerException();
}
Uri uri;
if (Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(context.getApplicationContext(), "com.realname.selfhelpdeclara.fileprovider", file);
} else {
uri = Uri.fromFile(file);
}
return uri;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage) {
return;
}
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
if (result != null) {
mUploadMessage.onReceiveValue(result);
} else {
if (resultCode == RESULT_OK) {
mUploadMessage.onReceiveValue(imageUri);
} else {
mUploadMessage.onReceiveValue(null);
}
}
mUploadMessage = null;
} else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) {
if (null == mUploadCallbackAboveL) {
return;
}
Uri result = (data == null || resultCode != RESULT_OK) ? null : data.getData();
if (result != null) {
mUploadCallbackAboveL.onReceiveValue(new Uri[]{result});
} else {
if (resultCode == RESULT_OK) {
Uri[] results = new Uri[]{imageUri};
mUploadCallbackAboveL.onReceiveValue(results);
} else {
mUploadCallbackAboveL.onReceiveValue(null);
}
}
mUploadCallbackAboveL = null;
}
}
5、调用 JS 代码
WebSettings webSettings = mWebView .getSettings();
webSettings.setJavaScriptEnabled(true); // 这里必须设置
mWebView.addJavascriptInterface(new InsertObj(), "jsObj");
以下方法是 Android 和 JS 的交互
public class InsertObj extends Object {
private static Activity mActivity;
private static WebView mWebView;
public InsertObj(Activity activity, WebView webView) {
mActivity = activity;
mWebView = webView;
}
// 给 html 提供的方法,js 中可以通过:var str = window.jsObj.HtmlcallJava(); 获取到
@JavascriptInterface
public String HtmlcallJava() {
return "Html call Java";
}
// 给 html 提供的有参函数 : window.jsObj.HtmlcallJava2("IT-homer blog");
@JavascriptInterface
public String HtmlcallJava2(final String result) {
return "Html call Java : " + result;
}
// Html 给我们提供的函数
@JavascriptInterface
public static void JavacallHtml() {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
// 这里是调用方法
mWebView.loadUrl("javascript: showFromHtml()");
Toast.makeText(mActivity, "clickBtn", Toast.LENGTH_SHORT).show();
}
});
}
// Html 给我们提供的有参函数
@JavascriptInterface
public static void JavacallHtml2(final String param) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mWebView.loadUrl("javascript: showFromHtml2('"+param+"')");
Toast.makeText(mActivity, "clickBtn2", Toast.LENGTH_SHORT).show();
}
});
}
}
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>无标题 1</title>
<script type="text/javascript">
function HtmlcallJava(){
var str = window.jsObj.HtmlcallJava();
alert(str);
}
function HtmlcallJava2(){
var str = window.jsObj.HtmlcallJava2("HTML");
alert(str);
}
function showFromHtml()
{
alert("我是js方法,我被Android后台调用");
}
function showFromHtml2(result)
{
alert("我是js方法,我被Android后台调用 "+result);
}
</script>
</head>
<body>
<button onclick="HtmlcallJava()">HtmlcallJava</button>
<button onclick="HtmlcallJava2()">HtmlcallJava2</button>
<input type="file" accept="image/*" id="capture" capture="camera">
</body>
</html>
8、设置 Cookie
public void setCookies(String cookie) {
if (!TextUtils.isEmpty(cookie)) {
String[] cookieArray = cookie.split(";");// 多个Cookie是使用分号分隔的
for (int i = 0; i < cookieArray.length; i++) {
int position = cookieArray[i].indexOf("=");// 在Cookie中键值使用等号分隔
if (position != -1) {
String cookieName = cookieArray[i].substring(0, position);// 获取键
String cookieValue = cookieArray[i].substring(position + 1);// 获取值
String value = cookieName + "=" + cookieValue;// 键值对拼接成 value
Log.i("cookie", value);
CookieManager.getInstance().setCookie(getDomain(url), value);// 设置 Cookie
}
}
}
}
/**
* 获取URL的域名
*/
private String getDomain(String url) {
url = url.replace("http://", "").replace("https://", "");
if (url.contains("/")) {
url = url.substring(0, url.indexOf('/'));
}
return url;
}
7、WebView 返回键,返回上一页而不是退出浏览器
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
8、销毁 WebView
@Override
protected void onDestroy(){
if (mWebview != null) {
mWebview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebview.clearHistory();
((ViewGroup) mWebview.getParent()).removeView(mWebview);
mWebview.destroy();
mWebview = null;
}
return super.onDestroy();
}
(完)