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这个位置

Android Studio 中使用 WebView 调用相机相册,需要使用 Android 系统提供的 WebChromeClient 和 WebViewClient 类。具体步骤如下: 1. 首先在 AndroidManifest.xml 文件中添加以下权限: ```xml <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 2. 在 Activity 中创建 WebView,并设置 WebChromeClient 和 WebViewClient: ```java WebView webView = findViewById(R.id.webview); webView.setWebChromeClient(new WebChromeClient() { // 处理打开相机相册的请求 @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { // 创建打开相机相册的 Intent Intent intent = fileChooserParams.createIntent(); try { // 启动 Intent startActivityForResult(intent, REQUEST_CODE_FILE_CHOOSER); } catch (ActivityNotFoundException e) { e.printStackTrace(); return false; } return true; } }); webView.setWebViewClient(new WebViewClient() { // 处理网页加载完成事件 @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); // 在网页中注入 JavaScript 代码,用于调用相机相册 view.loadUrl("javascript: function chooseImage() {window.android.chooseImage();}"); } }); ``` 3. 在 Activity 中重写 onActivityResult 方法,处理选择图片后的结果: ```java @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == REQUEST_CODE_FILE_CHOOSER) { if (resultCode == RESULT_OK && data != null) { // 获取选择的图片 Uri Uri uri = data.getData(); if (uri != null) { // 把 Uri 返回给网页 ValueCallback<Uri[]> filePathCallback = mFilePathCallback; if (filePathCallback != null) { filePathCallback.onReceiveValue(new Uri[]{uri}); mFilePathCallback = null; } } } else { // 如果选择图片失败,也要返回结果给网页 ValueCallback<Uri[]> filePathCallback = mFilePathCallback; if (filePathCallback != null) { filePathCallback.onReceiveValue(null); mFilePathCallback = null; } } } } ``` 4. 在 JavaScript 中调用 window.android.chooseImage() 方法,用于打开相机相册并选择图片: ```javascript function chooseImage() { // 创建 input 元素,用于触发选择图片的操作 var input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; input.onchange = function () { // 把选择图片的结果返回给 Android var uri = input.files; if (uri) { window.android.chooseImage(uri); } else { window.android.chooseImage(null); } }; // 触发点击 input 元素的操作,打开相机相册 input.click(); } ``` 以上就是在 Android Studio 中使用 WebView 调用相机相册的基本步骤。如果您还有其他问题,请随时提出。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值