Is there a way to get the class names in a given classes.dex file?

徘徊边缘 提交于 2019-12-07 15:57:23

问题


I am building a home automation app. I am trying to add a plugin system. I have as a test exported a test class (that subclasses Button) as an APK file and put it in my app's file directory. I was able to create a new instance of this class and put it in my View using DexClassLoader and .loadClass.

The next step is to scan all the APK's in this directory and get the names of the classes in them.

I found the DexFile class that does just that however it throws the following exceptions:

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)

It would seem that it is trying to find the optimized DexFile in the system cache but I do not have permissions to the cache directory. From what I can see this is probably by design and I don't have a problem with that. Is there another way to parse a DEX file and get the class names from it?

I have looked at the source for some of the dex decompiler projects. Do I have to roll my own solution?

Here is my test app code (from my Activity OnCreate) just in case I missed something:

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

回答1:


Instead of:

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

try:

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



回答2:


Another approach you might consider, would be to install the plugins as separate applications. You could have the plugin application expose a service, using a particular intent that you define. You would also need a pre-defined aidl interface that the service would implement. In your main application, you could then resolve that service intent, to find any plugin services.



来源:https://stackoverflow.com/questions/10214880/is-there-a-way-to-get-the-class-names-in-a-given-classes-dex-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!