webview 版本差异:
在Android 4.4以下(不包含4.4)系统WebView底层实现是采用WebKit内核,而在Android 4.4及其以上采用了chromium作为系统WebView的底层内核支持。在API上5.0以上和4.4以下也有一些差别,下面会介绍我在开发中遇到的一些问题和解决方法。
基本配置:
settings.setJavaScriptEnabled(true); //允许执行js脚本
settings.setSupportZoom(true);
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true); //和上面两个设置webview适配
settings.setDomStorageEnabled(true); //允许dom存储
settings.setCacheMode(WebSettings.LOAD_NO_CACHE); //无缓存
settings.setAllowFileAccess(true);// 允许访问文件数据
settings.setBlockNetworkImage(false);//同步请求图片
关于webSettings详细api可参考:http://blog.csdn.net/a2241076850/article/details/52983939
在开发中遇到的问题:
1、webview不能播放音乐:
在android4.2(17)后需要默认需要用户的手势进行媒体播放:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
contentWebView.getSettings().setMediaPlaybackRequiresUserGesture(false);
}
2、webview 切换后台依然执行,需要添加webview生命周期
webview.pause
webview.resume
webview.stop
webview.destroy
3、webview不能加载图片:
设置 settings.setBlockNetworkImage(false);后还不能显示,则是因为5.0后webview不知混合模式,
也就是不允许webview在https的请求中请求http,或者反过来
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
4、 内容错乱问题:
可能是因为开启了硬加速,需要把其关闭,或者因为修改了系统字体的大小,需要给webview设置固定的字体大小settings.setTextZoom(100), 或者没有做适配
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
,又或者h5同学没做适配,可放到系统浏览器打开测试,如果正常则是自身配置问题
5、webview js 无法打开窗口:
settings.setJavaScriptCanOpenWindowsAutomatically(true);
6、webview设置背景透明:
mWebView.setBackgroundColor(Color.parseColor("#00000000"));
7、横竖屏滚动条:
mWebView.setVerticalScrollBarEnabled(true);
mWebView.setHorizontalScrollBarEnabled(true);
8、webview 无法上传:
chromeClient=new WebViewUpload(null,mActivity);
webView.setWebChromeClient(chromeClient);
选择图片会回调到Activity的
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
WebViewUpload.uploadImgFromSysPhotos(resultCode,data);//上传图片
super.onActivityResult(requestCode, resultCode, data);
}
WebViewUpload代码:
package com.cs.csgamesdk.utils;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.ProgressBar;
import java.io.File;
/**
* Created by Administrator on 2018/1/22.
*/
public class WebViewUpload extends WebChromeClient{
private ValueCallback<Uri> mUploadMessage;//5.0以下
private ValueCallback<Uri[]> mValueCallback;//5.0以上返回对象不同
private Activity mActivity;
public WebViewUpload(ProgressBar pbar,Activity activity){
mActivity=activity;
}
public void openFileChooser(ValueCallback uploadMsg) {
mUploadMessage=uploadMsg;
mValueCallback=null;
goToPhotos();
}
//3.0--版本
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
L.e("tag","openFileChooser3.0--版本");
mUploadMessage=uploadMsg;
mValueCallback=null;
goToPhotos();
}
// For Android 4.1
public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
L.e("tag","openFileChooser4.1");
mUploadMessage=uploadMsg;
mValueCallback=null;
goToPhotos();
}
public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) {
L.e("tag","openFileChoose5.0");
mValueCallback=filePathCallback;//5.0
mUploadMessage=null;
goToPhotos();
return true;
}
public void goToPhotos() {
Intent intent;
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
mActivity.startActivityForResult(Intent.createChooser(intent, "选择操作"), REQUEST_CODE);
}
public void uploadImgFromSysPhotos(int resultCode, Intent intent) {
if (mUploadMessage != null) {//5.0以下
Uri result = intent == null || resultCode != -1 ? null
: intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage=null;
} else if (mValueCallback != null) {//5.0+
Uri[] uris = new Uri[1];
uris[0] = intent == null || resultCode != -1 ? null
: intent.getData();
if (uris[0]!=null){
mValueCallback.onReceiveValue(uris);
}
mValueCallback = null;
}
}
}
9、webview 图片下载:
webview中长按图片会返回一个url:
webView.setOnLongClickListener(new ImageDowload(mActivity,webView));
ImageDowload代码:
package com.cs.csgamesdk.imageloader;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.view.View;
import android.webkit.WebView;
import android.widget.Toast;
import com.cs.csgamesdk.utils.L;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2018/1/26.
*/
public class ImageDowload implements View.OnLongClickListener {
private Activity mActivity;
private WebView mWebview;
private String SAVE_PIC_PATH;
private String SAVE_REAL_PATH;
public ImageDowload(Activity activity, WebView webView){
mActivity=activity;
mWebview=webView;
}
@Override
public boolean onLongClick(View v) {
WebView.HitTestResult htr = mWebview.getHitTestResult();//获取所点击的内容
if (htr.getType() == WebView.HitTestResult.IMAGE_TYPE) {//判断被点击的类型为图片
if(htr.getExtra().contains("cs_wechat_qrcode.jpg")){
//下载保存二位码
getBitmap(htr.getExtra());
}
}
return false;
}
private void getBitmap(final String sUrl){
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
URL url = new URL(sUrl);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
if(conn.getResponseCode() == 200){
InputStream inputStream = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
if(bitmap==null){
L.e("tag","请求失败");
}else{
saveForCamera(bitmap,getFileName()+".png", "");
}
}else{
L.e("tag","请求失败");
}
} catch (Exception e) {
e.printStackTrace();
L.e("tag",e.toString());
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(mActivity,"保存成功", Toast.LENGTH_SHORT).show();
}
}.execute();
}
private String getFileName() {
String fileNameRandom = getCharacterAndNumber();
return fileNameRandom;
}
private String getCharacterAndNumber() {
String rel = "";
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
Date curDate = new Date(System.currentTimeMillis());
rel = formatter.format(curDate);
return rel;
}
private void saveForCamera(Bitmap paramBitmap, String fileName, String path){
SAVE_PIC_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
SAVE_REAL_PATH = SAVE_PIC_PATH + "/DCIM/Camera/";
path = SAVE_REAL_PATH + path;
File localFile = new File(path);
if (!localFile.exists()) {
localFile.mkdirs();
}
File file = new File(path, fileName);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
BufferedOutputStream bf = new BufferedOutputStream(new FileOutputStream(file));
paramBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bf);
bf.flush();
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
Intent localIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
localIntent.setData(Uri.fromFile(file));
mActivity.sendBroadcast(localIntent);
L.e("tag","保存成功");
}
}
10、无法请求https 、在webview中跳转url 、获取url的cookie
webView.setWebViewClient(webViewClient);
webViewClient代码:
private WebViewClient webViewClient=new WebViewClient() {
//在webview中跳转url
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//处理微信和支付宝支付
if(url.startsWith("alipays:") || url.startsWith("alipay")||url.startsWith("qq")|| url.startsWith("mqqapi:")||url.startsWith("weixin://wap/pay?")) {
try {
mActivity.startActivity(new Intent("android.intent.action.VIEW", Uri.parse(url)));
} catch (Exception e) {
}
return true;
}
view.loadUrl(url);
return true;
}
//重写此方法可以让webview处理https请求。
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();
}
//在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次。
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, final String url) {
//获取cookie
CookieManager cookieManager = CookieManager.getInstance();
String CookieStr = cookieManager.getCookie(url);
if (CookieStr != null) {
String[] cookies=CookieStr.split(";");
for (int i=0;i<cookies.length;i++){
Log.e("tag","cookie:"+cookies[i].trim());
}
}
super.onPageFinished(view, url);
}
};
11、使用本地资源,如果希望不请求网络获取资源,可把资源存放在assets中,通过重写
WebViewClient 的shouldInterceptRequest方法(该方法会在天天模拟器上存在问题,具体解释在代码中,手机不会)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
WebResourceResponse response = null;
response = super.shouldInterceptRequest(view, url);
return getWebResourceResponse(response,url);
}
如果获取到本地资源将不会请求网络,直接使用本地资源,getWebResourceResponse方法代码:
private WebResourceResponse getWebResourceResponse(WebResourceResponse response,String url){
//根据实际情况截取文件名,从而获取存放在assets的资源
L.d("tag","URL:"+url);
int index= url.indexOf("/",7);
String str=url.substring(index+1);
if(url.contains(".png")){
try {
response = new WebResourceResponse("image/png","UTF-8",context.getAssets().open(str));
} catch (IOException e) {
e.printStackTrace();
}
}else if(url.contains(".jpg")){
try {
response = new WebResourceResponse("image/jpeg","UTF-8",context.getAssets().open(str));
} catch (IOException e) {
e.printStackTrace();
}
}else if(url.contains(".gif")){
try {
response = new WebResourceResponse("image/gif","UTF-8",context.getAssets().open(str));
} catch (IOException e) {
e.printStackTrace();
}
}else if(url.contains(".js")){
try {
response = new WebResourceResponse("application/x-javascript","UTF-8",context.getAssets().open(str));
} catch (IOException e) {
e.printStackTrace();
}
}else if(url.contains(".css")){
try {
response = new WebResourceResponse("text/css","UTF-8",context.getAssets().open(str));
} catch (IOException e) {
e.printStackTrace();
}
} else{
try {
//天天模拟器出现闪退,由于context.getAssets().open(str)方法中的str有字符大小限制
response = new WebResourceResponse(null,"UTF-8",context.getAssets().open(str));
} catch (IOException e) {
e.printStackTrace();
}
}
return response;
}
12、webview设置cookie
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeAllCookie();
cookieManager.removeSessionCookie();//移除
cookieManager.setCookie(url,"test=123456");
cookieManager.setCookie(url,"token=sfsfsf123");//有几个添加几个
// L.e("tag","cookie:"+cookieManager.getCookie(url));//查看cookie
CookieSyncManager.getInstance().sync();