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); // 后续处理逻辑,如读取文件等 } }
关键注意事项
- assets文件无真实路径:assets目录下的文件仅存在于APK压缩包内,没有可直接访问的文件系统路径,必须通过
AssetManager或复制到私有目录后操作。 - Jar加载限制:Android类加载器无法直接加载assets内的Jar文件,必须先将Jar复制到应用的私有目录(如
cacheDir、filesDir)才能加载。
内容的提问来源于stack exchange,提问作者정한호
相关产品推荐
相关产品推荐

