美文网首页
Android 运行时获得类的完全限定名

Android 运行时获得类的完全限定名

作者: GhostInMatrix | 来源:发表于2017-08-17 21:34 被阅读0次

    最近有个需求是在push信息内制定某模块(Activty)名称,端上拿到该名称,在用户点击通知的时候自动打开对应Activity页面。
    老逻辑是这样实现的:
    每次新增一个功能模块的时候,都会在代码中使用switch语句进行选择判断:

        switch( nameFromPush){
            case "name1":
                startActivity(this,ActivityName1.class);
                break;
            case "name2":
                startActivity(this,ActivityName2.class);
                break;
            ...
            
        }
    

    这么做有一个问题,需要修改代码。每次都要修改。
    既然startActivity每次都要调用,且跳转的页面唯一取决于targetActivity的名称,那么,能否有一种方式能直接将push中的信息字段应用于startActivity()的第二个参数,从而废弃掉这种通过代码映射的方式呢。答案是肯定的,我们的思路即为下发targetActivity的类名,参数就可以直接使用。

    但随之而来的又一个问题在于,类名其实是需要使用完全限定名的,也就需要推送下发全称,比如
    startActivity(this,"com.ghostinmatrix.package1.TargetActivity.class");
    ,那么一旦这个模块修改了package(在类名本身不变的情况下),下发的push就不会生效了,因为app已经找不到这个类了。综上,push下发完全限定名是非常不合理的,只能下发类名。这就需要你在拿到push下发的“TargetActivity”,在app内生成它的完全限定名。我们可以使用如下方式:

    DexFile df = new DexFile(DuApp.getAppContext().getPackageCodePath());
                Enumeration<String> enumeration = df.entries();
                while (enumeration.hasMoreElements()) {
                    String classname = enumeration.nextElement();
                    if (classname.contains("com.baidu.lbs")) {
                        String[] name = classname.split("\\.");
                        hashMap.put(name[name.length - 1], classname);
                    }
                }
    

    这里要介绍一下DexFile类,你只需要知道,通过ApplicationContext.getPackageCodePath能够访问到这个App内所有加载的类。而DexFile就是这样一个加载的入口。

        /**
         * Return the full path to this context's primary Android package.
         * The Android package is a ZIP file which contains application's
         * primary code and assets.
         *
         * <p>Note: this is not generally useful for applications, since they should
         * not be directly accessing the file system.
         *
         * @return String Path to the code and assets.
         */
        public abstract String getPackageCodePath();
    
    

    注释大意为:返回这个context所对应的主包名,它是一个包含着app代码和资源的zip包。
    因此通过这个路径可以获得所有主包名下的所有类的全限定名。

    PS:对于Gradle 2.0.0以上的闪电编译(Instant Run)来说,存在一个问题,即通过上述方式不能获得apk中所有编译的类,而是只能找到其运行时和instant run所用到的.dex文件,(如com.tools.android.fd.runtime, com.tools.android.fd.common and com.tools.android.tools.ir.api)。其余的编译为.dex文件的类会被压缩到叫做instant-run.zip的压缩文件中放在同级目录下。不过不用担心,instant run只会用于Debug模式下的构建,而不会对Release模式有影响。

    回到正题,DexFile能够得到所有类的完全限定名,也就一定会包含push下发的类名,后面的就不用多说了吧。找到对应的全限定名,作为第二个参数,startActivity。

    相关文章

      网友评论

          本文标题:Android 运行时获得类的完全限定名

          本文链接:https://www.haomeiwen.com/subject/wejnrxtx.html