为什么没有找到Activity来处理Intent?

问题描述 投票:4回答:7

我没有采用常规的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完美配合。)

android android-intent android-package-managers
7个回答
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()创建的意图),区别在于

intent1:

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

intent2:

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

我将不得不相信你为创建自己的意图对象所做的工作还不足以让明确的意图工作。您将不得不向Android提供有关您的意图的更多信息,例如特定于组件名称(如上面的答案中所示)。


1
投票

'要接收隐式意图,您必须在intent过滤器中包含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


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的代码


0
投票

startActivity对待所有意图,好像他们宣布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


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实例上调用该方法,该实例将其转发到另一个进程,在本例中为系统进程。

到目前为止,还没有进行Intent过滤。

在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包的所有活动。这将从您的包中获取活动,然后调用 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,并相应地将匹配的IntentFilters添加到列表中。

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


0
投票

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

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

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


0
投票

让我在此添加一些额外的信息。如here所述,没有组件名称,意图是隐含的。

组件名称是可选的,但它是使意图显式化的关键信息,这意味着意图应仅传递给组件名称定义的应用程序组件。如果没有组件名称,则意图是隐式的,系统根据其他意图信息(例如下面描述的操作,数据和类别)决定哪个组件应该接收意图。如果需要在应用程序中启动特定组件,则应指定组件名称。

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

希望这会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.