麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 系統 > Android > 正文

Android獲取應用程序大小的方法

2020-04-11 11:56:27
字體:
來源:轉載
供稿:網友

今天碰到個問題,想獲取某個已安裝的包的大小,沒找到合適的方法。搜索了一下,發(fā)現PackageManager里面有個getPackageSizeInfo方法,可惜是hide的,而且它執(zhí)行之后,會將結果回調給IPackageStatsObserver的onGetStatsCompleted方法。后來想直接計算/data/app和/system/app里面的apk大小,可是有時候會碰到權限問題,需要root才可以獲取大小。        再后來,我想起系統的設置里面有一個應用程序管理,它里面列出了所有程序的占用空間大小、數據大小和緩存大小。恩,這個就是突破口。
以前寫過一篇獲取其他包的Context ,這個東西是真有用,這個結合反射,可以做很多神奇的事情,比如今天的這個。

上代碼:

Java代碼

復制代碼 代碼如下:

package chroya.demo; 

import java.lang.reflect.Constructor; 
import java.lang.reflect.Field; 
import java.lang.reflect.InvocationTargetException; 
import java.util.concurrent.CountDownLatch; 

import android.app.Activity; 
import android.content.Context; 
import android.content.pm.PackageStats; 
import android.content.pm.PackageManager.NameNotFoundException; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 

public class Main extends Activity { 
    private PackageStats ps; 

    public void getPackageStats(String packageName) { 
        try { 
            //獲取setting包的的Context 
            Context mmsCtx = createPackageContext("com.android.settings", 
                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); 
            //使用setting的classloader加載com.android.settings.ManageApplications類 
            Class<?> maClass = Class.forName("com.android.settings.ManageApplications", true, mmsCtx.getClassLoader()); 
            //創(chuàng)建它的一個對象 
            Object maObject = maClass.newInstance(); 

            /*
             * 將私有域mPm賦值。因為mPm在SizeObserver的invokeGetSize中用到了,
             * 卻因為沒有執(zhí)行onCreate而沒有初始化,所以要在此處初始化。
             */ 
            Field f_mPm = maClass.getDeclaredField("mPm"); 
            f_mPm.setAccessible(true);             
            f_mPm.set(maObject, mmsCtx.getPackageManager()); 

            /*
             * 給mHandler賦值為重新定義的Handler,以便接收SizeObserver的
             * onGetStatsCompleted回調方法中dispatch的消息,從中取PackageStats對象。
             * */ 
            Field f_mHandler = maClass.getDeclaredField("mHandler"); 
            f_mHandler.setAccessible(true); 
            f_mHandler.set(maObject, new Handler() { 
                  public void handleMessage(Message msg) { 
                      if(msg.what == 1) { 
                          //此處獲取到PackageStats對象 
                          ps = (PackageStats) msg.getData().getParcelable("ApplicationPackageStats");                          
                          Log.d("", ""+ps.codeSize);                           
                      } 
                  } 
            }); 

            //加載內部類SizeObserver 
            Class<?> sizeObserverClass = Class.forName("com.android.settings.ManageApplications$SizeObserver", true, mmsCtx.getClassLoader()); 
            Constructor sizeObserverConstructor = sizeObserverClass.getDeclaredConstructors()[0]; 
            sizeObserverConstructor.setAccessible(true); 
            /*
             * 創(chuàng)建SizeObserver對象,兩個參數,第一個是外部類的對象,
             * 也就是ManageApplications對象,第二個是msgId,也就是
             * 分發(fā)消息的id,跟Handler接收的msgId一樣。
             * */ 
            Object soObject = sizeObserverConstructor.newInstance(maObject, 1); 
            //執(zhí)行invokeGetSize方法 
            sizeObserverClass.getMethod("invokeGetSize", String.class, 
                    CountDownLatch.class).invoke(soObject, packageName, new CountDownLatch(1));          
        } catch (NameNotFoundException e) { 
            e.printStackTrace(); 
        } catch (ClassNotFoundException e) { 
            e.printStackTrace(); 
        } catch (IllegalAccessException e) { 
            e.printStackTrace(); 
        } catch (IllegalArgumentException e) { 
            e.printStackTrace(); 
        } catch (SecurityException e) { 
            e.printStackTrace(); 
        } catch (InvocationTargetException e) { 
            e.printStackTrace(); 
        } catch (NoSuchMethodException e) { 
            e.printStackTrace(); 
        } catch (InstantiationException e) { 
            e.printStackTrace(); 
        } catch (NoSuchFieldException e) { 
            e.printStackTrace(); 
        } 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);   
        getPackageStats("chroya.demo");        
    } 

注釋都在代碼里面了,稍微理解一下應該都能懂的。
獲取到PackageStats對象,就可以從中獲取到應用程序的占用空間大小、數據大小和緩存大小。

另,這畢竟只是hack code,不可能通用。這段代碼的局限性是,只有1.5能用,而且如果別人把setting包去掉了,也沒法使用。要寫出各版本SDK通用的代碼,就必須查看每個版本的setting包,看代碼有何變化,然后根據上面給出的思路為每個版本寫一個方法,就ok了。

想要獲得成功,首先要自己相信自己,再者要贏得周圍朋友的信任!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 欧美日韩大片在线观看 | 欧美激情精品久久久久久久久久 | 毛片网站视频 | free国产hd老熟bbw | 欧美黄色一区 | 私库av在线免费观看 | 成人做爰高潮片免费视频韩国 | 美女很黄很黄免费的 | 欧美日韩1区2区3区 黄片毛片一级 | 在线亚洲免费视频 | 日本欧美一区二区三区在线观看 | 涩涩天堂| 国产精品一区二区三区在线播放 | 欧美3p激情一区二区三区猛视频 | 夜夜看 | 久草在线高清视频 | 久久久久久麻豆 | 国产亚洲精品久久久久久久软件 | 羞羞视频.www在线观看 | 日本成人一二三区 | 午夜视频在线看 | 五月婷婷第四色 | 天天色综合6 | 久久久久久久久久久久99 | 亚洲va久久久噜噜噜久久男同 | 国产一区二区三区高清 | 黄色大片在线观看 | 久久性生活免费视频 | 九色国产| 欧美不卡三区 | 亚洲性爰 | 久久久久久久一区二区 | 久久综合九色综合久久久精品综合 | 天堂二区| 老司机免费福利午夜入口ae58 | 羞羞视频入口 | 吾色视频| 亚洲一级毛片 | 好吊一区二区三区 | 4p嗯啊巨肉寝室调教男男视频 | 免费欧美精品 |