Android R-ACTION_IMAGE_CAPTURE的startActivity显示不同的选项可供选择

问题描述

我的应用定位为支持30(R)。 我注意到,调用此应用时缺少某些应用程序可供选择:

baseActivity.startActivity(Intent(MediaStore.ACTION_IMAGE_CAPTURE))

定位到29时,此代码显示了拍照前要选择的几个应用程序:

  • 本机摄像头应用
  • B612相机应用程序

定位到30后,将直接打开相机应用程序(无法选择)。

我查看了android 11的更改,但没有发现任何特殊之处。 我这边需要改变吗?

感谢阅读/帮助

解决方法

一旦targetSdkVersion达到30,ACTION_IMAGE_CAPTURE will only display pre-installed camera apps,not user-installed apps

,

我找到了解决方法;
TL; DR:自己阅读应用程序的AndroidManifest.xml来查找相机应用程序。
注意: 这可能会导致您的应用被商店禁止。

步骤1: 使用PackageManager,创建所有已授予“摄像机许可”权限的应用程序的列表。

public static List<PackageInfo> getPackageInfosWithCameraPermission(Context context){
    //Get a list of compatible apps
    PackageManager pm = context.getPackageManager();
    List<PackageInfo> installedPackages = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
    ArrayList<PackageInfo> cameraPermissionPackages = new ArrayList<PackageInfo>();
    //filter out only camera apps
    for (PackageInfo somePackage : installedPackages) {
        //- A camera app should have the Camera permission
        boolean hasCameraPermission = false;
        if (somePackage.requestedPermissions == null || somePackage.requestedPermissions.length == 0) {
            continue;
        }
        for (String requestPermission : somePackage.requestedPermissions) {
            if (requestPermission.equals(Manifest.permission.CAMERA)) {
                //Ask for Camera permission,now see if it's granted.
                if (pm.checkPermission(Manifest.permission.CAMERA,somePackage.packageName) == PackageManager.PERMISSION_GRANTED) {
                    hasCameraPermission = true;
                    break;
                }
            }
        }
        if (hasCameraPermission) {
            cameraPermissionPackages.add(somePackage);
        }
    }
    return cameraPermissionPackages;
}

第2步:从APK文件(从PackageInfo)获取AndroidManifest

public static Document readAndroidManifestFromPackageInfo(PackageInfo packageInfo) {
    File publicSourceDir = new File(packageInfo.applicationInfo.publicSourceDir);
    
    //Get AndroidManifest.xml from APK
    ZipFile apkZipFile = new ZipFile(apkFile,ZipFile.OPEN_READ);
    ZipEntry manifestEntry = apkZipFile.getEntry("AndroidManifest.xml");
    InputStream manifestInputStream = apkZipFile.getInputStream(manifestEntry);
    try {
        Document doc = new CompressedXmlParser().parseDOM(manifestInputStream);
        return doc;
    } catch (Exception e) {
        throw new IOException("Error reading AndroidManifest",e);
    }
}

第3步:阅读AndroidManifest,以找到具有正确IntentFilter的Activity

public static List<ComponentName> getCameraComponentNamesFromDocument(Document doc) {
    @SuppressLint("InlinedApi")
    String[] correctActions = {MediaStore.ACTION_IMAGE_CAPTURE,MediaStore.ACTION_IMAGE_CAPTURE_SECURE,MediaStore.ACTION_VIDEO_CAPTURE};
    ArrayList<ComponentName> componentNames = new ArrayList<ComponentName>();
    Element manifestElement = (Element) doc.getElementsByTagName("manifest").item(0);
    String packageName = manifestElement.getAttribute("package");
    Element applicationElement = (Element) manifestElement.getElementsByTagName("application").item(0);
    NodeList activities = applicationElement.getElementsByTagName("activity");
    for (int i = 0; i < activities.getLength(); i++) {
        Element activityElement = (Element) activities.item(i);
        String activityName = activityElement.getAttribute("android:name");
        NodeList intentFiltersList = activityElement.getElementsByTagName("intent-filter");
        for (int j = 0; j < intentFiltersList.getLength(); j++) {
            Element intentFilterElement = (Element) intentFiltersList.item(j);
            NodeList actionsList = intentFilterElement.getElementsByTagName("action");
            for (int k = 0; k < actionsList.getLength(); k++) {
                Element actionElement = (Element) actionsList.item(k);
                String actionName = actionElement.getAttribute("android:name");
                for (String correctAction : correctActions) {
                    if (actionName.equals(correctAction)) {
                        //this activity has an intent filter with a correct action,add this to the list.
                        componentNames.add(new ComponentName(packageName,activityName));
                    }
                }
            }
        }
    }
    return componentNames;
}

第4步:创建所有Camera Apps的列表

List<> cameraApps = new ArrayList<>();
for (PackageInfo somePackage : cameraPermissionPackages) {
            Document doc = readAndroidManifestFromPackageInfo(somePackage);
            List<ComponentName> componentNames = getCameraComponentNamesFromDocument(doc);
            if (componentNames.size() == 0) {
                continue; //This is not a Camera app
            }
            cameraApps.add(cameraApp);
    }

第5步:向用户显示Camera Apps列表。
只需创建一个对话框或其他内容即可。

我已经将其计算到一个库中: https://github.com/frankkienl/Camera11

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...