首先我先描述一下我遇到的问题,在我把h5的项目嵌入安卓原生的外壳时,由于h5的
代码涉及到他们自己本地的存储,所以在我点击h5页面上的按钮后,页面没有任何响应,
在排查一顿之后,发像是因为没有兼容他们的localstorage,要实现兼容其实很简单
//兼容h5的localStorage
settings.setDomStorageEnabled(true);
settings.setAppCacheMaxSize(1024*1024*8);
String path = getApplicationContext().getCacheDir().getAbsolutePath();//把内部私有缓存目录'/data/data/包名/cache/'作为webview的appcache的缓存路径
settings.setAppCachePath(path);
settings.setAllowFileAccess(true);
settings.setAppCacheEnabled(true);
还有一个就是h5的项目中利用inputfile标签实现了调用系统相机以及图库的功能,而我们
安卓如果不做任何处理,原生的webview其实不能支持这样的功能,要支持这样的功能,主要
需要重写WebChromeClient,自己实现几个方法:
// For Android 3.0+
@SuppressWarnings({"rawtypes"})
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
vCbFileChooser = uploadMsg;
/*Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MainActivity.this.startActivityForResult(
Intent.createChooser(i,"文件选择"),
FILECHOOSER_RESULTCODE
);*/
selPic();
}
// For Android 3.0+
@SuppressWarnings({"unused", "rawtypes"})
public void openFileChooser(ValueCallback uploadMsg) {
openFileChooser(uploadMsg, "");
}
//For Android 4.1
@SuppressWarnings({"unused", "rawtypes"})
public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
// For Lollipop 5.0+ Devices
@SuppressWarnings("unchecked")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(
WebView mWebView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams
) {
if (vCbFileChooser != null) {
vCbFileChooser.onReceiveValue(null);
vCbFileChooser = null;
}
vCbFileChooser = filePathCallback;
selPic();
return true;
}
完整代码如下,我也尽量做了一些优化,提高加载h5时的渲染速度
public class MainActivity extends AppCompatActivity {
WebView wv_webview;
ImageView iv_start;
//String url="http://wxtest.51hbx.com/wap/FQcarInfo.html";//服务器
//String url="http://10.1.100.121/wap/FQcarInfo.html";//庆庆
String url="http://test.51hbx.com:2043/wap/FQcarInfo.html";//小飞
//String url="http://test.51hbx.com:2043/wap/adultrisks.html?productId=7";//小飞
WebSettings settings;
AlertDialog loadingDialog;
boolean hasTouch=true;
boolean hasRequest=false;
boolean firstTime=true;//记录是否是首次加载,避免显示空白页
String urlPrevious="";//记录上一次的url
String urlPreviousStart="";//记录上一次的url,
//保存状态
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
wv_webview.saveState(outState);
}
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wv_webview= (WebView) findViewById(R.id.wv_webview);
iv_start= (ImageView) findViewById(R.id.iv_start);
settings = wv_webview.getSettings();
//js交互
wv_webview.setVerticalScrollbarOverlay(true);
//设置webview支持js
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setAllowContentAccess(true);
settings.setDefaultTextEncodingName("UTF -8");//设置默认为utf-8
initCacheStrategies(settings);//配置缓存
initMyConfiguration(settings);//初始化部分配置,优化
if (null!=savedInstanceState)
{
wv_webview.restoreState(savedInstanceState);
}
else
{
// contain_wv.loadData(list.get(0).getContent(), "text/html;charset=UTF-8", null);
wv_webview.loadUrl(url);
}
wv_webview.addJavascriptInterface(new JsInterface(this),"AndroidWebView");
//添加客户端支持
wv_webview.setWebChromeClient(new MyWebChromeClient());
wv_webview.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.equals(urlPrevious))
{
urlPrevious=url;
return false;
}
else
{
urlPrevious=url;
view.loadUrl(url);
Log.e("==shouldOverride=","======="+url);
return super.shouldOverrideUrlLoading(view, url);
//return false;
}
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.e("===0====","===onPageStarted==="+url+":"+GapsTimes.effectiveTime(400));
if (!firstTime)
{
/*if (!url.equals(urlPreviousStart))
{*/
LoadingUtils.showDialogMethod(MainActivity.this);
/*}*/
}
else
{
firstTime=false;
}
urlPreviousStart=url;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (!wv_webview.getSettings().getLoadsImagesAutomatically()){
wv_webview.getSettings().setLoadsImagesAutomatically(true);
}
LoadingUtils.displayLoadingDialog();
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
LoadingUtils.displayLoadingDialog();
}
//加载页面资源会调用,每加载一次就会调用一次
@Override
public void onLoadResource(WebView view, String url) {
super.onLoadResource(view, url);
Log.e("===1====","===onLoadResource===");
}
});
}
private void initMyConfiguration(WebSettings settings) {
//解决webview加载网页不显示图片
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP)
{
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
if (Build.VERSION.SDK_INT>=19)
{
wv_webview.getSettings().setLoadsImagesAutomatically(true);
}
else
{
wv_webview.getSettings().setLoadsImagesAutomatically(false);
}
//提高渲染的优先级
settings.setRenderPriority(WebSettings.RenderPriority.HIGH);
settings.setBlockNetworkImage(true);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
//配置webview的缓存
private void initCacheStrategies(WebSettings settings) {
//配置浏览器的缓存
/*settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//配置h5的缓存
settings.setAppCacheEnabled(true);
String path = getApplicationContext().getCacheDir().getPath();//把内部私有缓存目录'/data/data/包名/cache/'作为webview的appcache的缓存路径
settings.setAppCachePath(path);
settings.setAppCacheMaxSize(5*1024*1024);*/
//另一种组合
//设置缓存模式
/*settings.setCacheMode(WebSettings.LOAD_DEFAULT);
//开启 DOM storage API 功能
settings.setDomStorageEnabled(true);*/
//兼容h5的localStorage
settings.setDomStorageEnabled(true);
settings.setAppCacheMaxSize(1024*1024*8);
String path = getApplicationContext().getCacheDir().getAbsolutePath();//把内部私有缓存目录'/data/data/包名/cache/'作为webview的appcache的缓存路径
settings.setAppCachePath(path);
settings.setAllowFileAccess(true);
settings.setAppCacheEnabled(true);
}
private class JsInterface {
private Context mContext;
public JsInterface(Context context) {
this.mContext = context;
}
//在js中调用window.AndroidWebView.showInfoFromJs(name),便会触发此方法。
@JavascriptInterface
public void showInfoFromJs(String name) {
Toast.makeText(mContext, name, Toast.LENGTH_SHORT).show();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode==KeyEvent.KEYCODE_BACK)&&wv_webview.canGoBack())
{
wv_webview.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDestroy() {
super.onDestroy();
wv_webview.stopLoading();
wv_webview.destroy();
wv_webview=null;
}
private final static int FILECHOOSER_RESULTCODE = 2;
private final static int TAKEPHOTO_RESULTCODE = 1;
private ValueCallback<Uri[]> vCbFileChooser;
String pathTakePhoto="";
Uri uriTakePhoto;
public class MyWebChromeClient extends WebChromeClient {
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
Log.e("==onProgressChanged==", "======" + newProgress);
if (newProgress >= 100) {
iv_start.setVisibility(View.GONE);
//解除数据阻止
settings.setBlockNetworkImage(false);
}
}
// For Android 3.0+
@SuppressWarnings({"rawtypes"})
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
vCbFileChooser = uploadMsg;
/*Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MainActivity.this.startActivityForResult(
Intent.createChooser(i,"文件选择"),
FILECHOOSER_RESULTCODE
);*/
selPic();
}
// For Android 3.0+
@SuppressWarnings({"unused", "rawtypes"})
public void openFileChooser(ValueCallback uploadMsg) {
openFileChooser(uploadMsg, "");
}
//For Android 4.1
@SuppressWarnings({"unused", "rawtypes"})
public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg, acceptType);
}
// For Lollipop 5.0+ Devices
@SuppressWarnings("unchecked")
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(
WebView mWebView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams
) {
if (vCbFileChooser != null) {
vCbFileChooser.onReceiveValue(null);
vCbFileChooser = null;
}
vCbFileChooser = filePathCallback;
selPic();
return true;
}
}
@SuppressWarnings("unused")
private void selPic() {
if (!checkSDcard()){return;}
String[] selectPicTypeStr = { "拍照","选择照片" };
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setItems(
selectPicTypeStr,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0://拍照
chkPrivBeforeTakePhoto();
break;
case 1://选择图片文件
choosePicFile();
break;
default:
break;
}
}
}
).setOnCancelListener(
new DialogInterface.OnCancelListener() {
@SuppressWarnings("unchecked")
@Override
public void onCancel(DialogInterface dialog) {
if (null != vCbFileChooser) {
vCbFileChooser.onReceiveValue(null);
vCbFileChooser = null;
}
}
}
).show();
}
private static final int PERMISSIONS_REQUEST_CODE_TAKE_PHOTO = 1;
@SuppressWarnings("unchecked")
private void chkPrivBeforeTakePhoto() {
if(
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
) {
if (null != vCbFileChooser) {
vCbFileChooser.onReceiveValue(null);
vCbFileChooser = null;
}
new AlertDialog
.Builder(this)
.setTitle("提示信息")
.setMessage("该功能需要您接受应用对一些关键权限(拍照)的申请,如之前拒绝过,可到手机系统的应用管理授权设置界面再次设置。")
.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, PERMISSIONS_REQUEST_CODE_TAKE_PHOTO);
}
})
.show();
} else {
chooseTakePhoto();
}
}
private void chooseTakePhoto() {
pathTakePhoto = Environment.getExternalStorageDirectory().getPath()
+ "/mbossclient/camera/temp/"
+ (System.currentTimeMillis() + ".jpg");
File vFile = new File(pathTakePhoto);
if (!vFile.exists()) {//必须确保文件夹路径存在,否则拍照后无法完成回调
File vDirPath = vFile.getParentFile();
vDirPath.mkdirs();
} else {
if (vFile.exists()) {
vFile.delete();
}
}
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
uriTakePhoto = Uri.fromFile(vFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uriTakePhoto);
startActivityForResult(intent, TAKEPHOTO_RESULTCODE);
}
private boolean checkSDcard() {
boolean flag = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
if(!flag){Toast.makeText(this, "请插入手机存储卡再使用本功能", Toast.LENGTH_SHORT).show();}
return flag;
}
/**
* 选择文件
*/
private void choosePicFile(){
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MainActivity.this.startActivityForResult(
Intent.createChooser(i,"文件选择"),
FILECHOOSER_RESULTCODE
);
}
@SuppressLint("NewApi")
@SuppressWarnings("unchecked")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {//从文件选择器选择照片
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if(null == vCbFileChooser) {return;}
vCbFileChooser.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
vCbFileChooser = null;
} else {
if(null == vCbFileChooser) {return;}
Uri result = (intent == null || resultCode != RESULT_OK)? null:intent.getData();
vCbFileChooser.onReceiveValue(new Uri[]{result});
vCbFileChooser = null;
}
} else if(requestCode == TAKEPHOTO_RESULTCODE){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if(null == vCbFileChooser) {return;}
if(null == uriTakePhoto) {
vCbFileChooser.onReceiveValue(null);
vCbFileChooser = null;
return;
}
addImageGallery(pathTakePhoto);
Uri[] uris = new Uri[1];
uris[0] = uriTakePhoto;
vCbFileChooser.onReceiveValue(uris);
vCbFileChooser = null;
uriTakePhoto = null;
pathTakePhoto = null;
} else {
if(null == vCbFileChooser) {return;}
if(null == uriTakePhoto) {
vCbFileChooser.onReceiveValue(null);
vCbFileChooser = null;
return;
}
addImageGallery(pathTakePhoto);
vCbFileChooser.onReceiveValue(new Uri[]{uriTakePhoto});
vCbFileChooser = null;
uriTakePhoto = null;
pathTakePhoto = null;
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
/**
* 解决拍照后在相册中找不到的问题
*/
private void addImageGallery(String path) {
if (null == path || "".equals(path)) {
return;
}
File file = new File(pathTakePhoto);
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, file.getAbsolutePath());
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
}