为什么找不到活动来处理意图?

时间:2019-02-02 11:40:13

标签: android android-intent android-package-managers

我希望自己创建启动意图,而不是常规的getPackageManager().getLaunchIntentForPackage("com.example.app")方式。

Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setPackage("com.example.app");
startActivity(intent);

如果com.example.app已安装,启用并具有正确的清单,为什么Android找不到活动? (它与getLaunchIntentForPackage完美搭配。)

7 个答案:

答案 0 :(得分:2)

我了解到您正在尝试启动具有已知程序包名称(com.example.app)的已知应用程序的Launcher活动。我假设您具有有关该应用程序的信息。因此,您可以通过如下明确的意图启动它:

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.app", "com.example.app.MainActivity"));
if(intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

编辑:分析两个意图对象(intent1 ==您自己的意图VS intent2 ==从getLaunchIntentForPackage()创建的意图),区别是

意图1:

  

{act = android.intent.action.MAIN   cat = [android.intent.category.LAUNCHER] pkg = com.example.app}

意图2:

  

{act = android.intent.action.MAIN   cat = [android.intent.category.LAUNCHER] flg = 0x10000000   pkg = com.example.app   cmp = com.example.app / .MainActivity}

我将不得不相信,创建自己的意图对象所做的工作不足以使显式意图发挥作用。您将必须向Android提供有关您的意图的更多信息,例如特定于组件名称(如上面我的答案所示)。

答案 1 :(得分:1)

“要接收隐式意图,必须在意图过滤器中包括CATEGORY_DEFAULT类别。” -您的接收应用程序有这个吗?

示例:

<activity android:name="ShareActivity">
     <intent-filter>
         <action android:name="android.intent.action.SEND"/>
         <category android:name="android.intent.category.DEFAULT"/>
         <data android:mimeType="text/plain"/>
     </intent-filter>
</activity>

摘录自: https://developer.android.com/guide/components/intents-filters#Receiving

您还可以检查以确保有活动可以接收您的广播:

 PackageManager packageManager = getPackageManager();
 List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
 boolean isIntentSafe = activities.size() > 0;

摘录自: https://developer.android.com/training/basics/intents/sending#java

答案 2 :(得分:1)

这是将android.content.Intent#CATEGORY_DEFAULT添加到所有startActivity代码中的函数。

ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
        try {
            return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
                    PackageManager.MATCH_DEFAULT_ONLY | flags
                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
        } catch (RemoteException e) {
        }
        return null;
    }

/**
     * Resolution and querying flag: if set, only filters that support the
     * {@link android.content.Intent#CATEGORY_DEFAULT} will be considered for
     * matching.  This is a synonym for including the CATEGORY_DEFAULT in your
     * supplied Intent.
     */
    public static final int MATCH_DEFAULT_ONLY  = 0x00010000;

这是一切开始的代码 http://androidxref.com/7.1.2_r36/xref/frameworks/base/core/java/android/app/ContextImpl.java#766

答案 3 :(得分:0)

startActivity all 意图视为已声明CATEGORY_DEFAULT

  • 即使您的代码中没有intent.addCategory(Intent.CATEGORY_DEFAULT);

  • 即使添加intent.removeCategory(Intent.CATEGORY_DEFAULT);

  • 即使您的意图是明确的*:intent.setPackage("com.example.app");
    *提供“ 目标应用的程序包名称或标准组件类名称”。

...除非不是

如果您设置目标活动的类名,系统将不会寻找CATEGORY_DEFAULT

Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName("com.example.app", "com.example.app.NameOfTheActivityToBeStarted");
startActivity(intent);

标头来源:the <category> element's page上的蓝色注释。
明确意图的定义来源:developer.android.com

答案 4 :(得分:0)

您要求查看在startActivity之后执行的代码,就在这里。

在您的应用中:
Activity.startActivity(Intent)个通话
Activity.startActivity(Intent, Bundle),它调用
Activity.startActivityForResult(Intent, int),它调用
FragmentActivity.startActivityForResult(Intent, int),它调用
Activity.startActivityForResult(Intent, int),它调用
Activity.startActivityForResult(Intent, int, Bundle),它调用
Instrumentation.execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle),它会调用 IActivityManager.startActivity(IApplicationThread, String, Intent, String, IBinder, String, int, int, ProfilerInfo, Bundle)

最后一行的调用是一个远程进程调用,这意味着在您的应用程序进程中,该方法在代理IActivityManager实例上被调用,该实例将其转发到另一个进程(在本例中为系统进程)。 / p>

到目前为止,尚未进行意图过滤。

在Android的系统进程中,IActivityManager解析为ActivityManagerService,并且:

ActivityManagerService.startivity(IApplicationThread, String, Intent, String, IBinder, String, int, int, ProfilerInfo, Bundle)通话
ActivityManagerService.startActivityAsUser(IApplicationThread, String, Intent, String, IBinder, String, int, int, ProfilerInfo, Bundle, int),它调用
ActivityStackSupervisor.startActivityMayWait(IApplicationThread, int, String, Intent, String, IVoiceInteractionSession, IVoiceInteractor, IBinder, String, int, int, ProfilerInfo, WaitResult, Configuration, Bundle, boolean, int, IActivityContainer, TaskRecord),它调用
ActivityStackSupervisor.resolveActivity(Intent, String, int, ProfilerInfo, int),它调用
IPackageManager.resolveIntent(Intent, String, int, int)

这是添加MATCH_DEFAULT_ONLY的地方,如nkalra0123所说。

此外,这是另一个远程方法调用。 IPackageManager解析为PackageManagerService,从那里开始像这样:

PackageManagerService.resolveIntent(Intent, String, int, int)通话
PackageManagerService.queryIntentActivities(Intent, String, int, int),它尝试获取所有Intent包的Activity。这会从您的包裹中获取活动,然后调用
PackageService.ActivityIntentResolver.queryIntentForPackage(Intent, String, int, ArrayList<PackageParser.Activity>, int),它会在您的程序包中获取 IntentFilters ,然后调用
PackageService.ActivityIntentResolver.queryIntentFromList(Intent, String, boolean , ArrayList<F[]>, int),它调用
IntentResolver.buildResolveList(...),它会根据您的Intent中的数据运行它找到的所有IntentFilter,并考虑我们是否需要CATEGORY_DEFAULT,并将匹配的IntentFilter添加到列表中。

所有这些调用方法调用然后返回,最终某个地方的某个对象将发现没有匹配的IntentFilter。我在这里省略了,因为这是答案的相关部分。

答案 5 :(得分:0)

您需要为所需的应用创建组件名称,例如:

Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(ComponentName.createRelative("com.whatsapp",".Main"));
intent.setPackage("com.whatsapp");

组件名称表示您需要打开的活动,完整的软件包名称,第二个参数是该软件包的类名称。

答案 6 :(得分:0)

让我在其中添加一些其他信息。如here所述,如果没有组件名称,则意图是隐式的。

  

组件名称是可选的,但这是关键信息   使意图明确,意味着意图应该是   仅交付给由组件名称定义的应用程序组件。   没有组件名称,意图是隐式的,系统   决定哪个组件应基于另一个组件接收意图   意向信息(例如动作,数据和类别,已描述)   下面)。如果您需要启动应用程序中的特定组件,则可以   应该指定组件名称。

Context.startActivity方法需要DEFAULT类别才能在未明确指定其组件名称时解析您的活动。检查this link中的第一个示例。

希望这会有所帮助。