如何通过Azure DevOps Pipeline为TestFlight发布添加指定内部测试组
解决方案:通过App Store Connect API自动添加内部测试组
由于AppStoreRelease@1任务暂不支持直接配置TestFlight内部测试组,我们可以在发布任务后添加脚本任务,调用苹果官方的App Store Connect API来将构建分配给指定的内部测试组。
实现步骤
1. 准备必要信息
你需要提前获取以下内容:
- API密钥、密钥ID、Issuer ID(与现有任务中使用的一致)
- 应用ID(可在App Store Connect的应用详情页找到)
- 内部测试组ID(在App Store Connect的「TestFlight > 内部测试」页面,点击目标测试组后,URL中
groups/后的数字即为组ID)
2. 修改Azure Pipeline YAML配置
在现有AppStoreRelease@1任务后添加PowerShell任务,调用API完成测试组分配:
- stage: AppStoreRelease jobs: - job: ReleaseJob displayName: Distribute To TestFlight steps: - task: AppStoreRelease@1 inputs: authType: 'ApiKey' apiKeyId: 'apiKeyId' apiKeyIssuerId: 'apiKeyIssuerId' apitoken: 'apiToken' releaseTrack: 'TestFlight' appIdentifier: 'com.app.identifier' appType: 'iOS' ipaPath: '$(build.artifactStagingDirectory)/**/*.ipa' shouldSkipWaitingForProcessing: true shouldSkipSubmission: true releaseNotes: 'whatToTest.txt' # 新增:调用App Store Connect API分配内部测试组 - task: PowerShell@2 displayName: 'Assign Build to Internal Test Groups' inputs: targetType: 'inline' script: | # 配置参数 $apiKey = "$(apiToken)" $apiKeyId = "apiKeyId" $issuerId = "apiKeyIssuerId" $appId = "你的应用ID" # 替换为实际应用ID $testGroupIds = @("测试组ID1", "测试组ID2") # 替换为你的内部测试组ID # 生成JWT认证令牌 $header = @{ alg = "ES256" kid = $apiKeyId iss = $issuerId exp = [math]::Floor((Get-Date -UFormat %s) + 3600) # 1小时有效期 } | ConvertTo-Json -Compress $headerBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($header)) -replace '\+', '-' -replace '/', '_' -replace '=' $payloadBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('{}')) -replace '\+', '-' -replace '/', '_' -replace '=' $signatureInput = "$headerBase64.$payloadBase64" $privateKey = [System.Security.Cryptography.ECDsa]::CreateFromPem($apiKey) $signature = $privateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($signatureInput), [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.SignaturePadding]::Pkcs1) $signatureBase64 = [Convert]::ToBase64String($signature) -replace '\+', '-' -replace '/', '_' -replace '=' $jwtToken = "$headerBase64.$payloadBase64.$signatureBase64" # 获取最新上传的构建ID $buildsUrl = "https://api.appstoreconnect.apple.com/v1/builds?filter[app]=$appId&sort=-uploadedDate&limit=1" $buildResponse = Invoke-RestMethod -Uri $buildsUrl -Headers @{ "Authorization" = "Bearer $jwtToken" } -Method Get $latestBuildId = $buildResponse.data[0].id # 分配构建到每个内部测试组 foreach ($groupId in $testGroupIds) { $assignUrl = "https://api.appstoreconnect.apple.com/v1/betaGroups/$groupId/relationships/builds" $body = @{ data = @( @{ type = "builds" id = $latestBuildId } ) } | ConvertTo-Json -Compress Invoke-RestMethod -Uri $assignUrl -Headers @{ "Authorization" = "Bearer $jwtToken"; "Content-Type" = "application/json" } -Method Patch -Body $body Write-Host "已将构建分配到测试组:$groupId" }
3. 关键说明
- JWT令牌生成:脚本自动生成符合苹果API要求的认证令牌,有效期1小时。
- 最新构建匹配:通过API获取刚上传的最新构建,确保分配的是当前Pipeline发布的版本。
- 多测试组支持:
$testGroupIds数组可添加多个测试组ID,一次性完成批量分配。
注意事项
- 确保你的API密钥拥有「TestFlight Beta Tester」和「App Store Connect API」的权限。
- 如果苹果后台仍在处理构建(即使设置了
shouldSkipWaitingForProcessing: true),可能导致API调用失败,可在脚本中添加循环检查构建状态的等待逻辑。
内容的提问来源于stack exchange,提问作者Rishabhanand Jha
相关产品推荐
相关产品推荐

