iOS——自动打包上传

为了不去每次都做这些繁琐的操作,我们只能做一个懒得程序狗,也就是将整个过程进行脚本化……

之前写过一篇关于自动打包上传代码的教程,最近又开始需要上线APP,发现新版的Mac对之前的教程不支持了,就换了一种方式,这次试用fir.

http://al1020119.github.io/blog/2016/12/26/ios-daobao/

工作中一般两种情况,

1.打包Ad-Hoc给测试人员,或者内部人员测试
2.打包product发布到App Store

所以,为了不去每次都做这些繁琐的操作,我们只能做一个懒得程序狗,也就是将整个过程进行脚本化

大概的步骤是

写个bash脚本,执行自动打包iOS版本,到指定的目录 (有条件的公司,可以自己搭个小服务器,这样谁都可以随时随地的打包)
将打包好的文件上传到fir.im (当然上传到自己公司的服务器或者任何地方都行,只是fir.im我一直用,觉得比较方便)
开发一个内部使用的类似APPStore,上面放着自己公司的所有APP,每次有更新的时候,测试童鞋直接通过这个自己下载新APP就可以了

主要命令

编译workspace

xcodebuild -workspace workspacename -scheme schemename -configuration [-configuration configurationname] clean build SYMROOT=(SYMROOT)

编译project

xcodebuild -target targetname -configuration [-configuration configurationname] clean build SYMROOT=(SYMROOT)

查看配置信息

xcodebuild -list

xcrun打包ipa

xcrun -sdk iphoneos PackageApplication -v projectName.app -o ipaName.ipa

其他

在终端输入:xcodebuild –help 或 –h查看具体的选项
显示xcodebuildversion:xcodebuild –version
显示当前系统安装的sdk:xcodebuild –showsdks
显示当前目录下project Information:xcodebuild –list

xcodebuild&xcrun

xcodebuild->Build
xcrun->Api

终端查看对应版本

iCocosdeiMac:115科技 iCocos$ xcrun --version
xcrun version 31.
iCocosdeiMac:115科技 iCocos$ xcodebuild -version
Xcode 8.2.1
Build version 8C1002

xcodebuild 是苹果提供的打包项目或者工程的命令

需要在包含 name.xcodeproj 的目录下执行 xcodebuild 命令,且如果该目录下有多个 projects,那么需要使用 -project 指定需要 build 的项目。
在不指定 build 的 target 的时候,默认情况下会 build project 下的第一个 target
当 build workspace 时,需要同时指定 -workspace 和 -scheme 参数,scheme 参数控制了哪些 targets 会被 build 以及以怎样的方式 build。
有一些诸如 -list, -showBuildSettings, -showsdks 的参数可以查看项目或者工程的信息,不会对 build action 造成任何影响,放心使用。

使用xcodebuild和xcrun打包签名

我这里就使用公司项目作为测试,方便查找问题和后续打包上传

1. 终端输入

xcodebuild -project T 115科技.xcodeproj -target 115科技 -configuration Release 

xcodebuild -project T 曹理鹏(iCocos)-梦工厂.xcodeproj -target 曹理鹏(iCocos)-梦工厂 -configuration Debug 

这是骚等所有走完之后就能看到对应的信息,表示build成功

Signing Identity: "iPhone Developer: xxx(59xxxxxx)"
Provisioning Profile: "iOS Team Provisioning Profile: *"

且在该目录下会多出一个 build 目录,该目录下有 Release-iphoneos 和 曹理鹏(iCocos)-梦工厂.build 文件,根据我们 build -configuration 配置的参数不同,Release-iphoneos 的文件名会不同。

在 Release-iphoneos 文件夹下,有我们需要的曹理鹏(iCocos)-梦工厂.app文件,但是要安装到真机上,我们需要将该文件导出为ipa文件,这里使用 xcrun 命令。

xcrun -sdk iphoneos -v PackageApplication ./build/Release-iphoneos/曹理鹏(iCocos)-梦工厂.app -o ~/Desktop/曹理鹏(iCocos)-梦工厂.ipa

这个时候桌面上就会出现一个曹理鹏(iCocos)-梦工厂.ipa文件,这就是我们平时Archive之后的问题,也正是我们所需要的ipa包

但是xcodebuild期间我出现了一个这样的错误

ld: library not found for -lAFNetworking
clang: error: linker command failed with exit code 1 (use -v to see invocation)

** BUILD FAILED **


The following build commands failed:
Ld build/曹理鹏(iCocos)-梦工厂.build/Release-iphoneos/曹理鹏(iCocos)-梦工厂.build/Objects-normal/armv7/曹理鹏(iCocos)-梦工厂 normal armv7
Ld build/曹理鹏(iCocos)-梦工厂.build/Release-iphoneos/曹理鹏(iCocos)-梦工厂.build/Objects-normal/arm64/曹理鹏(iCocos)-梦工厂 normal arm64
(2 failures)

貌似是linker command failed with exit code 1经典错误,但是然并卵,于是看了一下pingpong从零开始写个自动打包IPA脚本中的build方式,也有类似的问题。多谢pingpong帮我解决了这个问题。

iCocosdeiMac ios (develop) $ xcodebuild
2016-05-02 13:05:04.623 xcodebuild[1015:16272] [MT] PluginLoading: Required plug-in compatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/XcodeColors.xcplugin' not present in DVTPlugInCompatibilityUUIDs
2016-05-02 13:05:04.625 xcodebuild[1015:16272] [MT] PluginLoading: Required plug-in compatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/OMColorSense.xcplugin' not present in DVTPlugInCompatibilityUUIDs
=== BUILD TARGET xxx OF PROJECT xxx WITH THE DEFAULT CONFIGURATION (Release) ===

Check dependencies

Write auxiliary files
write-file /Users/iCocos/Documents/code/xxx/ios/build/xxx.build/Release-iphoneos/xxx.build/xxx.hmap
write-file /Users/iCocos/Documents/code/xxx/ios/build/xxx.build/Release-iphoneos/xxx.build/xxx-own-target-headers.hmap
write-file /Users/iCocos/Documents/code/xxx/ios/build/xxx.build/Release-iphoneos/xxx.build/Script-492B764475E022A63FB67F55.sh

解决方案是:执行xcodebuild需要指定你所需要对应的workspace和scheme

xcodebuild -workspace /Users/iCocos/Desktop/MBA/最新Git源代码/曹理鹏(iCocos)-梦工厂/曹理鹏(iCocos)-梦工厂.xcworkspace -scheme 曹理鹏(iCocos)-梦工厂

执行前,先查看下-list,这个可以知道xcodebuild命令下对应的参数需要填写的内容

iCocosdeiMac ios (develop) $ xcodebuild -list
2016-05-02 15:24:26.656 xcodebuild[16535:154176] [MT] PluginLoading: Required plug-in compatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/XcodeColors.xcplugin' not present in DVTPlugInCompatibilityUUIDs
2016-05-02 15:24:26.661 xcodebuild[16535:154176] [MT] PluginLoading: Required plug-in compatibility UUID ACA8656B-FEA8-4B6D-8E4A-93F4C95C362C for plug-in at path '~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/OMColorSense.xcplugin' not present in DVTPlugInCompatibilityUUIDs
Information about project "xxx":
Targets:
xxx
xxxTests

Build Configurations:
Debug
Release

If no build configuration is specified and -scheme is not passed then "Release" is used.

Schemes:
xxx

然后,成功了,如下:

Entitlements:

{
"application-identifier" = "L64TE3S9T9.com.曹理鹏(iCocos)-梦工厂.shaoshang";
"aps-environment" = development;
"com.apple.developer.pass-type-identifiers" =     (
"L64TE3S9T9.*"
);
"com.apple.developer.team-identifier" = L64TE3S9T9;
"get-task-allow" = 1;
}


builtin-productPackagingUtility -entitlements -format xml -o /Users/iCocos/Library/Developer/Xcode/DerivedData/曹理鹏(iCocos)-梦工厂-aqiwhxodbfeztuebgnzgbgicurgl/Build/Intermediates/曹理鹏(iCocos)-梦工厂.build/Debug-iphoneos/曹理鹏(iCocos)-梦工厂.build/曹理鹏(iCocos)-梦工厂.app.xcent

CodeSign /Users/iCocos/Library/Developer/Xcode/DerivedData/曹理鹏(iCocos)-梦工厂-aqiwhxodbfeztuebgnzgbgicurgl/Build/Products/Debug-iphoneos/曹理鹏(iCocos)-梦工厂.app
cd /Users/iCocos/Desktop/MBA/最新Git源代码/曹理鹏(iCocos)-梦工厂
export CODESIGN_ALLOCATE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/Users/iCocos/.rvm/gems/ruby-2.3.0/bin:/Users/iCocos/.rvm/gems/ruby-2.3.0@global/bin:/Users/iCocos/.rvm/rubies/ruby-2.3.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/iCocos/.rvm/bin:/usr/local/mysql/bin/mysql"

Signing Identity:     "iPhone Developer: Songbai He (73N6HPPJDP)"
Provisioning Profile: "iOS Team Provisioning Profile: com.曹理鹏(iCocos)-梦工厂.shaoshang"
(34c1d23b-ade5-4d0f-9329-7b16009b30c2)

/usr/bin/codesign --force --sign F8BAED0C84DB84AAA84769FED9FEAA9E80825C29 --entitlements /Users/iCocos/Library/Developer/Xcode/DerivedData/曹理鹏(iCocos)-梦工厂-aqiwhxodbfeztuebgnzgbgicurgl/Build/Intermediates/曹理鹏(iCocos)-梦工厂.build/Debug-iphoneos/曹理鹏(iCocos)-梦工厂.build/曹理鹏(iCocos)-梦工厂.app.xcent --timestamp=none /Users/iCocos/Library/Developer/Xcode/DerivedData/曹理鹏(iCocos)-梦工厂-aqiwhxodbfeztuebgnzgbgicurgl/Build/Products/Debug-iphoneos/曹理鹏(iCocos)-梦工厂.app

Validate /Users/iCocos/Library/Developer/Xcode/DerivedData/曹理鹏(iCocos)-梦工厂-aqiwhxodbfeztuebgnzgbgicurgl/Build/Products/Debug-iphoneos/曹理鹏(iCocos)-梦工厂.app
cd /Users/iCocos/Desktop/MBA/最新Git源代码/曹理鹏(iCocos)-梦工厂
export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/Users/iCocos/.rvm/gems/ruby-2.3.0/bin:/Users/iCocos/.rvm/gems/ruby-2.3.0@global/bin:/Users/iCocos/.rvm/rubies/ruby-2.3.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/iCocos/.rvm/bin:/usr/local/mysql/bin/mysql"
export PRODUCT_TYPE=com.apple.product-type.application
builtin-validationUtility /Users/iCocos/Library/Developer/Xcode/DerivedData/曹理鹏(iCocos)-梦工厂-aqiwhxodbfeztuebgnzgbgicurgl/Build/Products/Debug-iphoneos/曹理鹏(iCocos)-梦工厂.app

** BUILD SUCCEEDED **

下面就是验证你全栈的时候到了,其实也没有那么难,就是一点脚本而已

先git 指令,pull到最新的分支

# git update
git checkout $BRANCHNAME
if [ $? -ne 0 ]; then
exit 1
fi

git pull 
#pod update --verbose --no-repo-update
if [ $? -ne 0 ]; then
exit 1
fi

成功之后你同意会看到提示信息

logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
Deleting expired sessions...118 completed.

xcodebuild进行编译

xcodebuild \
-workspace $SORCEPATH/曹理鹏(iCocos)-梦工厂.xcworkspace \
-scheme $SCHEMENAMEPLQ \
-configuration Debug \
CODE_SIGN_IDENTITY="iPhone Developer: Songbai He(73N6HPPJDP)”  \
PROVISIONING_PROFILE="com.曹理鹏(iCocos)-梦工厂.shaoshang" \
clean \
build \
-derivedDataPath $IPAPATH/$BRANCHNAME/$DATE

测试与发布只需要更改对应的参数即可

-configuration Debug

-configuration Release

用xcrun打包成ipa包

xcrun -sdk iphoneos PackageApplication \
-v $IPAPATH/Build/Products/Debug-iphoneos/$SCHEMENAME.app \
-o $IPAPATH/$IPANAME

生成ipa包,上传到fir.im

一:1.注册fir.拿到token

fir.im官网:https://fir.im

注册号账号,点击右上角个人信息,进入API token 拿到token,并保存

二:安装fir-cli

fir-cli 使用 Ruby 构建, 无需编译, 只要安装相应 gem 即可.

$ ruby -v # > 1.9.3

$ gem install fir-cli

三:Mac新版之后可能由于源的问题导致无法安装(由于10.11引入了 rootless, 无法直接安装 fir-cli)

一般都是这么安装的:使用 Homebrew 及 RVM 安装 Ruby, 再安装 fir-cli

Install Homebrew:

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Install RVM:

$ \curl -sSL https://get.rvm.io | bash -s stable --ruby

Install fir-cli:

$ gem install fir-cli

四:在终端登录并查看信息

  1. $ fir login

按照提示输入token,然后

iCocosdeiMac:曹理鹏(iCocos)-梦工厂 iCocos$ fir login  
Please enter your fir.im API Token: 849ad212b94683b4c3087248d422d124
I, [2017-04-18T13:58:01.184043 #14531]  INFO -- : Login succeed, previous user's email: al10201119@163.com
I, [2017-04-18T13:58:01.185131 #14531]  INFO -- : Login succeed, current  user's email: al10201119@163.com
I, [2017-04-18T13:58:01.185223 #14531]  INFO -- : 
  1. $fir me

    登录成功,就会显示用户信息

    I, [2017-04-18T13:58:21.876164 #14545] INFO – : Login succeed, current user’s email: al10201119@163.com
    I, [2017-04-18T13:58:21.876246 #14545] INFO – : Login succeed, current user’s name: al10201119
    I, [2017-04-18T13:58:21.876261 #14545] INFO – :

  1. 使用fir指令,上传我们的ipa包
fir login -T c525718a775b954882xxxxxxxx       # fir.im token

fir publish $IPAPATH/Develop/xxx.ipa
  1. 最后你会看到

    恭喜!!!上传fir.im成功!

也可以直接使用执行脚本

#author iCocos

#注意:脚本目录和xxxx.xcodeproj要在同一个目录,如果放到其他目录,请自行修改脚本。
#工程名字(Target名字)
Project_Name="Target名字,系统默认和工程名字一样"
#配置环境,Release或者Debug
Configuration="Release"

#AdHoc版本的Bundle ID
AdHocBundleID="com.xxx"
#AppStore版本的Bundle ID
AppStoreBundleID="com.xxx"
#enterprise的Bundle ID
EnterpriseBundleID="com.xxx"

# ADHOC
#证书名#描述文件
ADHOCCODE_SIGN_IDENTITY="iPhone Distribution: xxxx"
ADHOCPROVISIONING_PROFILE_NAME="xxxx-xxxx-xxxx-xxxx"

#AppStore证书名#描述文件
APPSTORECODE_SIGN_IDENTITY="iPhone Distribution: xxxx"
APPSTOREROVISIONING_PROFILE_NAME="xxxx-xxxx-xxxx-xxxx"

#企业(enterprise)证书名#描述文件
ENTERPRISECODE_SIGN_IDENTITY="iPhone Distribution: xxxxx"
ENTERPRISEROVISIONING_PROFILE_NAME="xxxx-xxxx-xxxx-xxxx"

#加载各个版本的plist文件
ADHOCExportOptionsPlist=./ADHOCExportOptionsPlist.plist
AppStoreExportOptionsPlist=./AppStoreExportOptionsPlist.plist
EnterpriseExportOptionsPlist=./EnterpriseExportOptionsPlist.plist

ADHOCExportOptionsPlist=${ADHOCExportOptionsPlist}
AppStoreExportOptionsPlist=${AppStoreExportOptionsPlist}
EnterpriseExportOptionsPlist=${EnterpriseExportOptionsPlist}

echo "~~~~~~~~~~~~选择打包方式(输入序号)~~~~~~~~~~~~~~~"
echo "  1 appstore"
echo "  2 adhoc"
echo "  3 enterprise"

# 读取用户输入并存到变量里
read parameter
sleep 0.5
method="$parameter"

# 判读用户是否有输入
if [ -n "$method" ]
then

#clean下
xcodebuild clean -xcodeproj ./$Project_Name/$Project_Name.xcodeproj -configuration $Configuration -alltargets

if [ "$method" = "1" ]
then

#appstore脚本
xcodebuild -project $Project_Name.xcodeproj -scheme $Project_Name -configuration $Configuration -archivePath build/$Project_Name-appstore.xcarchive clean archive build  CODE_SIGN_IDENTITY="${APPSTORECODE_SIGN_IDENTITY}" PROVISIONING_PROFILE="${APPSTOREROVISIONING_PROFILE_NAME}" PRODUCT_BUNDLE_IDENTIFIER="${AppStoreBundleID}"
xcodebuild -exportArchive -archivePath build/$Project_Name-appstore.xcarchive -exportOptionsPlist $AppStoreExportOptionsPlist -exportPath ~/Desktop/$Project_Name-appstore.ipa
elif [ "$method" = "2" ]
then
#adhoc脚本
xcodebuild -project $Project_Name.xcodeproj -scheme $Project_Name -configuration $Configuration -archivePath build/$Project_Name-adhoc.xcarchive clean archive build CODE_SIGN_IDENTITY="${ADHOCCODE_SIGN_IDENTITY}" PROVISIONING_PROFILE="${ADHOCPROVISIONING_PROFILE_NAME}" PRODUCT_BUNDLE_IDENTIFIER="${AdHocBundleID}"
xcodebuild -exportArchive -archivePath build/$Project_Name-adhoc.xcarchive -exportOptionsPlist $ADHOCExportOptionsPlist -exportPath ~/Desktop/$Project_Name-adhoc.ipa
elif [ "$method" = "3" ]
then
#企业打包脚本
xcodebuild -project $Project_Name.xcodeproj -scheme $Project_Name -configuration $Configuration -archivePath build/$Project_Name-enterprise.xcarchive clean archive build CODE_SIGN_IDENTITY="${ENTERPRISECODE_SIGN_IDENTITY}" PROVISIONING_PROFILE="${ENTERPRISEROVISIONING_PROFILE_NAME}" PRODUCT_BUNDLE_IDENTIFIER="${EnterpriseBundleID}"
xcodebuild -exportArchive -archivePath build/$Project_Name-enterprise.xcarchive -exportOptionsPlist $EnterpriseExportOptionsPlist -exportPath ~/Desktop/$Project_Name-enterprise.ipa
else
echo "参数无效...."
exit 1
fi
fi

这里还有一个大神使用PHP干了一票,虽然还在学习PHP中,但是有机会也要试一下

这里目前只是实现了Ad-Hoc打包上传,关于App Store其实也就是更改参数,和对应的地址,后续会退出相应的文章界面具体实战……

坚持原创技术分享,您的支持将鼓励我继续创作!