preface

Each update of the project requires more than a dozen packages. Guangfa said that the automatic package script inherited from it suddenly did not work, and now every package upload has to be done until midnight, so it will be better to change the name to Dilute hair. Watching him grow bald, I couldn’t hide my fatherly love and had to share it with him (forced, of course).

In this project, there are more than ten packages with different ICONS and App names. Manual packaging is not only slow, but also the error probability of repetitive boring work increases exponentially. So if your project is going to have to pack several packages, it’s worth taking the time to learn how to auto-pack. If you pack only one bag, the automatic packing time is faster, but the learning cost is still there, depending on your opinion.

The key is to use re-signature to modify custom images, App names, etc., without repeated compilation, can greatly reduce the packaging time.

Certificate of knowledge

Online certificate configuration is no lack of good articles, a lot of search, but most did not introduce what are used.

  • CSR:Certificate Singing Request file

Contains information about the computer. So you don’t need to fill in any information about publishing.

  • Certificates: Publisher Certificates. Apple Develop ID a certificate of authorization for a computer.

After the computer has this certificate, it has the right to test, package and publish all apps under the Apple Developer ID. Notice that there is no App specified, in other words, nothing to do with App.

Contains information about the computer and information about Apple Developer.

  • The link between CSR and Certificates

As mentioned above, Certificates contain information about computers, which comes from the CSR. So when you create Certificates, you need to submit a CSR.

  • Certificates Export p12 files

It says you have the license to do those things. If another computer wants to publish, it also needs a certificate. Creating a new certificate also works, but it is usually enough to create a distribution certificate for a developer account, and Apple has a limit on the number of certificates. Exporting the P12 file in this case is equivalent to copying a certificate (within the limit set by Apple). Once installed on another computer, the other computer has the right.

So far, the author is confused that the CSR contains the information of the computer, and then can be copied to other computers for use, what is the use. I hope the big man can explain it.


What is mentioned above is not directly related to App. The following links are established with App.

  • App IDs

Register your App under the Apple Developer. Name and Bundle ID are required here. The Bundle ID here will match the certificate in Xcode.

I heard from Li Dasen before that if you create a new project and change it to the Bundle ID in the company’s project, the App can also be tested on the real machine because the Bundle ID is matched.

  • Provisioning Profiles: PP files. Mobileprovision suffix.

Includes appID, developer certificate.

When created, there is a difference between development and release. The former to choose equipment, the latter not.

Once the download is created, Xcode will automatically match it, or you can manually match it.

  • When you’re working on a project that you’re not responsible for, people will usually send you.p12 and.mobileprovision files. The former grants your computer Apple Developer ID privileges, the latter grants App privileges.

Automatic packaging

This article uses XcodeBuild.

Automatic packing is a pain in the head. Always had a fear of the command line, just one step at a time. Learn about command-line commands first, and then create a new project to familiarize yourself with them.

Xcodebuild profile

Xcodebuild is a command provided by Xcode to package a project or project.

To view the document, type man xcodeBuild.

Here’s the big guy’s summary.

Type xcodebuild -h to see help.

Usage: xcodebuild [-project <projectname>] [[-target <targetname>]...|-alltargets] [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [<buildsetting>=<value>]... [<buildaction>]... xcodebuild [-project <projectname>] -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [<buildsetting>=<value>]... [<buildaction>]... xcodebuild -workspace <workspacename> -scheme <schemeName> [-destination <destinationspecifier>]... [-configuration <configurationname>] [-arch <architecture>]... [-sdk [<sdkname>|<sdkpath>]] [-showBuildSettings] [<buildsetting>=<value>]... [<buildaction>]... xcodebuild -version [-sdk [<sdkfullpath>|<sdkname>] [<infoitem>] ] xcodebuild -list [[-project <projectname>]|[-workspace <workspacename>]] [-json] xcodebuild -showsdks xcodebuild -exportArchive -archivePath <xcarchivepath> -exportPath <destinationpath> -exportOptionsPlist <plistpath> xcodebuild -exportLocalizations -localizationPath <path> -project <projectname> [-exportLanguage <targetlanguage>...]  xcodebuild -importLocalizations -localizationPath <path> -project <projectname>Copy the code

Xcodebuild try

You can create a new project, Test. Then in Xcode, copy the Bundle Identifier for the company project (which has the certificate), and you’ll see that the certificate matches. (If you don’t have a certificate, look back at the certificate knowledge and read on.) With this project, you can feel the commands.

Packing Method 1

I don’t think it’s as good as method 2, and Apple scrapped one of the tools.

So we compile.app, and then we convert it to.IPA.

Once the terminal is in the project folder, try the first build command.

Xcodebuild-project test. xcodeproj -target test-configuration Release.

Unsurprisingly, the above text will be printed, including the signature identity and configuration file. Test/build/ release-iphoneOS/test.app.dsym.

Xcrun is deprecated in Xcode8.3. If you need to use xcrun: error: Unable to find Utility “PackageApplication”, not a developer tool or in PATH)

After processing, execute the following command to convert to IPA.

xcrun -sdk iphoneos PackageApplication build/Release-iphoneos/Test.app -o ~/Desktop/Test.ipa
Copy the code

Packing Method 2

Use Archive first, then exprotArchive, similar to the interface step of manual packaging.

(Run xcodebuild-list first, remember Scheme)

Xcodebuild archive-scheme Test -archivePath ~/Desktop/ test. xcarchive after the terminal goes to the project folder, run xcodebuild archive-scheme Test -archivePath ~/Desktop/ test. xcarchive.

My guess is that the above and Xcode packaging correspond to this interface.

As you can see from the above figure, exportoptions.plist should be configured separately because of different publishing channels. Xcodebuild -exportArchive -archivePath < xCarchivePath > -exportPath < destinationPath > -exportOptionsPlist Last in .

There are two path configurations.

  • Copy over by manually packaging.
  • Create a new plist file and add key pairs. (Assuming you know how to add).
The exportoptions. plist file contains the following fields and their configurations are as follows: Method: indicates the packaging type. The value can be app-Store, ad-hoc, Enterprise, or development. ProvisioningProfiles: dictionary, required by Xcode9, key-value pair is {bundleID: description file name}, preferably use the UUID corresponding to the description file name. SigningCertificate: indicates the certificate type. The development environment is iPhone Developer, and the production environment is iPhone Distribution. SigningStyle: "Manual" or "automatic". Enter "manual". StripSwiftSymbols: Enter YES. TeamID: indicates the ID of the open team, which can be viewed by clicking the certificate details in the keystring. UploadBitcode: YES UploadSymbols: is YES.Copy the code

I still recommend manual packaging, copy the past and make changes (in the future, other projects can be used only with minor changes, do not need to manually package and copy again). Through the graphical interface, you can better understand the meaning of these fields and the corresponding operations.

I took a screenshot from the Enterprise. Other because the author does not have a certificate, relied on everybody to try.

And then it goes on in the terminal

xcodebuild -exportArchive -archivePath ~/Desktop/Test.xcarchive -exportPath ~/Desktop/Test.api -exportOptionsPlist ./ExportOptions.plist
Copy the code

Xcodebuild will be packaged, other methods are not commonly used, there are few online learning resources, I do not want to explore. Let’s go to the packaging script.


Automatic packaging script

The author referred to the summary of iOS batch packaging in the article of my brother @tsui_Yuenhong, and set up a script by myself, which used the new method suggested by Apple and supplemented some shortcomings of my brother’s script.

First, the author’s sad story. I’ve uploaded a package to the App Store before, and the whole process is hilarious. But this project, a total of more than 20 packages, update a version often hit more than 10 packages. Knock it down and it’s gone. Because the code is basically the same, re-signing can greatly reduce the packaging time.

The author’s project packaging has the following requirements.

To put it simply, it is to customize corresponding ICONS and functions for different users.

  1. You can replace bundle information
  2. Replace audio image resources
  3. You can execute different code
  4. Generate the corresponding PList file
  5. Upload it to the Dandelion distribution platform

Ideas:

  1. So let’s compile the.app file.
  2. Using the commanddefaults writeTo modify the project file, modified to achieve bundleName/bundleDisplayName key-value pairs, implement a custom App name, display name, and generate the corresponding file.
  3. Use the cp command to replace the image resource.
  4. The signature.
  5. The export of ipa.

Problems encountered by the author:

Toggle icon pits

Check out the official recommended icon sizes. Of course, other sizes will also be accepted by the App icon and automatically adapt.

Plan 1 (Unsolved)

  • The author tries to use this scheme. The principle is to use the same picture to cover the picture in the package, re-signature, to achieve the purpose of modifying ICONS. However, after the package image is overwritten, the installation icon does not change (it may need to be modified in info.plist)Icon files (iOS 5)(However, this field is AppIcon?? I don’t know what else the underlying configuration is), so I won’t try.

Scheme 2

  • This method places the icon in the project, not in xcassets.

  • AppIcon’s name must correspond! It is difficult to predict what will happen because the cp command line should be replaced completely, as shown in the following figure. (In my project, the only graphs are 60@2x and 60@3x.)

  • When packaged, the AppIcon icon is in the.app file directory, not in BundleResources.

You can execute different code.

Heavy signature

I suggest you read this article first. Re-signing (packaging) iOS applications

Come out entitlements. Plist, re-signature is used.


digression

The author still encountered a pit when re-signing. The progress bar of the packaged software download turned round, but it could not be finished. Checked a period of time, just know the reason is re signature is not successful. So the script must be terminated if it fails to re-sign.

With an iTunes downgrade article, PP assistant seems not updated or what, can only use the old version of iTunes to debug it, really tired ah. Install iTunes drop back 12.6.3 downloadable application package version tutorial Mac 】 【 Windows |


The script

My brother’s script 1 (256s running time) is faster than my script 2 (306s running time).

But script 1 uses apple’s deprecated methods, so try Script 2 when things go wrong.

The difference between the two scripts is that the.app script comes out first, and the.ipa script comes out later. The Archive package contains.app and.ipa.

  • A script

Ready Entitlements. Plist (this article has access to tutorial, Cmd+ F search “re signature to use “). And make sure this function runs xcrun (deprecated in Xcode8.3).

The IPA is exported using xcRun after compilation and finally re-signed.

The script was posted in the summary of my brother’s article about iOS bulk packaging.

The author encountered the icon replacement failure problem when using this script. It has nothing to do with the script, but related to the project configuration. See the solution above.

But I think there are some problems with this script. For example, the script was not terminated after the operation such as re-signing failed, which caused the author to be confused when he uploaded the script to Dandelion and failed to download it. This is a serious problem. However, with proper judgment, an exit should solve the problem.

  • The second script

Prepared Entitlements. Plist (this article has access to tutorial, Cmd+ F search “re signature to use “) and ExportOptions. Plistist ‘ ‘(this article has access to tutorial, Cmd+ F search” there are two ways to configure “).

Use Archive first, then exprotArchive (similar to the manual packaging process), and finally re-sign.

The script is posted below. Note that the author uses Project instead of Project in many places.

# 1.Configuration Info

The project path needs to be modified
projectDir="Your project path"

Package build path suggestion desktop
ipaPath="Ipa generation path"

The icon path needs to be modified
iconPath="Icon path"

The following files are used to re-sign to generate IPA
Entitlements=$ipaPath/Entitlements.plist
ExportOptions=$ipaPath/ExportOptions.plist

# version number
bundleVersion="2.0.0"

# select package number ("1" "2" "3")
appPackNum=("1" "2")

# dandelion distribution parameters not distributed ignorable default not distributed The following two keys are the default test url corresponding keys
ISUPLOAD=0
USERKEY="xxx"
APIKEY="xxx"

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - optional If you need to replace the app icon -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- #

# configure App information array format :"AppName(corresponding to project appinfo.plist)" "icon" "AppName in Url"
#Schemes:
# 1.app1 app1Icon app1UrlName
# 2.app2 app2Icon app2UrlName
# 3.app3 app3Icon app3UrlName

# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - #

# number of packages
appPackNumLength=${#appPackNum[*]}

appInfos=(
          "app1" "app1Icon" "app1UrlName"
          "app2" "app2Icon" "app2UrlName"
          "app3" "app3Icon" "app3UrlName"
          )

appInfosLength=${#appInfos[*]}

# Scheme Name
schemeName="xx"

# Start time
beginTime=`date +%s`

# Generate xcarchive path, suggested desktop
mkdir ${ipaPath}/Payload
rm -rf ${ipaPath}/Payload/*
buildDir="${ipaPath}/Payload"

Turn off autosignature to manual signature
# Build builds xcarchive
xcodebuild archive -workspace ${projectDir}/YouXiaoYun.xcworkspace -scheme ${schemeName} -archivePath ${buildDir}/Project.xcarchive
#
if[[$? = 0]];then # $? Represents the return value of the previous command. Returns 0 if the previous command was executed successfully, 1 otherwise.
    echo "\033[31m compiled successfully \n \033[0m"
else
    echo "\033[31m failed \n \033[0m"
    exit 0
fi

Create a package directory
mkdir ${ipaPath}/AllPack

Path to store all IPAs locally
allIPAPackPath="${ipaPath}/allPack"

# Choose one of the following
# 1.---- all packed ----
#for (( i=0; i<appInfosLength; i+=3 )); do

# 2.---- Custom packaging ----
for (( j=0; j<$appPackNumLength; j++)); do i=`expr ${appPackNum[$j]} - 1` i=`expr $i3 ` \ *# App Bundle Name (CFBundleName)
appName=${appInfos[${i}]}

# App DisPlay Name
appDisplayName=${appInfos[${i}]}

# App Icon Name
appIconName=${appInfos[$i+1]}

# App Download Name
appDownloadName=${appInfos[$i+2]}

Create different APP IPA directories
mkdir $allIPAPackPath/$appName
rm -rf $allIPAPackPath/$appName/ *echo "\033[31m appName:$appName appIconName:$appIconName appDownloadName:$appDownloadName\n \033[0m"

# Copy the icon to the directory of the app to be modified
cp -Rf $iconPath/$appName/ *${buildDir}/Project.xcarchive/Products/Applications/Project.app

if[[$? = 0]];then
 echo "\033[31m $appNameModify icon successfully \033[0m"
else
 echo "\033[31m $appNameFailed to modify icon \033[0m"
 exit 0
fi

# modified Plist
defaults write $ipaPath/Payload/xx.app/info.plist "CFBundleName" $appName
defaults write $ipaPath/Payload/xx.app/info.plist "CFBundleDisplayName" $appDisplayName

if[[$? = 0]];then
  echo "\033[31m $appNameModify Plist successfully \033[0m"
else
  echo "\033[31m $appNameFailed to modify Plist \033[0m"
  exit 0
fi

Sign # heavy
xattr -cr ${buildDir}/Project.xcarchive/Products/Applications/Project.app
codesign -f -s "xx co., LTD" --entitlements $Entitlements ${buildDir}/Project.xcarchive/Products/Applications/Project.app
if[[$? = 0]];then
    echo "\033[31m $appNameRe-signature successful \n \033[0m"
else
    echo "\033[31m $appNameFailed to re-sign \n \033[0m"
    exit 0
fi

# generate ipa
xcodebuild -exportArchive -archivePath $ipaPath/Payload/Project.xcarchive -exportPath ${ipaPath}/$appDownloadName.ipa -exportOptionsPlist $ExportOptions

if[[$? = 0]];then
    echo "\033[31m \n $appNameIPA generation success \n\n\n\n\033[0m"
else
    echo "\033[31m \n $appNameFailed to generate IPA \n\n\n\n\033[0m"
    exit 0
fi

# to create Plist
plist_path=$allIPAPackPath/$appName/$appDownloadName.plist

cat << EOF > $plist_path<? xml version="1.0" encoding="UTF-8"? > <! DOCTYPE plist PUBLIC"- / / / / DTD PLIST Apple 1.0 / / EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>items</key>
    <array>
        <dict>
            <key>assets</key>
            <array>
                <dict>
                    <key>kind</key>
                    <string>software-package</string>
                    <key>url</key>
                    <string>https://xxxxxxxxxxxx/$appDownloadName.ipa</string>
                </dict>
                <dict>
                    <key>kind</key>
                    <string>display-image</string>
                    <key>url</key>
                    <string>https://xxxxxxxxxxxx/${appIconName}.png</string>
                </dict>
                <dict>
                    <key>kind</key>
                    <string>full-size-image</string>
                    <key>url</key>
                    <string>https://xxxxxxxxxxxx/${appIconName}PNG </string> </dict> </array> <key>metadata</key> <dict> <key>bundle-identifier</key> <string> Your bundid</string> <key>bundle-version</key> <string>$bundleVersion</string>
                <key>kind</key>
                <string>software</string>
                <key>title</key>
                <string>$appDownloadName</string>
            </dict>
        </dict>
    </array>
</dict>
</plist>
EOF

# mobile
mv ${ipaPath}/$appDownloadName.ipa ${allIPAPackPath}/$appName

done

# 6. Upload dandelion distribution platform

if [[ $ISUPLOAD= 1]];then
    echo "\n Start uploading dandelions... \n"
    curl -F "file=@$AllIPAPackPath/$appName/$appDownloadName.ipa/Project.ipa" \
    -F "uKey=$USERKEY" \
    -F "_api_key=$APIKEY"\
    http://www.pgyer.com/apiv1/app/upload
    # Judge the upload result
    if[[$? = 0]];then
        echo "\n ~~~~~~~\^o^/~~~~ Upload to dandelion success ~~~~\^o^/~~~ \n"
    else
        echo "~ ~ ~ ~ ~ \ \ n (╯ - ╰) / ~ ~ ~ ~ ~ ~ ~ upload dandelion failure ~ ~ ~ ~ ~ \ (╯ - ╰) / ~ ~ ~ ~ ~ \ n"
    fi
fi

Delete irrelevant files
rm -rf $ipaPath/Payload

# End time
endTime=`date +%s`
echo -e $[endTime - beginTime] seconds
Copy the code

reference

  • Summary of iOS bulk packaging
  • Automatic packaging and publishing scripts for iOS
  • IOS – Automated packaging solutions
  • IOS bulk packaging, re-signing to replace icon, launchScreen
  • Re-signing (packaging) iOS applications