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