pipeline { agent {label 'macos'} tools { nodejs 'node22' } environment { UNIAPP_APP_ID = '__UNI__EDE52' // uni-app 应用ID APP_DIR = "Ios/HBuilder-Hello" // iOS 项目根目录 PROJECT_NAME = 'HBuilder-Hello' // 项目名称(xcodeproj 前缀) ASSETS_DIR = "${APP_DIR}/${PROJECT_NAME}/Pandora/apps/${UNIAPP_APP_ID}/www" // 静态资源目录 SCHEME_NAME = 'HBuilder' // Xcode 编译 Scheme CONFIGURATION = 'Release' // 编译模式:Release/Debug ARCHIVE_PATH = "${APP_DIR}/build/HBuilder.xcarchive" // 归档文件输出路径 SOURCE_SDK="${HOME}/Library/SDK" // IOS的SDK存放路径 TARGET_LINK="${APP_DIR}/../SDK" // ====================== 证书配置 ====================== CERT_DIR = 'certificate/ios' // 证书文件存放目录 P12_FILE = "${CERT_DIR}/生产证书.p12" // 开发证书 p12 路径 P12_PASSWORD = "123456" // p12 证书导入密码 PROFILE_FILE = "${CERT_DIR}/jiaixuepro.mobileprovision" // 描述文件路径 MAC_LOGIN_PWD = "667788" // Mac 登录密码(解锁钥匙串) EXPORT_OPTIONS_PLIST = "${CERT_DIR}/ExportOptions.plist" // 导出配置文件路径 // ====================== 手动签名必须的变量 ====================== DEVELOPMENT_TEAM = "2EP6SRRN43" // 苹果开发者团队ID CERTIFICATE_NAME = "Apple Distribution: Bank of Jilin Co., Ltd. (2EP6SRRN43)" // 证书名称(钥匙串里看) PROVISIONING_PROFILE_UUID = "e3487fe1-19dc-4fc7-90df-11caf27da0c6" // 描述文件UUID // ====================== TestFlight上传配置 ====================== API_KEY = "ACRB9XFL9G" // App Store Connect API 密钥ID API_ISSUER = "69a6de7f-3378-47e3-e053-5b8c7c11a4d1" // API 密钥对应的Issuer ID API_TYPE = "ios" // 应用类型(固定为ios) P8_FILE = "${CERT_DIR}/AuthKey_ACRB9XFL9G.p8" // .p8 密钥文件 APP_NAME = "吉AI学" API_ENDPOINT = "https://api.appstoreconnect.apple.com/v1" } stages { stage('打印环境变量') { steps { echo "使用的 UNIAPP_APP_ID:${env.UNIAPP_APP_ID}" echo "IOS资源目录:${env.ASSETS_DIR}" sh "node -v" // 打印 NodeJS 版本 sh "npm -v" // 打印 NPM } } stage('清理旧构建') { steps { sh "rm -rf dist/" // 清理 UniApp 打包生成的 dist 目录 sh "rm -rf ${env.ARCHIVE_PATH}" // 清理 上次的构建文件 } } stage('安装依赖') { steps { echo "✅ 安装 UniApp 依赖(忽略平台+开权限+强制)" sh "npm install --force --unsafe-perm --ignore-platform" } } stage('读取 manifest 版本号 → 写入环境变量') { steps { script { // 2. 读取并设置为 环境变量(全局可用) env.versionName = sh( script: ''' node -p "require('json5').parse(require('fs').readFileSync('./src/manifest.json','utf8')).versionName" ''', returnStdout: true ).trim() env.versionCode = sh( script: ''' node -p "require('json5').parse(require('fs').readFileSync('./src/manifest.json','utf8')).versionCode" ''', returnStdout: true ).trim() } // 测试输出(你能看到成功了) echo "✅ 版本名称:${env.versionName}" echo "✅ 版本号:${env.versionCode}" } } //stage('安装证书 & 描述文件') { // steps { // echo "# =============== 安装 p12 证书 ===============" // sh ''' // security unlock-keychain -p ${MAC_LOGIN_PWD} ~/Library/Keychains/login.keychain-db >/dev/null 2>&1 // security import ${P12_FILE} -k ~/Library/Keychains/login.keychain-db -P ${P12_PASSWORD} -A >/dev/null 2>&1 // security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k ${MAC_LOGIN_PWD} ~/Library/Keychains/login.keychain-db >/dev/null 2>&1 // ''' // echo "# =============== 安装描述文件 ===============" // sh ''' // mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" // cp "${PROFILE_FILE}" "$HOME/Library/MobileDevice/Provisioning Profiles/" // ''' // } //} //stage('打包uniapp') { // steps { // sh "npm run build:app-plus:${env.BRANCH_NAME}" // } //} //stage('复制UniApp资源到目录') { // steps { // echo "开始复制 dist 资源到 ${ASSETS_DIR}" // // 先创建目标目录(防止目录不存在报错) // sh "mkdir -p ${ASSETS_DIR}" // // 把 dist 里所有文件 复制 到安卓资源目录(推荐) // sh "cp -rf dist/build/app/* ${ASSETS_DIR}/" // echo "✅ 资源复制完成" // } //} // //stage('️清理旧构建内容') { // steps { // sh """ // xcodebuild clean \\ // -project ${APP_DIR}/${PROJECT_NAME}.xcodeproj \\ // -scheme ${SCHEME_NAME} \\ // -configuration ${CONFIGURATION} // """ // // } //} //stage('创建SDK软链接') { // steps { // sh ''' // # 删除旧的软链接/目录 // rm -rf "${TARGET_LINK}" // // # 创建软链接(不进入任何目录) // ln -s "${SOURCE_SDK}" "${TARGET_LINK}" // // # 验证链接是否生效 // ls -la "${TARGET_LINK}" // ''' // } //} //stage('✅ 开始归档(静默模式)') { // steps { // script { // // Groovy 里拼接命令,随便写注释,不会影响 shell // def xcodeCommand = [ // 'xcodebuild archive', // // 项目路径 // "-project ${APP_DIR}/${PROJECT_NAME}.xcodeproj", // // Scheme 配置 // "-scheme ${SCHEME_NAME}", // // 编译模式 Release/Debug // "-configuration ${CONFIGURATION}", // // 归档输出路径 // "-archivePath ${ARCHIVE_PATH}", // // 平台通用 iOS // "-destination generic/platform=iOS", // // 版本号 // "MARKETING_VERSION=${versionName}", // "CURRENT_PROJECT_VERSION=${versionCode}", // // // 手动签名 // "CODE_SIGN_STYLE=Manual", // "CODE_SIGN_IDENTITY='${CERTIFICATE_NAME}'", // "PROVISIONING_PROFILE_SPECIFIER='${PROVISIONING_PROFILE_UUID}'", // "PROVISIONING_PROFILE='${PROVISIONING_PROFILE_UUID}'", // "DEVELOPMENT_TEAM='${DEVELOPMENT_TEAM}'", // // // 钥匙串 // "OTHER_CODE_SIGN_FLAGS='--keychain ~/Library/Keychains/login.keychain-db'", // // // 编译所有架构 // "ONLY_ACTIVE_ARCH=NO", // // // 清空编译参数 // "OTHER_CFLAGS=''", // "OTHER_CPLUSPLUS_FLAGS=''", // "OTHER_SWIFT_FLAGS=''", // "> /dev/null 2>&1" // ].join(' ') // 拼接成一行完整命令 // // 打印最终命令 // echo "执行命令:${xcodeCommand}" // // 执行! // sh(xcodeCommand) // } // } //} //stage('✅ 开始导出 IPA安装包') { // steps { // sh ''' // xcodebuild -exportArchive \\ // -archivePath ${ARCHIVE_PATH} \\ // -exportPath ${APP_DIR}/build \\ // -exportOptionsPlist ${EXPORT_OPTIONS_PLIST} \\ // -allowProvisioningUpdates // ''' // } //} //stage('🚀 验证并上传 TestFlight') { // steps { // echo "✅ 开始验证 IPA 有效性" // sh ''' // mkdir -p $HOME/private_keys // cp -f "${P8_FILE}" $HOME/private_keys/ // ''' // // 1. 先验证 IPA(必须这一步,提前拦截错误) // sh """ // xcrun altool --validate-app \\ // --file ${APP_DIR}/build/${SCHEME_NAME}.ipa \\ // --type ${API_TYPE} \\ // --apiKey ${API_KEY} \\ // --apiIssuer ${API_ISSUER} // """ // // echo "✅ IPA 验证成功!开始上传到 TestFlight" // // echo "🎉 全部完成!请到 App Store Connect TestFlight 查看构建" // } //} stage('🔐 生成 JWT') { steps { script { // 一行式 node -e "代码" 必须写在同一行! JWT_TOKEN = sh( script: ''' node -e "const fs=require('fs');const jwt=require('jsonwebtoken');const privateKey=fs.readFileSync(process.env.P8_FILE,'utf8');const token=jwt.sign({iss:process.env.API_ISSUER,exp:Math.floor(Date.now()/1000)+1200,aud:'appstoreconnect-v1'},privateKey,{algorithm:'ES256',header:{kid:process.env.API_KEY}});console.log(token);" ''', returnStdout: true ).trim() echo "✅ JWT 生成成功:${JWT_TOKEN}" } } } } post { always { echo '流水线已结束' } success { echo '🎉 项目部署成功!' } failure { echo '⚠️ 部署失败,请检查日志!' } } }