You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android动态加载Java生成的JAR文件实现方法问询

Android动态加载Dex文件中Java类的实现方案

刚好做过类似的需求,给你一套完整的实现方案,完全能满足你想要的调用方式:

1. 前置准备确认

你已经用dx --dex --output=dynamic.dex your.jar把Jar转成了Dex文件,接下来要把这个dynamic.dex放到应用可访问的路径,推荐放在assets目录(打包进APK),或者外部存储(需要对应权限)。

2. 核心实现思路

因为编译时主应用没有动态类的引用,直接new DynamicLoadedClassInJar()会报错,所以我们用接口约定的方式来实现强类型调用,和你想要的写法几乎一致。

步骤1:定义公共接口

在主应用中定义一个接口,同时把这个接口复制一份到你的动态Jar项目中,让动态类实现这个接口:

// 主应用和动态Jar都要包含这个接口,包名、类名、方法必须完全一致
public interface DynamicInterface {
    void executeBusiness();
    String getDynamicData();
}

步骤2:动态Jar中的类实现接口

你的动态Jar里的目标类要实现上面的接口:

// 动态Jar中的类
public class DynamicLoadedClassInJar implements DynamicInterface {
    @Override
    public void executeBusiness() {
        // 这里写你的动态类业务逻辑
        Log.d("DynamicClass", "动态类方法执行了");
    }

    @Override
    public String getDynamicData() {
        return "我是来自动态加载类的返回值";
    }
}

步骤3:主应用中加载Dex并实例化类

写一个加载工具类,用DexClassLoader来加载Dex文件,然后实例化类并强转成接口类型:

public class DexClassLoaderHelper {

    public static DynamicInterface loadDynamicClass(Context context) {
        try {
            // 1. 把assets中的dex文件复制到内部存储(因为DexClassLoader不能直接加载assets里的文件)
            File dexFile = new File(context.getFilesDir(), "dynamic.dex");
            if (!dexFile.exists()) {
                copyAssetToFile(context, "dynamic.dex", dexFile);
            }

            // 2. 创建DexClassLoader:参数分别是dex路径、优化dex的存储目录、native库路径、父类加载器
            File optimizedDexDir = context.getDir("dex_optimize", Context.MODE_PRIVATE);
            DexClassLoader dexLoader = new DexClassLoader(
                    dexFile.getAbsolutePath(),
                    optimizedDexDir.getAbsolutePath(),
                    null, // 没有native库就传null
                    context.getClassLoader()
            );

            // 3. 加载目标类并实例化
            Class<?> dynamicClass = dexLoader.loadClass("com.your.dynamic.package.DynamicLoadedClassInJar");
            // 强转成接口类型,这样就能像普通类一样调用方法了
            return (DynamicInterface) dynamicClass.newInstance();

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 辅助方法:把assets文件复制到内部存储
    private static void copyAssetToFile(Context context, String assetName, File destFile) throws IOException {
        InputStream is = context.getAssets().open(assetName);
        FileOutputStream fos = new FileOutputStream(destFile);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = is.read(buffer)) != -1) {
            fos.write(buffer, 0, length);
        }
        is.close();
        fos.close();
    }
}

步骤4:调用动态类

现在你就能像你期望的那样调用动态类了:

// 在Activity或者其他业务代码中使用
DynamicInterface dynamicObj = DexClassLoaderHelper.loadDynamicClass(this);
if (dynamicObj != null) {
    // 调用动态类的方法
    dynamicObj.executeBusiness();
    String data = dynamicObj.getDynamicData();
    Log.d("MainApp", "动态类返回数据:" + data);
}

3. 重要注意事项

  • 接口一致性:主应用和动态Jar中的接口必须完全一致(包名、类名、方法签名、返回值都不能变),否则强转时会抛出ClassCastException。
  • 权限问题:如果从外部存储加载Dex,Android 10及以下需要申请READ_EXTERNAL_STORAGE权限,Android 10+建议使用Scoped Storage。
  • 混淆配置:主应用中的DynamicInterface不能被混淆,要在proguard-rules.pro中添加:
    -keep interface com.your.main.package.DynamicInterface { *; }
    
  • Dex生成验证:确保用dx命令生成的Dex没有错误,可以用dexdump工具查看Dex中的类是否存在。

内容的提问来源于stack exchange,提问作者Andrean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:05:08