Webview 调用相册相机失败问题 (包含android7.0 适配)

相信大家在网上肯定有很多文章关于webview 调用相册相机失败问题 也有很多坑 所以我就不一一类举了,小楼也是踩了很多坑 ,总结了很多才告知给各位,希望大家少踩坑,这里包括对android 7.0 的适配 关于Android6.0动态权限管理适配我就没有去写出来了 这个很简单. 可以参考鸿洋大神写的android 6.0动态权限申请博客,非常详细。

webview 调用系统相册相机 相信大家知道要重写webcromeclient 方法,至于为什么可以自行度娘,相信会有更完善的解释,webcromeclient 主要是帮助webview 处理各种通知和请求事件的方法。

好了不多说 

大家肯定知道在android7.0 之后文件存储的位置不再是以往那种很容易就能拿到,google 加强了这方面的安全机制,所以可以借助一个fileProvider类 ,我们可以用这个进行一种特殊的内容传递提供取到系统的某些文件。

fileprovider 为android 四大组件之一,相信懂得人可以自行跳过 不懂的小白 还是老样子 度娘教你.(本人初涉1年多了也才刚懂这个,抽象)


贴代码

如果你要做7.0适配的话,要使用fileprovider 组件,这个必须在清单文件进行注册的,首先要在你的项目res文件目录下添加一个xml文件夹,然后创建一个文件file-paths,如图

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <!--填写你要所要申请访问的目录地址,name最好是你的目录名,path是你要申请的目录-->
    <external-path name="camera_photos" path="."  />
    <external-path name="cache" path="Android/data/com.example.app2/cache" />
    <external-path name="images" path="Pictures/" />
    <external-path name="dcim" path="DCIM/" />
</paths>

再在清单文件中添加

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.app2.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>

注意 android:authorites = ""; 这里填你自己项目的包名.fileprovider

包名 清单文件里就有,以前我还看到有小白手打包名的

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.app2">

package 后面就是你自己项目的包名

这样fileprovider 就准备好了 ,可以在项目中快乐的使用了


下面贴主要代码

private Uri imageUri;

//自定义 WebChromeClient 辅助WebView处理图片上传操作【<input type=file> 文件上传标签】
public class MyChromeWebClient extends WebChromeClient {
    // For Android 3.0-
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        Log.d(TAG, "openFileChoose(ValueCallback<Uri> uploadMsg)");
        mUploadMessage = uploadMsg;
        take();


    }

    // For Android 3.0+
    public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
        Log.d(TAG, "openFileChoose( ValueCallback uploadMsg, String acceptType )");
        mUploadMessage = uploadMsg;
        take();

    }

    //For Android 4.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        Log.d(TAG, "openFileChoose(ValueCallback<Uri> uploadMsg, String acceptType, String capture)");
        mUploadMessage = uploadMsg;

        take();

    }

    // For Android 5.0+
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        Log.d(TAG, "onShowFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)");
        mUploadCallbackAboveL = filePathCallback;

        take();

        return true;
    }
}

private void take() {
    File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");        // Create the storage directory if it does not exist
    if (!imageStorageDir.exists()) {
        imageStorageDir.mkdirs();
    }
    File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
    if (Build.VERSION.SDK_INT >= 24) {
        imageUri = FileProvider.getUriForFile(AndroidBuildActivity.this, "com.example.app2.fileprovider", file);
    } else {
        imageUri = Uri.fromFile(file);
    }
    final List<Intent> cameraIntents = new ArrayList();
    final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    final PackageManager packageManager = getPackageManager();
    final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
    for (ResolveInfo res : listCam) {
        final String packageName = res.activityInfo.packageName;
        final Intent i = new Intent(captureIntent);
        i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
        i.setPackage(packageName);
        i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        cameraIntents.add(i);

    }
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
    AndroidBuildActivity.this.startActivityForResult(chooserIntent, FILE_CHOOSER_RESULT_CODE);
}

@SuppressWarnings("null")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {
    if (requestCode != FILE_CHOOSER_RESULT_CODE
            || mUploadCallbackAboveL == null) {
        return;
    }
    Uri[] results = null;
    if (resultCode == Activity.RESULT_OK) {
        if (data == null) {

            results = new Uri[]{imageUri};
        } else {
            String dataString = data.getDataString();
            ClipData clipData = data.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 {
        mUploadCallbackAboveL.onReceiveValue(results);
        mUploadCallbackAboveL = null;
        return;

    }
    if (results != null) {
        mUploadCallbackAboveL.onReceiveValue(results);
        mUploadCallbackAboveL = null;
    } else {
        results = new Uri[]{imageUri};
        mUploadCallbackAboveL.onReceiveValue(results);
        mUploadCallbackAboveL = null;
    }
    return;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == FILE_CHOOSER_RESULT_CODE) {
        if (null == mUploadMessage && null == mUploadCallbackAboveL) return;
        Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
        if (mUploadCallbackAboveL != null) {
            onActivityResultAboveL(requestCode, resultCode, data);
        } else if (mUploadMessage != null) {
            if (result != null) {
                String path = getPath(getApplicationContext(),
                        result);
                Uri uri = Uri.fromFile(new File(path));
                mUploadMessage
                        .onReceiveValue(uri);
            } else {
                mUploadMessage.onReceiveValue(imageUri);
            }
            mUploadMessage = null;

        }
    }
}

@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];
            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }                // TODO handle non-primary volumes
        } else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
            return getDataColumn(context, contentUri, null, null);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }
    return null;
}

public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};
    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null) cursor.close();
    }
    return null;
}

public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

这套代码就可以完美解决webview 调用相机相册失败问题 

    File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");        // Create the storage directory if it does not exist
    if (!imageStorageDir.exists()) {
        imageStorageDir.mkdirs();
    }
    File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
    if (Build.VERSION.SDK_INT >= 24) {
        imageUri = FileProvider.getUriForFile(AndroidBuildActivity.this, "com.example.app2.fileprovider", file);
    } else {
        imageUri = Uri.fromFile(file);
    }

这里就是适配android7.0 的判断 ,android7.0 正好对应API=24 

注意当不是7.0的话 还是老样子 从之前的位置获取文件

  imageUri = FileProvider.getUriForFile(AndroidBuildActivity.this, "com.example.app2.fileprovider", file);

这句代码就是使用fileprovier 获取真实路径位置,注意这边的      “com.example.app2.fileprovider”要和你清单文件里面的一模一样 ,要不然还是拿不到的。

在h5页面要有这一行代码

<input type="fileid="cameraInputstyle="display: noneaccept="image/*"/>

如果成功后图片将返回到id= cameraInput这个位置

猜你喜欢

转载自blog.csdn.net/qq_33266474/article/details/80662246