Reputation: 57156
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.
Upvotes: 22
Views: 32824
Reputation: 407
You can do it simplier by gettting path to apk file, and checking its lenght:
final PackageManager pm = context.getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(context.getPackageName(), 0);
File file = new File(applicationInfo.publicSourceDir);
long size = file.length();
Upvotes: 24
Reputation: 92
You can get Size of apps without AIDL Files -------> Kotlin Language
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_LAUNCHER)
val list = packageManager.queryIntentActivities(intent,0)
// Set adapter to LIST VIEW
listView.adapter = getApps(list)
}
private fun getApps(List: MutableList<ResolveInfo>): List<AppData> {
val list = ArrayList<AppData>()
for (packageInfo in List) {
val packageName = packageInfo.activityInfo.packageName
// return size in form of Bytes(Long)
val size = File(packageManager.getApplicationInfo(packageName,0).publicSourceDir).length()
val item = AppData(Size)
list += item
}
return list
}
}
// Make Data Class
data class AppData(val size: Long)
Remember to convert it in MB from Bytes
Upvotes: 0
Reputation: 41
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()
.
Method getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
Upvotes: 4
Reputation: 141
Here is additional answer @Josef Pfleger 's, for comment
“I found that some device doesn't have getPackageSizeInfo() then you get this java.lang.NoSuchMethodException: getPackageSizeInfo()” @ ATom Nov 29 '11 at 15:56.
After api 16( Build.VERSION.SDK_INT >16),the method
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.
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 :)
private String formateFileSize(long size) {
return Formatter.formatFileSize(MainActivity.this, size);
}
Upvotes: 5
Reputation: 1
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);
}
}
Upvotes: -2
Reputation: 74507
Unfortunately there is currently no official way to do that. However, you can call 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
:
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 hack and should not be used for public applications.
Upvotes: 30