【问题标题】:Cordova Android clicking input type=file brings up system file browser, not camera optionsCordova Android 点击 input type=file 会打开系统文件浏览器,而不是相机选项
【发布时间】:2019-12-26 09:58:49
【问题描述】:

问题

在 Cordova Android 中,当点击 html type="file" 输入时,系统文件选择器会出现,而不是相机选项。

预计会发生什么?

如果我在系统浏览器中执行相同的操作,我会得到预期的对话框:

版本信息

"cordova-android": "^8.0.0",
"cordova-plugin-camera": "^4.1.0"

cordova-cli 9.0.0

完整的test case repo here

这是我的第一个 Android Cordova 应用程序,我是否缺少某个插件?我不记得在任何阶段都被要求获得使用相机的权限,所以我想知道我是否在上面链接的 config.xml 中遗漏了什么?

【问题讨论】:

标签: android cordova cordova-plugin-camera


【解决方案1】:

您需要设置captureaccept 属性,如下所示:

<input type="file" capture="camera" accept="image/*" />

编辑

另外,请确保您的 platforms/android/AndroidManifest.xml 包含以下元素:

<application android:allowBackup="false" android:hardwareAccelerated="true" android:icon="@mipmap/icon" android:label="@string/app_name">
    <provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="android.support.v4.content.FileProvider">
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
    </provider>
    <provider android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
    </provider>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

如果它们不存在,则创建文件 platforms/android/res/xml/file_paths.xml,其中包含:

<!-- file_paths.xml -->
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <cache-path name="photos" path="photos/" />
</paths>

和文件platforms/android/res/xml/camera_provider_paths.xml:

<!-- camera_provider_paths.xml -->
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

如果这似乎仍然不起作用,您可能还需要在 platforms/android/CordovaLib/src/org/apache/cordova/engine 目录中添加/修改 SystemWebChromeClient.java 文件以包含以下内容:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
    // Image from file intent
    boolean multiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE;
    String type = "*/*";
    if (fileChooserParams.getAcceptTypes() != null && fileChooserParams.getAcceptTypes().length > 0) {
        type = fileChooserParams.getAcceptTypes()[0];
    }
    Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT);
    fileIntent.addCategory(Intent.CATEGORY_OPENABLE);
    fileIntent.setTypeAndNormalize(type);
    fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiple);

    // Image from camera intent
    Uri tempUri = null;
    Intent captureIntent = null;
    if (fileChooserParams.isCaptureEnabled()) {
        captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        Context context = parentEngine.getView().getContext();
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) && captureIntent.resolveActivity(context.getPackageManager()) != null) {
            try {
                File tempFile = createTempFile(context);
                Log.d(LOG_TAG, "Temporary photo capture file: " + tempFile);
                tempUri = createUriForFile(context, tempFile);
                Log.d(LOG_TAG, "Temporary photo capture URI: " + tempUri);
                captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempUri);
            } catch (IOException e) {
                Log.e(LOG_TAG, "Unable to create temporary file for photo capture", e);
                captureIntent = null;
            }
        } else {
            Log.w(LOG_TAG, "Device does not support photo capture");
            captureIntent = null;
        }
    }
    final Uri captureUri = tempUri;

    // Chooser intent
    Intent chooserIntent = Intent.createChooser(fileIntent, null);
    if (captureIntent != null) {
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { captureIntent });
    }

    try {
        Log.i(LOG_TAG, "Starting intent for file chooser");
        parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
            @Override
            public void onActivityResult(int requestCode, int resultCode, Intent intent) {
                // Handle result
                Uri[] result = null;
                if (resultCode == Activity.RESULT_OK) {
                    List<Uri> uris = new ArrayList<Uri>();
                    if (intent == null && captureUri != null) { // camera
                        Log.v(LOG_TAG, "Adding camera capture: " + captureUri);
                        uris.add(captureUri);

                    } else if (intent.getClipData() != null) { // multiple files
                        ClipData clipData = intent.getClipData();
                        int count = clipData.getItemCount();
                        for (int i = 0; i < count; i++) {
                            Uri uri = clipData.getItemAt(i).getUri();
                            Log.v(LOG_TAG, "Adding file (multiple): " + uri);
                            if (uri != null) {
                                uris.add(uri);
                            }
                        }

                    } else if (intent.getData() != null) { // single file
                        Log.v(LOG_TAG, "Adding file (single): " + intent.getData());
                        uris.add(intent.getData());
                    }

                    if (!uris.isEmpty()) {
                        Log.d(LOG_TAG, "Receive file chooser URL: " + uris.toString());
                        result = uris.toArray(new Uri[uris.size()]);
                    }
                }
                filePathsCallback.onReceiveValue(result);
            }
        }, chooserIntent, FILECHOOSER_RESULTCODE);
    } catch (ActivityNotFoundException e) {
        Log.w("No activity found to handle file chooser intent.", e);
        filePathsCallback.onReceiveValue(null);
    }
    return true;
}

【讨论】:

  • @Titan 如果这对您有用,请随时将其标记为正确
  • 恐怕不行,我已经尝试了许多接受和捕获的组合,但都没有任何作用。我已经编辑了我的问题,并带有一个指向最小测试用例 repo 的链接。
  • @Titan 更新了我的答案,提供了可能解决您问题的其他建议
  • @Titan 你解决了这个问题吗?
猜你喜欢
  • 1970-01-01
  • 2015-03-12
  • 1970-01-01
  • 2012-10-24
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-04
相关资源
最近更新 更多