intent.resolveActivity returns API 30 中为空
intent.resolveActivity returns null in API 30
看着 intent.resolveActivity != null but launching the intent throws an ActivityNotFound exception 我写道打开一个浏览器或一个带有深层链接的应用程序:
private fun openUrl(url: String) {
val intent = Intent().apply {
action = Intent.ACTION_VIEW
data = Uri.parse(url)
// setDataAndType(Uri.parse(url), "text/html")
// component = ComponentName("com.android.browser", "com.android.browser.BrowserActivity")
// flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_GRANT_READ_URI_PERMISSION
}
val activityInfo = intent.resolveActivityInfo(packageManager, intent.flags)
if (activityInfo?.exported == true) {
startActivity(intent)
} else {
Toast.makeText(
this,
"No application can handle the link",
Toast.LENGTH_SHORT
).show()
}
}
没用。在 API 30 模拟器中找不到浏览器,而常见的 solution 可以工作:
private fun openUrl(url: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(
this,
"No application can handle the link",
Toast.LENGTH_SHORT
).show()
}
}
第一种方法不行,因为intent.resolveActivityInfo
或intent.resolveActivity
returnsnull
。但对于 PDF 查看器,它 .
我们应该解散 intent.resolveActivity
吗?
这似乎是由于 the new restrictions on "package visibility" introduced in Android 11。
基本上,从 API 级别 30 开始,如果您的目标是该版本或更高版本,则您的应用无法查看大多数外部包或直接与之交互,除非通过一揽子 QUERY_ALL_PACKAGES
许可,或通过在您的清单中包含适当的 <queries>
元素。
确实,您的第一个代码片段在获得该许可或清单中适当的 <queries>
元素的情况下按预期工作;例如:
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
目前可用的信息不是非常具体,但确实说明:
The PackageManager
methods that return results about other apps, such as queryIntentActivities()
, are filtered based on the calling app's <queries>
declaration
虽然您的示例使用的是 Intent
方法——即 resolveActivityInfo()
– 实际上是在内部调用 PackageManager
“查询”方法。受此更改影响的每个方法和功能的详尽列表可能不可行,但可以安全地假设如果涉及 PackageManager
,您可能会用新限制检查其行为。
除了下面的代码之外,Mike 所说的对我有用。
<manifest ... >
<uses-feature android:name="android.hardware.camera"
android:required="true" />
...
</manifest>
感谢 ,我添加了对 Browser
、Camera
和 Gallery
的查询。将它们放在 AndroidManifest
内的任何部分(在 <application>
标签之前或之后)。
看着 MediaStore.ACTION_IMAGE_CAPTURE and Intent.ACTION_GET_CONTENT 我得到了两个动作。
<queries>
<!-- Browser -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<!-- Camera -->
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
<!-- Gallery -->
<intent>
<action android:name="android.intent.action.GET_CONTENT" />
</intent>
</queries>
不需要我回答,所以我还有
<uses-feature
android:name="android.hardware.camera"
android:required="false"
/>
对我来说,我试图发送一封电子邮件,所以我需要像这样在清单中设置查询:
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="*" />
</intent>
</queries>
然后像这样发送电子邮件并检查电子邮件客户端:
private fun sendEmail(to: Array<String>) {
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = Uri.parse("mailto:") // only email apps should handle this
intent.putExtra(Intent.EXTRA_EMAIL, to)
// intent.putExtra(Intent.EXTRA_SUBJECT, subject)
if (intent.resolveActivity(requireContext().packageManager) != null) {
startActivity(intent)
}
}
对于需要启动Activity
的情况(不仅检查是否存在),在this advise之后我删除了
if (intent.resolveActivity(packageManager) != null)
startActivity(intent);
并写了 instaed
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(getContext(), getString(R.string.error), Toast.LENGTH_SHORT).show();
}
无需在 Manifest
处添加任何 <queries>
。在 Api 28 和 Api 30 上测试。
您可以在 AndroidManifest 中添加 QUERY_ALL_PACKAGES 权限。它不需要 运行 次权限请求。
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
要迭代 Avital 的答案,如果您想启动一个 Intent 并了解它是否已启动,则无需声明任何内容:
private fun startIntent(intent: Intent): Boolean {
return try {
context.startActivity(intent)
true
} catch (e: ActivityNotFoundException) {
Logger.error("Can't handle intent $intent")
false
}
}
如果您使用意图操作 ACTION_INSERT
,根据文档,您需要将 intent-filter
添加到使用 activity 和操作 INSERT
中,并且使用指定的 mimeType
,使 intent.resolveActivity(view.context.packageManager) != null
return 为真。
<activity ...>
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<data android:mimeType="vnd.android.cursor.dir/event" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
由于用户提出的问题没有设置任何限制,所以你可以这样做,它会使用你在 INTNET 中传递的 EMAIL ID 直接导航到 GMAIL
val emailTo = "user@gmail.com" // just ex. write the email address you want
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("mailto:$emailTo")
startActivity(intent) // <---- this is work for activity and fragment both
看着 intent.resolveActivity != null but launching the intent throws an ActivityNotFound exception 我写道打开一个浏览器或一个带有深层链接的应用程序:
private fun openUrl(url: String) {
val intent = Intent().apply {
action = Intent.ACTION_VIEW
data = Uri.parse(url)
// setDataAndType(Uri.parse(url), "text/html")
// component = ComponentName("com.android.browser", "com.android.browser.BrowserActivity")
// flags = Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_GRANT_READ_URI_PERMISSION
}
val activityInfo = intent.resolveActivityInfo(packageManager, intent.flags)
if (activityInfo?.exported == true) {
startActivity(intent)
} else {
Toast.makeText(
this,
"No application can handle the link",
Toast.LENGTH_SHORT
).show()
}
}
没用。在 API 30 模拟器中找不到浏览器,而常见的 solution 可以工作:
private fun openUrl(url: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
Toast.makeText(
this,
"No application can handle the link",
Toast.LENGTH_SHORT
).show()
}
}
第一种方法不行,因为intent.resolveActivityInfo
或intent.resolveActivity
returnsnull
。但对于 PDF 查看器,它
我们应该解散 intent.resolveActivity
吗?
这似乎是由于 the new restrictions on "package visibility" introduced in Android 11。
基本上,从 API 级别 30 开始,如果您的目标是该版本或更高版本,则您的应用无法查看大多数外部包或直接与之交互,除非通过一揽子 QUERY_ALL_PACKAGES
许可,或通过在您的清单中包含适当的 <queries>
元素。
确实,您的第一个代码片段在获得该许可或清单中适当的 <queries>
元素的情况下按预期工作;例如:
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
</queries>
目前可用的信息不是非常具体,但确实说明:
The
PackageManager
methods that return results about other apps, such asqueryIntentActivities()
, are filtered based on the calling app's<queries>
declaration
虽然您的示例使用的是 Intent
方法——即 resolveActivityInfo()
– 实际上是在内部调用 PackageManager
“查询”方法。受此更改影响的每个方法和功能的详尽列表可能不可行,但可以安全地假设如果涉及 PackageManager
,您可能会用新限制检查其行为。
除了下面的代码之外,Mike 所说的对我有用。
<manifest ... >
<uses-feature android:name="android.hardware.camera"
android:required="true" />
...
</manifest>
感谢 Browser
、Camera
和 Gallery
的查询。将它们放在 AndroidManifest
内的任何部分(在 <application>
标签之前或之后)。
看着 MediaStore.ACTION_IMAGE_CAPTURE and Intent.ACTION_GET_CONTENT 我得到了两个动作。
<queries>
<!-- Browser -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<!-- Camera -->
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
<!-- Gallery -->
<intent>
<action android:name="android.intent.action.GET_CONTENT" />
</intent>
</queries>
<uses-feature
android:name="android.hardware.camera"
android:required="false"
/>
对我来说,我试图发送一封电子邮件,所以我需要像这样在清单中设置查询:
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="*" />
</intent>
</queries>
然后像这样发送电子邮件并检查电子邮件客户端:
private fun sendEmail(to: Array<String>) {
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = Uri.parse("mailto:") // only email apps should handle this
intent.putExtra(Intent.EXTRA_EMAIL, to)
// intent.putExtra(Intent.EXTRA_SUBJECT, subject)
if (intent.resolveActivity(requireContext().packageManager) != null) {
startActivity(intent)
}
}
对于需要启动Activity
的情况(不仅检查是否存在),在this advise之后我删除了
if (intent.resolveActivity(packageManager) != null)
startActivity(intent);
并写了 instaed
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
Toast.makeText(getContext(), getString(R.string.error), Toast.LENGTH_SHORT).show();
}
无需在 Manifest
处添加任何 <queries>
。在 Api 28 和 Api 30 上测试。
您可以在 AndroidManifest 中添加 QUERY_ALL_PACKAGES 权限。它不需要 运行 次权限请求。
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
要迭代 Avital 的答案,如果您想启动一个 Intent 并了解它是否已启动,则无需声明任何内容:
private fun startIntent(intent: Intent): Boolean {
return try {
context.startActivity(intent)
true
} catch (e: ActivityNotFoundException) {
Logger.error("Can't handle intent $intent")
false
}
}
如果您使用意图操作 ACTION_INSERT
,根据文档,您需要将 intent-filter
添加到使用 activity 和操作 INSERT
中,并且使用指定的 mimeType
,使 intent.resolveActivity(view.context.packageManager) != null
return 为真。
<activity ...>
<intent-filter>
<action android:name="android.intent.action.INSERT" />
<data android:mimeType="vnd.android.cursor.dir/event" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
由于用户提出的问题没有设置任何限制,所以你可以这样做,它会使用你在 INTNET 中传递的 EMAIL ID 直接导航到 GMAIL
val emailTo = "user@gmail.com" // just ex. write the email address you want
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("mailto:$emailTo")
startActivity(intent) // <---- this is work for activity and fragment both