如何区分企业版和正式版?

需求来源

  • 每年99美元的开发者账号,开发完后提交苹果市场审核,这个我们叫appstore
  • 每年299美元的企业版账号,开发完后在企业内网发布,让内部员工或者特殊用户试用,这个我们叫enterprise。更确切地应该叫'inhouse'。
  • 这看起来应该是同一个程序,但是实际上并不是同一个程序。因为Bundle identifier不能用同一个。
  • 更深层次一点,代码签名和打包完全是两套,Team IdentifierProvisioning ProfileSigning Identity,这几个要素都是不相同的。
  • 手动改一下工程的设置也没有多复杂,不过现在基本上在用Jenkins自动打包。怎么办?每次打包的时候都要区分什么版,然后手动改?这显然失去了自动打包的意义
  • 运维人员反馈说替换Info.plist文件非常麻烦,二进制的,变动比较频繁,所以希望Info.plist用同一个。
  • 为了区分企业版和正式版,程序名称最好能够不一样,怎么修改Info.plist里面的内容?

基本知识

  • Jenkins可以用XCode插件,不过我们这里使用xcodebuild命令。可以通过终端输入命令尝试,调好了稍微改一下,复制粘贴过去基本能用了,比较灵活
  • 苹果官网的命令介绍xcodebuild。在终端输入xcodebuild -usage也能看到这些信息。输入xcodebuild -help可以获得更详细的信息。多看看还是有用的,不过还是要实际操作才能理解,实际使用的时候也应该大大简化。
  • 以下几个参数的含义需要事先了解一下
    clean:清除上次编译的结果,防止相互影响,一般都要用一下
    build:编译,得到两个文件:xxx.appxxx.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的文件的下载和导入等准备工作先做好

  1. 切换到标签Targets->Build Settings->Signing,以下几个标签分别设置好,分为DebugRelease两种模式。
    Code Signing Identity:证书
    Development Team:账号主体,企业版和正式版的邮箱账号主体都不一样
    Provisioning Profile:以前的真机调试文件
  2. 切换到标签Targets->Build Settings->Packaging,以下几个标签分别设置好,分为DebugRelease两种模式。
    Info.plist File:配置文件,DebugRelease可以配置得不一样,这个变动有点大,这里暂时不用
    Product Bundle IdentifierBundle Id,这个要和证书对应起来。这个需要改,企业版和正式版要不一样
    Product Name:编译build之后,.app文件的名字,可以不改,中间文件,关心的人不多
  3. 切换到标签Targets->General,检查一下标签Signing(Debug)Signing(Release),看看设置的对不对。如果设置不对,这里有红叉提醒的
  4. 注意标签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的命令用得比较多
  • 这个适合workspaceprojecttargetscheme都相同的工程。如果名字不一样,具体参数给对就可以了
  • build可以不加,就像在XCode中,直接点Product->Archive一样,会自己调用build命令的,这里只是为了过程完整而加上的
  • 最终的结果是企业版的.xcarchive、.ipa在文件夹enterprise中;正式版的.xcarchive、.ipa在文件夹appstore中。

此方案的不足之处

  • 过于依赖XCode的设置
  • 改变了DebugRelease的基本功能定义。
  • 企业版和正式版,由于模式不一样,可能差异比较大。比如,很多开发者会在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。每个Targetbundle idprovisioning profile等都可以分别指定,所以像单个Target那样用命令行来动态指定的方式就显得比较复杂。
对于workspace管理的工程,-workspace-scheme两个参数是必要的。而要像单个Target那样灵活地修改bundle idprovisioning 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.

methodteamID这两个参数指定一下,就起到了老格式修改签名文件的功能

在导出时修改签名是可行的,比如编译打包时用正式版证书打包,在导出时用企业版打包。不过这里有个比较尴尬的问题,就是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就能够看懂了

其他编译命令

网上出现过xcrunxctool,不过现在好像不需要用到
xcodebuild和xcrun自动化编译ipa包 笔记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容