Comment puis-je vérifier si une application est une application non-système dans Android?
je reçois une liste d'objets ApplicationInfo
avec packageManager.gettinstalledapplications (0) et tenter de les catégoriser selon qu'il s'agit ou non d'une application système.
pendant un certain temps, j'ai utilisé la technique décrite ici , mais après avoir vu que dans mon application, certaines des applications n'étaient pas dans la liste des applications non-système (comme Facebook , qui lorsque disponible demande au système de s'installer sur la carte SD). Après la lecture suivante la documentation réelle pour ApplicationInfo.FLAG_SYSTEM , et en comprenant qu'il ne filtre pas réellement les applications système, je suis maintenant à la recherche d'une nouvelle approche.
à mon avis, il y a un grand écart entre les uid des applications système et non-système que je peux comprendre pour faire cette distinction, mais pour l'instant je n'ai pas trouvé de réponse. J'ai aussi regardé dans d'autres indicateurs, comme ApplicationInfo.FLAG_EXTERNAL_STORAGE
, cependant je supporte L'API 1.5.
est-ce que quelqu'un a une VRAIE solution à cela (n'impliquant pas FLAG_SYSTEM
)?
11 réponses
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);
}
}
j'avais l'impression que toutes les applications de l'image système étaient des applications système (et normalement installées dans /system/app
).
si FLAG_SYSTEM
n'est défini que pour les applications système, cela fonctionnera même pour les applications en stockage externe:
boolean isUserApp(ApplicationInfo ai) {
int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
return (ai.flags & mask) == 0;
}
une alternative est d'utiliser le programme de ligne de commande pm
dans 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();
puis:
boolean isUserApp(String pckg) {
return !mSystemApps.contains(pckg);
}
vous pouvez vérifier la signature de la demande qu'il a signé 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 faire pour vérifier si l'application est le système d'application ou non (En signature)
Eh bien, c'est une solution bâclée à mon avis (et si /data/app n'est pas le répertoire apps sur tous les appareils?), mais après une recherche approfondie, c'est ce que j'ai trouvé:
for (ApplicationInfo ai : appInfo) {
if (ai.sourceDir.startsWith("/data/app/")) {
//Non-system app
}
else {
//System app
}
}
si une Application est une application non-système, elle doit avoir une intention de lancement par laquelle elle peut être lancée. Si l'intention de lancement est nul, alors c'est une application système.
exemple D'applications système: "com.Android.navigateur.fournisseur", "com.Google.Android.voicesearch".
pour les applications ci-dessus, vous obtiendrez NULL lorsque vous interrogez pour l'intention de lancement.
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
}
}
il y a un petit malentendu ici. Pour Android, la notion d'une" application système "est celui qui est installé sur l'image du système, il est dit rien sur ce développeur d'où il vient. Donc, si un OEM décide de précharger Facebook sur L'image du système, il s'agit d'une application système et il le restera, quel que soit l'endroit où les mises à jour de L'application seront installées. Ils ne seront pas installés sur l'image du système, bien sûr, parce qu'il est en lecture seule.
So ApplicationInfo.FLAG_SYSTEM est correct, mais ce n'est pas la question que vous posez. Je pense que vous demandez si un paquet est signé avec le certificat du système. Ce qui n'est pas nécessairement un bon indicateur de quoi que ce soit, cela peut varier d'un appareil à l'autre et certains composants surprenants sur vanilla Android ne sont pas signés avec le certificat de système, même si vous pouvez vous attendre à ce qu'ils soient.
dans les nouvelles versions D'Android il ya un nouveau chemin, / system / priv-app/ qui tente d'être l'emplacement d'installation pour système "réel" des applications. Les applications qui sont simplement pré-chargées sur l'image système finissent alors dans /system/app/. Voir PSBA Privilégié vs app Système
il y a 2 types de Non - système applications:
- applications téléchargées à partir de Google Play Store
- applications préchargées par le fabricant de l'appareil
ce code retournera une liste de toutes les demandes 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));
}
}
if (!packageInfo.sourceDir.toLowerCase().startsWith("/system/"))
si vous avez un fichier APK et que vous voulez vérifier si l'application système ou L'utilisateur est installé une logique Simple:- les fichiers app système ne sont pas inscriptibles
private boolean isSystemApkFile(File file){
return !file.canWrite();
}
voici un article que j'ai écrit dans ce but.
exemple D'Usage:
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;
}
}
Voici différentes manières de voir si l'application est un système d'application par son nom (utilisé certains des codes dans ce 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;
}
}