详解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(ValueCallback uploadMsg,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,ValueCallback filePathCallback, 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; privateValueCallback mUMA; 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=heightRatio4、需要注意的问题
在打release包的时候,因为混淆的问题,点击又会没有反应,这是因为openFileChooser()是系统api,所以需要在混淆是不混淆该方法。
-keepclassmembersclass*extendsandroid.webkit.WebChromeClient{ publicvoidopenFileChooser(...); }当点击拍照之后,如果相机是横屏拍照的话,当拍照结束之后跳回app的时候,会导致app端当前的webView页面销毁并重新打开,需要在androidManifest.xml中当前Activity添加:
android:configChanges="orientation|keyboardHidden|screenSize"以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。