美文网首页iPA 打包
如何区分企业版和正式版?

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

作者: 勇往直前888 | 来源:发表于2017-03-02 19:31 被阅读296次

    需求来源

    • 每年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包 笔记

    相关文章

      网友评论

        本文标题:如何区分企业版和正式版?

        本文链接:https://www.haomeiwen.com/subject/qsexgttx.html