自 Android 13 起无法启动任意 Activity

问题描述 投票:0回答:6

我构建了一个小型个人应用程序,它允许我为不同的 URL 指定不同的浏览器。在 Android 13 之前,它运行良好,但在 Android 13 之后的某个时候,它开始出现故障。我怀疑这与应用程序启动任意 Activity 的权限(或缺乏权限)有关,但仔细阅读文档却没有得到任何结果。

这个过程是这样的:

我查询所有活动以查找具有 URI 作为其数据属性的

Intent

Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); // uri is some location like 'https://www.google.com' PackageManager pm = context.getPackageManager(); List<ResolveInfo> allTargets = pm.queryIntentActivities(intent, PackageManager.MATCH_ALL);
我循环遍历 

allTargets

 根据其名称寻找我想要的浏览器:

ResolveInfo target = null; for (ResolveInfo b : allTargets) { String appName = b.loadLabel(pm).toString(); // targetBrowserName will be something like "Chrome" if(appName.equalsIgnoreCase(targetBrowserName)) { target = b; break; } }
然后我尝试使用 url 启动此浏览器

ActivityInfo activity = target.activityInfo; ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name); targetIntent = new Intent(Intent.ACTION_MAIN); targetIntent.addCategory(Intent.CATEGORY_LAUNCHER); targetIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); targetIntent.setComponent(name); targetIntent.setData(uri); startActivity(targetIntent);
这个 

now 失败并出现如下错误:

android.content.ActivityNotFoundException: Unable to find explicit activity class {com.android.chrome/com.google.android.apps.chrome.IntentDispatcher}; have you declared this activity in your AndroidManifest.xml, or does your intent not match its declared <intent-filter>? at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4803) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4836) at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:54) at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2308) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:201) at android.os.Looper.loop(Looper.java:288) at android.app.ActivityThread.main(ActivityThread.java:7898) at java.lang.reflect.Method.invoke(Native Method)
我尝试了启动代码的各种排列(提醒一下,

工作正常)。例如

targetIntent = pm.getLaunchIntentForPackage(activity.applicationInfo.packageName); targetIntent.setAction(Intent.ACTION_VIEW); targetIntent.addCategory(Intent.CATEGORY_BROWSABLE); targetIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
但是我仍然遇到相同的错误(尽管在上述情况下仍然找不到不同的 Activity 类)

我知道应用程序可见性受到限制,但我认为我已被覆盖,因为我的

AndroidManifest.xml

中有此内容

<!-- As per guidelines, QUERY_ALL_PACKAGES is required to list all browsers --> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
阅读文档,我注意到我

没有在清单中有一个<queries>

元素(这是新的吗?),所以我添加了这个:

<queries> <intent> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" /> </intent> </queries>
没有喜悦。

有人知道以编程方式启动基于已知/特定[浏览器]应用程序的

正确方法吗?或者也许 Android 13 中发生了什么变化才能使这段代码再次工作?

谢谢!

编辑下面的正确答案

下面答案中提供的指导有效。这是最终代码的摘要版本:

// Create an intent with the destination URL Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(uri); // List all activities that support this intent, and choose one: PackageManager pm = context.getPackageManager(); List<ResolveInfo> allTargets = pm.queryIntentActivities(intent, PackageManager.MATCH_ALL); ResolveInfo target = null; for (ResolveInfo b : allTargets) { String appName = b.loadLabel(pm).toString(); // targetBrowserName is something like "Chrome" if(appName.equalsIgnoreCase(targetBrowserName)) { target = b; break; } } // Set the specific component to be launched ActivityInfo activity = target.activityInfo; ComponentName name = new ComponentName(activity.applicationInfo.packageName, activity.name); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); intent.setComponent(name); // Start startActivity(intent);
    
android android-intent android-activity
6个回答
9
投票
似乎与此行为更改相关

https://developer.android.com/about/versions/13/behavior-changes-13#intent-filters

当您的应用向另一个面向 Android 13 或更高版本的应用的导出组件发送意图时,当且仅当它与接收应用中的元素匹配时,才会传递该意图。不匹配的意图将被阻止。

为了确保这确实是您的问题,请检查 logcat 中的标签

PackageManager

。类似 
W/PackageManager( 1828): Access blocked: ComponentInfo{com.android.chrome/com.google.android.apps.chrome.Main}
 的内容应该出现在那里

我还没有过多研究它是如何工作的,但似乎现在我们需要在使用外部活动之前查询它们,除非它们没有意图过滤器。这将“激活”组件,然后您使用的意图需要“匹配”其他应用程序意图过滤器:

意图与意图过滤器相匹配,不仅可以发现要激活的目标组件,还可以发现有关设备上组件集的信息。例如,Home 应用程序通过查找具有指定 ACTION_MAIN 操作和 CATEGORY_LAUNCHER 类别的意图过滤器的所有活动来填充应用程序启动器。仅当 Intent 中的操作和类别与过滤器匹配时,匹配才会成功,如 IntentFilter 类的文档中所述。

https://developer.android.com/guide/components/intents-filters#imatch

我也遇到了类似的问题。它不起作用的原因是我在调用

intent.setData

 后通过调用 
queryIntentActivities
 修改了 Uri。看起来这使得组件的激活无效。

总结:在

intent.setData

 使意图生效后不调用 
queryIntentActivities
 


2
投票
出现错误

Unable to find explicit activity class {com.google.android.apps.translate/com.google.android.apps.translate.TranslateActivity}; have you declared this activity in your AndroidManifest.xml, or does your intent not match its declared <intent-filter>?
就我而言,帮助删除Android 13的intent.addCategory(Intent.CATEGORY_LAUNCHER)

final Intent intent = new Intent(); intent.setAction(Intent.ACTION_PROCESS_TEXT); intent.setType("text/plain"); //Fix for Android 13 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { intent.addCategory(Intent.CATEGORY_LAUNCHER); } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); intent.setComponent(name); intent.putExtra(Intent.EXTRA_TEXT, selecteText); intent.putExtra(Intent.EXTRA_PROCESS_TEXT, selecteText); intent.putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, selecteText); a.startActivity(intent);
    

0
投票
将架构添加到导出活动中的意图过滤器。 这对我的 SDK 33 有帮助

<intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="https"/> </intent-filter>
    

0
投票
我遇到了同样的问题,但在 android 13 中出现了不匹配意图和意图过滤器的错误。

我在意图过滤器中为数据标签定义了memeType

并且在发送意图时使用 setDataAndType 而不是 setData,特别是当数据是内容时:

检查此链接

https://developer.android.com/guide/components/intents-filters#imatch:~:text=指定%20the%20MIME,到%20the%20系统.

<receiver android:name="com.android.calendar.alerts.AlertReceiver" android:exported="true"> <intent-filter> <action android:name="maddev.calendar2.REMIND_ME"/> <data android:scheme="content" android:mimeType="text/plain"/> </intent-filter>

Intent intent = new Intent(CalendarContract.ACTION_EVENT_REMINDER);
        intent.setComponent(
                new ComponentName(
                        ActivityUtils.INSTANCE.getInstalledEtarAppPkg(context),
                        "com.android.calendar.alerts.AlertReceiver"
                )
        );
        intent.setDataAndType(ContentUris.withAppendedId(CalendarAlerts.CONTENT_URI, alarmTime),"text/plain");
        intent.putExtra(CalendarAlerts.ALARM_TIME, alarmTime);
        intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
在这种情况下,我解决了 Android 13 中的问题


0
投票
当我将应用程序调整到 Android 13 时,我遇到了相同的错误消息。特别是,应用程序 A 在调用

startActivity(myIntent) 打开应用程序 B 时崩溃了。

首先,错误消息并不完全是无稽之谈,而是高度误导性的。在 Android 13 中,

MyIntent 中的 categoryaction 都必须与应用程序 B 的意图过滤器中的内容匹配。在我的例子中,类别是错误的。

其次,调用无异常成功,同时应用程序A成功请求MANAGE_EXTERNAL_STORAGE。当应用程序 A 返回该权限时,它将再次崩溃。我认为,人们可能会认为这是 Android 13 中的一种不当行为。

第三,捕获异常并显示错误消息通常是一个好主意,以避免在没有用户反馈的情况下突然崩溃。


-1
投票
如果您运行的 SDK 目标低于 33,请执行以下操作:

if (Build.VERSION.SDK_INT < 33) { intent.addCategory(Intent.CATEGORY_LAUNCHER) }
    
© www.soinside.com 2019 - 2024. All rights reserved.