Android 获取已安装的应用程序大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1806286/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting installed app size
提问by yanchenko
I'm trying to figure out how to get the size of an installed app.
What's already failed:
- new File('/data/app/some.apk')
- reports incorrect size
- PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer)
- is @hide
and relies on some obscure IPackageStatsObserver
for result so I can't call it via reflection.
我想弄清楚如何获取已安装应用程序的大小。
什么是已经失败:
- new File('/data/app/some.apk')
-报告不正确的大小
- PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer)
-是@hide
和依赖于一些模糊IPackageStatsObserver
的结果,所以我不能通过反射调用它。
回答by Josef Pfleger
Unfortunately there is currently noofficial wayto do that. However, you cancall the PackageManager
's hidden getPackageSize
method if you import the PackageStats
and IPackageStatsObserver
AIDLs into our project and generate the stubs. You can then use reflection to invoke getPackageSize
:
不幸的是,目前没有官方方法可以做到这一点。但是,如果将和AIDL 导入我们的项目并生成存根,则可以调用PackageManager
的隐藏getPackageSize
方法。然后您可以使用反射来调用: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);
}
});
That's obviously a big hackand should not be usedfor public applications.
这显然是一个大黑客,不应该用于公共应用程序。
回答by krawiec
You can do it simplier by gettting path to apk file, and checking its lenght:
您可以通过获取 apk 文件的路径并检查其长度来更简单地完成此操作:
final PackageManager pm = context.getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(appInfo.getPackage(), 0);
File file = new File(applicationInfo.publicSourceDir);
int size = file.length();
回答by droida
Here is additional answer @Josef Pfleger 's, for comment
这是@Josef Pfleger 的其他答案,供评论
“I found that some device doesn't have getPackageSizeInfo() then you get this java.lang.NoSuchMethodException: getPackageSizeInfo()” @ ATom Nov 29 '11 at 15:56.
“我发现某些设备没有 getPackageSizeInfo() 然后你得到这个 java.lang.NoSuchMethodException: getPackageSizeInfo()”@ ATom 2011 年 11 月 29 日 15:56。
After api 16( Build.VERSION.SDK_INT >16),the method
api 16(Build.VERSION.SDK_INT >16)后,方法
PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer);
changed into:
改变成:
PackageManager.getPackageSizeInfo(String packageName, int userHandle, IPackageStatsObserver observer);
And the explain for the new added param userHandle
is :The user whose size information should be retrieved.
新添加的参数的解释userHandle
是:应该检索其尺寸信息的用户。
So we should do it like this:
所以我们应该这样做:
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;}
The class needed to callback like:
需要回调的类,如:
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);
}
}
And use this method to parse long2string,then you can see xx MB
instead of long
like 2342334 :)
并使用此方法解析long2string,然后您可以看到xx MB
而不是long
像2342334 :)
private String formateFileSize(long size) {
return Formatter.formatFileSize(MainActivity.this, size);
}
回答by Tomas
Remember the needed permission, I solved these issues by adding the following permission to the manifest:
记住所需的权限,我通过向清单添加以下权限解决了这些问题:
< uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
Or this wrong: not use getDeclaredMethod()
,should be use getMethod()
.
或者这个错误:不使用getDeclaredMethod()
,应该使用getMethod()
。
Method getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
Method getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
回答by shefi
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);
}
}