有没有办法在给定的classes.dex文件中获取类名?

时间:2012-04-18 17:40:42

标签: android dex

我正在构建一个家庭自动化应用程序。我想添加一个插件系统。我作为测试导出了一个测试类(该子类为Button)作为APK文件并将其放入我的应用程序的文件目录中。我能够使用DexClassLoader.loadClass创建此类的新实例并将其放入我的视图中。

下一步是扫描此目录中的所有APK并获取其中的类名称。

我发现DexFile类就是这样做的,但它引发了以下异常:

04-18 17:26:15.697: E/dalvikvm(726): Can't open dex cache '/data/dalvik-cache/data@data@com.strutton.android.testplugin@files@testloadclass.apk@classes.dex': No such file or directory

04-18 17:26:15.705: I/dalvikvm(726): Unable to open or create cache for /data/data/com.strutton.android.testplugin/files/testloadclass.apk (/data/dalvik-cache/data@data@com.strutton.android.testplugin@files@testloadclass.apk@classes.dex)

似乎它试图在系统缓存中找到优化的DexFile,但我没有缓存目录的权限。从我可以看到这可能是设计,我没有问题。还有另一种解析DEX文件并从中获取类名的方法吗?

我查看了一些dex反编译器项目的来源。我是否必须推出自己的解决方案?

这是我的测试应用代码(来自我的活动OnCreate)以防万一我错过了一些东西:

    try {
        ArrayList<String> UIPlugins = new ArrayList<String>();
        final File filesDir = this.getFilesDir();
        final File tmpDir = getDir("dex", 0);
        final DexClassLoader classloader = new DexClassLoader( filesDir.getAbsolutePath()+"/testloadclass.apk",
                tmpDir.getAbsolutePath(),
                null, this.getClass().getClassLoader());
        final Class<Button> classToLoad = 
                (Class<Button>) classloader.loadClass("com.strutton.android.testloadclass.MyTestClass_IRDroidUIPlugIn");
        Button mybutton = classToLoad.getDeclaredConstructor(Context.class).newInstance(this);
        mybutton.setId(2);
        mybutton.setOnClickListener(this);
        main.addView(mybutton);
        // Up to here everything works as expected
        // This line throws the exceptions
        DexFile mDexFile = new DexFile(filesDir.getAbsolutePath()+"/testloadclass.apk";);
        Enumeration<String> classNames = mDexFile.entries();
        while (classNames.hasMoreElements()){
            String className = classNames.nextElement();
            if (className.endsWith("IRDroidUIPlugIn")){
                UIPlugins.add(className);
            }
        }
        final Class<Button> classToLoad = 
                (Class<Button>) classloader.loadClass("com.strutton.android.testloadclass.MyTestClass_IRDroidUIPlugIn");
        Button mybutton = classToLoad.getDeclaredConstructor(Context.class).newInstance(this);
        mybutton.setId(2);
        mybutton.setOnClickListener(this);
        main.addView(mybutton);
        btn.setText(tmpDir.getAbsolutePath());
      } catch (Exception e) {
        e.printStackTrace();
    }

2 个答案:

答案 0 :(得分:4)

而不是:

DexFile mDexFile = new DexFile(filesDir.getAbsolutePath()+"/testloadclass.apk";);

尝试:

DexFile mDexFile = DexFile.loadDex(filesDir.getAbsolutePath()+"/testloadclass.apk", tmpDir.getAbsolutePath()+"/testloadclass.odex", 0);

答案 1 :(得分:0)

您可能会考虑的另一种方法是将插件安装为单独的应用程序。您可以使用您定义的特定意图让插件应用程序公开服务。您还需要一个服务将实现的预定义的aidl接口。在主应用程序中,您可以解析该服务意图,以查找任何插件服务。