android.content.pm.PackageManager
用于检索与设备上当前安装的应用程序包相关的各种信息的类。
要获取应用相关的信息,都用到它。
通过 Context#getPackageManager 实例化。
获取所有已安装的应用,
private void getAllInstallApp() {
List list = getPackageManager().getInstalledPackages(0);
if (null != list && list.size() > 0) {
Log.d(TAG, " getAllInstallApp -- list.size() : " + list.size());
for (PackageInfo p : list) {
Log.d(TAG, "getAllInstallApp -- p.packageName : " + p.packageName);
}
}
}
这样写,AS 报黄
As of Android 11, this method no longer returns information about all apps; see https://g.co/dev/packagevisibility for details
Android R(11) 上获取到的应用数量也不全,adb shell pm list package 结果有 189 个,这样获取到的是 74 个(包括系统应用和自己,但不包括安装的第三方应用)。
在注册文件 AndroidManifest.xml 里添加
后,获取到 189 个了。涉及用户隐私,慎用!!
AS 也报黄
A declaration should generally be used instead of QUERY_ALL_PACKAGES; see https://g.co/dev/packagevisibility for details
最终写法:
;queries
标签,填入需要查询的包名。
这样就获取到 77 个了(原来的74个 加上 queries里的 3 个)。
可以通过 获取已安装应用列表,然后过滤包名判断,
也就可以直接判断,
private boolean isPkgInstall(String pkgName){
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return false;
}
PackageInfo packageInfo = null;
try {
packageInfo = getPackageManager().getPackageInfo(pkgName, 0);
if (null != packageInfo) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return false;
}
private boolean isSystemApp(String pkgName) {
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return false;
}
try {
PackageInfo info = getPackageManager().getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return false;
}
private boolean isPersistApp(String pkgName) {
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return false;
}
try {
PackageInfo info = getPackageManager().getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
if ((info.applicationInfo.flags &
(ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) ==
(ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT)) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return false;
}
通过 PackageInfo
拿到,
代码 | 说明 |
---|---|
packageInfo.applicationInfo.loadLabel(PackageManager pm) | 应用名称 ,对应 AndroidManifest.xml 里的 android:label |
packageInfo.applicationInfo.loadIcon(PackageManager pm) | Drawable 类型的应用图标 |
packageInfo.packageName | 包名,如 com.android.settings |
packageInfo.versionName | 版本,如 1.0 |
packageInfo.sharedUserId | 对应 AndroidManifest.xml 里的 android:sharedUserId , Setings 的是 android.uid.system , Bluetooth 的是 com.android.bluetooth , 自己写的 Demo 未添加 android:sharedUserId 标签获取到的是 null |
packageInfo.sharedUserLabel | 获取到的是 0 |
packageInfo.lastUpdateTime | 上次更新时间,是 System.currentTimeMillis() 形式的 |
代码示例,
private void getPkgInfo(String pkgName){
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return;
}
PackageInfo packageInfo = null;
PackageManager packageManager = getPackageManager();
try {
packageInfo = packageManager.getPackageInfo(pkgName, 0);
if (null != packageInfo) {
String label = (String) packageInfo.applicationInfo.loadLabel(packageManager);
Drawable icon = (Drawable) packageInfo.applicationInfo.loadIcon(packageManager);
String strPName = packageInfo.packageName;
String strVersionName = packageInfo.versionName;
String sharedUserId = packageInfo.sharedUserId;
int sharedUserLabel = packageInfo.sharedUserLabel;
long uTime = packageInfo.lastUpdateTime;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
通过 PackageInfo
获取。
注意,实例化 PackageInfo 时传入的参数是 PackageManager.GET_PERMISSIONS
。
private void getPkgPermissionInfo(String pkgName){
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return;
}
PackageInfo pInfo = null;
PackageManager packageManager = getPackageManager();
try {
pInfo = packageManager.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS);
if (null != pInfo) {
String[] permissions = pInfo.requestedPermissions;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
打印出的结果就是注册文件 AndroidManifest.xml 里声明的,如
android.permission.WAKE_LOCK 、android.permission.READ_EXTERNAL_STORAGE 、android.permission.WRITE_EXTERNAL_STORAGE 等,
模拟器测试,这三个权限我没申请也有 ,
android.permission.ACCESS_NETWORK_STATE
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.FOREGROUND_SERVICE
通过 PackageInfo
获取。
注意,实例化 PackageInfo 时传入的参数是 PackageManager.GET_SIGNATURES
。
try {
PackageInfo info = getPackageManager().getPackageInfo("com.android.settings", PackageManager.GET_SIGNATURES);
Signature[] signatures = info.signatures;
String str = signatures[0].toString();
} catch (Exception e){
e.printStackTrace();
}
str 输出为 :android.content.pm.Signature@b2d95fc0
通过 PackageInfo
获取。
注意,实例化 PackageInfo 时传入的参数是 PackageManager.GET_SIGNATURES
。
获取方法是一样的,只是初始化 MessageDigest
时传的值不同,
/**
* 获取 MD5 、SHA1 、SHA256
* @param algorithm : 只能是 MD5 、SHA1 、SHA256
* 返回值是这种形式:22:13:F1:91:ED:BC:92:E7:44:1B:34:9E:45:90:AB:76
* */
private String getAppSignatureAlgorithm(String pkgName, String algorithm){
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return null;
}
try {
PackageInfo info = getPackageManager().getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
Signature[] signatures = info.signatures;
byte[] signBytes = signatures[0].toByteArray();
MessageDigest mDigest = MessageDigest.getInstance(algorithm);
byte[] bytesMd5 = mDigest.digest(signBytes);
StringBuilder builder = new StringBuilder();
for (byte b : bytesMd5) {
builder.append(String.format("%02X", b)).append(":");// byte 转 16 进制
}
builder.replace(builder.length()-1, builder.length(),"");// 删除最后的 :
return builder.toString();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
使用示例,
String PKG_SETTINGS = "com.android.settings";
String sMd5 = getAppSignatureAlgorithm(PKG_SETTINGS, "MD5");
String sSha1 = getAppSignatureAlgorithm(PKG_SETTINGS, "SHA1");
String sSha256 = getAppSignatureAlgorithm(PKG_SETTINGS, "SHA256");
结果可以参考 AndroidStudio查看apk签名信息_android studio查看apk签名版本-CSDN博客 验证
使用 checkSignatures
方法,源码注释,
/**
* Compare the signatures of two packages to determine if the same
* signature appears in both of them. If they do contain the same
* signature, then they are allowed special privileges when working
* with each other: they can share the same user-id, run instrumentation
* against each other, etc.
*
* @param packageName1 First package name whose signature will be compared.
* @param packageName2 Second package name whose signature will be compared.
*
* @return Returns an integer indicating whether all signatures on the
* two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
* all signatures match or < 0 if there is not a match ({@link
* #SIGNATURE_NO_MATCH} or {@link #SIGNATURE_UNKNOWN_PACKAGE}).
*
* @see #checkSignatures(int, int)
*/
@CheckResult
@SignatureResult
public abstract int checkSignatures(@NonNull String packageName1,
@NonNull String packageName2);
示例,
int ret = getPackageManager().checkSignatures("com.android.settings","com.test.luodemo");// -3
int ret1 = getPackageManager().checkSignatures("com.android.settings", "com.android.bluetooth");// 0
ret = -3 ,对应 PackageManager.SIGNATURE_NO_MATCH 。
ret1 = 0 ,对应 PackageManager.SIGNATURE_MATCH 。
看 PackageInfo
源码,获取四大组件需要传对应的 flag ,
/**
* Array of all {@link android.R.styleable#AndroidManifestActivity
* <activity>} tags included under <application>,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_ACTIVITIES} was set.
*/
public ActivityInfo[] activities;
/**
* Array of all {@link android.R.styleable#AndroidManifestReceiver
* <receiver>} tags included under <application>,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_RECEIVERS} was set.
*/
public ActivityInfo[] receivers;
/**
* Array of all {@link android.R.styleable#AndroidManifestService
* <service>} tags included under <application>,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_SERVICES} was set.
*/
public ServiceInfo[] services;
/**
* Array of all {@link android.R.styleable#AndroidManifestProvider
* <provider>} tags included under <application>,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PROVIDERS} was set.
*/
public ProviderInfo[] providers;
示例代码,
本例只是拿到 name ,所以用 ComponentInfo
,
要拿到启动模式(launchMode)等信息,还是用 ActivityInfo
、ServiceInfo
、ProviderInfo
。
/**
* @param type : 0 activity , 1 service , 2 provider , 3 receiver
* */
private void getPkgComponent(String pkgName, int type){
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return;
}
PackageInfo pInfo = null;
PackageManager packageManager = getPackageManager();
try {
switch (type){
case 1:
pInfo = packageManager.getPackageInfo(pkgName, PackageManager.GET_SERVICES);
break;
case 2:
pInfo = packageManager.getPackageInfo(pkgName, PackageManager.GET_PROVIDERS);
break;
case 3:
pInfo = packageManager.getPackageInfo(pkgName, PackageManager.GET_RECEIVERS);
break;
case 0:
default:
pInfo = packageManager.getPackageInfo(pkgName, PackageManager.GET_ACTIVITIES);break;
}
if (null != pInfo) {
ComponentInfo[] componentInfos = null;
switch (type){
case 1:
componentInfos = pInfo.services;
break;
case 2:
componentInfos = pInfo.providers;
break;
case 3:
componentInfos = pInfo.receivers;
break;
case 0:
default:
componentInfos = pInfo.activities;
break;
}
if (null != componentInfos && componentInfos.length > 0) {
Log.d(TAG, "getPkgComponent -- componentInfos.length : " + componentInfos.length);
for (ComponentInfo info : componentInfos) {
Log.d(TAG , "getPkgComponent -- info : " + info.name);
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
输出结果是这样的 :
com.test.luodemo.packagemanager.PackageManagerTestActivity
com.test.luodemo.alarmtest.MyIntentService
com.test.luodemo.alarmtest.MyWakefulReceiver
com.test.luodemo.provider.LContentProvider
PackageManager.deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer)
源码说明,
/**
* Attempts to delete the cache files associated with an application.
* Since this may take a little while, the result will
* be posted back to the given observer. A deletion will fail if the calling context
* lacks the {@link android.Manifest.permission#DELETE_CACHE_FILES} permission, if the
* named package cannot be found, or if the named package is a "system package".
*
* @param packageName The name of the package to delete
* @param observer An observer callback to get notified when the cache file deletion
* is complete.
* {@link android.content.pm.IPackageDataObserver#onRemoveCompleted(String, boolean)}
* will be called when that happens. observer may be null to indicate that
* no callback is desired.
*
* @hide
*/
@SuppressWarnings("HiddenAbstractMethod")
@UnsupportedAppUsage
public abstract void deleteApplicationCacheFiles(@NonNull String packageName,
@Nullable IPackageDataObserver observer);
这个方法使用由限制:
使用方法:
public void clearCache() {
mMetricsFeatureProvider.action(getContext(), MetricsEvent.ACTION_SETTINGS_CLEAR_APP_CACHE);
mClearCachePreference.setClearingCache(true);
mPackageManager.deleteApplicationCacheFiles(mEntry.info.packageName,
new IPackageDataObserver.Stub() {
public void onRemoveCompleted(final String packageName,
final boolean succeeded) {
mHandler.post(new Runnable() {
@Override
public void run() {
mClearCachePreference.setClearingCache(false);
cacheCleared(succeeded);
}
});
}
});
mClearCachePreference.refresh();
}
compileOnly files('libs/framework.jar')
反射调用,mark 下反射的写法
private final IPackageDataObserver iPackageDataObserver = new IPackageDataObserver.Stub() {
@Override
public void onRemoveCompleted(String packageName, boolean isSucceed) throws RemoteException {
}
};
private void clearPkgCacheData(String pkgName){
if (null == pkgName || TextUtils.isEmpty(pkgName)) {
return;
}
PackageManager packageManager = getPackageManager();
Class> classPm = null;
try {
classPm = Class.forName("android.content.pm.PackageManager");
Method method = classPm.getDeclaredMethod("deleteApplicationCacheFiles", String.class, IPackageDataObserver.class);
method.setAccessible(true);
method.invoke(packageManager, pkgName, iPackageDataObserver);
} catch (Exception e) {
e.printStackTrace();
}
}
不是系统应用,反射可以调用到,但是会报错,
Caused by: java.lang.SecurityException: Neither user 10156 nor current process has
android.permission.INTERNAL_DELETE_CACHE_FILES.
设置为系统应用就可以了。