web-dev-qa-db-ja.com

Android:ランチャーに表示されるインストール済みアクティビティのリストを、重複なしに取得する方法

ユーザーがインストール済みアプリのリストを表示し、それらの1つを選択して、スケジュールどおりに起動できるアプリを作成しています。 stackoverflowのチュートリアルを使用して、インストールされたアクティビティ、それらのパッケージ名、およびアイコンのリストを取得する方法を理解することができました(つまり、 here -いくつかの方法)。念のため、これが私が活動を始める方法です、それは完璧に機能します、ここで問題はありません:

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

問題は、インストールされているアプリのリストを取得することです。インストールされているアプリケーションのリストを取得するには、2つの方法があります。

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

アイコンがない上記のすべてのアイテムは起動できません。

secondアプローチにも問題があります。リスト内のいくつかの項目が重複しています: app list with duplicates

デバッガーでブレークポイントを設定すると、これらの「マップ」アイテムに異なるアクティビティ名(「com.google.Android.maps.MapsActivity」、「com.google.Android.maps.LatitudeActivity」、「com.google」)があることがわかります.Android.maps.PlacesActivity」など)。

2番目の方法を使用することにしました。これは、自分のニーズにより適したリストが得られるためです。ただし、重複を除外してアプリのデフォルトのアクティビティのみを表示する方法が見つからないため、ランチャーに表示されます。 (あなたの携帯電話のアプリのリストには4つではなく1つの「マップ」しか表示されません)。 ApplicationInfo.FLAG_SYSTEMを使用してシステムアプリを除外しようとしましたが、これにより、マップやその他のプリインストールアプリなど、必要な多くのアプリが削除されます。 queryIntentActivitiesを実行するときにPackageManager.MATCH_DEFAULT_ONLYフラグを使用してみましたが、これにより多くのアプリが除外され、数個しか残りません。

ここでちょっと迷ってしまい、どうすればいいのかわかりません。インストール済みアプリのリストを取得することに関するスタックオーバーフローに関するすべての質問を読みましたが、この問題が発生したことはありません。誰か助けてください重複していないインストール済みの起動可能なアプリのリストを取得するにはどうすればよいですか?

29
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
Satheeshkumar

遅れる可能性がありますが、ランチャーがあり、重複するアプリがないすべてのアプリ(連絡先、マップなどのシステムアプリを含む)を取得する完璧な方法を見つけました。 Satheeshの答えは機能している可能性がありますが(自分でチェックしていません)、複数のアクティビティを選択したかったため、以下のコードを使用してインストール済みアプリを取得しました。

私は2番目のアプローチを使用し、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));
14
Ashish Tanna

以下のコードを試して、何が起こったかを知らせてください。

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    
}
6
Yugandhar Babu

同じ要件がありました。最終的に、アプリリストを絞り込むために別の条件を追加しました。アプリに「ランチャーインテント」があるかどうかを確認しました。

したがって、結果のコードは次のようになります...

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

}
3
joecizac

@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
Trinea