I have a Safari Extension deployed to test flight built and deployed using CLI tools in Azure Devops. It appears to be building, signing, and deploying properly. But when users try to install on TestFlight, they see an error saying something about an invalid provisioning profile. This seems to just be on the "installer" portion of the app. The extension shows up in safari settings and is otherwise useable. The users just aren't seeing the splash screen that instructs them to go to Safari Settings.
I'm not really sure what's wrong here. This is what my build pipeline looks like
- task: Bash@3
displayName: "Build export.plist file"
inputs:
targetType: 'inline'
script:
/usr/libexec/PlistBuddy -c "Add :method string mac-application" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :provisioningProfiles dict" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :provisioningProfiles:$(APP_IDENTIFIER) string $(InstallDistProvisioningProfile.provisioningProfileUuid)" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :signingCertificate string '$(InstallDistCerts.signingIdentity)'" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :signingStyle string manual" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :teamID string $(APPLE_TEAM_ID)" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :iCloudContainerEnvironment string Production" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :stripSwiftSymbols bool true" $(Pipeline.Workspace)/export.plist &&
/usr/libexec/PlistBuddy -c "Add :compileBitcode bool false" $(Pipeline.Workspace)/export.plist
- task: Xcode@5
displayName: "Build Safari Extension"
inputs:
action: "archive"
sdk: "macosx"
packageApp: true
xcodeVersion: "15"
args: "-verbose CODE_SIGNING_REQUIRED=Yes CODE_SIGNING_ALLOWED=Yes"
exportOptions: "plist"
exportOptionsPlist: '$(Pipeline.Workspace)/export.plist'
exportMethod: "mac-application"
archivePath: '$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive'
signingOption: "default"
- script: |
xcodebuild -exportArchive \
-archivePath $(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive \
-exportPath $(Build.ArtifactStagingDirectory) \
-exportOptionsPlist $(Pipeline.Workspace)/export.plist
displayName: 'Export Distribution-signed App'
- task: DownloadSecureFile@1
displayName: "Download Provisioning Profile"
name: downloadProvisioningProfile
inputs:
secureFile: $(PROVISIONING_PROFILE_DIST)
- script: |
cp "$(downloadProvisioningProfile.secureFilePath)" "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.app/Contents/embedded.provisionprofile"
displayName: "Embed provisioning profile in Top-Level Executable"
- script: |
cp "$(downloadProvisioningProfile.secureFilePath)" "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.app/Contents/PlugIns/SafariDesktopExtension Extension.appex/Contents/embedded.provisionprofile"
displayName: "Embed provisioning profile in Extension"
- script: |
codesign --deep --force --verify --verbose --sign "$(InstallDistCerts.signingIdentity)" --entitlements "$(rootFolder)/safari/SafariDesktopExtension/SafariDesktopExtension/SafariDesktopExtension.entitlements" $(Build.ArtifactStagingDirectory)/SafariDesktopExtension.app
displayName: "Codesign"
- task: Bash@3
displayName: "Package Application"
inputs:
targetType: "inline"
script: |
productbuild --sign "$(InstallInstallerCert.signingIdentity)" --component "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.app" /Applications "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.pkg"
I'm sure there's a bit of garbage here as I'm new to developing in the apple ecosystem. But it appears to work and the resulting .pkg can be submitted successfully.
Effectively, that's building an archive using a plist for export options, exporting the archive for distribution, copying the distribution provisioning profile for the top-level executable (the one that's not working) and the extension itself, code signing, and packaging using the installer cert.
The provisioning profile (attached to a Mac distribution certificate) mentioned has the correct application identifier and matches the entitlements.
I'm not really sure what's going on here and the generic "invalid provisioning profile" error isn't helping. Any help would be appreciated. I'd also love to know if this could hold up a release.
I was able to resolve this by
- dropping use of the xcode@5 task and use
xcodebuild
directly - dropping
xcodebuild -exportArchive
and handling that myself by manually dropping in my provisioning profiles, manually signing withcodesign
, and packaging withproductBuild
At first, it seemed that I was using -exportArchive
wrong having selected Mac-Application
instead of app-connect
as the export method. Fixing that worked well enough after I included my installer provisioning profile in the plist, however I ran into issues with the distribution provisioning profiles here as the embedded application (safari extension) had a different bundle-id than the top-level application. This required that I do all of that manually (though I bet resolve itself if I update the bundle identifier to match, but I'm short on time and I'm going to stick with this for now unless it causes me problems...)
For posterities sake, the working pipeline is:
- task: InstallAppleCertificate@2
displayName: "Install Developer Certificate"
name: InstallAppleCertificate
inputs:
certSecureFile: $(APPLE_DEV_CERT)
certPwd: $(APPLE_DEV_CERT_PASSWORD)
- task: InstallAppleCertificate@2
displayName: "Install Distribution Certificate"
name: InstallDistCerts
inputs:
certSecureFile: $(APPLE_DIST_CERT)
certPwd: $(APPLE_DIST_CERT_PASSWORD)
- task: InstallAppleProvisioningProfile@1
displayName: "Install Distribution Provisioning Profile"
name: InstallDistProvisioningProfile
inputs:
provProfileSecureFile: $(PROVISIONING_PROFILE_DIST)
- task: InstallAppleCertificate@2
displayName: "Install Installer Certificate"
name: InstallInstallerCert
inputs:
certSecureFile: $(APPLE_INSTALLER_CERT)
certPwd: $(APPLE_INSTALLER_CERT_PASSWORD)
- task: InstallAppleProvisioningProfile@1
displayName: "Install Extension Distribution Provisioning Profile"
name: InstallExtDistProvisioningProfile
inputs:
provProfileSecureFile: $(EXTENSION_PROVISIONING_PROFILE)
- task: Bash@3
displayName: "Update Safari Bundle Version"
inputs:
workingDirectory: "browser-extensions"
filePath: "browser-extensions/update-pbxproj-version.sh"
- template: build-extension.yml
- script: |
sudo xcodebuild -project "browser-extensions/chrome-v2/safari/SafariDesktopExtension/SafariDesktopExtension.xcodeproj" \
-scheme SafariDesktopExtension \
-configuration Release \
archive \
-archivePath '$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive' \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO
displayName: 'Archive Xcode Project'
- task: DownloadSecureFile@1
displayName: "Download Provisioning Profile"
name: downloadProvisioningProfile
inputs:
secureFile: $(PROVISIONING_PROFILE_DIST)
- task: DownloadSecureFile@1
displayName: "Download Provisioning Profile"
name: downloadExtensionProvisioningProfile
inputs:
secureFile: $(EXTENSION_PROVISIONING_PROFILE)
- script: |
sudo cp "$(downloadProvisioningProfile.secureFilePath)" "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive/Products/Applications/SafariDesktopExtension.app/Contents/embedded.provisionprofile"
displayName: "Embed provisioning profile in Top-Level Executable"
- script: |
sudo cp "$(downloadExtensionProvisioningProfile.secureFilePath)" "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive/Products/Applications/SafariDesktopExtension.app/Contents/PlugIns/SafariDesktopExtension Extension.appex/Contents/embedded.provisionprofile"
displayName: "Embed provisioning profile in Extension"
- script: |
# Sign the nested app extension
sudo codesign --verbose --sign "$(InstallDistCerts.signingIdentity)" \
--entitlements "$(rootFolder)/safari/SafariDesktopExtension/SafariDesktopExtension Extension/SafariDesktopExtension_Extension.entitlements" \
"$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive/Products/Applications/SafariDesktopExtension.app/Contents/PlugIns/SafariDesktopExtension Extension.appex"
# Sign additional components if necessary (e.g., frameworks, helper apps)
find "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive/Products/Applications/SafariDesktopExtension.app/Contents/Frameworks" -type f -name "*.dylib" -or -name "*.framework" | while read component; do
sudo codesign --force --verbose --sign "$(InstallDistCerts.signingIdentity)" "$component"
done
# Sign the main app
sudo codesign --force --verbose --sign "$(InstallDistCerts.signingIdentity)" \
--entitlements "$(rootFolder)/safari/SafariDesktopExtension/SafariDesktopExtension/SafariDesktopExtension.entitlements" \
"$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive/Products/Applications/SafariDesktopExtension.app"
displayName: "Codesign"
- task: Bash@3
displayName: "Package Application"
inputs:
targetType: "inline"
script: |
productbuild --sign "$(InstallInstallerCert.signingIdentity)" --component "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.xcarchive/Products/Applications/SafariDesktopExtension.app" /Applications "$(Build.ArtifactStagingDirectory)/SafariDesktopExtension.pkg"
- task: PublishBuildArtifacts@1
inputs:
PathToPublish: "$(Build.ArtifactStagingDirectory)"
ArtifactName: "SafariDesktopExtension"
displayName: "Publish Desktop Extension Artifact"