无法打开相机意图。 queryIntentActivities 在 api 级别 30 返回一个空列表,但在级别 29 中找到结果。发生了啥变化?

Posted

技术标签:

【中文标题】无法打开相机意图。 queryIntentActivities 在 api 级别 30 返回一个空列表,但在级别 29 中找到结果。发生了啥变化?【英文标题】:Can't open camera intent. queryIntentActivities returns an empty list on api level 30 but finds results in level 29. What changed?无法打开相机意图。 queryIntentActivities 在 api 级别 30 返回一个空列表,但在级别 29 中找到结果。发生了什么变化? 【发布时间】:2021-01-23 06:45:24 【问题描述】:

我正在使用 queryIntentActivities 查询活动,它在 api 级别 29 中运行良好,但一旦我升级到级别 30,结果总是为空。

这是意图:

val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.putExtra("android.intent.extras.CAMERA_FACING", typeCamera)
uri?.grantWriteForIntent(activity, intent)
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
if (intent.isIntentSafe(activity)) 
    activity.__waitResult__ = true
    activity.startActivityForResult(intent, requestCode)

然后是isIntentSafe函数:

fun Intent?.isIntentSafe(context: Context) =
    if (this == null)
        false
    else
        context.packageManager.queryIntentActivities(this, PackageManager.MATCH_DEFAULT_ONLY).size > 0

这就是queryIntentActivites 在第 30 级为空而在第 29 级有内容的地方。有谁知道这些级别之间发生了什么变化会产生这种效果?

我应该补充一点,如果我在两个 api 级别中跳过isIntentSafe 检查,那么无论如何活动都可以正常启动。但我想知道为什么 isIntentSafe 在较新的 api 中停止工作。

编辑:我已经尝试改变前置摄像头的意图,就像在这个答案 How to launch front camera with intent? 中一样,这并没有什么不同。

【问题讨论】:

【参考方案1】:

我再次经历了Android 11的变化,发现"Media intent actions require default system camera"。

所以我搜索了一下,找到了solution from CommonsGuy。稍微修改一下代码,打开前置摄像头,马上就生效了!

fun enhanceCameraIntent(context: Context, baseIntent: Intent, title: String): Intent 
    val pm = context.packageManager

    val cameraIntents =
        CAMERA_CANDIDATES.map  Intent(baseIntent).setPackage(it) 
            .filter  pm.queryIntentActivities(it, 0).isNotEmpty() 
            .toTypedArray()

    return if (cameraIntents.isEmpty()) 
        baseIntent
     else 
        Intent
            .createChooser(baseIntent, title)
            .putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents)
    


fun openFrontFacingCamera(activity: BaseActivity, uri: Uri?, requestCode: Int) 
    try 
        val baseIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

        uri?.grantWriteForIntent(activity, baseIntent)
        baseIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
        baseIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
        baseIntent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true)

        activity.startActivityForResult(
            enhanceCameraIntent(activity, baseIntent, MediaStore.ACTION_IMAGE_CAPTURE),
            requestCode
        )
     catch (ex: ActivityNotFoundException) 
        Log.d("No default camera", "Activity not found!")
    

和以前一样,向 CommonsGuy 致敬!

【讨论】:

【参考方案2】:

在 Android 11 中,有新的rules 用于与设备上安装的应用进行交互。

因此,如果您的应用面向 Android 11 或更高版本,您可能需要在应用的清单文件中添加 <queries> 元素:

<queries>
  <intent>
    <action android:name="android.media.action.IMAGE_CAPTURE" />
  </intent>
</queries>

您还可以在此guide 中找到更多详细信息。

【讨论】:

Android Studio 会抱怨我直接在清单中添加了一个 标签,并在上面加上芥末背景,并说“这里不允许使用这个标签”。

以上是关于无法打开相机意图。 queryIntentActivities 在 api 级别 30 返回一个空列表,但在级别 29 中找到结果。发生了啥变化?的主要内容,如果未能解决你的问题,请参考以下文章

Galaxy Tab Limited Edition 中的相机图像捕获意图无法返回

相机意图打开相机应用程序(仅第一次)

意图以方形模式打开默认相机

相机未按意图打开

我可以从我的 so 中读取打开的相机意图吗

打开相机意图时如何防止android应用程序方向