web-dev-qa-db-fra.com

Comment vérifier si une application est une application non-système sous Android?

Je reçois une liste d'objets ApplicationInfo avec packageManager.getInstalledApplications (0) et j'essaie de les classer par catégorie, qu'il s'agisse ou non d'une application système.

Pendant un certain temps, j'utilisais la technique décrite ici , mais après avoir constaté que dans mon application, certaines applications ne figuraient pas dans la liste des applications non-système (telles que Facebook, qui demande le système à s’installer sur la carte SD). Après avoir lu la documentation actuelle de ApplicationInfo.FLAG_SYSTEM , et compris qu’il ne filtre pas les applications système, je suis à la recherche d’une nouvelle approche. 

Mon hypothèse est qu'il y a un grand fossé entre les UID du système et les applications non-système que je peux rassembler pour faire cette distinction, mais je n'ai pas encore trouvé de réponse. J'ai également examiné d'autres indicateurs, tels que ApplicationInfo.FLAG_EXTERNAL_STORAGE, mais je supporte l'API 1.5.

Est-ce que quelqu'un a une vraie solution à cela (n'impliquant pas FLAG_SYSTEM)?

31
Phil

Eh bien, c’est à mon avis une solution peu rentable (que se passe-t-il si/data/app n’est pas le répertoire des applications sur tous les appareils?), Mais après une recherche approfondie, voici ce que j’ai trouvé:

for (ApplicationInfo ai : appInfo) {
    if (ai.sourceDir.startsWith("/data/app/")) {
        //Non-system app
    }
    else {
        //System app
    }
}
6
Phil
PackageManager pm = mcontext.getPackageManager();
List<PackageInfo> list = pm.getInstalledPackages(0);

for(PackageInfo pi : list) {
    ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);

    System.out.println(">>>>>>packages is<<<<<<<<" + ai.publicSourceDir);

    if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
        System.out.println(">>>>>>packages is system package"+pi.packageName);          
    }
}
24
Nitin

J'avais l'impression que toutes les applications de l'image système sont des applications système (et sont normalement installées dans /system/app).

Si FLAG_SYSTEM est uniquement défini pour les applications système, cela fonctionnera même pour les applications du stockage externe:

boolean isUserApp(ApplicationInfo ai) {
    int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
    return (ai.flags & mask) == 0;
}

Une alternative consiste à utiliser le programme en ligne de commande pm sur votre téléphone.

Syntaxe:

pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]

pm list packages: prints all packages, optionally only
  those whose package name contains the text in FILTER.  Options:
    -f: see their associated file.
    -d: filter to only show disbled packages.
    -e: filter to only show enabled packages.
    -s: filter to only show system packages.
    -3: filter to only show third party packages.
    -i: see the installer for the packages.
    -u: also include uninstalled packages.

Code:

ProcessBuilder builder = new ProcessBuilder("pm", "list", "packages", "-s");
Process process = builder.start();

InputStream in = process.getInputStream();
Scanner scanner = new Scanner(in);
Pattern pattern = Pattern.compile("^package:.+");
int skip = "package:".length();

Set<String> systemApps = new HashSet<String>();
while (scanner.hasNext(pattern)) {
    String pckg = scanner.next().substring(skip);
    systemApps.add(pckg);
}

scanner.close();
process.destroy();

Ensuite:

boolean isUserApp(String pckg) {
    return !mSystemApps.contains(pckg);
}
23
sergio91pt

Vous pouvez vérifier la signature de l'application qu'il a signée avec le système. Comme ci-dessous 

/**
 * Match signature of application to identify that if it is signed by system
 * or not.
 * 
 * @param packageName
 *            package of application. Can not be blank.
 * @return <code>true</code> if application is signed by system certificate,
 *         otherwise <code>false</code>
 */
public boolean isSystemApp(String packageName) {
    try {
        // Get packageinfo for target application
        PackageInfo targetPkgInfo = mPackageManager.getPackageInfo(
                packageName, PackageManager.GET_SIGNATURES);
        // Get packageinfo for system package
        PackageInfo sys = mPackageManager.getPackageInfo(
                "Android", PackageManager.GET_SIGNATURES);
        // Match both packageinfo for there signatures
        return (targetPkgInfo != null && targetPkgInfo.signatures != null && sys.signatures[0]
                .equals(targetPkgInfo.signatures[0]));
    } catch (PackageManager.NameNotFoundException e) {
        return false;
    }
}

Vous pouvez obtenir plus de code sur mon blog Comment vérifier si l'application est une application système ou non (Par signature signée)} _

15
Pankaj Kumar

Si une application est une application non-système, elle doit avoir une intention de lancement permettant de la lancer. Si l'intention de lancement est nulle, il s'agit d'une application système.

Exemple d'applications système: "com.Android.browser.provider", "com.google.Android.voicesearch". 

Pour les applications ci-dessus, vous obtiendrez NULL lorsque vous demanderez l’intention de lancer.

PackageManager pm = getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for(ApplicationInfo packageInfo:packages){
    if( pm.getLaunchIntentForPackage(packageInfo.packageName) != null ){
                String currAppName = pm.getApplicationLabel(packageInfo).toString();
               //This app is a non-system app
    }
}
5
Darshan Patel

Il y a un peu de malentendu ici. Pour Android, la notion d '"application système" est celle qui est installée sur l'image système, elle ne dit que rien sur le développeur d'origine. Ainsi, si un OEM décide de précharger Facebook sur l'image système, il s'agit d'une application système et le restera, quel que soit l'endroit où les mises à jour de l'application sont installées. Ils ne seront certainement pas installés sur l'image du système, car celle-ci est en lecture seule.

Donc ApplicationInfo.FLAG_SYSTEM est correct, mais cela ne semble pas être la question que vous vous posez. Je pense que vous demandez si un paquet est signé avec le certificat système. Ce qui n’est pas forcément un bon indicateur de tout, cela peut varier d’un appareil à l’autre et certains composants surprenants de Vanilla Android ne sont pas signés avec le certificat système, même si on pouvait s’y attendre.

Dans les versions plus récentes d'Android, il existe un nouveau chemin,/system/priv-app /, qui tente de devenir l'emplacement d'installation des "vraies" applications système. Les applications qui sont simplement préchargées sur l'image système se retrouvent ensuite dans/system/app /. Voir Application AOSP Privileged vs System

5
cyngus

Il existe 2 types d'applications non-système :

  1. Applications téléchargées depuis Google Play Store
  2. Applications préchargées par le fabricant de l'appareil

Ce code renverra une liste de toutes les applications ci-dessus:

ArrayList<ApplicationInfo> mAllApp = 
        mPackageManager.getInstalledApplications(PackageManager.GET_META_DATA);

for(int i = 0; i < mAllApp.size(); i++) {
    if((mAllApp.get(i).flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
         // 1. Applications downloaded from Google Play Store
        mAllApp1.add(mAllApp.get(i));
    }

    if((mAllApp.get(i).flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
        // 2. Applications preloaded in device by manufecturer
        mAllApp1.add(mAllApp.get(i));
    }
}
4
Kushal

Si vous avez un fichier APK et que vous souhaitez vérifier, l’application système ou l’utilisateur est-il installé Une logique simple: -Application système Les fichiers ne sont pas accessibles en écriture

private boolean isSystemApkFile(File file){
   return !file.canWrite();
}
1
Shivam Agrawal

Voici différentes manières possibles de voir si l'application est une application système par son nom de package (utilisé certains des codes de ce message).

package com.test.util;

import Android.content.Context;
import Android.content.pm.ApplicationInfo;
import Android.content.pm.PackageInfo;
import Android.content.pm.PackageManager;
import Android.content.pm.PackageManager.NameNotFoundException;

import Java.io.IOException;
import Java.io.InputStream;
import Java.util.HashSet;
import Java.util.Scanner;
import Java.util.Set;
import Java.util.regex.Pattern;

import timber.log.Timber;


public class SystemAppChecker {
    private PackageManager packageManager = null;

    public SystemAppChecker(Context context) {
        packageManager = context.getPackageManager();
    }

    /**
     * Check if system app by 'pm' command-line program
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is a system app.
     */
    public boolean isSystemAppByPM(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        ProcessBuilder builder = new ProcessBuilder("pm", "list", "packages", "-s");
        Process process = null;
        try {
            process = builder.start();
        } catch (IOException e) {
            Timber.e(e);
            return false;
        }

        InputStream in = process.getInputStream();
        Scanner scanner = new Scanner(in);
        Pattern pattern = Pattern.compile("^package:.+");
        int skip = "package:".length();

        Set<String> systemApps = new HashSet<String>();
        while (scanner.hasNext(pattern)) {
            String pckg = scanner.next().substring(skip);
            systemApps.add(pckg);
        }

        scanner.close();
        process.destroy();

        if (systemApps.contains(packageName)) {
            return true;
        }
        return false;
    }

    /**
     * Check if application is preloaded.
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is preloaded.
     */
    public boolean isSystemPreloaded(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(
                    packageName, 0);
            if (ai.sourceDir.startsWith("/system/app/") || ai.sourceDir.startsWith("/system/priv-app/")) {
                return true;
            }
        } catch (NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }

    /**
     * Check if the app is system signed or not
     *
     * @param packageName
     *            package of application. Cannot be blank.
     * @return <code>true</code> if application is signed by system certificate,
     *         otherwise <code>false</code>
     */
    public boolean isSystemSigned(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            // Get packageinfo for target application
            PackageInfo targetPkgInfo = packageManager.getPackageInfo(
                    packageName, PackageManager.GET_SIGNATURES);
            // Get packageinfo for system package
            PackageInfo sys = packageManager.getPackageInfo(
                    "Android", PackageManager.GET_SIGNATURES);
            // Match both packageinfo for there signatures
            return (targetPkgInfo != null && targetPkgInfo.signatures != null && sys.signatures[0]
                    .equals(targetPkgInfo.signatures[0]));
        } catch (PackageManager.NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }

    /**
     * Check if application is installed in the device's system image
     *
     * @param packageName
     *            package name of application. Cannot be null.
     * @return <code>true</code> if package is a system app.
     */
    public boolean isSystemAppByFLAG(String packageName) {
        if (packageName == null) {
            throw new IllegalArgumentException("Package name cannot be null");
        }
        try {
            ApplicationInfo ai = packageManager.getApplicationInfo(
                    packageName, 0);
            // Check if FLAG_SYSTEM or FLAG_UPDATED_SYSTEM_APP are set.
            if (ai != null
                    && (ai.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
                return true;
            }
        } catch (NameNotFoundException e) {
            Timber.e(e);
        }
        return false;
    }
}
1
Vinayak Bevinakatti
if (!packageInfo.sourceDir.toLowerCase().startsWith("/system/"))
1
MiladCoder

Voici un AppUtil que j'ai écrit à cet effet .
Exemple d'utilisation:

new AppsUtil(this).printInstalledAppPackages(AppsUtil.AppType.USER);

AppsUtil.Java

import Java.util.ArrayList;
import Java.util.List;

import Android.content.Context;
import Android.content.pm.ApplicationInfo;
import Android.content.pm.PackageInfo;
import Android.content.pm.PackageManager;
import Android.content.pm.PackageManager.NameNotFoundException;
import Android.util.Log;

public class AppsUtil
{
    public static final String  TAG = "PackagesInfo";
    private Context             _context;
    private ArrayList<PckgInfo> _PckgInfoList;

    public enum AppType 
    {
        ALL {
            @Override
            public String toString() {
              return "ALL";
            }
          },
        USER {
            @Override
            public String toString() {
              return "USER";
            }
          },
        SYSTEM {
            @Override
            public String toString() {
              return "SYSTEM";
            }
          }
    }

    class PckgInfo
    {
        private AppType appType;
        private String  appName     = "";
        private String  packageName = "";
        private String  versionName = "";
        private int     versionCode = 0;

        private void prettyPrint()
        {
            Log.i(TAG, appName + "\n  AppType: " + appType.toString() + "\n  Package: " + packageName + "\n  VersionName: " + versionName + "\n  VersionCode: " + versionCode);
        }
    }

    public AppsUtil(Context context)
    {
        super();
        this._context = context;
        this._PckgInfoList = new ArrayList<PckgInfo>();
    }

    public void printInstalledAppPackages(AppType appType)
    {
        retrieveInstalledAppsPackages();
        Log.i(TAG, "");
        for (int i = 0; i < _PckgInfoList.size(); i++)
        {
            if (AppType.ALL == appType)
            {
                _PckgInfoList.get(i).prettyPrint();
            }
            else
            {
                if (_PckgInfoList.get(i).appType == appType)
                    _PckgInfoList.get(i).prettyPrint();
            }
        }
    }

    public ArrayList<PckgInfo> getInstalledAppPackages(AppType appType)
    {
        retrieveInstalledAppsPackages();
        ArrayList<PckgInfo> resultPInfoList = new ArrayList<PckgInfo>();

        if (AppType.ALL == appType)
        {
            return _PckgInfoList;
        }
        else
        {
            for (int i = 0; i < _PckgInfoList.size(); i++)
            {
                if (_PckgInfoList.get(i).appType == appType)
                    resultPInfoList.add(_PckgInfoList.get(i));
            }
            return resultPInfoList;
        }
    }

    private void retrieveInstalledAppsPackages()
    {
        PackageManager pm = _context.getPackageManager();
        List<PackageInfo> packs = pm.getInstalledPackages(0);
        for (PackageInfo pi : packs)
        {
            try
            {
                PckgInfo newInfo = new PckgInfo();
                ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);

                newInfo.appType = getAppType(ai);
                newInfo.appName = pi.applicationInfo.loadLabel(pm).toString();
                newInfo.packageName = pi.packageName;
                newInfo.versionName = pi.versionName;
                newInfo.versionCode = pi.versionCode;
                _PckgInfoList.add(newInfo);
            }
            catch (NameNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    }

    AppType getAppType(ApplicationInfo ai)
    {
        AppType resultType ;
        if (isUserApp(ai))
            resultType = AppType.USER;
        else
            resultType = AppType.SYSTEM;

        return resultType;
    }

    boolean isUserApp(ApplicationInfo ai)
    {
        int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
        return (ai.flags & mask) == 0;
    }
}
0
AivarsDa