需求来源
- 每年99美元的开发者账号,开发完后提交苹果市场审核,这个我们叫
appstore
。 - 每年299美元的企业版账号,开发完后在企业内网发布,让内部员工或者特殊用户试用,这个我们叫
enterprise
。更确切地应该叫'inhouse'。 - 这看起来应该是同一个程序,但是实际上并不是同一个程序。因为
Bundle identifier
不能用同一个。 - 更深层次一点,代码签名和打包完全是两套,
Team Identifier
、Provisioning Profile
、Signing Identity
,这几个要素都是不相同的。 - 手动改一下工程的设置也没有多复杂,不过现在基本上在用
Jenkins
自动打包。怎么办?每次打包的时候都要区分什么版,然后手动改?这显然失去了自动打包的意义 - 运维人员反馈说替换
Info.plist
文件非常麻烦,二进制的,变动比较频繁,所以希望Info.plist
用同一个。 - 为了区分企业版和正式版,程序名称最好能够不一样,怎么修改
Info.plist
里面的内容?
基本知识
-
Jenkins
可以用XCode
插件,不过我们这里使用xcodebuild
命令。可以通过终端输入命令尝试,调好了稍微改一下,复制粘贴过去基本能用了,比较灵活 - 苹果官网的命令介绍xcodebuild。在终端输入
xcodebuild -usage
也能看到这些信息。输入xcodebuild -help
可以获得更详细的信息。多看看还是有用的,不过还是要实际操作才能理解,实际使用的时候也应该大大简化。 - 以下几个参数的含义需要事先了解一下
clean:清除上次编译的结果,防止相互影响,一般都要用一下
build:编译,得到两个文件:xxx.app
,xxx.dSYM
archive:打包,得到文件:xxx.xcarchive
;会自己调用build
命令;所以常常省略build
命令
-exportArchive:提取安装包,得到文件:xxx.ipa
- 文件位置
xxx.app、xxx.dSYM:默认位置在XCode的偏好设置目录,可以通过一下菜单查看XCode->Preferences...->Locations->Derived Data
相对路径为Build-> Products->Debug-iphoneos
或者Build-> Products->Release-iphoneos
xxx.xcarchive、xxx.ipa:用命令行的情况下,默认在终端的当前目录。相对路径在命令行中可以指定
方案1:利用XCoede的Debug和Release模式区分
企业版就用Debug模式,正式版就用Release模式。工程配置好之后,只要稍微改一下命令就可以同时得到企业版和正式版的ipa包,前面的需求可以“基本满足”
这个要求是XCode7,具体的可以参考ios,jenkins,参数化构建,shell,xcodebuild,多bundle identifier,版本号同步
XCode7的配置
企业版和正式的的账号,密码,相应的p12导入,Provisioning Profile的文件的下载和导入等准备工作先做好
- 切换到标签
Targets->Build Settings->Signing
,以下几个标签分别设置好,分为Debug
、Release
两种模式。
Code Signing Identity:证书
Development Team:账号主体,企业版和正式版的邮箱账号主体都不一样
Provisioning Profile:以前的真机调试文件 - 切换到标签
Targets->Build Settings->Packaging
,以下几个标签分别设置好,分为Debug
、Release
两种模式。
Info.plist File:配置文件,Debug
和Release
可以配置得不一样,这个变动有点大,这里暂时不用
Product Bundle Identifier:Bundle Id
,这个要和证书对应起来。这个需要改,企业版和正式版要不一样
Product Name:编译build
之后,.app
文件的名字,可以不改,中间文件,关心的人不多 - 切换到标签
Targets->General
,检查一下标签Signing(Debug)
和Signing(Release)
,看看设置的对不对。如果设置不对,这里有红叉提醒的 - 注意标签
Targets->General->Identity
,这里的选项Bundle Identifier
,只显示一个。这里千万不要改,不然Targets->Build Settings->Packaging
下面设置会被改成一样。这个千万要注意。
命令行
// Debug模式是企业版,在文件夹enterprise中,输出增加_enterprise后缀
xcodebuild -workspace xxx.xcworkspace -scheme xxx -configuration Debug clean build archive -archivePath enterprise/xxx_enterprise
xcodebuild -exportArchive —exportFormat ipa -archivePath enterprise/xxx_enterprise.xcarchive -exportPath enterprise/xxx_enterprise -exportWithOriginalSigningIdentity
// Release模式是正式版,在文件夹appstore中
xcodebuild -workspace xxx.xcworkspace -scheme xxx -configuration Release clean build archive -archivePath appstore/xxx
xcodebuild -exportArchive —exportFormat ipa -archivePath appstore/xxx.xcarchive -exportPath appstore/xxx -exportWithOriginalSigningIdentity
-
xxx
替换为具体的工程名就可以了 - 目前大多数工程都有
cocoaPods
,会自动引入workspace
,所以这条基于workspace
的命令用得比较多 - 这个适合
workspace
、project
、target
、scheme
都相同的工程。如果名字不一样,具体参数给对就可以了 -
build
可以不加,就像在XCode中,直接点Product->Archive
一样,会自己调用build
命令的,这里只是为了过程完整而加上的 - 最终的结果是企业版的
.xcarchive、.ipa
在文件夹enterprise
中;正式版的.xcarchive、.ipa
在文件夹appstore
中。
此方案的不足之处
- 过于依赖
XCode
的设置 - 改变了
Debug
和Release
的基本功能定义。 - 企业版和正式版,由于模式不一样,可能差异比较大。比如,很多开发者会在
Debug
版本输出一些调试信息
对于不足之处的改进
- 模式Debug和Release,只是我们的习惯用法。原来XCode还支持自定义的模式创建
- 另外,至于程序显示名称,程序图标,启动图等等Info.plist中的配置项,可以通过自定义变量的方法实现。
- 这里有一篇文章写的很好,可以参考来做,增加一个企业版的配置,那么这个方案就能满足要求了。
Xcode多种Build Configuration配置使用 - 按照上面的文章操作,方案是可行的。不过要注意的一点是,对于workspace的情况,每个工程都要新建相应的配置,包括Pods工程。
- Pods修改了工程配置之后,别忘了执行
pod update
命令,不然修改不会生效。我们在实际用的时候就忘了,算是一个小坑
方案2:采用命令行指定签名参数
如果能够通过命令行的方式,灵活地指定签名证书,可以让企业版和正式版采用相同的模式(同为Debug
或者Release
),那么将是比方案1更为灵活地方案。
通过对xcodebuild
命令的实际使用以及查找相关资料,应该分为单个Target
的工程和由workspace
管理的多个project
,多个Target
的工程两种情况考虑。下面这篇文章很好地说明了这一点
动手搭建 iOS CI 环境之「了解 xcodebuild 命令」
Case1:单个Target
的工程
由于证书可以对应到Target
,所以只有一个Target
的工程可以通过命令行灵活地指定证书等信息。
Jenkins学习(三)脚本打包
iOS自动打包并发布脚本
xcodebuild命令简单使用
打包脚本
打开终端,cd到工程目录,和xxx.xcodeproj文件在同一目录
xcodebuild -project xxx.xcodeproj -scheme xxx -configuration Debug DEVELOPMENT_TEAM=xxxxx PROVISIONING_PROFILE="xxxxxx-xxxx-xxxx-xxxx-xxxxxx" PROVISIONING_PROFILE_SPECIFIER="xxxxxx" CODE_SIGN_IDENTITY="iPhone Developer: xxx (xxxxx)" PRODUCT_BUNDLE_IDENTIFIER=com.xxx.xxx.enterprise clean archive -archivePath enterprise/xxx_enterprise
这里-project xxx.xcodeproj
可以省略
企业版和正式通过更换上面key=value的值进行区分
如何查找这些键值对?
Xcode6内置环境变量(Build Setting Macros)
打开终端,cd到工程目录,通过以下脚本可以查看当前的Build Setting
xcodebuild -showBuildSettings -scheme xxx -configuration Debug
如何查看证书
打开终端,输入以下命令
security find-identity -v -p codesigning
Case2:由workspace
管理的工程
现在实际的工程一般都会用到大量的第三方库,第三方库一般会引入CocoaPods进行管理,默认会创建一个workspace
。由于workspace
可以包含多个Project
,而每个Project
又可以包含多个Target
。每个Target
的bundle id
、provisioning profile
等都可以分别指定,所以像单个Target
那样用命令行来动态指定的方式就显得比较复杂。
对于workspace
管理的工程,-workspace
、 -scheme
两个参数是必要的。而要像单个Target
那样灵活地修改bundle id
、provisioning profile
等参数是很不方便的。先不考虑修改签名参数。
Step1: 打包
打开终端,cd到workspace所在目录,输入以下命令
xcodebuild -workspace xxx.xcworkspace -scheme xxx -configuration Debug clean archive -archivePath archiveOutput/xxx
archiveOutput
可以换为其他喜欢的文件夹的名字,在当前目录下,这里是相对路径
Step2: 导出ipa包
- 按照原始的签名文件导出,不改签名,这是最保守的方式
xcodebuild -exportArchive -exportFormat ipa -archivePath archiveOutput/xxx.xcarchive -exportPath archiveOutput/xxx_original -exportWithOriginalSigningIdentity
- 指定签名文件,修改签名
xcodebuild -exportArchive —exportFormat ipa -archivePath archiveOutput/xxx.xcarchive -exportPath archiveOutput/xxx_appstore -exportProvisioningProfile "xxxxxx"
- XCode7之后,命令格式稍微有调整,上面的格式仍然可以用,但是会出警告。之后的格式如下:
xcodebuild -exportArchive -archivePath <xcarchivepath> -exportPath <destinationpath> -exportOptionsPlist <plistpath>
exportOptionsPlist
解释
Available keys for -exportOptionsPlist:
compileBitcode : Bool
For non-App Store exports, should Xcode re-compile the app from bitcode? Defaults to YES.
embedOnDemandResourcesAssetPacksInBundle : Bool
For non-App Store exports, if the app uses On Demand Resources and this is YES, asset packs are embedded in the app bundle so that the app can be tested without a server to host asset packs. Defaults to YES unless onDemandResourcesAssetPacksBaseURL is specified.
iCloudContainerEnvironment
For non-App Store exports, if the app is using CloudKit, this configures the "com.apple.developer.icloud-container-environment" entitlement. Available options: Development and Production. Defaults to Development.
manifest : Dictionary
For non-App Store exports, users can download your app over the web by opening your distribution manifest file in a web browser. To generate a distribution manifest, the value of this key should be a dictionary with three sub-keys: appURL, displayImageURL, fullSizeImageURL. The additional sub-key assetPackManifestURL is required when using on demand resources.
method : String
Describes how Xcode should export the archive. Available options: app-store, ad-hoc, package, enterprise, development, and developer-id. The list of options varies based on the type of archive. Defaults to development.
onDemandResourcesAssetPacksBaseURL : String
For non-App Store exports, if the app uses On Demand Resources and embedOnDemandResourcesAssetPacksInBundle isn't YES, this should be a base URL specifying where asset packs are going to be hosted. This configures the app to download asset packs from the specified URL.
teamID : String
The Developer Portal team to use for this export. Defaults to the team used to build the archive.
thinning : String
For non-App Store exports, should Xcode thin the package for one or more device variants? Available options: <none> (Xcode produces a non-thinned universal app), <thin-for-all-variants> (Xcode produces a universal app and all available thinned variants), or a model identifier for a specific device (e.g. "iPhone7,1"). Defaults to <none>.
uploadBitcode : Bool
For App Store exports, should the package include bitcode? Defaults to YES.
uploadSymbols : Bool
For App Store exports, should the package include symbols? Defaults to YES.
method
和teamID
这两个参数指定一下,就起到了老格式修改签名文件的功能
在导出时修改签名是可行的,比如编译打包时用正式版证书打包,在导出时用企业版打包。不过这里有个比较尴尬的问题,就是Bundle ID不能更改,有可能会导致签名不一致而不能安装。签名是不同,但是Info.plist文件内容还是一样的。这样必然导致有一个ipa包不能用。
方法2小结
对于单Target的工程来说,可以用命令行灵活配置企业版和正式版。但是对于大多数的workspace管理的工程来说,这种方法很难达到目的。虽然可以在导出ipa的时候更改签名,但是bundle id不会变,这个导致区分困难。至于在打包前修改参数,有点复杂,目前还没有找到好的方法。
在xcodebuild中修改的build settings是在内存中动态修改的,并不会更改实际的文件。下次读出来之后,就像从来没修改过一样
修改Info.plit
文件
PlistBuddy
这是系统提供的操作plist文件的工具,不在默认的PATH
里,需要通过绝对路径/usr/libexec/PlistBuddy
引用。
可以CD到工程目录,使用相对路径。注意./开头
/usr/libexec/PlistBuddy -c 'set:CFBundleDisplayName "用户看到的程序名称"' ./相对目录/info.plist
也可以在任意地方,采用绝对目录
/usr/libexec/PlistBuddy -c 'set:CFBundleDisplayName "用户看到的程序名称"' 绝对目录/info.plist
如果设置成功,不会有任何输出,不过确实起作用了。如果出错,会有错误信息,常见的比如文件不存在:
File Doesn't Exist, Will Create: /ifaex_ios/info.plist
Set: Entry, ":CFBundleDisplayName", Does Not Exist
其他话题
其他工具,不用Jekins
网上有介绍其他打包工具,比如fastlane
iOS打包发布工具fastlane初级攻略
这个据说很好用,可以研究一下,作为方案三。这个另外写一篇来记录学习情况。
通过Info.plist
本地化文件InfoPlist.strings
修改Info.plist
内容
- 在工程中引入文件
InfoPlist.strings
,里面的内容如下
企业版:
CFBundleDisplayName="xxx企业版";
CFBundleIdentifier="com.xxx.yyy.enterprise";
正式版:
CFBundleDisplayName="xxx";
CFBundleIdentifier="com.xxx.yyy";
-
试验结果:
CFBundleDisplayName
设置符合预期
CFBundleIdentifier
在打包安装的时候会出错
这里借用了应用程序本地化的机制,实现了修改Info.plist
文件的目标。只是这种做法改变了本地化文件设置的初衷,不是非常好 -
常用的Key值说明
Info.plist中常用的key简介
文件Info.plist
是二进制的,看不懂也不方便修改,怎么办?
XCode的标签Targets->Build Settings->Packaging
,下面有个选项Info.plist Output Encoding
,选项有binary、XML、same-as-input
;默认是binary
。估计只要改为same-as-input
就能够看懂了
其他编译命令
网上出现过xcrun
和xctool
,不过现在好像不需要用到
xcodebuild和xcrun自动化编译ipa包 笔记
网友评论