How do I check if an app is a non-system app in Android?

后端 未结 13 1185
无人共我
无人共我 2020-11-28 22:51

I am getting a list of ApplicationInfo Objects with packageManager.getInstalledApplications(0) and attempting to categorize them by whether or not they are a sy

相关标签:
13条回答
  • 2020-11-28 23:15

    Here are different possible ways to see if the app is a system app by its package name (used some of the codes in this post)

    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;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 23:16

    There are 2 type of Non - system applications :

    1. Apps downloaded from Google Play Store
    2. Preloaded apps by device manufacturer

    This code will return a list of all above applications:

    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));
        }
    }
    
    0 讨论(0)
  • 2020-11-28 23:17

    I was under the impression that all apps in the system image are system apps (and normally installed in /system/app).

    If FLAG_SYSTEM is only set to system applications, this will work even for apps in external storage:

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

    An alternative is to use the pm command-line program in your phone.

    Syntax:

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

    Then:

    boolean isUserApp(String pckg) {
        return !mSystemApps.contains(pckg);
    }
    
    0 讨论(0)
  • 2020-11-28 23:17

    This is a simplified and more efficient version of other responses listed here. It is more efficient if you just iterate directly over the ApplicationInfos.

        List<ApplicationInfo> applications = context.getPackageManager()
                .getInstalledApplications(PackageManager.GET_META_DATA);
        for(ApplicationInfo appInfo : applications){
            if((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0){
                // Not a system app
            }
        }
    
    0 讨论(0)
  • 2020-11-28 23:19

    Here is an AppUtil I wrote for that purpose.
    Usage example:

    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 讨论(0)
  • 2020-11-28 23:22

    You can check the signature of application which it signed with system. Like below

    /**
     * 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;
        }
    }
    

    You can get more code on my blog How to check if application is system app or not (By signed signature)

    0 讨论(0)
提交回复
热议问题