I have an Xcode project that is used to build multiple apps. I use the same code with a different bundle ID with its own app in the app store connect.
I have used Jenkins and Fast Lane to achieve CI/CD for this project. I have created a Jenkinsfile with a pipeline script that provides the details and the bundle identifier for the multiple apps. When I try the Jenkins job it works correctly for the first app whose bundle identifier is the same as the one provided in the build setting of the Xcode project. So when Jenkins runs the details of the second app, the archive fails stating “No provisioning profile found”. The provisioning profile and everything were correctly fetched but failed during the build. I’m guessing the issue is with Jenkins archiving the Xcode project build using the bundle ID mentioned in the build settings which is the bundle ID of the first app. How do I resolve this issue? I was not able to find a way to change the bundle ID and the corresponding provisioning profile during the build (from Xcode build settings). Is there a way to upload multiple apps using the same Jenkins job and fast lane pipeline?
Currently, the details are passed to build settings using an xcconfig file which has details of the apps I'm building with this xcode project.
Thanks in advance.
Edit:
Jenkinsfile Script:
pipeline {
agent any
environment {
LANG = 'en_US.UTF-8'
LANGUAGE = 'en_US.UTF-8'
LC_ALL = 'en_US.UTF-8'
// Other environment variables as needed
}
stages {
stage('Build and Deploy') {
steps {
script {
// Define shop-specific information for all the shops
def shopInfo = [
[
shopName: 'shopName',
shopDomain: 'shopDomain',
shopifyApiKey: 'shopifyApiKey',
shopifyStoreToken: 'shopifyStoreToken',
bundleIdentifier: 'bundleIdentifier'
],
[
shopName: 'shopName',
shopDomain: 'shopDomain',
shopifyApiKey: 'shopifyApiKey',
shopifyStoreToken: 'shopifyStoreToken',
bundleIdentifier: 'bundleIdentifier'
]
// Add information for other shops here
]
def infoPlistPath = ‘path to Info.plist' // Update with the correct path
// Retrieve the Fastlane username and password from Jenkins credentials
def fastlaneUser = ''
def fastlanePassword = ''
// Iterate through the shop information
for (shop in shopInfo) {
// Set shop-specific details
def shopName = shop.shopName
def shopDomain = shop.shopDomain
def shopifyApiKey = shop.shopifyApiKey
def shopifyStoreToken = shop.shopifyStoreToken
def bundleIdentifier = shop.bundleIdentifier
// Set shop-specific environment variables including the bundle identifier
withEnv([
"SHOP_NAME=${shopName}",
"SHOP_DOMAIN=${shopDomain}",
"SHOPIFY_API_KEY=${shopifyApiKey}",
"SHOPIFY_STORE_TOKEN=${shopifyStoreToken}",
"BUNDLE_IDENTIFIER=${bundleIdentifier}",
'FASTLANE_USER=username,
'FASTLANE_PASSWORD=password’
]) {
// Change the working directory to the Fastlane directory
dir('/Users/shahnasek/Documents/Work/beCo-Store-iOS/beCo-Store/fastlane') {
// Run commands to modify Info.plist
sh "/usr/libexec/PlistBuddy -c 'Set :ShopName $SHOP_NAME' $infoPlistPath"
sh "/usr/libexec/PlistBuddy -c 'Set :ShopDomain $SHOP_DOMAIN' $infoPlistPath"
sh "/usr/libexec/PlistBuddy -c 'Set :ShopifyAPIKey $SHOPIFY_API_KEY' $infoPlistPath"
sh "/usr/libexec/PlistBuddy -c 'Set :StoreToken $SHOPIFY_STORE_TOKEN' $infoPlistPath"
sh "/usr/libexec/PlistBuddy -c 'Set :CFBundleIdentifier $BUNDLE_IDENTIFIER' $infoPlistPath"
// Use the Fastlane username and password directly
sh 'bundle exec fastlane beta'
// Additional steps or cleanup as needed
}
}
}
}
}
}
}
}
Fastlane script:
default_platform(:ios)
platform :ios do desc "Description of what the lane does" lane :beta do xcode_select("/Applications/Xcode.app")
bundle_identifier = sh("ruby get_bundle_identifier.rb", log: true).strip
puts "Fetched bundle identifier: #{bundle_identifier}"
latest_build_number = latest_testflight_build_number(
app_identifier: bundle_identifier
)
UI.message("Latest TestFlight Build Number: #{latest_build_number}")
increment_build_number(
build_number: latest_build_number + 1
)
match(
type: "appstore",
app_identifier: bundle_identifier,
git_url: “gitURL"
)
app_store_connect_api_key(
key_id: "key_id",
issuer_id: "issuer_id",
key_filepath: "key_filepath",
duration: 1200,
in_house: false
)
gym( scheme: "beCo-Store", export_options: { method: "app-store", provisioningProfiles: { bundle_identifier => "match AppStore #{bundle_identifier}" }, signingCertificate: "iPhone Distribution" } )
sync_code_signing(
type: "appstore",
git_url: "git_url",
app_identifier: bundle_identifier
)
upload_to_testflight(
skip_waiting_for_build_processing: true, # Add this to skip waiting
wait_processing_interval: 30, # Increase the interval
app_platform: 'ios'
)
end end