详解Android WebView的input上传照片的兼容问题
问题
前几天接到的一个需求,是关于第三方理财产品的H5上传照片问题。
对方说他们的新的需求,需要接入方配合上传资产照片的需求,测试之后发现我们这边的app端,IOS端上传没有问题,而Android端则点击没有任何反应。
对方H5调用的方式是通过
解决问题
因为Android的版本碎片问题,很多版本的WebView都对唤起函数有不同的支持。
我们需要重写WebChromeClient下的openFileChooser()(5.0及以上系统回调onShowFileChooser())。我们通过Intent在openFileChooser()中唤起系统相机和支持Intent的相关app。
在系统相机或者相关app中一顿操作之后,当返回app的时候,我们在onActivityResult()中将选择好的图片通过ValueCallback的onReceiveValue方法返回给WebView。
附上代码:
1、首先是重写各个版本的WebChromeClient的支持
webView.setWebChromeClient(newWebChromeClient(){
//ForAndroid3.0+
publicvoidopenFileChooser(ValueCallbackuploadMsg){
selectImage();
mUM=uploadMsg;
Intenti=newIntent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MyBaseWebViewActivity.this.startActivityForResult(Intent.createChooser(i,"FileChooser"),FCR);
}
//ForAndroid3.0+,abovemethodnotsupportedinsomeandroid3+versions,insuchcaseweusethis
publicvoidopenFileChooser(ValueCallbackuploadMsg,StringacceptType){
selectImage();
mUM=uploadMsg;
Intenti=newIntent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MyBaseWebViewActivity.this.startActivityForResult(
Intent.createChooser(i,"FileBrowser"),
FCR);
}
//ForAndroid4.1+
publicvoidopenFileChooser(ValueCallbackuploadMsg,StringacceptType,Stringcapture){
selectImage();
mUM=uploadMsg;
Intenti=newIntent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MyBaseWebViewActivity.this.startActivityForResult(Intent.createChooser(i,"FileChooser"),MyBaseWebViewActivity.FCR);
}
//ForAndroid5.0+
publicbooleanonShowFileChooser(
WebViewwebView,ValueCallbackfilePathCallback,
WebChromeClient.FileChooserParamsfileChooserParams){
selectImage();
if(mUMA!=null){
mUMA.onReceiveValue(null);
}
mUMA=filePathCallback;
IntenttakePictureIntent=newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
if(takePictureIntent.resolveActivity(MyBaseWebViewActivity.this.getPackageManager())!=null){
FilephotoFile=null;
try{
photoFile=createImageFile();
takePictureIntent.putExtra("PhotoPath",mCM);
}catch(IOExceptionex){
Log.e(TAG,"Imagefilecreationfailed",ex);
}
if(photoFile!=null){
mCM="file:"+photoFile.getAbsolutePath();
filePath=photoFile.getAbsolutePath();
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(photoFile));
}else{
takePictureIntent=null;
}
}
IntentcontentSelectionIntent=newIntent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("*/*");
Intent[]intentArray;
if(takePictureIntent!=null){
intentArray=newIntent[]{takePictureIntent};
}else{
intentArray=newIntent[0];
}
IntentchooserIntent=newIntent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT,contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE,"ImageChooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,intentArray);
startActivityForResult(chooserIntent,FCR);
returntrue;
}
});
2、选完照片之后
/**
*打开图库,同时处理图片
*/
privatevoidselectImage(){
compressPath=Environment.getExternalStorageDirectory().getPath()+"/QWB/temp";
Filefile=newFile(compressPath);
if(!file.exists()){
file.mkdirs();
}
compressPath=compressPath+File.separator+"compress.png";
Fileimage=newFile(compressPath);
if(image.exists()){
image.delete();
}
}
//Createanimagefile
privateFilecreateImageFile()throwsIOException{
@SuppressLint("SimpleDateFormat")StringtimeStamp=DateUtils.nowTimeDetail();
StringimageFileName="img_"+timeStamp+"_";
FilestorageDir=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
returnFile.createTempFile(imageFileName,".jpg",storageDir);
}
privateStringmCM;
privateStringfilePath="";
privateValueCallbackmUM;
privateValueCallbackmUMA;
privatefinalstaticintFCR=1;
StringcompressPath="";
@Override
protectedvoidonActivityResult(intrequestCode,intresultCode,Intentintent){
super.onActivityResult(requestCode,resultCode,intent);
if(Build.VERSION.SDK_INT>=21){
Uri[]results=null;
//Checkifresponseispositive
if(resultCode==Activity.RESULT_OK){
if(requestCode==FCR){
if(null==mUMA){
return;
}
if(intent==null){
//CapturePhotoifnoimageavailable
if(mCM!=null){
//results=newUri[]{Uri.parse(mCM)};
results=newUri[]{afterChosePic(filePath,compressPath)};
}
}else{
StringdataString=intent.getDataString();
if(dataString!=null){
results=newUri[]{Uri.parse(dataString)};
LogUtil.d("tag",intent.toString());
//StringrealFilePath=getRealFilePath(Uri.parse(dataString));
//results=newUri[]{afterChosePic(realFilePath,compressPath)};
}
}
}
}
mUMA.onReceiveValue(results);
mUMA=null;
}else{
if(requestCode==FCR){
if(null==mUM)return;
Uriresult=intent==null||resultCode!=RESULT_OK?null:intent.getData();
mUM.onReceiveValue(result);
mUM=null;
}
}
}
/**
*选择照片后结束
*/
privateUriafterChosePic(StringoldPath,StringnewPath){
FilenewFile;
try{
newFile=FileUtils.compressFile(oldPath,newPath);
}catch(Exceptione){
e.printStackTrace();
newFile=null;
}
returnUri.fromFile(newFile);
}
3、工具类
publicclassFileUtils{
/**
*把图片压缩到200K
*
*@paramoldpath
*压缩前的图片路径
*@paramnewPath
*压缩后的图片路径
*@return
*/
publicstaticFilecompressFile(Stringoldpath,StringnewPath){
BitmapcompressBitmap=FileUtils.decodeFile(oldpath);
BitmapnewBitmap=ratingImage(oldpath,compressBitmap);
ByteArrayOutputStreamos=newByteArrayOutputStream();
newBitmap.compress(Bitmap.CompressFormat.PNG,100,os);
byte[]bytes=os.toByteArray();
Filefile=null;
try{
file=FileUtils.getFileFromBytes(bytes,newPath);
}catch(Exceptione){
e.printStackTrace();
}finally{
if(newBitmap!=null){
if(!newBitmap.isRecycled()){
newBitmap.recycle();
}
newBitmap=null;
}
if(compressBitmap!=null){
if(!compressBitmap.isRecycled()){
compressBitmap.recycle();
}
compressBitmap=null;
}
}
returnfile;
}
privatestaticBitmapratingImage(StringfilePath,Bitmapbitmap){
intdegree=readPictureDegree(filePath);
returnrotaingImageView(degree,bitmap);
}
/**
*旋转图片
*@paramangle
*@parambitmap
*@returnBitmap
*/
publicstaticBitmaprotaingImageView(intangle,Bitmapbitmap){
//旋转图片动作
Matrixmatrix=newMatrix();;
matrix.postRotate(angle);
System.out.println("angle2="+angle);
//创建新的图片
BitmapresizedBitmap=Bitmap.createBitmap(bitmap,0,0,
bitmap.getWidth(),bitmap.getHeight(),matrix,true);
returnresizedBitmap;
}
/**
*读取图片属性:旋转的角度
*@parampath图片绝对路径
*@returndegree旋转的角度
*/
publicstaticintreadPictureDegree(Stringpath){
intdegree=0;
try{
ExifInterfaceexifInterface=newExifInterface(path);
intorientation=exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION,ExifInterface.ORIENTATION_NORMAL);
switch(orientation){
caseExifInterface.ORIENTATION_ROTATE_90:
degree=90;
break;
caseExifInterface.ORIENTATION_ROTATE_180:
degree=180;
break;
caseExifInterface.ORIENTATION_ROTATE_270:
degree=270;
break;
}
}catch(IOExceptione){
e.printStackTrace();
}
returndegree;
}
/**
*把字节数组保存为一个文件
*
*@paramb
*@paramoutputFile
*@return
*/
publicstaticFilegetFileFromBytes(byte[]b,StringoutputFile){
Fileret=null;
BufferedOutputStreamstream=null;
try{
ret=newFile(outputFile);
FileOutputStreamfstream=newFileOutputStream(ret);
stream=newBufferedOutputStream(fstream);
stream.write(b);
}catch(Exceptione){
//log.error("helper:getfilefrombyteprocesserror!");
e.printStackTrace();
}finally{
if(stream!=null){
try{
stream.close();
}catch(IOExceptione){
//log.error("helper:getfilefrombyteprocesserror!");
e.printStackTrace();
}
}
}
returnret;
}
/**
*图片压缩
*
*@paramfPath
*@return
*/
publicstaticBitmapdecodeFile(StringfPath){
BitmapFactory.Optionsopts=newBitmapFactory.Options();
opts.inJustDecodeBounds=true;
opts.inDither=false;//DisableDitheringmode
opts.inPurgeable=true;//Telltogcthatwhetheritneedsfree
opts.inInputShareable=true;//Whichkindofreferencewillbeusedto
BitmapFactory.decodeFile(fPath,opts);
finalintREQUIRED_SIZE=400;
intscale=1;
if(opts.outHeight>REQUIRED_SIZE||opts.outWidth>REQUIRED_SIZE){
finalintheightRatio=Math.round((float)opts.outHeight
/(float)REQUIRED_SIZE);
finalintwidthRatio=Math.round((float)opts.outWidth
/(float)REQUIRED_SIZE);
scale=heightRatio
4、需要注意的问题
在打release包的时候,因为混淆的问题,点击又会没有反应,这是因为openFileChooser()是系统api,所以需要在混淆是不混淆该方法。
-keepclassmembersclass*extendsandroid.webkit.WebChromeClient{
publicvoidopenFileChooser(...);
}
当点击拍照之后,如果相机是横屏拍照的话,当拍照结束之后跳回app的时候,会导致app端当前的webView页面销毁并重新打开,需要在androidManifest.xml中当前Activity添加:
android:configChanges="orientation|keyboardHidden|screenSize"
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。