Почему не найдена активность для обработки намерений? - PullRequest
0 голосов
/ 02 февраля 2019

Вместо обычного getPackageManager().getLaunchIntentForPackage("com.example.app") способа, я хочу создать намерение запуска самостоятельно.

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

Почему Android не находит активность, если com.example.app установлен, включен иимеет правильный манифест?(Отлично работает с getLaunchIntentForPackage.)

Ответы [ 7 ]

0 голосов
/ 12 февраля 2019

Вам необходимо создать имя компонента для необходимого приложения, например:

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

Имя компонента представляет действие, которое вам нужно открыть, полное имя пакета, а второй параметр - имя класса дляэтот пакет.

0 голосов
/ 13 февраля 2019

Позвольте мне добавить дополнительную информацию в этом.как описано здесь , без имени компонента намерение является неявным.

Имя компонента является необязательным, но это важная часть информации, которая делает намерение явным, означая, чтонамерение должно быть доставлено только компоненту приложения, определенному именем компонента.Без имени компонента намерение является неявным, и система решает, какой компонент должен получить намерение, основываясь на другой информации о намерениях (такой как действие, данные и категория - как описано ниже).Если вам нужно запустить определенный компонент в вашем приложении, вы должны указать имя компонента.

Категория DEFAULT необходима для метода Context.startActivity для разрешения вашегодействие, когда имя его компонента не указано явно.Проверьте первый пример в этой ссылке .

Надеюсь, это поможет.

0 голосов
/ 11 февраля 2019

Вы просили увидеть код, выполняемый после 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, который пересылает его другому процессу, в данном случае системному процессу.

Upк этому моменту фильтрация намерений не выполнялась.

В системном процессе 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(...), который запускает все найденные фильтры IntentFilter для данных в вашем Intent, учитывая, нужен ли нам CATEGORY_DEFAULT, и добавляя соответствующие IntentFilters в список соответственно.

Все эти вызовывызовы методов затем возвращаются, и в конце концов некоторый объект где-нибудь обнаружит, что не было соответствующих IntentFilters.Я опускаю это здесь, потому что это важная часть ответа.

0 голосов
/ 08 февраля 2019

Это функция, где 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 голосов
/ 07 февраля 2019

Я понимаю, что вы пытаетесь запустить Launcher-активность известного приложения с известным именем пакета (com.example.app).Я предполагаю, что у вас есть информация о приложении.Таким образом, вы можете запустить его с помощью явного намерения, например, так:

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 более подробную информацию о ваших намерениях, например, указав имя компонента (как показано в моем ответе выше).

0 голосов
/ 06 февраля 2019

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);

Источник заголовка: синяя заметка на странице элемента .
Источник определения явного намерения: developer.android.com .

0 голосов
/ 02 февраля 2019

'Чтобы получить неявные намерения, вы должны включить категорию 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

...