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

Android Studio中从纯Java Jar文件获取文件路径的可行性问询

Android中Assets目录下Jar文件获取同目录文件路径的可行性方案

可行性结论

可行,但你尝试的test.getProtectionDomain().getCodeSource().getLocation()方法在Android环境下无效,原因是:

Android应用打包后,assets目录下的所有资源都会被整合进APK压缩包,你的test.jar并不是独立存在于文件系统的实体,而是作为APK的一部分被加载,因此通过ProtectionDomain获取Jar位置的Java标准API在这个场景下会返回null,无法获取有效路径。

解决方案

由于Jar代码运行在Android应用进程内,必须依赖Android上下文或提前传递的文件信息来访问assets资源,以下两种方案可实现需求:

方案1:通过Android上下文(Context)传递访问能力

修改Java模块的test()方法,接收Context参数,借助Android的AssetManager访问target.jar:

// Java模块中的TestClass
public class TestClass {
    public void test(Context context) {
        try {
            // 直接获取target.jar的输入流(assets内文件无真实文件路径,只能通过流访问)
            InputStream targetStream = context.getAssets().open("target.jar");
            // 后续处理逻辑,如读取文件内容等
            targetStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在Android端调用时,需先将assets中的test.jar复制到应用私有目录(类加载器无法直接加载assets内的Jar),再用DexClassLoader加载类并调用方法:

// MainActivity.kt
private fun loadJarAndInvokeTest() {
    val cacheDir = cacheDir
    val jarFilePath = File(cacheDir, "test.jar").absolutePath

    // 先将assets中的test.jar复制到缓存目录
    if (!File(jarFilePath).exists()) {
        assets.open("test.jar").use { input ->
            FileOutputStream(jarFilePath).use { output ->
                input.copyTo(output)
            }
        }
    }

    // 加载Jar中的类
    val classLoader = DexClassLoader(
        jarFilePath,
        cacheDir.absolutePath,
        null,
        javaClass.classLoader
    )
    val testClass = classLoader.loadClass("com.yourpackage.TestClass")
    val testInstance = testClass.newInstance()

    // 调用带Context参数的test方法
    val testMethod = testClass.getMethod("test", Context::class.java)
    testMethod.invoke(testInstance, this)
}

方案2:提前传递文件路径(适配无参test()方法)

如果必须保留无参的test()方法,可在调用前将target.jar复制到应用私有目录,再通过静态变量传递路径:

// MainActivity.kt
private fun prepareTargetJarAndInvokeTest() {
    val cacheDir = cacheDir
    // 复制target.jar到缓存目录
    val targetFilePath = File(cacheDir, "target.jar").absolutePath
    if (!File(targetFilePath).exists()) {
        assets.open("target.jar").use { input ->
            FileOutputStream(targetFilePath).use { output ->
                input.copyTo(output)
            }
        }
    }

    // 复制并加载test.jar
    val jarFilePath = File(cacheDir, "test.jar").absolutePath
    if (!File(jarFilePath).exists()) {
        assets.open("test.jar").use { input ->
            FileOutputStream(jarFilePath).use { output ->
                input.copyTo(output)
            }
        }
    }

    val classLoader = DexClassLoader(
        jarFilePath,
        cacheDir.absolutePath,
        null,
        javaClass.classLoader
    )
    val testClass = classLoader.loadClass("com.yourpackage.TestClass")

    // 设置静态变量传递路径
    val pathField = testClass.getDeclaredField("TARGET_JAR_PATH")
    pathField.isAccessible = true
    pathField.set(null, targetFilePath)

    // 调用无参test方法
    val testInstance = testClass.newInstance()
    val testMethod = testClass.getMethod("test")
    testMethod.invoke(testInstance)
}

对应Java模块的代码:

// Java模块中的TestClass
public class TestClass {
    public static String TARGET_JAR_PATH;

    public void test() {
        if (TARGET_JAR_PATH == null) {
            throw new IllegalStateException("Target jar path not set");
        }
        File targetJar = new File(TARGET_JAR_PATH);
        // 后续处理逻辑,如读取文件等
    }
}

关键注意事项

  1. assets文件无真实路径:assets目录下的文件仅存在于APK压缩包内,没有可直接访问的文件系统路径,必须通过AssetManager或复制到私有目录后操作。
  2. Jar加载限制:Android类加载器无法直接加载assets内的Jar文件,必须先将Jar复制到应用的私有目录(如cacheDir、filesDir)才能加载。

内容的提问来源于stack exchange,提问作者정한호

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 00:45:19