Gradle执行带空格参数的Xcode构建并通过xcpretty实时管道输出问题
Gradle执行Xcode构建并通过xcpretty实时输出的解决方案
方案一:基于Gradle exec块实现(推荐)
直接通过shell包装命令,既支持管道语法,也能正确处理带空格的参数,同时可实时输出构建日志:
// 可选:参数转义方法,避免变量包含特殊字符导致命令异常 def escapeShellArg(String arg) { return "'" + arg.replace("'", "'\\''") + "'" } exec { executable 'sh' args = [ '-c', """xcodebuild archive \ -project ${buildDir}/iPhone/Unity-iPhone.xcodeproj/ \ -archivePath ${buildDir}/iPhone/Unity-iPhone.xcarchive \ -sdk iphoneos \ GCC_GENERATE_DEBUGGING_SYMBOLS=YES \ DEBUG_INFORMATION_FORMAT=dwarf-with-dsym \ DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT=NO \ DWARF_DSYM_FOLDER_PATH=iOS_Dsym \ DEBUGGING_SYMBOLS=YES \ DEVELOPMENT_TEAM=RPGSNMH65P \ CODE_SIGN_IDENTITY=${escapeShellArg(appleIdentity)} \ CODE_SIGN_STYLE=Manual \ USYM_UPLOAD_AUTH_TOKEN=${escapeShellArg(appcenter_login_token)} \ PROVISIONING_PROFILE_SPECIFIER_APP=${escapeShellArg(provisioningProfile)} \ -configuration Release \ -scheme ${escapeShellArg(schemeName)} \ | xcpretty """ ] // 实时输出日志到控制台 standardOutput = System.out errorOutput = System.err // 如果需要同时保存日志到文件,可将管道部分改为 | xcpretty | tee build_output.log }
方案二:基于Groovy Process手动实现
如果不想通过shell包装,可手动构造两个进程建立管道,完全避免参数空格解析问题:
// 构造xcodebuild参数数组,数组元素会被当成独立参数,天然支持带空格的参数值 def xcodebuildArgs = [ 'xcodebuild', 'archive', '-project', "${buildDir}/iPhone/Unity-iPhone.xcodeproj/", "-archivePath", "${buildDir}/iPhone/Unity-iPhone.xcarchive", "-sdk", "iphoneos", "GCC_GENERATE_DEBUGGING_SYMBOLS=YES", "DEBUG_INFORMATION_FORMAT=dwarf-with-dsym", "DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT=NO", "DWARF_DSYM_FOLDER_PATH=iOS_Dsym", "DEBUGGING_SYMBOLS=YES", "DEVELOPMENT_TEAM=RPGSNMH65P", "CODE_SIGN_IDENTITY=${appleIdentity}", "CODE_SIGN_STYLE=Manual", "USYM_UPLOAD_AUTH_TOKEN=${appcenter_login_token}", "PROVISIONING_PROFILE_SPECIFIER_APP=${provisioningProfile}", "-configuration", "Release", "-scheme", "${schemeName}" ] // 分别启动xcodebuild和xcpretty进程 def xcodebuildProc = xcodebuildArgs.execute() def xcprettyProc = ['xcpretty'].execute() // 建立管道:将xcodebuild的标准输出传给xcpretty的输入,错误输出直接打印到控制台 Thread.start { xcodebuildProc.errorStream.eachLine { println it } } Thread.start { xcodebuildProc.inputStream.eachLine { line -> xcprettyProc.out.println(line) xcprettyProc.out.flush() } xcprettyProc.out.close() } // 实时打印xcpretty的输出 xcprettyProc.inputStream.eachLine { println it } xcprettyProc.errorStream.eachLine { println it } // 等待进程执行完成,检查返回码 xcodebuildProc.waitFor() xcprettyProc.waitFor() if (xcodebuildProc.exitValue() != 0) { throw new GradleException("Xcode构建失败,退出码:${xcodebuildProc.exitValue()}") }
原代码异常原因说明
- 直接将
| xcpretty加入exec的args列表无效:|是shell特有的管道语法,Gradle exec默认直接启动可执行文件,不会经过shell解析,会被当成xcodebuild的普通参数导致命令报错。 - 字符串形式的execute()方法会自动按空格拆分参数,即便手动加引号也会被错误解析,而数组形式的execute()虽然能正确处理带空格的参数,但本身不支持管道语法,需要手动处理进程间数据流。
- 未配置输出流实时转发时,Gradle会缓存所有输出直到进程执行完成,才会一次性打印,导致无法实时查看进度。
内容的提问来源于stack exchange,提问作者ohthepain
相关产品推荐
相关产品推荐

