Android WebView 拍照和选择图片正确用法
前言:Android 有些项目需要在WebView
上调用手机系统相册来上传图片,开发过程中发现在很多机器上无法正常唤起系统相册来选择图片,要知道WebView 嵌套网页中有js调取拍照和选择图片上传的功能,这个需要在我们的代码中去实现方法。
首先,准备变量和WebView的基础设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private WebView mWebView = null; //5.0以下使用 private ValueCallback mUploadMessage; // 5.0及以上使用 private ValueCallback<Uri[]> mUploadMessageAboveL; //图片 private final static int FILE_CHOOSER_RESULT_CODE = 135; //拍照图片路径 private String mCameraFielPath; mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setDomStorageEnabled(true); mWebView.getSettings().setAllowFileAccess(true); |
其次,WebView的WebChromeClient()重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | mWebView.setWebChromeClient(new WebChromeClient() { @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); } @Override public void onProgressChanged(WebView view, int progress) { super.onProgressChanged(view, progress); } // For Android < 3.0 public void openFileChooser(ValueCallback<Uri> valueCallback) { mUploadMessage = valueCallback; openImageChooser(); } // For Android >= 3.0 public void openFileChooser(ValueCallback valueCallback, String acceptType) { mUploadMessage = valueCallback; openImageChooser(); } //For Android >= 4.1 public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) { mUploadMessage = valueCallback; openImageChooser(); } // For Android >= 5.0 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { mUploadMessageAboveL = filePathCallback; openImageChooser(); return true; } }); |
再者,实现openImageChooser()代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | private void openImageChooser() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if(takePictureIntent.resolveActivity(this.getPackageManager()) != null){ File photoFile = null; try{ photoFile = FileUtil.createTempImageFile(); }catch(Exception ex){ MLog.e(TAG, "Image file creation failed", ex); } if(photoFile != null){ mCameraFielPath = photoFile.getAbsolutePath(); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); }else{ takePictureIntent = null; } } Intent imageIntent = new Intent(Intent.ACTION_GET_CONTENT); imageIntent.addCategory(Intent.CATEGORY_OPENABLE); imageIntent.setType("image/*"); Intent[] intentArray; if(takePictureIntent != null){ intentArray = new Intent[]{takePictureIntent}; }else{ intentArray = new Intent[0]; } Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, imageIntent); chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); startActivityForResult(chooserIntent, FILE_CHOOSER_RESULT_CODE); } |
对了,上面有个创建临时图片文件的代码实现如下:
1 2 3 4 5 6 7 | public static File createImageFile() throws IOException{ @SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "img_" + timeStamp + "_"; File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return File.createTempFile(imageFileName, ".jpg", storageDir); } |
接着,需要重写Activity的onActivityResult()这个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (null == mUploadMessage && null == mUploadMessageAboveL) return; if (resultCode != RESULT_OK) { if (mUploadMessageAboveL != null) { mUploadMessageAboveL.onReceiveValue(null); mUploadMessageAboveL = null; } if (mUploadMessage != null) { mUploadMessage.onReceiveValue(null); mUploadMessage = null; } return; } Uri result = null; if (requestCode == FILE_CHOOSER_RESULT_CODE) { if (null != data && null != data.getData()) { result = data.getData(); } if (result == null && FileUtil.isExist(mCameraFielPath)) { result = Uri.fromFile(new File(mCameraFielPath)); } if (mUploadMessageAboveL != null) { onActivityResultAboveL(data, result); } else if (mUploadMessage != null) { mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void onActivityResultAboveL(Intent intent, Uri uri) { Uri[] results = null; if (intent != null) { String dataString = intent.getDataString(); ClipData clipData = intent.getClipData(); if (clipData != null) { results = new Uri[clipData.getItemCount()]; for (int i = 0; i < clipData.getItemCount(); i++) { ClipData.Item item = clipData.getItemAt(i); results[i] = item.getUri(); } } if (dataString != null) results = new Uri[]{Uri.parse(dataString)}; }else { if (uri != null){ results = new Uri[]{uri}; } } mUploadMessageAboveL.onReceiveValue(results); mUploadMessageAboveL = null; } |
OK,到这你就可以试试了,你用写好的WebBrowserActivity装载:https://www.baidu.com/,或者https://www.google.com.hk/,使用搜索框中的图片搜索功能。或者你你自己创建一个html,如下:
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html> <html> <head> <meta name="viewport" content="user-scalable=no"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <input id="input" type="file"/> </body> </html> |
OK!OK!可以了吧,这回可以运行了吧,可以了,run吧。
1 | mWebView.loadUrl("https://www.baidu.com/"); |
但是,有的人又该发问了,Release下怎么不可以使用呀?莫慌,这个时候你就要想到DR定律:只要Debug下正常Release下不正常,那就首先考虑混淆的事。解决版本如下:
1 2 3 4 | -keepclassmembers class * extends android.webkit.WebChromeClient { public void openFileChooser(...); public void onShowFileChooser(...); } |
对了,上面代码里面用到了FileUtil,我也放出来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | public class FileUtil { public static String addSlash(String pPath) { if (!TextUtils.isEmpty(pPath)) { if (!pPath.endsWith(File.separator)) { pPath = pPath + File.separator; } }else { pPath = File.separator; } return pPath; } public static boolean isExist(String pFilePath) { try { File file = new File(pFilePath); return file.exists(); } catch (Exception e) { return false; } } @NonNull public static File createTempImageFile() throws IOException { String imageFileName = "img_" + formatDate(System.currentTimeMillis())+ "_"; File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return File.createTempFile(imageFileName, ".jpg", storageDir); } /** * 格式成 yyyy-MM-dd HH:mm:ss * * @param pLongDate milliseconds * @return */ public static String formatDate(long pLongDate) { String dateFormat = "yyyy-MM-dd HH:mm:ss"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat, Locale.getDefault()); String resultString = ""; try { resultString = simpleDateFormat.format(new Date(pLongDate)); } catch (Exception e) { e.printStackTrace(); } return resultString; } } |
到这里就完满结束了,你还有问题的话。
请QQ我136049925或者加入QQ群:179730949。
发表评论
要发表评论,您必须先登录。