我希望自己创建启动意图,而不是常规的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
完美搭配。)
答案 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中的第一个示例。
希望这会有所帮助。