Android项目集成Dalvik VM编译工具遇路径错误问题求助
Android项目Dalvik集成编译的路径错误解决
我正在开发一个游戏核心,除编译模块外所有部分均已完成。最初尝试编写如下代码进行编译:
package com.ccs.gencorelite.compiler; import java.io.IOException; public class ProjectCompiler { public static void compileProject(String projectPath, String outputPath) { try { ProcessBuilder builder = new ProcessBuilder( "aapt", "package", "-f", "-M", projectPath + "/AndroidManifest.xml", "-S", projectPath + "/res", "-I", "file:///resources/android.jar", "-F", outputPath + "/app.apk" ); builder.redirectErrorStream(true); Process process = builder.start(); // 等待进程完成 int exitCode = process.waitFor(); // 检查退出状态 if (exitCode == 0) { System.out.println("项目编译成功。"); } else { System.out.println("项目编译出错。"); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
之后出现了编译权限错误,于是我重写了该类,并将build-tools34、platforms、platform-tools、sdk34文件夹添加到assets目录中,重写后的代码如下:
package com.ccs.gencorelite.compiler; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class ProjectCompiler { public static void compileJavaFiles(String projectPath) { String javaCompilerPath = "file:///android_asset/compiler/bt34/javac"; String[] javacCmd = { javaCompilerPath, "-d", projectPath + "/bin", projectPath + "/src/**/*.java" }; executeCommand(javacCmd); } public static void compileResources(String projectPath) { String aaptPath = "file:///android_asset/compiler/bt34/aapt"; String[] aaptCmd = { aaptPath, "package", "-f", "-m", "-J", projectPath + "/gen", "-S", projectPath + "/res", "-I", "file:///android_resources/android.jar" }; executeCommand(aaptCmd); } public static void convertToDalvikBytecode(String projectPath) { String dxPath = "file:///android_asset/compiler/bt34/dx"; String[] dxCmd = { dxPath, "--dex", "--output=" + projectPath + "/bin/classes.dex", projectPath + "/bin" }; executeCommand(dxCmd); } public static void executeCommand(String[] command) { try { Process process = new ProcessBuilder(command).start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); process.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } }
现在出现了以下错误:
java.io.IOException: Cannot run program "file:///android_assets/compiler/bt34/javac": error=2, No such file or directory 2024-05-09 22:14:26.305 28386-28386 System.err com.ccs.gencorelite W java.io.IOException: Cannot run program "file:///android_assets/compiler/bt34/aapt": error=2, No such file or directory 2024-05-09 22:14:26.312 28386-28386 System.err com.ccs.gencorelite W java.io.IOException: Cannot run program "file:///android_assets/compiler/bt34/dx": error=2, No such file or directory
核心解决方案
1. 问题根源
Android的file:///android_asset/是Content URI,并非文件系统的绝对路径,ProcessBuilder无法直接通过该URI执行文件。同时,assets目录中的文件是压缩在APK内的,默认没有执行权限,必须先复制到应用的私有可写目录才能使用。
2. 复制assets工具到私有目录并添加权限
添加工具方法负责复制文件并设置执行权限:
import android.content.Context; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; private void copyAssetToPrivateDir(Context context, String assetRelativePath, String destRelativePath) throws IOException { InputStream inputStream = context.getAssets().open(assetRelativePath); File destFile = new File(context.getFilesDir(), destRelativePath); // 创建目标目录 if (!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } OutputStream outputStream = new FileOutputStream(destFile); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } inputStream.close(); outputStream.close(); // 赋予执行权限 destFile.setExecutable(true); }
在编译流程启动前,先复制所有需要的工具:
// 在编译前调用,需传入Context try { copyAssetToPrivateDir(context, "compiler/bt34/javac", "compiler/bt34/javac"); copyAssetToPrivateDir(context, "compiler/bt34/aapt", "compiler/bt34/aapt"); copyAssetToPrivateDir(context, "compiler/bt34/dx", "compiler/bt34/dx"); copyAssetToPrivateDir(context, "resources/android.jar", "resources/android.jar"); } catch (IOException e) { e.printStackTrace(); }
3. 修改编译方法的路径
使用应用私有目录的绝对路径调用工具:
public static void compileJavaFiles(Context context, String projectPath) { String javacPath = new File(context.getFilesDir(), "compiler/bt34/javac").getAbsolutePath(); String[] javacCmd = { javacPath, "-d", projectPath + "/bin", projectPath + "/src/**/*.java" }; executeCommand(javacCmd); } public static void compileResources(Context context, String projectPath) { String aaptPath = new File(context.getFilesDir(), "compiler/bt34/aapt").getAbsolutePath(); String androidJarPath = new File(context.getFilesDir(), "resources/android.jar").getAbsolutePath(); String[] aaptCmd = { aaptPath, "package", "-f", "-m", "-J", projectPath + "/gen", "-S", projectPath + "/res", "-I", androidJarPath }; executeCommand(aaptCmd); } public static void convertToDalvikBytecode(Context context, String projectPath) { String dxPath = new File(context.getFilesDir(), "compiler/bt34/dx").getAbsolutePath(); String[] dxCmd = { dxPath, "--dex", "--output=" + projectPath + "/bin/classes.dex", projectPath + "/bin" }; executeCommand(dxCmd); }
4. 额外注意事项
- 确保assets中的工具是对应目标设备架构的版本(如arm64-v8a、armeabi-v7a),否则会出现“无法执行二进制文件”错误。
- Android 10及以上版本无需申请外部存储权限,应用私有目录
getFilesDir()是安全可写的。 - 可以只在第一次启动时复制工具,避免重复复制浪费资源。
内容的提问来源于stack exchange,提问作者Dmytro Parkhomenko
相关产品推荐
相关产品推荐

