如何在Xcode项目中集成apktool可执行文件与jar包并实现调用
问题1:文件存放方案与路径获取方法
- 不要把
apktool可执行文件和apktool.jar放在Assets.xcassets目录下,该目录下的所有资源都会被Xcode编译为统一的Assets.car归档文件,无法直接获取单个文件的POSIX路径供shell调用。 - 正确做法是将两个文件直接拖入项目,在弹出的添加选项中勾选对应Target的Target Membership,同时确保文件被添加到目标的Build Phases > Copy Bundle Resources列表中,Xcode会在构建时自动将这两个文件拷贝到App包的
Contents/Resources目录下。 - 路径获取的正确代码:
// 直接通过Bundle获取资源路径,不需要手动拼接 guard let apktoolPath = Bundle.main.path(forResource: "apktool", ofType: nil), FileManager.default.fileExists(atPath: apktoolPath) else { // 异常处理:可执行文件不存在 return -1 }
- 额外注意:需要保证
apktool可执行文件有执行权限,你可以在构建阶段添加Run Script脚本来自动修复权限,避免打包后权限丢失:
chmod +x "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/Contents/Resources/apktool"
问题2:正确调用apktool的实现方案
- 原生的
Process调用需要注意环境变量问题,apktool本质是shell脚本,依赖系统Java运行环境,建议通过/usr/bin/env启动来自动加载系统环境变量,避免找不到Java的问题。 - 修正后的完整执行代码示例:
@discardableResult func runApktool(_ args: String...) -> Int32 { let task = Process() // 通过env加载系统环境变量 task.launchPath = "/usr/bin/env" // 获取apktool可执行文件路径 guard let apktoolPath = Bundle.main.path(forResource: "apktool", ofType: nil) else { print("错误:apktool可执行文件不存在") return -1 } // 拼接参数:第一个参数是apktool路径,后面是业务参数 var allArguments = [apktoolPath] allArguments.append(contentsOf: args) task.arguments = allArguments // 可选:添加管道捕获输出日志,方便排查问题 let outputPipe = Pipe() task.standardOutput = outputPipe task.standardError = outputPipe task.launch() task.waitUntilExit() // 可选:打印执行日志 let logData = outputPipe.fileHandleForReading.readDataToEndOfFile() if let log = String(data: logData, encoding: .utf8), !log.isEmpty { print("apktool执行日志:\(log)") } return task.terminationStatus }
- 调用示例:如果要解码APK,直接传对应参数即可:
let status = runApktool("d", "/path/to/your/test.apk", "-o", "/path/to/output/folder") if status == 0 { print("执行成功") } else { print("执行失败,错误码:\(status)") }
- 额外注意:如果你的App开启了沙盒模式,需要在
Signing & Capabilities中勾选Allow Unsigned Executable Memory、Disable Library Validation两个权限,否则子进程调用会被沙盒拦截;如果不需要上架App Store,直接关闭沙盒可避免各类权限问题。
内容的提问来源于stack exchange,提问作者Saad Mahboob
相关产品推荐
相关产品推荐

