Android R - ACTION_IMAGE_CAPTURE 的 startActivity 显示不同的选项供选择
Android R - startActivity of ACTION_IMAGE_CAPTURE shows different options to choose
我的目标是让我的应用支持 30 (R)。
我注意到有些应用程序在调用时缺少选择:
baseActivity.startActivity(Intent(MediaStore.ACTION_IMAGE_CAPTURE))
当定位到 29 时,此代码显示了几个应用程序供您选择:
- 原生相机应用
- B612 相机应用程序
定位到30后,直接打开相机应用(没有选项可以选择)。
我查看了 android 11 项更改,但没有发现任何特别之处。
我这边有什么需要改变的吗?
感谢reading/helping
一旦您的 targetSdkVersion
达到 30,ACTION_IMAGE_CAPTURE
will only display pre-installed camera apps, not user-installed apps。
我找到了解决方法;
TL;DR:自己阅读 AndroidManifest.xml 的应用程序以找到相机应用程序。
注意:这可能会导致您的应用被商店禁止。
第一步:
使用 PackageManager,创建已授予 Camera-permission 的所有应用程序的列表。
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-file(来自 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 步:创建所有相机应用的列表
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 步:向用户显示相机应用列表。
只需创建一个对话框或其他东西即可。
我已经把它写进了图书馆:
https://github.com/frankkienl/Camera11
我的目标是让我的应用支持 30 (R)。 我注意到有些应用程序在调用时缺少选择:
baseActivity.startActivity(Intent(MediaStore.ACTION_IMAGE_CAPTURE))
当定位到 29 时,此代码显示了几个应用程序供您选择:
- 原生相机应用
- B612 相机应用程序
定位到30后,直接打开相机应用(没有选项可以选择)。
我查看了 android 11 项更改,但没有发现任何特别之处。 我这边有什么需要改变的吗?
感谢reading/helping
一旦您的 targetSdkVersion
达到 30,ACTION_IMAGE_CAPTURE
will only display pre-installed camera apps, not user-installed apps。
我找到了解决方法;
TL;DR:自己阅读 AndroidManifest.xml 的应用程序以找到相机应用程序。
注意:这可能会导致您的应用被商店禁止。
第一步: 使用 PackageManager,创建已授予 Camera-permission 的所有应用程序的列表。
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-file(来自 PackageInfo)
获取 AndroidManifestpublic 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 步:创建所有相机应用的列表
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 步:向用户显示相机应用列表。
只需创建一个对话框或其他东西即可。
我已经把它写进了图书馆: https://github.com/frankkienl/Camera11