我正在试图弄清楚如何获得已安装应用的大小
什么已经失败:
- new File('/data/app/some.apk')
- 报告尺寸不正确
- PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer)
- @hide
并依赖于一些模糊IPackageStatsObserver
的结果,因此我无法通过反思来调用它。
答案 0 :(得分:27)
不幸的是,目前有no官方way来做这件事。但是,如果您将PackageManager
和getPackageSize
AIDL导入我们的项目并生成存根,可以调用PackageStats
的隐藏IPackageStatsObserver
方法。然后,您可以使用反射来调用getPackageSize
:
PackageManager pm = getPackageManager();
Method getPackageSizeInfo = pm.getClass().getMethod(
"getPackageSizeInfo", String.class, IPackageStatsObserver.class);
getPackageSizeInfo.invoke(pm, "com.android.mms",
new IPackageStatsObserver.Stub() {
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
Log.i(TAG, "codeSize: " + pStats.codeSize);
}
});
对于公共应用程序来说,这显然是大黑客和should not be used。
答案 1 :(得分:18)
您可以通过获取apk文件的路径并检查其长度来简化:
final PackageManager pm = context.getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(appInfo.getPackage(), 0);
File file = new File(applicationInfo.publicSourceDir);
int size = file.length();
答案 2 :(得分:5)
以下是@Josef Pfleger的补充答案,以供评论
“我发现某些设备没有getPackageSizeInfo()然后你得到这个java.lang.NoSuchMethodException:getPackageSizeInfo()”@ ATom 11月29日11:15。
在api 16(Build.VERSION.SDK_INT> 16)之后,方法
PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer);
改为:
PackageManager.getPackageSizeInfo(String packageName, int userHandle, IPackageStatsObserver observer);
新添加的参数userHandle
的解释是:应该检索其大小信息的用户。
所以我们应该这样做:
int sysVersion= Build.VERSION.SDK_INT;
if (pkgName != null) {// packageName
PackageManager pm = getPackageManager();
try {
Class<?> clz = pm.getClass();
if (sysVersion>16) {
Method myUserId=UserHandle.class.getDeclaredMethod("myUserId");//ignore check this when u set ur min SDK < 17
int userID = (Integer) myUserId.invoke(pm);
Method getPackageSizeInfo = clz.getDeclaredMethod(
"getPackageSizeInfo", String.class,int.class,
IPackageStatsObserver.class);//remember add int.class into the params
getPackageSizeInfo.invoke(pm,pkgName, userID, new PkgSizeObserver());
} else {//for old API
Method getPackageSizeInfo = clz.getDeclaredMethod(
"getPackageSizeInfo", String.class,
IPackageStatsObserver.class);
getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver());
}
} catch (Exception ex) {
Log.e(TAG, "NoSuchMethodException");
ex.printStackTrace();
throw ex;}
该类需要回调,如:
private class PkgSizeObserver extends IPackageStatsObserver.Stub {
/***
* @param pStatus
* @param succeeded
*/
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
cachesize = pStats.cacheSize;//remember to declare these fields
datasize = pStats.dataSize;
codesize = pStats.codeSize;
totalsize = cachesize + datasize + codesize;
Log.i("123","cachesize--->" + cachesize + " datasize---->"
+ datasize + " codeSize---->" + codesize);
}
}
使用此方法解析long2string,然后您可以看到xx MB
而非long
,如2342334:)
private String formateFileSize(long size) {
return Formatter.formatFileSize(MainActivity.this, size);
}
答案 3 :(得分:3)
记住所需的权限,我通过向清单添加以下权限来解决这些问题:
< uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
或者错误:不使用getDeclaredMethod()
,应该使用getMethod()
。
Method getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
答案 4 :(得分:0)
您可以获取没有AIDL文件的应用大小 -----------> Kotlin语言
arr.forEach(a=>{
console.log(Object.keys(a))
console.log(arr.filter(ar=>ar.hasOwnProperty(Object.keys(a)[0])))
})
记住要以字节为单位将其转换为MB
答案 5 :(得分:-2)
package inc.xiomi.apkextrator.entity;
import android.annotation.SuppressLint;
import android.content.ComponentName;
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.content.pm.PackageStats;
import android.content.pm.ResolveInfo;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.concurrent.Semaphore;
public class AppInfo implements Comparable<Object> {
private Context ctx;
private ResolveInfo ri;
private ComponentName componentName = null;
private PackageInfo pi = null;
private Drawable icon = null;
String size = null;
String name = null;
// Code size will be here
long codeSize = 0;
PackageManager packageManager;
// Semaphore to handle concurrency
Semaphore codeSizeSemaphore = new Semaphore(1, true);
public AppInfo(Context ctx, ResolveInfo ri) {
this.ctx = ctx;
this.ri = ri;
packageManager = ctx.getPackageManager();
this.componentName = new ComponentName(ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name);
try {
pi = ctx.getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (NameNotFoundException e) {
}
}
public String getName() {
if (name != null) {
return name;
} else {
try {
return getNameFromResolveInfo(ri);
} catch (NameNotFoundException e) {
return getPackageName();
}
}
}
public String getSize() {
if (size != null) {
return size;
} else {
try {
return getSizeFromResolveInfo(ri);
} catch (Exception e) {
return getPackageName();
}
}
}
public String getActivityName() {
return ri.activityInfo.name;
}
public String getPackageName() {
return ri.activityInfo.packageName;
}
public ComponentName getComponentName() {
return componentName;
}
public String getComponentInfo() {
if (getComponentName() != null) {
return getComponentName().toString();
} else {
return "";
}
}
public ResolveInfo getResolveInfo() {
return ri;
}
public PackageInfo getPackageInfo() {
return pi;
}
public String getVersionName() {
PackageInfo pi = getPackageInfo();
if (pi != null) {
return pi.versionName;
} else {
return "";
}
}
public int getVersionCode() {
PackageInfo pi = getPackageInfo();
if (pi != null) {
return pi.versionCode;
} else {
return 0;
}
}
public Drawable getIcon() {
if (icon == null) {
icon = getResolveInfo().loadIcon(ctx.getPackageManager());
/*
Drawable dr = getResolveInfo().loadIcon(ctx.getPackageManager());
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
icon = new BitmapDrawable(ctx.getResources(), AppHelper.getResizedBitmap(bitmap, 144, 144));
*/
}
return icon;
}
@SuppressLint("NewApi")
public long getFirstInstallTime() {
PackageInfo pi = getPackageInfo();
if (pi != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
return pi.firstInstallTime;
} else {
return 0;
}
}
@SuppressLint("NewApi")
public long getLastUpdateTime() {
PackageInfo pi = getPackageInfo();
if (pi != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
return pi.lastUpdateTime;
} else {
return 0;
}
}
@Override
public int compareTo(Object o) {
AppInfo f = (AppInfo) o;
return getName().compareTo(f.getName());
}
@Override
public String toString() {
return getName();
}
/**
* Helper method to get an applications name!
*
* @param ri
* @return
* @throws android.content.pm.PackageManager.NameNotFoundException
*/
public String getNameFromResolveInfo(ResolveInfo ri) throws NameNotFoundException {
String name = ri.resolvePackageName;
if (ri.activityInfo != null) {
Resources res = ctx.getPackageManager().getResourcesForApplication(ri.activityInfo.applicationInfo);
Resources engRes = getEnglishRessources(res);
if (ri.activityInfo.labelRes != 0) {
name = engRes.getString(ri.activityInfo.labelRes);
if (name == null || name.equals("")) {
name = res.getString(ri.activityInfo.labelRes);
}
} else {
name = ri.activityInfo.applicationInfo.loadLabel(ctx.getPackageManager()).toString();
}
}
return name;
}
public String getSizeFromResolveInfo(ResolveInfo ri) throws Exception {
try {
codeSizeSemaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
// Collect some other statistics
// Collect code size
try {
Method getPackageSizeInfo = packageManager.getClass().getMethod("getPackageSizeInfo",
String.class,
android.content.pm.IPackageStatsObserver.class);
getPackageSizeInfo.invoke(packageManager, ri.activityInfo.packageName,
new android.content.pm.IPackageStatsObserver.Stub() {
// Examples in the Internet usually have this method as @Override.
// I got an error with @Override. Perfectly works without it.
public void onGetStatsCompleted(PackageStats pStats, boolean succeedded)
throws RemoteException {
codeSize = pStats.codeSize;
Log.e("codeSize", codeSize + "");
codeSizeSemaphore.release();
}
});
} catch (Exception e) {
e.printStackTrace(System.err);
}
return String.valueOf(codeSize);
}
public Resources getEnglishRessources(Resources standardResources) {
AssetManager assets = standardResources.getAssets();
DisplayMetrics metrics = standardResources.getDisplayMetrics();
Configuration config = new Configuration(standardResources.getConfiguration());
config.locale = Locale.US;
return new Resources(assets, metrics, config);
}
}