在使用intent.resolveActivity时,在调用此方法时,考虑向您的清单添加一个查询声明(queries declaration),特别是在Android 11上。

31

我有一个打开意图的扩展函数用于我的活动:

fun Activity.openIntent(action: String?, type: String?, uri: Uri?) {
    Intent()
        .apply {
            action?.let { this.action = it }
            uri?.let { this.data = it }
            type?.let { this.type = it }
        }
        .also { intent ->
            packageManager?.let {
                if (intent.resolveActivity(it) != null)
                    startActivity(intent)
                else
                    showToast(R.string.application_not_found)
            }
        }
}

我的targetSdkVersion30。在intent.resolveActivity(it)中,它给我一个警告:

当调用此方法时,请考虑在您的清单中添加查询声明。

那么我该怎么做才能解决这个警告?

4个回答

41
最简单的解决方案是摆脱resolveActivity()。将其替换为:
            packageManager?.let {
                if (intent.resolveActivity(it) != null)
                    startActivity(intent)
                else
                    showToast(R.string.application_not_found)
            }

随着:

            try {
                startActivity(intent)
            } catch (ex: ActivityNotFoundException) {
                showToast(R.string.application_not_found)
            }

这样做可以得到相同的结果,且性能稍微更好,同时还能消除警告。

另一种选择是加入QUERY_ALL_PACKAGES权限。但这可能会导致您被Play商店禁止。

否则,您需要:

  • 构建一个包含您的应用程序可能进行的每个openIntent()调用的列表

  • 向您的清单文件添加<queries>元素,其中列出了所有可能的Intent结构,您希望能够使用resolveActivity()来使用这些结构

  • 定期重复此过程,以防您添加了新的openIntent()方案


应用程序无法安装:INSTALL_PARSE_FAILED_MANIFEST_MALFORMED。如果我在清单中添加了一个查询元素,就会出现这个错误。https://gist.github.com/sudhirkhanger/fbb613b38f25c44ad0342a237a2d06e6 - Sudhir Singh Khanger
@SudhirSinghKhanger: none不是一个有效的MIME类型,因此该元素毫无用处。尝试移除它。 - CommonsWare
@abhiarora:这篇官方博客文章提到了resolveActivity()。它恰好在特定的上下文中提到了它(在URL上启动Web浏览器),该上下文还有其他解决方案(FLAG_ACTIVITY_REQUIRE_NON_BROWSER)。 - CommonsWare
但它没有提到 resolveActivity 会返回 null。我认为这篇文章只是提供了一种替代方法,而没有指出 resolveActivity 不起作用。 - abhiarora
1
@abhiarora:你要求文档。在快速搜索中,那是我找到的最接近的东西。 - CommonsWare
显示剩余2条评论

10

替换

if (intent.resolveActivity(it) != null)

随着

if (it.resolveActivity(intent, 0) != null)

而警告将会消失。


it 是什么对象? - azizbekian
1
它是一个PackageManager。 - Tatsuya Fujisaki

10

从Android 11开始(即如果您的应用程序针对Android 11),不是所有应用程序都会对您的应用程序可见。一些应用程序默认可见,但是为了通过您的应用程序访问其他应用程序,您将不得不在清单中声明查询语句,否则您的应用程序将无法访问它们。您可以在这里阅读相关内容

因此,如果您的应用程序针对Android 11,并且需要访问可能默认不可见的应用程序,则需要在清单文件中添加查询语句

在您的情况下,此警告不适用,因为我认为您正在使用隐式意图打开其他应用程序。使用隐式意图,可以访问其他应用程序,而不受应用程序可见性的影响。如果您的应用程序目标为Android 10或更低版本,则可以抑制警告,因为所有应用程序默认可见。

为了抑制lint警告,您可以执行以下操作之一:

  1. 添加抑制注释,例如:
@SuppressLint("QueryPermissionsNeeded")
fun Activity.openIntent(action: String?, type: String?, uri: Uri?): Activity {
  1. 在你的应用程序模块构建gradle文件中的android块中添加以下内容:
lintOptions {
    ignore "QueryPermissionsNeeded"
}

似乎只有lintOptions块可以完成这项工作。谢谢! - Itay Feldman
1
两者都可以完成工作。你可以使用其中任何一个。 - Xid
此警告并不适用,因为我相信您正在使用隐式意图打开其他应用程序 -- 此警告来自于resolveActivity()调用,需要<queries>元素才能工作。 - CommonsWare
是的,那就是我所写的。虽然这仅适用于显式意图和针对API 30的应用程序,正如官方Android文档中所指定的那样。我已经在我的答案中提供了相应的参考资料。 - Xid
你应该如何以及为什么要显式地打开WhatsApp?Google发明了Intents,你不再需要明确指出谁在执行某个任务。如果用户有另一种可以完成此任务的替代通讯应用,那又有谁会在意呢? - The incredible Jan

4

从API级别30开始,包的可见性受到限制。因此,请在<application>标记之外的AndroidManifest文件中添加适当的query

<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="http" />
    </intent>
</queries>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接