Xcode —— 使用Multi-Target管控相似 App


前言

在公司发展过程中,除了开发维护自有品牌外,针对有实力有潜质的客户,公司还会接受OEM「贴牌开发」的合作方式。在硬件产品方面,OEM方式主要体现于「外观重新开模改丝印」,「PCB重新layout」和「功能定制开发」;在App方面,主要体现于「App Logo修改」,「欢迎页面修改」,「关于我们页面修改」,「App背景颜色修改」和「功能定制开发」。
目前公司的客户中,大概有5个客户是以OEM的方式进行合作的,所以,对于App,需要采用一个容易维护的方式来管控公司及所有OEM客户的App。

问题描述

针对「前言」中描述的情况,需要解决的问题可以归纳如下:

  • 6个App的代码需要共用,尽量减少代码间的差异
  • 每个App的「应用名称」、「应用图标」、「欢迎页面」及「关于我们页面」均不同
  • 在个别功能或页面在实现上,每个App均有一定差异性
  • 每个App对应的开发者帐号均不同

解决方案

在Xcode中,有一个「Mutil-Target」功能,在苹果官方文档中对于Target是这样描述的:

「A target specifies a product to build and contains the instructions for building the product form a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system -- the source files and instructions for processing those source files -- required to build that product. Projects can contain one or more targets, each of which productes one product.」

这段话大概可以理解为「同一个Xcode工程中,每一个target可以对应一个独立的App,通过target相关的配置,可以定义每个Target(即App)的build属性:例如「需要编译哪些文件」、「App名称」、「App的Bundle ID」等」。这么看来,使用Target功能,即可满足此次需求。

添加Target的过程可分为以下几步:

新建Target

根据需求,新Target的大部分内容跟原Target相似,所以我们使用「Duplicate」的方式来「复制生成」新Target。点击Target名称可以很方便地改名,假设名称改为「NewTarget」。


设置「App名称」

设置info.plist文件
  1. 添加「NewTarget」后,可以发现工程中多了一个「Target_copy-info.plist」,在此,我们将其名称改为「NewTarget-info.plist」,一般来说,此文件内容不需要修改。

  2. 在「TARGETS」中选择「NewTarget」,进入工程的「Build Setting」页面,找到「Packaging」分类,把里面的「info.plist File」改为「NewTarget-info.plist」

  3. 此时回到「General」页面,就可以对Bundle Identifier」和「Team」等选项进行修改了。

设置infoPlist.strings文件
  1. 在工程目录中新建文件夹「NewTargetInfo」。

  2. 找到工程文件夹中的infoPlist.strings文件(注意,每种语言均有一个infoPlist.strings文件),将其复制到文件夹「NewTargetInfo」中。

  3. 在Xcode工程中新建Group「NewTarget-Info」,将「NewTarget-info.plist」拖到该Group中,同时,通过「Add Files to “Target”」选项将步骤2)中的infoPlist.strings文件添加到Group「NewTarget-Info」。


  4. 选中「infoPlist.strings」,在「Utilities View」中的「Target Membership」选项,选择此「infoPlist.strings」属于哪个Target,注意,这里不能多选,只能选中「NewTarget」。


  5. 打开「infoPlist.strings」文件,在各个语言文件中添加下述语句,其中「AppName」根据需求填写。

    "CFBundleDisplayName" = "AppName";

添加「App图标」及「启动页面」

添加「App图标」

添加「App图标」相对简单

  1. 进入「Images.xcassets」中,通过「按住Option按钮拖拽」的方式,得到原来的「AppIcon」的拷贝,将其改名为「NewTarget AppIcon」;

  2. 右键「Show in Finder」,将新的App图标按照相同的名称拷贝进文件夹,覆盖原有图标。

  3. 进入「NewTarget」的「General」页面,找到「App Icons and Launch Images」分类,在「App Icons Source」选项中选择「NewTarget AppIcon」;

添加「启动页面」

「启动页面」分两种情况,一种是IOS7及以下版本的「启动页面」,一种是IOS8及以上版本的「启动页面」

对于IOS7及以下版本

参考「App图标」的三步配置,即可为「NewTarget」创建新的「启动页面」

对于IOS8及以上版本

由于IOS8及以上版本的启动页面使用的是「Launch Screen」,而「Launch Screen」的样式只能通过修改.xib页面实现,不可编写任何代码。假设「Launch Screen」中只有一个ImageView元件,ImageView元件的image为「welcomePage.png」,那么,我们可以在工程中添加多个同名但不同内容的welcomePage.png,并通过「Target Membership」来定义不同的「welcomePage.png」分别关联哪个Target,即可实现不同Target使用不同「启动页面」的目的。

添加预编译宏

对于不同Target间代码级别的差异,我们可以通过预编译宏来实现代码预编译。进入「Target」的「Build Settings」界面,找到「Preprocessor Macros」选项,在「Debug」及「Release」选项中,按需增加宏定义。例如,为「NewTarget」添加宏定义

"TARGET_TYPE"="NEW_TARGET"

那么在代码中,即可通过预编译语句实现代码的差别编译。

#if TARGET_TYPE == NEW_TARGET
    //do something for NewTarget
#else
    //do something for OtherTarget
#end

Manage Schemes

最后一步!将系统默认生成的 build Scheme 名称改为「New Target Release」即可,当然,还可以按需添加不同的 scheme.

坑!!!

奇怪的编译问题

_Warning: The Copy Bundle Resources build phase contains this target's Info.plist file 'Simart-Info.plist'._

原因:在「Target-Info.plist」的「Target Membership」选项中误选了某个Target,正常情况下,「Target-Info.plist」在「Target Membership」选项中是不选择任何一个Target的。

Unable to run command 'CpResource Simart.app' - this target might include its own product.
Unable to run command 'Touch Simart.app' - this target might include its own product.

原因:在「Products」Group中的某个product的「Target Membership」中给误选了某个Target,正常情况下product不应该关联到任何一个Target。

App名称无法修改

原因:在修改「NewTarget」的「InfoPlist.strings」文件时,发现无论如何修改,App名称都会显示OriginalTarget的App名称,排查后发现,「OriginalTarget」的「InfoPlist.strings」的「Target Membership」中除了勾选了「OriginalTarget」外,还勾选了「NewTarget」,这就导致了在编译「NewTarget」时,错误地读取了「OriginalTarget」的「InfoPlist.strings」文件。

重新检查一遍所有Target「InfoPlist.strings」的「Target Membership」选项,保证关联的唯一性和正确性即可。

「启动页面」无法显示

此问题出现在IOS8.0及以上版本中。

问题具体表现为:无论使用模拟器或者真机调试,在切换Target时,均会「随机」出现「启动页面」变成白色。检查了很多遍各个Target的配置,并未发现问题。

最后,Achive每个Target的AD HOC版本,并通过fir.im进行分发测试,发现每个Target的「启动页面」均正常,难道这是Xcode-7.2.1的Bug?目前不得而知,待后续跟进...

总结

总的来说,使用「Multi-Target」方案,算是「完美地」解决了此次需求。同时,此方案也可用于「发布独立的测试版本」「发布有限制的App版本」等需求。

总而言之,只要理解了A target defines a single product,具体怎么用就看项目的实际需求了。

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

推荐阅读更多精彩内容