Как установить размер приложения

Я пытаюсь выяснить, как получить размер установленного приложения.
Что уже не удалось:
- new File('/data/app/some.apk') - сообщает неправильный размер
- PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer) - @hide и полагается на некоторый неясный IPackageStatsObserver результат, поэтому я не могу называть его через отражение.

Ответ 1

К сожалению, в настоящее время no официального что. Однако вы можете вызвать PackageManager скрытый getPackageSize, если вы импортируете PackageStats и IPackageStatsObserver AIDL в наш проект и сгенерируйте заглушки. Затем вы можете использовать отражение для вызова 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);
        }
    });

Очевидно, что большой взлом и не должны использоваться для общедоступных приложений.

Ответ 2

Вы можете сделать это проще, пройдя путь к файлу apk и проверив его длину:

final PackageManager pm = context.getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(appInfo.getPackage(), 0);
File file = new File(applicationInfo.publicSourceDir);
int size = file.length();

Ответ 3

Вот дополнительный ответ @Josef Pfleger, для комментариев

"Я обнаружил, что на каком-то устройстве нет getPackageSizeInfo(), после чего вы получите это java.lang.NoSuchMethodException: getPackageSizeInfo()" @ATom 29.11.11 в 15:56.

После 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);
}

Ответ 4

Запомните необходимое разрешение, я решил эти проблемы, добавив к манифесту следующее разрешение:

< uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />

Или это неправильно: не использовать getDeclaredMethod(), следует использовать getMethod().

Method getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);

Ответ 5

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);
    }
}