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

Swift 5 macOS应用中ADB命令实现、工具打包及参数问题排查

搞定你的macOS ADB应用开发问题

Hey there! Let's walk through how to build your macOS app that interacts with Android devices using ADB—fixing your current shell function issue, packaging platform-tools, and implementing all the features you need.

1. 先修复你的Shell函数参数错误

Your current shell function has a mix-up in how it handles ADB commands. The Process class in Swift works like this:

  • executableURL (or launchPath in older versions) points directly to the ADB executable file, not a command string.
  • arguments is an array of the parameters you want to pass to ADB, not a hardcoded "args" or full command.

For example, to run adb devices, you need to tell Process to use the ADB executable, then pass ["devices"] as arguments. Here's a revised, reusable function that fixes this and even captures output/errors:

func runADBCommand(arguments: [String]) -> Int32 {
    let task = Process()
    
    // Get path to ADB inside your app bundle (we'll set this up next)
    guard let adbPath = Bundle.main.url(
        forResource: "adb",
        withExtension: "",
        subdirectory: "platform-tools"
    )?.path else {
        print("ADB executable not found in app bundle")
        return -1
    }
    
    task.executableURL = URL(fileURLWithPath: adbPath)
    task.arguments = arguments
    
    // Capture output and error messages
    let outputPipe = Pipe()
    let errorPipe = Pipe()
    task.standardOutput = outputPipe
    task.standardError = errorPipe
    
    do {
        try task.run()
        
        // Read and print output/error (optional, but helpful for debugging)
        let outputString = String(
            data: outputPipe.fileHandleForReading.readDataToEndOfFile(),
            encoding: .utf8
        )
        let errorString = String(
            data: errorPipe.fileHandleForReading.readDataToEndOfFile(),
            encoding: .utf8
        )
        
        outputString.flatMap { print("ADB Output:\n\($0)") }
        errorString.flatMap { print("ADB Error:\n\($0)") }
        
        task.waitUntilExit()
        return task.terminationStatus
    } catch {
        print("Failed to run ADB command: \(error.localizedDescription)")
        return -1
    }
}

Now to list connected devices, just call:

let deviceStatus = runADBCommand(arguments: ["devices"])

No more "unknown command args" errors!

2. Package platform-tools into your app

To avoid forcing users to install the Android SDK, you can bundle the platform-tools directly into your app:

  • Download the macOS version of platform-tools (from the Android developer site)
  • Unzip the folder, then drag the entire platform-tools directory into your Xcode project
  • In the Xcode File Inspector, make sure your app target is checked under "Add to targets" and "Copy items if needed" is enabled
  • To ensure ADB has executable permissions, add a Run Script phase in your target's Build Phases:
    chmod +x "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/Contents/Resources/platform-tools/adb"
    

This way, your app will always have access to ADB without relying on external installs.

3. Implement your core features

With the fixed command function and bundled ADB, you can now build out each feature you need:

Push .txt/.obb files to Android

Use the adb push command, which takes a local file path and a remote device path:

func pushFile(localPath: String, remotePath: String) -> Int32 {
    return runADBCommand(arguments: ["push", localPath, remotePath])
}

// Example: Push a local text file to the device's Downloads folder
let pushStatus = pushFile(
    localPath: "/Users/yourname/Documents/notes.txt",
    remotePath: "/sdcard/Download/"
)

Install APK files

Use adb install (add -r to overwrite an existing installation):

func installAPK(apkPath: String, overwriteExisting: Bool = false) -> Int32 {
    var args = ["install"]
    if overwriteExisting {
        args.append("-r")
    }
    args.append(apkPath)
    return runADBCommand(arguments: args)
}

// Example: Install an APK the user selects
installAPK(apkPath: "/Users/yourname/Downloads/myapp.apk")

Grant app permissions

Use adb shell pm grant to give permissions to a specific app:

func grantAppPermission(packageName: String, permission: String) -> Int32 {
    return runADBCommand(arguments: ["shell", "pm", "grant", packageName, permission])
}

// Example: Grant storage permission to an app
let grantStatus = grantAppPermission(
    packageName: "com.yourcompany.yourapp",
    permission: "android.permission.WRITE_EXTERNAL_STORAGE"
)

4. Important macOS Sandbox Notes

macOS apps run in a sandbox by default, so you can't access arbitrary files on the user's system without permission. Use NSOpenPanel to let users select files (like APKs or text files) instead of hardcoding paths:

func promptForFile(allowedTypes: [String], completion: @escaping (String?) -> Void) {
    let openPanel = NSOpenPanel()
    openPanel.allowsMultipleSelection = false
    openPanel.canChooseDirectories = false
    openPanel.allowedFileTypes = allowedTypes
    
    if openPanel.runModal() == .OK {
        completion(openPanel.url?.path)
    } else {
        completion(nil)
    }
}

// Example: Prompt user to select an APK
promptForFile(allowedTypes: ["apk"]) { apkPath in
    guard let path = apkPath else { return }
    let status = installAPK(apkPath: path)
    print("Installation status code: \(status)")
}

Also, make sure users enable USB debugging on their Android devices and trust your macOS computer when prompted—otherwise ADB won't detect the device.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 15:32:33