簡體   English   中英

通過命令行將iOS應用程序存檔並分發到App Store

[英]Archive & Distribute iOS app to App Store via command line

通常在向App Store提交iOS應用程序時,我從Xcode執行產品 - >存檔,然后選擇分發到App Store。 我可以使用以下命令成功存檔構建:

xcodebuild -scheme "myScheme" archive -archivePath /my/path/myArchive

但是如何使用正確的配置文件進行簽名過程並通過命令行分發?

對於臨時構建,我在歸檔后生成我的ipa:

xcodebuild -exportArchive -exportFormat IPA -archivePath myArchive.xcarchive -exportPath /my/path/myFile.ipa -exportProvisioningProfile 'my adhoc profile name'

但是,在分發到應用程序商店時,我甚至需要生成ipa嗎? 無論哪種方式,如何使用正確的配置文件進行簽名並通過命令行分發?

請參閱答案底部的Xcode 8更新。

要首先回答問題的最后部分 - 是的,需要App Store配置文件才能通過iTunes連接提交您的應用程序。 除非具有正確的配置文件,否則它不會通過預驗證步驟。 您需要在成員中心中創建App Store分發配置文件

添加iOS配置文件截圖

選擇“App Store”並單擊繼續

問題的第一部分有點困難,因為使用命令行工具創建,簽名和分發存檔和IPA文件的記錄很少。 實現腳本化解決方案充滿了陷阱,因為在某些情況下工具的行為不符合預期,並且需要更詳細地了解開發人員帳戶,密鑰鏈,簽名證書和配置文件之間的關系。

以下是一個腳本示例,可用於創建具有嵌入式Ad Hoc配置文件的存檔,為Ad Hoc分發創建IPA。 作為獎勵,創建DSYMs zip文件以上傳到TestFlight。 然后再呈現兩個腳本。 第一個將從現有的xcarchive創建一個AppA版本的IPA,第二個將顯示如何修改xcarchive,以便第三方可以為Enterprise In House分發重新簽名。

此自動構建腳本假定供應配置文件在使用源代碼簽入的名為ProvisioningProfiles的目錄中可用。 它還假定解鎖持有簽名證書的鑰匙串的密碼存儲在構建用戶主目錄中的受保護文件中。

#!/bin/sh

# SETME
# set to name of signing certification usually starts something like "iPhone Distribution: ...."
# (the associated private key must be available in the key store)
#
# use the command "security find-identity" to list all the possible values available
#
codeSignIdentity="iPhone Distribution"

# SETME
# set to location of Ad Hoc provisioning profile
# (this profile must have the codeSignIdentity specified above included in it)
#
provisioningProfile=ProvisioningProfiles/MyAppAdHocDistribution.mobileprovision

# The keychain needs to be unlocked for signing, which requires the keychain
# password. This is stored in a file in the build account only accessible to
# the build account user
if [ ! -f $HOME/.pass ] ; then
    echo "no keychain password file available"
    exit 1
fi

case `stat -L -f "%p" $HOME/.pass`
in
    *400) ;;
    *)
        echo "keychain password file permissions are not restrictive enough"
        echo "chmod 400 $HOME/.pass"
        exit 1
        ;;
esac

#
# turn off tracing if it is on for security command
# to prevent logging of password
#
case `set -o | grep xtrace`
in
    *on) xon=yes ;;
    *) xon=no ;;
esac

#
# unlock the keychain, automatically lock keychain on script exit
#
[ $xon == yes ] && set +x
security unlock-keychain -p `cat $HOME/.pass` $HOME/Library/Keychains/login.keychain
[ $xon == yes ] && set -x
trap "security lock-keychain $HOME/Library/Keychains/login.keychain" EXIT

#
# Extract the profile UUID from the checked in Provisioning Profile.
#
uuid=`/usr/libexec/plistbuddy -c Print:UUID /dev/stdin <<< \
        \`security cms -D -i $provisioningProfile\``

#
# Copy the profile to the location XCode expects to find it and start the build,
# specifying which profile and signing identity to use for the archived app
#
cp -f $provisioningProfile \
        "$HOME/Library/MobileDevice/Provisioning Profiles/$uuid.mobileprovision"

#
# Build the xcarchive - this will only be done once, will will then
# distribute it for Ad Hoc, App Store and Enterprise In House scenarios
# (profile must be specified by UUID for this step)
#
xcodebuild \
    -workspace MyApp.xcworkspace \
    -scheme MyApp \
    -archivePath build/MyApp.xcarchive \
    archive \
    PROVISIONING_PROFILE="$uuid" \
    CODE_SIGN_IDENTITY="$codeSignIdentity"

#
# Create a zip of the DSYMs for TestFlight
#
/usr/bin/zip -r MyApp.dSYM.zip build/MyApp.xcarchive/dSYMs/MyApp.app.dSYM

#
# now distribute the xcarchive using an Ad Hoc profile
# (for QA testing for example)
#
profileName=`/usr/libexec/plistbuddy -c Print:Name /dev/stdin <<< \
        \`security cms -D -i $provisioningProfile\``

#
# The profile must be specified by name for this step
#
xcodebuild \
        -exportArchive \
        -exportFormat IPA \
        -archivePath build/MyApp.xcarchive \
        -exportPath MyAppForAdHoc.ipa \
        -exportProvisioningProfile "$profileName"

要使用App Store Distribution配置文件重新分發xcarchive,請使用新配置文件重新導出xcarchive(Ad Hoc和App Store配置文件的簽名標識相同)。

# SETME
# set to location of App Store provisioning profile
#
appStoreProvisioningProfile=ProvisioningProfiles/MyAppAppStoreDistribution.mobileprovision

#
# Extract the App Store profile UUID from the checked in Provisioning Profile.
#
uuid=`/usr/libexec/plistbuddy -c Print:UUID /dev/stdin <<< \
        \`security cms -D -i $appStoreProvisioningProfile\``

#
# Copy the profile to the location XCode expects to find it and start the export,
# specifying which profile to use for the archived app
# (Profile must match with signing identity used to create xcarchive)
#
cp -f $appStoreProvisioningProfile \
        "$HOME/Library/MobileDevice/Provisioning Profiles/$uuid.mobileprovision"

#
# Extract the enterprise profile name from the checked in App Store Provisioning Profile.
# and redistribute the xcarchive as an App Store ready IPA
#
profileName=`/usr/libexec/plistbuddy -c Print:Name /dev/stdin <<< \
        \`security cms -D -i $appStoreProvisioningProfile\``

#
# Profile must be specified by name for this step
#
xcodebuild \
    -exportArchive \
    -exportFormat IPA \
    -archivePath build/MyApp.xcarchive \
    -exportPath MyAppForStore.ipa \
    -exportProvisioningProfile "$profileName"

最后,為了完成,如果您想使用新的身份和配置文件重新簽名xcarchive,該怎么辦? 如果您將內部分發的xcarchives分發給第三方公司,則可能會發生這種情況。 收件人需要使用其企業證書簽署您的xcarchive以進行分發。 xcodebuild不能被強制覆蓋xcarchive中的現有代碼簽名,因此必須直接使用codesign。

# SETME
# set to name of enterprise signing certification usually starts something like
# "iPhone Distribution: ...."
#
# use the command "security find-identity" to list all the possible values available
#
enterpriseCodeSignIdentity="iPhone Distribution: Acme Ltd"

# SETME
# set to location of Enterprise In-House provisioning profile
# (this profile must be associated with the enterprise code signing identity)
#
enterpriseProvisioningProfile=ProvisioningProfiles/MyAppInHouseDistribution.mobileprovision

# SETME
# A resigning of the app with a different certificate requires a new bundle ID
# that is registered by the Enterprise and is included in the In-House distribution
# profile (This could be automatically extracted from the Enterprise In-House distribution
# profile, I leave that as an ETTR)
enterpriseBundleId="com.enterprise.myapp"

#
# Extract the enterprise profile UUID from the checked in Provisioning Profile.
#
euuid=`/usr/libexec/plistbuddy -c Print:UUID /dev/stdin <<< \
        \`security cms -D -i $enterpriseProvisioningProfile\``

#
# Copy the profile to the location XCode expects to find it and start the build,
# specifying which profile and signing identity to use for the archived app
#
cp -f $enterpriseProvisioningProfile \
        "$HOME/Library/MobileDevice/Provisioning Profiles/$euuid.mobileprovision"

#
# Copy, modify and resign the xcarchive ready for Enterprise deployment
# (has to be resigned as the production certificate is different for enterprise)
#
cp -Rp build/MyApp.xcarchive build/MyAppEnterprise.xcarchive

#
# Remove old code signature
#
rm -rf build/MyAppEnterprise.xcarchive/Products/Applications/MyApp.app/_CodeSignature

#
# copy in the enterprise provisioning profile
#
cp $enterpriseProvisioningProfile \
        build/MyAppEnterprise.xcarchive/Products/Applications/MyApp.app/embedded.mobileprovision

#
# Modify the bundle id to that of the enterprise bundle id
#   
/usr/libexec/plistbuddy -c "Set:CFBundleIdentifier $enterpriseBundleId" \
        build/MyAppEnterprise.xcarchive/Products/Applications/MyApp.app/Info.plist

#
# resign the xcarchive with the enterprise code signing identity
#
/usr/bin/codesign -f -v -s $enterpriseCodeSignIdentity \
        build/MyAppEnterprise.xcarchive/Products/Applications/MyApp.app 

#
# Update the DSYM bundle id and create a zip of the DSYMs for TestFlight (if applicable)
#
/usr/libexec/plistbuddy -c "Set:CFBundleIdentifier com.apple.xcode.dsym.${enterpriseBundleId}" \
        build/MyAppEnterprise.xcarchive/dSYMs/MyApp.app.dSYM/Contents/Info.plist
/usr/bin/zip -r MyAppEnterprise.dSYM.zip build/MyAppEnterprise.xcarchive/dSYMs/MyApp.app.dSYM

#
# Extract the enterprise profile Name from the checked in Provisioning Profile.
#
enterpriseProfileName=`/usr/libexec/plistbuddy -c Print:Name /dev/stdin <<< \
        l\`security cms -D -i $enterpriseProvisioningProfile\``

#
# Profile must be specified by name for this step
#
xcodebuild \
    -exportArchive \
    -exportFormat IPA \
    -archivePath build/MyAppEnterprise.xcarchive \
    -exportPath MyAppEnterprise.ipa \
    -exportProvisioningProfile "$enterpriseProfileName"

如果腳本是作為launchd守護程序運行的,請參閱此答案https://stackoverflow.com/a/9482707/2351246以解決從launchd守護程序訪問登錄密鑰鏈的問題。

OSX Mavericks和Yosemite的更新

在OSX Mavericks(v10.9.5)和OSX Yosemite上,您可能會看到代碼簽名錯誤:

Codesign check fails : ...../MyApp.app: resource envelope is obsolete

在這里查看此帖子的原因xcodebuild - codesign -vvvv說“資源信封已過時”

要在引用的帖子中實現Apple Support建議的更改,請運行以下命令:

 sudo perl -pi.bak -e 's/--verify"./--verify", "--no-strict",/ if /codesign.*origApp/;' `xcrun -sdk iphoneos -f PackageApplication`

更新Xcode8

在Xcode8中,我之前的答案中描述的過程不再適用於新的自動管理簽名功能,因此您需要選擇手動簽名才能使用此方法。

如果您希望使用自動簽名,以下是基於我們嘗試使用IBM Jazz和Jenkins一個CI環境的一些觀察。

  1. 如果您有一台CI計算機可以使自動代碼簽名工作。 我發現您必須在CI計算機上創建並將開發人員帳戶分配給Xcode實例。 這是一個手動步驟,我發現無法從命令行導入開發人員配置文件。

  2. 如果您使用具有多個構建計算機的分布式CI環境,則它無法正常工作。 首先你有上述問題,你必須手動將開發者帳戶添加到Xcode的所有實例,其次,每個帳戶必須是不同的Apple ID,否則你會得到公共構建帳戶的證書生成問題(所有機器)共享一個帳戶,導致開發人員證書中的沖突,因為它綁定到特定的計算機)。

我們運行分布式Jenkins CI環境,因此我們堅持手動簽名,但導出IPA的方法發生了變化,現在必須使用-exportOptionsPlist選項。

更改存檔命令:

#
# Build the xcarchive - this will only be done once, will will then
# distribute it for Ad Hoc, App Store and Enterprise In House scenarios
#
xcodebuild \
    -workspace MyApp.xcworkspace \
    -scheme MyApp \
    -archivePath build/MyApp.xcarchive \
    archive 

存檔使用與構建帳戶關聯的iOS Developer證書進行簽名(因此請確保它已在密鑰鏈中安裝了一個)。 現在,可以使用xcodebuild的-exportOptionsPlist選項將存檔導出為Ad-hoc,Enterprise和App Store的IPA格式。

使用以下內容創建名為exportAppStore.plist的文件,並將其保存在頂級項目目錄中。

<?xml version="1.0" encoding="UTF-8"?>                                                                                                                                                                                                                                                                                                     
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>app-store</string>
</dict>
</plist>

有關-exportOptionsPlist選項可用的完整鍵列表,請參閱輸出xcodebuild -help

現在修改export archive命令以使用新的導出選項plist文件

xcodebuild \
    -exportArchive \
    -archivePath build/MyApp.xcarchive \
    -exportOptionsPlist exportAppStore.plist \
    -exportPath MyAppForStore.ipa

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM