Android: как получить список установленных действий, как они отображаются в лаунчере, без дубликатов - PullRequest
27 голосов
/ 28 марта 2012

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

Intent launchIntent = packageManager.getLaunchIntentForPackage(packageName);
launchIntent.setAction(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(launchIntent);

Проблема заключается в получении списка установленных приложений. Я нашел два способа получить список установленных приложений:

1) использовать

PackageManager pm = getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplication(PackageManager.GET_META_DATA) 

и из каждого элемента из apps вы можете получить его имя и метку пакета (имена приложений).

2) использовать

PackageManager pm = getPackageManager();    
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mainIntent, 0);
for(ResolveInfo info : resolveInfos) {
    ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
    //...
    //get package name, icon and label from applicationInfo object    
}

Ошибка метода first : он возвращает все установленные пакеты, включая системные службы, которые могут не содержать никаких действий и поэтому не запускаются. Вот скриншот с примером: app list with packages

Все элементы выше без значков не запускаются.

Также существует проблема с вторым подходом: несколько элементов в списке имеют дубликаты: app list with duplicates

Когда я устанавливаю точку останова в отладчике, я вижу, что эти элементы «Карты» имеют разные имена действий («com.google.android.maps.MapsActivity», «com.google.android.maps.LatitudeActivity», « com.google.android.maps.PlacesActivity "и т. д.).

Я решил использовать второй подход, потому что он дает список, который больше подходит для моих нужд, но я не могу найти способ отфильтровать дубликаты и показать только активность по умолчанию для приложения, как они появляются в Launcher (вы видите только одну «Карты» в списке приложений вашего телефона, а не четыре). Я попытался отфильтровать системные приложения через ApplicationInfo.FLAG_SYSTEM, но это удаляет многие приложения, которые я хочу иметь, включая Карты и другие предустановленные приложения. Я пытался использовать флаг PackageManager.MATCH_DEFAULT_ONLY при выполнении queryIntentActivities, но это также отфильтровывает многие приложения, оставляя только несколько.

Я как бы потерялся здесь, и я не знаю, что делать. Я прочитал все вопросы на stackoverflow о получении списка установленных приложений, но эта проблема никогда не поднималась. Пожалуйста, помогите кому-нибудь? Как получить список установленных запускаемых приложений, в которых нет дубликатов?

Ответы [ 5 ]

14 голосов
/ 28 марта 2012
Intent localIntent2 = new Intent("android.intent.action.PICK_ACTIVITY");
Intent localIntent3 = new Intent("android.intent.action.MAIN",null);
localIntent3.addCategory("android.intent.category.LAUNCHER");   
localIntent2.putExtra("android.intent.extra.INTENT",localIntent3);
startActivityForResult(localIntent2, 1);

Попробуйте этот код.В нем будут перечислены только те приложения, которые установлены на вашем устройстве.

14 голосов
/ 22 июня 2014

Возможно, я опоздал, но я просто нашел идеальный способ получить все приложения, имеющие программу запуска и не дублированные приложения (включая системные приложения, такие как контакты, карты и т. Д.).Хотя ответ Satheesh мог бы сработать (я сам не проверял), но я хотел выбрать несколько действий, поэтому я использовал приведенный ниже код для получения установленных приложений.

Я использовал ваш второй подход и отбросил дубликаты пакетов, используя HashSet.Вот окончательный код:

    final PackageManager packageManager = getPackageManager();
    Intent intent = new Intent(Intent.ACTION_MAIN, null);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> resInfos = packageManager.queryIntentActivities(intent, 0);
    //using hashset so that there will be no duplicate packages, 
    //if no duplicate packages then there will be no duplicate apps
    HashSet<String> packageNames = new HashSet<String>(0);
    List<ApplicationInfo> appInfos = new ArrayList<ApplicationInfo>(0);

    //getting package names and adding them to the hashset
    for(ResolveInfo resolveInfo : resInfos) {
        packageNames.add(resolveInfo.activityInfo.packageName);
    }

    //now we have unique packages in the hashset, so get their application infos
    //and add them to the arraylist
    for(String packageName : packageNames) {
        try {
            appInfos.add(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA));
        } catch (NameNotFoundException e) {
            //Do Nothing
        }
    }

    //to sort the list of apps by their names
    Collections.sort(appInfos, new ApplicationInfo.DisplayNameComparator(packageManager));
6 голосов
/ 28 марта 2012

Попробуйте код ниже и дайте мне знать, что произошло.

PackageManager manager = getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

List<ResolveInfo> resolveInfos= manager.queryIntentActivities(mainIntent, 0);
// Below line is new code i added to your code
Collections.sort(resolveInfos, new ResolveInfo.DisplayNameComparator(manager));

for(ResolveInfo info : resolveInfos) {
     ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
     //...
     //get package name, icon and label from applicationInfo object    
}
3 голосов
/ 27 ноября 2016

Оба @Ashish Tanna и Jozze правы, но производительность может быть небольшая проблема.

Это лучшая производительность.

Set<String> packageNameSet = new HashSet<>();
PackageManager pm = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mainIntent, 0);
for(ResolveInfo info : resolveInfos) {
    // be added
    ApplicationInfo applicationInfo;
    if (info == null || (applicationInfo = info.activityInfo.applicationInfo) == null
            || !applicationInfo.enabled || packageNameSet.contains(applicationInfo.packageName)) {
        continue;
    }
    packageNameSet.add(applicationInfo.packageName);

    //...
    //get package name, icon and label from applicationInfo object
}

(1) Добавить HashSet
(2) Оцените, включено ли приложение
(3) Оцените, есть ли внутри хэш-сет

3 голосов
/ 24 апреля 2015

У меня было такое же требование. В конечном итоге я добавил еще одно условие для фильтрации списка приложений. Я только что проверил, имеет ли приложение «намерение запуска».

Итак, результирующий код выглядит как ...

PackageManager pm = getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_GIDS);

for (ApplicationInfo app : apps) {
    if(pm.getLaunchIntentForPackage(app.packageName) != null) {
        // apps with launcher intent
        if((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) {
            // updated system apps
        } else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {
            // system apps
        } else {
            // user installed apps
        }
        appsList.add(app);
    }

}
...