通过类加载器从 dex 文件中访问 app 的类
Posted
技术标签:
【中文标题】通过类加载器从 dex 文件中访问 app 的类【英文标题】:accessing to classes of app from dex file by classloader 【发布时间】:2013-12-02 19:10:12 【问题描述】:我有一个应用程序从服务器接收 dex 文件,然后将其保存在 sdcard 上并加载它以供
做一些功能。我正在从我的 dex 文件中加载我的应用程序的类,如下所示
dex文件
public class Main
public void onCreate()
System.out.print("------------onCreate------------");
try
final ClassLoader classloader = ClassLoader.getSystemClassLoader();
final Class<Object> classToLoad = (Class<Object>) classloader.loadClass("com.example.myapp.M");
final Object myInstance = classToLoad.newInstance();
final Method doSomething = classToLoad.getMethod("doSomething");
doSomething.invoke(myInstance);
catch (Exception e)
e.printStackTrace();
应用代码
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try
final String libPath = Environment.getExternalStorageDirectory() + "/Lib/lib.apk";
final File tmpDir = getDir("dex", 0);
final DexClassLoader classloader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
final Class<Object> classToLoad = (Class<Object>) classloader.loadClass("com.example.lib.Main");
final Object myInstance = classToLoad.newInstance();
final Method doSomething = classToLoad.getMethod("onCreate");
doSomething.invoke(myInstance);
catch (Exception e)
e.printStackTrace();
我的应用程序中的 M 类
public class M
public void doSomething()
Log.e("doSomething", "--------------------doSomething----");
但它让我跟随错误。我的代码有什么问题
11-19 08:24:12.718: W/System.err(10867): java.lang.ClassNotFoundException: Didn't find class "com.example.myapp2.M" on path: .
11-19 08:24:12.738: W/System.err(10867): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:65)
11-19 08:24:12.747: W/System.err(10867): at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
11-19 08:24:12.758: W/System.err(10867): at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
11-19 08:24:12.758: W/System.err(10867): at com.example.lib.Main.onCreate(Main.java:15)
11-19 08:24:12.768: W/System.err(10867): at java.lang.reflect.Method.invokeNative(Native Method)
11-19 08:24:12.788: W/System.err(10867): at java.lang.reflect.Method.invoke(Method.java:511)
11-19 08:24:12.788: W/System.err(10867): at com.example.myapp2.MainActivity.onCreate(MainActivity.java:28)
11-19 08:24:12.798: W/System.err(10867): at android.app.Activity.performCreate(Activity.java:5104)
11-19 08:24:12.818: W/System.err(10867): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
11-19 08:24:12.828: W/System.err(10867): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
11-19 08:24:12.828: W/System.err(10867): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
11-19 08:24:12.828: W/System.err(10867): at android.app.ActivityThread.access$600(ActivityThread.java:141)
11-19 08:24:12.828: W/System.err(10867): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
11-19 08:24:12.828: W/System.err(10867): at android.os.Handler.dispatchMessage(Handler.java:99)
11-19 08:24:12.838: W/System.err(10867): at android.os.Looper.loop(Looper.java:137)
11-19 08:24:12.847: W/System.err(10867): at android.app.ActivityThread.main(ActivityThread.java:5041)
11-19 08:24:12.847: W/System.err(10867): at java.lang.reflect.Method.invokeNative(Native Method)
11-19 08:24:12.847: W/System.err(10867): at java.lang.reflect.Method.invoke(Method.java:511)
11-19 08:24:12.857: W/System.err(10867): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
11-19 08:24:12.898: W/System.err(10867): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
11-19 08:24:12.898: W/System.err(10867): at dalvik.system.NativeStart.main(Native Method)
【问题讨论】:
消息ClassNotFoundException: Didn't find class on path .
中对您来说有什么歧义
"path"。我可以通过类加载器从 dex 文件访问我的应用程序的类。如果可以,如何指定访问路径?
【参考方案1】:
看看您是否遵循这些步骤。
-
SD 卡上的库文件是 APK 还是包含 (Classes.dex) 文件的 JAR?
将 APK 文件复制到应用程序目录 /data/data/your.app.name/tmp 的临时文件夹中。这一点很重要,因为出于安全原因,Android 不允许您从 SD 卡中加载内容。
按照此处所述使用
DexClassLoader
-> How to load a Java class dynamically on android/dalvik?
使用这个类加载器实例来加载任何动态类文件。
如果您有超过 1 个 JAR 文件,请将它们合并到一个 DEX 文件/APK 中。
要将您的 Java JAR 文件或类转换为 DEX,您需要使用 Android SDK 的 dx.bat。这是一个要执行的示例 ANT 脚本。这也可以通过命令行使用类似的参数来完成。
<exec executable="dx.bat">
<arg value="--dex" />
<arg value="--output=$target.directory.fullpath/$apk.name" />
<arg value="--positions=lines" />
<arg path="$classes.directory.full.path" />
</exec>
【讨论】:
我可以从我的 jar 文件中访问我的应用程序的类吗?你能解释一下我该怎么做吗? 我想从我的 jar 文件的类中调用我的应用程序的方法 是的,您的插件 JAR(DEX 格式)文件可以调用应用程序的方法而无需显式执行任何操作,因为它必须充当父类加载器。 查看DexClassLoader
的构造函数,您将父类加载器设置为输入之一。 DexClassLoader。您可以使用 activity.getClassLoader() 方法获取父类加载器以传递给DexClassLoader()
构造函数
我在 jar 文件中使用了上面的代码,我又得到了那个错误。什么是错误路径?【参考方案2】:
我找到了我需要更改的答案
final Class<Object> classToLoad = (Class<Object>)classloader.loadClass("com.example.myapp.M");
到
final Class<Object> classToLoad = (Class<Object>)Class.forName("com.example.myapp.M");
在我的 dex 文件中
【讨论】:
它对你的工作方式很奇怪。你没有在任何地方提到你的 .jar 文件路径...... 那么,如果你这样做,它是否会加载 com.example.myapp.M 需要的所有其他类(尚未加载)? Zohreh 您是否从 SD 卡加载类文件?或者其他一些外部存储目录?我很好奇,因为@Swaroop 说你无法从 SD 卡加载它们。【参考方案3】:@zohreh 替换下面的行
final DexClassLoader classloader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, this.getClass().getClassLoader());
到
final DexClassLoader classloader = new DexClassLoader(libPath, tmpDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
【讨论】:
【参考方案4】:列出的答案对我不起作用。但是,通过Thread.currentThread().getContextClassLoader()
获取ClassLoader
原来是有效的:
final Class<Object> classToLoad = (Class<Object>) Class.forName("com.example.myapp.M", true, Thread.currentThread().getContextClassLoader());
【讨论】:
以上是关于通过类加载器从 dex 文件中访问 app 的类的主要内容,如果未能解决你的问题,请参考以下文章
是否可以通过使用Java Reflection从注入的DEX中获取app的类对象?
Android 逆向类加载器 ClassLoader ( 加载 Android 组件的类加载器 | 双亲委派机制实例分析 )