Github Actions中执行bundle exec fastlane beta编译Flutter iOS项目时Archive失败问题排查
bundle exec fastlane beta编译失败(Exit status 65)的问题 首先啊,Exit status 65是Xcode构建脚本执行失败的典型报错,结合你本地能跑通但CI环境直接挂掉的情况,大概率是CI环境的依赖、权限或者证书配置和本地不一致导致的。下面是针对你的情况的排查和修复步骤,你可以一步步试:
一、调整CocoaPods和依赖安装的顺序与权限
看你的Actions脚本,在ios目录下先装了CocoaPods又跑了bundle install,但这里可能有两个坑:一是CI环境下装gem如果不加--user-install很容易碰到权限报错;二是直接用pod install可能没用到Gemfile里指定的版本,导致依赖不一致。
我建议你修改这两步:
- 把Gem安装命令改成这样,避免权限问题:
gem install cocoapods -v 1.10.1 --user-install gem install fastlane -v 2.177.0 --user-install - 把
Install tools里的pod install换成bundle exec pod install,确保用的是bundle管理的版本:- name: Install tools run: | flutter precache flutter pub get cd ./ios bundle exec pod install
二、给Flutter构建脚本添加执行权限
那个失败的Script-9740EEB61CF901F6004384FC.sh是Flutter自动生成的构建脚本,CI环境下有时候会丢失执行权限,导致跑不起来。你可以在Actions里加一步专门处理:
在Install tools步骤之后,新增:
- name: Fix Flutter build script permissions run: | cd ./ios chmod +x "$(find . -name "flutter_build_script.sh" -o -name "Script-*.sh")"
这行命令会自动找到所有Flutter相关的脚本并赋予执行权限,比手动写路径靠谱多了。
三、优化Keychain和证书配置
你的fastlane里已经创建了keychain,但CI环境下有时候解锁不彻底,导致证书没法被Xcode访问到。我建议你在create_keychain之后加一行解锁命令:
unlock_keychain( name: ENV['MATCH_KEYCHAIN_NAME'], password: ENV["MATCH_KEYCHAIN_PASSWORD"] )
另外,在match的配置里加上force_for_new_devices: true,确保新的CI机器能正确导入证书:
match( app_identifier: ENV["APP_IDENTIFIER"], git_url: ENV["GIT_URL"], type: "adhoc", readonly: is_ci, keychain_name: ENV['MATCH_KEYCHAIN_NAME'], keychain_password: ENV["MATCH_KEYCHAIN_PASSWORD"], force_for_new_devices: true )
四、调整Xcode构建参数,提升CI稳定性
在build_app里加几个适配CI环境的参数:
build_app( workspace: "Runner.xcworkspace", scheme: "Runner", export_method: "ad-hoc", clean: true, # 先清缓存再构建,避免旧文件干扰 use_legacy_build_api: false, # 针对Xcode12+的适配 export_options: { signingStyle: "manual", provisioningProfiles: { ENV["APP_IDENTIFIER"] => "你的AdHoc描述文件名" # 这里可以填match生成的描述文件名,或者直接指定 } } )
另外,你还可以给Flutter和CocoaPods加缓存,既省时间又避免重复安装的问题:
- name: Cache Flutter & CocoaPods dependencies uses: actions/cache@v2 with: path: | ~/.pub-cache ios/Pods key: ${{ runner.os }}-flutter-${{ hashFiles('pubspec.lock') }}-cocoapods-${{ hashFiles('ios/Podfile.lock') }}
五、移除多余的环境变量
看你的Actions里传递了FLUTTER_ROOT,但subosito/flutter-action这个action已经帮你设置好正确的FLUTTER_ROOT了,手动传反而可能导致冲突,建议把这一行删掉。
最后,如果还是不行,一定要看详细日志
Github Actions的构建日志里,那个失败的PhaseScriptExecution步骤下面有详细的报错信息,比如找不到Flutter命令、证书无效、某个依赖缺失之类的,这才是定位问题最关键的线索,别只看Exit status 65这个表面报错。
内容的提问来源于stack exchange,提问作者Dolphin

