当前位置: 移动技术网 > 移动技术>移动开发>Android > Android获取应用程序大小的方法

Android获取应用程序大小的方法

2019年07月24日  | 移动技术网移动技术  | 我要评论

今天碰到个问题,想获取某个已安装的包的大小,没找到合适的方法。搜索了一下,发现packagemanager里面有个getpackagesizeinfo方法,可惜是hide的,而且它执行之后,会将结果回调给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()); 
            //创建它的一个对象 
            object maobject = maclass.newinstance(); 

            /*
             * 将私有域mpm赋值。因为mpm在sizeobserver的invokegetsize中用到了,
             * 却因为没有执行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); 
            /*
             * 创建sizeobserver对象,两个参数,第一个是外部类的对象,
             * 也就是manageapplications对象,第二个是msgid,也就是
             * 分发消息的id,跟handler接收的msgid一样。
             * */ 
            object soobject = sizeobserverconstructor.newinstance(maobject, 1); 
            //执行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了。

想要获得成功,首先要自己相信自己,再者要赢得周围朋友的信任!

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网