packageManager.getInstalledApplications(0) でApplicationInfo
オブジェクトのリストを取得し、それらがシステムアプリケーションかどうかで分類しようとしています。
しばらくの間、ここで説明した手法を使用していました、ただし、アプリケーションでそれを確認した後、一部のアプリが非システムアプリリストにありませんでした(- Facebook。使用可能な場合、システムにSDカードへのインストールを要求します)。次に ApplicationInfo.FLAG_SYSTEM の実際のドキュメントを読み、実際にシステムアプリをフィルター処理しないことを理解した後、新しいアプローチを探しています。
私の推測では、システムのUIDとシステム以外のアプリのUIDの間に大きなギャップがあり、これを区別するために集めることができますが、現時点ではまだ答えが見つかりません。 ApplicationInfo.FLAG_EXTERNAL_STORAGE
などの他のフラグも調べましたが、API 1.5をサポートしています。
誰もこれに本当の解決策を持っていますか(FLAG_SYSTEM
を含まない)?
まあ、それは私の意見ではずさんなソリューションです(/ data/appがすべてのデバイスのアプリディレクトリではない場合はどうなりますか?)
for (ApplicationInfo ai : appInfo) {
if (ai.sourceDir.startsWith("/data/app/")) {
//Non-system app
}
else {
//System app
}
}
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);
}
}
システムイメージ内のすべてのアプリはシステムアプリであるという印象を受けました(通常は/system/app
)。
FLAG_SYSTEM
はシステムアプリケーションにのみ設定されます。これは外部ストレージのアプリでも機能します。
boolean isUserApp(ApplicationInfo ai) {
int mask = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
return (ai.flags & mask) == 0;
}
別の方法は、電話機でpm
コマンドラインプログラムを使用することです。
構文:
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.
コード:
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();
次に:
boolean isUserApp(String pckg) {
return !mSystemApps.contains(pckg);
}
システムで署名したアプリケーションの署名を確認できます。以下のように
/**
* 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;
}
}
私のブログでより多くのコードを入手できます アプリケーションがシステムアプリかどうかを確認する方法(署名付き署名による)
アプリケーションがシステム以外のアプリケーションである場合、それを起動できる起動インテントが必要です。起動インテントがnullの場合、システムアプリです。
システムアプリの例:「com.Android.browser.provider」、「com.google.Android.voicesearch」。
上記のアプリの場合、Intentの起動をクエリするとNULLになります。
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
}
}
ここには少し誤解があります。 Android「システムアプリ」の概念は、システムイメージにインストールされるものであり、nothingと言うしたがって、OEMがFacebookをシステムイメージにプリロードすることを決定した場合、それはシステムアプリであり、アプリの更新プログラムがインストールされる場所に関係なく、引き続きインストールされます。確かに、システムイメージは読み取り専用です。
したがって、ApplicationInfo.FLAG_SYSTEMは正しいですが、それはあなたが尋ねている質問ではないようです。パッケージがシステム証明書で署名されているかどうかを尋ねていると思います。これは必ずしも良い指標ではありません。これはデバイスごとに異なる可能性があり、Vanillaのいくつかの驚くべきコンポーネントAndroidはシステム証明書で署名されていません。
Androidの新しいバージョンでは、「実際の」システムアプリのインストール場所を試みる新しいパス/ system/priv-app /があります。システムイメージは/ system/app /になります AOSP Privileged vs System app を参照してください
非システムアプリケーションには2つのタイプがあります:
このコードは、上記のすべてのアプリケーションのリストを返します。
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));
}
}
アプリがパッケージ名でシステムアプリかどうかを確認するさまざまな方法を次に示します(この投稿のコードの一部を使用)
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;
}
}
APKファイルがあり、確認したい場合は、システムアプリまたはユーザーがインストールしたシンプルロジック:-システムアプリファイルは書き込み不可
private boolean isSystemApkFile(File file){
return !file.canWrite();
}
if (!packageInfo.sourceDir.toLowerCase().startsWith("/system/"))
これは、ここにリストされている他の応答の簡略化されたより効率的なバージョンです。 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
}
}
以下は、そのために書いたAppUtilです。
使用例:
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;
}
}