1、webview 1.0版本 ---最简单的加载网页
mWebView.loadUrl("http://blog.csdn.net/");
这样基本上是可以显示网页的,不过显示的内容可能和你想象的不大一样,因为没有配置各种setting。比如JS的使用,缩放,是否可以访问文件等等。
2、webview 1.1版本 -- 设置各种参数
// HTML5支持的配置
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDefaultTextEncodingName("utf-8");
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setAllowFileAccess(true); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setUserAgentString("userAgent");
// pc网页屏幕自动适配
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
//支持多窗口模式
webSettings.supportMultipleWindows();
//html的支持
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
// 启用数据库
webSettings.setDatabaseEnabled(true);
String dir = context.getApplicationContext()
.getDir("database", Context.MODE_PRIVATE).getPath();
// 设置数据库路径
webSettings.setDatabasePath(dir);
// 使用localStorage则必须打开
webSettings.setDomStorageEnabled(true);
// 启用地理定位
webSettings.setGeolocationEnabled(true);
// 设置定位的数据库路径
webSettings.setGeolocationDatabasePath(dir);
根据我们的需求合理设置WebSettings。这样我们基本上可以打开自己想要的页面,也有了和页面相应的交互了。但是这个可能还满足不了工作上的需求。比如我要在Webview内部跳转,加上进度条,对某些链接进行特殊处理等等,而不是点击调到系统的浏览器里面。那么我们开始下一个版本。
3、webview 1.2版本
我们需要认识一下 两个新朋友
- WebViewClient类:处理各种通知 & 请求事件
-
WebChromeClient :辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
首先来看一下WebViewClient 中的shouldOverrideUrlLoading方法的描述
Give the host application a chance to take over the control when a new
* url is about to be loaded in the current WebView. If WebViewClient is not
* provided, by default WebView will ask Activity Manager to choose the
* proper handler for the url. If WebViewClient is provided, return true
* means the host application handles the url, while return false means the
* current WebView handles the url.
* This method is not called for requests using the POST "method".
中文意思大概是:当一个新的URL加载到这个WebView里的时候,主程序拥有一个接管控制权的机会,如歌这个类没有使用,默认是询问Activity Manager 选择一个恰当的处理程序给这个webview。如果我们使用这个WebViewClient,如果返回true,那么意味着交给主程序去处理这个URL,如果返回false,那么就是当前webview处理这个url。该方法不使用 POST的请求方式。翻译的很烂,英语好的可以替我翻译一下。
当我看到这个的时候也是一知半解,啥意思啊,主程序处理和webview的处理区别在哪里呢?那我们就做个demo来看一下吧。
mWebView.setWebViewClient(new MyWebViewClient());
public class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
boolean isOverride = super.shouldOverrideUrlLoading(view, url);
Log.i("webview","url shouldOverrideUrlLoading:"+isOverride+"");
return isOverride;
}
}
如果我们设置了setWebViewClient,就说明以后的URL处理交给了这个webview,这个也是webviewclient的含义,然后我们来看返回值得区别。通过看源码或者英文描述,默认返回false,就是说明我们不会重写URl的loading,也就是说一切的点击都这在这个webview里面,相当于我们自己的浏览器。
如果返回true就说明你劫持了这个url,你想做什么自己决定,可以劫持这个url我们重新打开一个WebActivity。这样我们就可以对特定的url做处理了。
比如其他的onLoadResource、onReceivedHttpError、onPageStarted、onPageFinished就很简单了,根据名字就知道大概的功能了,就不一一讲解了。大家可以测试一下。
如果我们想要给我们的webview加上进度条又该怎么办呢?那就需要WebChromeClient大兄弟了。
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
}
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
super.onReceivedIcon(view, icon);
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) {
return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
}
这几个是比较常用的方法。
onProgressChanged可以监听到打开页面的进度。
onReceivedTitle可以获取页面的title
onReceivedIcon可以获取页面的Icon
onShowFileChooser webview调用系统的文件系统
重点和难点是 webview如何如何能打开比如图库,摄像头等功能。
因为不同android版本的打开方法不一样所以我们要
//For Android 3.0+
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
}
// For Android < 3.0
public void openFileChooser(ValueCallback uploadMsg) {
openFileChooser(uploadMsg, "");
}
// For Android > 4.1.1
public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
// For Android > 5.0
@Override
public boolean onShowFileChooser(WebView webView, com.tencent.smtt.sdk.ValueCallback valueCallback, FileChooserParams fileChooserParams) {
mOpenFileChooserCallBack.openFileChooserCallBackAndroid5(valueCallback, "");
return true;
}
根据不同api来调用我们的处理函数。
既然js会调用这些方法中的一个,其实也就是分为5.0以上和以下两个回调方法。那么我们也相应的让activity回调webview的这个方法。
public interface OpenFileChooserCallBack {
void openFileChooserCallBack(ValueCallback uploadMsg, String acceptType);
void openFileChooserCallBackAndroid5(ValueCallback uploadMsg, String acceptType);
}
然后就是打开图库或者摄像头
@Override
public void openFileChooserCallBack(ValueCallback uploadMsg, String acceptType) {
mValueCallback = uploadMsg;
if (checkRights()) {
showOptions();
}
}
@Override
public void openFileChooserCallBackAndroid5(ValueCallback uploadMsg, String acceptType) {
mValueCallbackAndroid5 = uploadMsg;
if (checkRights()) {
showOptions();
}
}
//检车读写文件 拍照像个权限
private boolean checkRights() {
if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
//申请WRITE_EXTERNAL_STORAGE权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA},
WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
return false;
}
return true;
}
public void showOptions() {
android.app.AlertDialog.Builder alertDialog = new android.app.AlertDialog.Builder(this);
alertDialog.setOnCancelListener(new ReOnCancelListener());
alertDialog.setTitle("选择图片");
alertDialog.setItems(new String[]{"相机选取", "拍照", "取消"}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
mSourceIntent = ImageUtil.choosePicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_PICK_IMAGE);
overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right);
} else if (which == 1) {
mSourceIntent = ImageUtil.takeBigPicture();
startActivityForResult(mSourceIntent, REQUEST_CODE_IMAGE_CAPTURE);
overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right);
} else {
dialog.dismiss();
dialog.cancel();
}
}
}
);
alertDialog.show();
}
那么怎么把图片的信息交给js呢?
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i("webview", "onActivityResult");
if (resultCode != Activity.RESULT_OK) {
return;
}
switch (requestCode) {
case REQUEST_CODE_IMAGE_CAPTURE:
case REQUEST_CODE_PICK_IMAGE: {
try {
if (mValueCallback == null && mValueCallbackAndroid5 == null) {
return;
}
String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);
if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
Log.i("webview", "sourcePath empty or not exists.");
break;
}
Uri uri = Uri.fromFile(new File(sourcePath));
if (mValueCallback != null) {
mValueCallback.onReceiveValue(uri);
Log.i("webview", " mValueCallback.onReceiveValue(uri)"+uri);
}
if (mValueCallbackAndroid5 != null) {
mValueCallbackAndroid5.onReceiveValue(new Uri[]{uri});
Log.i("webview", " mValueCallbackAndroid5.onReceiveValue(uri)"+uri);
}
//通知更新图库
if (requestCode == REQUEST_CODE_IMAGE_CAPTURE) {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
}
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
我们回调方法里面ValueCallback
对于交互http://blog.csdn.net/carson_ho/article/details/52693322大神写的很好,可以参考这个。