Hi all,
I am writing a MacOS app that makes use of the Android Debug Bridge (ADB) tool. To achieve this I am using a Process
to run an ADB executable.
My issue is that when I run a command, I don't see anything come through the standardOutput
of the Process
until the command finishes.
For example, if I run the ADB pull
command in the terminal, it outputs the completion percentage of the file transfer as it is running. This output occurs over one line and is updated as the percentage updates. It looks something like this:
[ 5%] myFile.txt
Once the transfer finishes, the line changes to something like this:
myFile.txt: 1 file pulled, 0 skipped. 34.9 MB/s (1459978240 bytes in 39.871s)
When I run this same command through a Process
in my MacOS app, I do not see the percentage updates come through; only the final line confirming the transfer was successful.
I can't figure out why this is the case. I am fairly sure my process is configured correctly; if I instead make it execute a shell script that slowly outputs a fake loading bar (updating over a single line), I receive those updates through the standard output pipe as I would expect.
Here is what my testing code looks like:
let outputPipe = Pipe()
var progressObserver: NSObjectProtocol!
func testAdb() {
let process = Process()
process.standardOutput = outputPipe
process.arguments = adbArgs
process.executableURL = Bundle.main.url(forResource: "adb", withExtension: nil)!
outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
progressObserver = NotificationCenter.default.addObserver(
forName: NSNotification.Name.NSFileHandleDataAvailable,
object: outputPipe.fileHandleForReading,
queue: nil
) { notification -> Void in
print("Data available")
let data = self.outputPipe.fileHandleForReading.availableData
if data.count > 0 {
let str = String(data: data, encoding: String.Encoding.utf8)
print(str!)
self.outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
} else {
NotificationCenter.default.removeObserver(self.progressObserver!)
}
}
do {
print("Running...")
try process.run()
print("...checking available data...")
let data = try outputPipe.fileHandleForReading.readToEnd()!
print("...got available data!")
let output = String(data: data, encoding: .utf8)!
let sanitisedOutput = output.trimmingCharacters(in: .whitespacesAndNewlines)
print("Result: \(sanitisedOutput)")
} catch {
print("ADB Error: \(error)")
}
}
I have also tried setting the readabilityHandler
on the Pipe
but that hasn't helped. My guess is that ADB might be doing something differently than a simple shell script would.
I'm not too familiar with how the standard output works, so I am hoping that someone here could help me with this. Thanks.