¿Cómo puedo verificar si una aplicación no es una aplicación de sistema en Android?

Obtengo una lista de objetos de ApplicationInfo con packageManager.getInstalledApplications (0) y trato de clasificarlos según sean o no una aplicación del sistema.

Durante un tiempo he estado usando la técnica descrita aquí , sin embargo, después de ver que en mi aplicación, algunas aplicaciones no estaban en la lista de aplicaciones que no son del sistema (como Facebook , que cuando está disponible le pide al sistema que se instale en SD tarjeta). Después de leer la documentación actual de ApplicationInfo.FLAG_SYSTEM , y de entender que no filtra las aplicaciones del sistema, ahora estoy buscando un nuevo enfoque.

Supongo que hay una gran brecha entre los UID del sistema y las aplicaciones que no son del sistema que puedo reunir para hacer esta distinción, pero hasta ahora no he encontrado una respuesta. También busqué otras banderas, como ApplicationInfo.FLAG_EXTERNAL_STORAGE , sin embargo, apoyo API 1.5.

¿Alguien tiene una solución real para esto (sin involucrar a FLAG_SYSTEM )?

 PackageManager pm = mcontext.getPackageManager(); List 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); } } 

Tenía la impresión de que todas las aplicaciones en la imagen del sistema son aplicaciones del sistema (y normalmente están instaladas en /system/app ).

Si FLAG_SYSTEM solo está configurado para aplicaciones del sistema, esto funcionará incluso para aplicaciones en almacenamiento externo:

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

Una alternativa es usar el progtwig de línea de comandos pm en su teléfono.

Sintaxis:

 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. 

Código:

 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 systemApps = new HashSet(); while (scanner.hasNext(pattern)) { String pckg = scanner.next().substring(skip); systemApps.add(pckg); } scanner.close(); process.destroy(); 

Entonces:

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

Puede verificar la firma de la aplicación que firmó con el sistema. Como abajo

 /** * 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 true if application is signed by system certificate, * otherwise false */ 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; } } 

Puedes obtener más código en mi blog Cómo verificar si la aplicación es una aplicación de sistema o no (Por firma firmada)

Bueno, en mi opinión, es una solución descuidada (¿y si / data / app no es el directorio de aplicaciones en todos los dispositivos?), Pero después de una búsqueda exhaustiva, esto es lo que se me ocurrió:

 for (ApplicationInfo ai : appInfo) { if (ai.sourceDir.startsWith("/data/app/")) { //Non-system app } else { //System app } } 

Si una Aplicación es una aplicación que no pertenece al sistema, debe tener un Intento de lanzamiento para poder lanzarla. Si el bash de lanzamiento es nulo, entonces es una aplicación del sistema.

Ejemplo de aplicaciones del sistema: “com.android.browser.provider”, “com.google.android.voicesearch”.

Para las aplicaciones anteriores, obtendrá NULL cuando realice una consulta para ejecutar Intent.

 PackageManager pm = getPackageManager(); List 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 } } 

Hay un poco de malentendido aquí. Para Android, la noción de una “aplicación de sistema” es aquella que se instala en la imagen del sistema, no dice nada sobre de qué desarrollador proviene. Por lo tanto, si un OEM decide precargar Facebook en la imagen del sistema, es una aplicación del sistema y seguirá siéndolo, independientemente de dónde se instalen las actualizaciones de la aplicación. No se instalarán en la imagen del sistema, seguro, porque es de solo lectura.

Entonces ApplicationInfo.FLAG_SYSTEM es correcto, pero esa no parece ser la pregunta que está haciendo. Creo que estás preguntando si un paquete está firmado con el certificado del sistema. Lo cual no es necesariamente un buen indicador de nada, esto puede variar de un dispositivo a otro y algunos componentes sorprendentes en Android vanilla no están firmados con el certificado del sistema, aunque es de esperar que lo sean.

En las versiones más nuevas de Android, hay una nueva ruta, / system / priv-app / que intenta ser la ubicación de instalación de las aplicaciones del sistema “reales”. Las aplicaciones que están precargadas en la imagen del sistema terminan en / system / app /. Vea la aplicación AOSP Privileged vs System

 if (!packageInfo.sourceDir.toLowerCase().startsWith("/system/")) 

Hay 2 tipos de aplicaciones que no son del sistema :

  1. Aplicaciones descargadas de Google Play Store
  2. Aplicaciones precargadas en el dispositivo por manufecturer

A continuación, el código mostrará la lista de todas las aplicaciones anteriores:

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

Si tiene un archivo APK y quiere verificar, ¿es la aplicación del sistema o el usuario instalado una lógica simple: – Aplicación del sistema Los archivos no se pueden escribir

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

Aquí hay un AppUtil que escribí para ese propósito.
Ejemplo de uso:

 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 _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(); } 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 getInstalledAppPackages(AppType appType) { retrieveInstalledAppsPackages(); ArrayList resultPInfoList = new ArrayList(); 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 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; } } 

Aquí hay diferentes formas posibles de ver si la aplicación es una aplicación del sistema por su nombre de paquete (usó algunos de los códigos en esta publicación)

 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 true 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 systemApps = new HashSet(); 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 true 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 true if application is signed by system certificate, * otherwise false */ 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 true 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; } }