iOS - 創(chuàng)建大量相似App的另外一種選擇

本篇文章主要針對iOS應用開發(fā)中, 針對需要創(chuàng)建許多相似的應用App提出一種新穎的解決方案。

關于如何創(chuàng)建大量相似的App,iOS大神@唐巧曾在他的博文《猿題庫iOS客戶端的技術細節(jié)(一):使用多target來構建大量相似App》提出了一種可行性非常高的解決方案。我本人也將該實現(xiàn)方案應用到了某二手車應用開發(fā)中, 通過創(chuàng)建多個target的方式創(chuàng)建了N個某某拍的應用。但是這種方案真的適用于所有場景么? 除了使用這種方案能否有其它的方式去解決這個問題呢?

基于多Target的應用實踐

我剛開始接觸到開發(fā)多個相似App應用的需求的時候, 也采用了多個target的解決方案。主要做了以下工作:

  1. 建立多個Target (通過Duplicate行為)
  2. 為每一個Target指定LaunchImage和IconImage, LauchImage和IconImage由同一個image assert管理
  3. 為每一個Target指定了Info.PlistInfoPlist.strings, InfoPlist.strings的作用僅僅是為了指定CFBundleDisplayName
  4. 為每一個Target創(chuàng)建了一個用于配置應用特征的JSON描述文件, 用于對每個Target的特征進行配置修改。
  5. 部署自動化打包平臺,防止有N個Target就手動打N次包。
配置Configuration的各個xcconfig

在上述工作中, 1、2、3均和配置項有關, 5與項目開發(fā)無關, 4是和具體的開發(fā)業(yè)務相關的。每一項的配置都沒有什么技術深度和難度, 4的實現(xiàn)和具體需求相關, 對于極度相似的應用更多的行為是換膚和換key。

這里稍微提以下關于InfoPlist.strings的指定, 每一個Target只能識別一個InfoPlist.strings, 而且還不能重命名。需要為每一個Target創(chuàng)建一個物理文件夾, 然后在對應的文件夾下放置InfoPlist.strings防止命名沖突, 每一個InfoPlist.strings只能指定唯一識別的Target對象。(原理我還沒有找到, 找到我就更新下博文哈~)

差異性較大的Target處理

什么? 差異性大你還放在一個工程里? 架構就有問題。是的, 差異性較大的工程就應該拆分成不同的工程, 然后共享的代碼通過framework以及靜態(tài)庫引用的方式抽離出去。<font color='orange'>但是, 時間是道坎!</font> 假如你時間很緊怎么辦? 本文給出一種時間很緊時候的<font color='red'>臨時</font>解決方案(注意: 決必是臨時的, 時間是海綿, 需要去擠的!)

在時間非常緊的情況下, 可以通過拆分AppDelegate來實現(xiàn)(代價其實非常沉重, 會link好多無用的類)。拆分AppDelegate其實就要在main.m里面賦值不同的AppDelegate即可實現(xiàn)。main函數(shù)中argv包含了app的名字, 可以通過該名字去鑒別載入的AppDelegate。

#import <UIKit/UIKit.h>

#import "STAppDelegate.h"
#import "STPAppDelegate.h"

int main(int argc, char * argv[])
{
    @autoreleasepool {
        char demoStr[] = "/stdemo.app"; // 檢查stdemo target
        char *p= strstr(*argv, demoStr);
        if(NULL != p){
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([STAppDelegate class]));
        }else{
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([STPAppDelegate class]));
        }
    }
}

PS: 切記, 臨時解決方案, 如需根治, <font style="font-size:1.5em">拆分工程</font>!

基于多Target實現(xiàn)的好處

  1. 直觀

    一目了然, 可以看到所有已創(chuàng)建的Target醒目的列在Build列表中。每一個Target都有對應的Tagret配置界面可以看到每一個項目配置圖標以及Info.plist對應信息。

  2. 靈活性高

    可以根據(jù)項目需要Link需要的類, 根據(jù)Target來指定鏈接不同的類和資源文件, 而不用一口氣全部都Link進來。

基于多Target遇到的坑

如果沒有遇到坑, 那就不會去重新尋找一個更好的解決方案了?;诙郥arget的方式去創(chuàng)建大量相似的App的坑主要提現(xiàn)在多人協(xié)作上。

個人之前在實現(xiàn)多Target項目的時候遇到的問題不多, 但是隨著時間推移, 維護開發(fā)遇到了兩個比較明顯的問題:

  1. 類的Target指定遺漏

    在多個Target的環(huán)境下, 我們每新建一個類文件都要給類文件指定對應的Target, 如果不小心忘記指定對應的Target, 則會會在編譯階段報錯。

    配置Configuration的各個xcconfig
  2. 配置文件描述龐大, 難以修改

    多個Target會導致項目的pbxproj臃腫, 因為pbxproj文件維護了項目的所有文件id和group層級關系, 多一個target就幾乎多了一倍的描述信息, 可想而知, 這個pbxporj文件是有多龐大。

    光文件龐大頂多引起Xcode項目的配置文件加載慢, 但是遇到?jīng)_突的時候可就頭疼了, 幾萬行的描述文件。

    配置Configuration的各個xcconfig
  3. 配置文件修改不同步

配置文件修改不同步是基于已創(chuàng)建N個Target的前提下, 因為項目的推進, 需要對每一個項目文件進行固定的修改, 但是存在修改遺漏的情況。

對于這種場景, 有一種比較好的方案是自己動手寫腳本來替換編譯配置項, 保證每一個Target的配置項目均被替換。Mac開發(fā)工具中自帶的PlistBuddy在處理配置項目替換上絕對是個神器。

重新思考

雖然在項目中遇到了不少坑,但是解決這些坑并不需要大量的時間(那是因為時間被打散了, 組合起來估計也不少了),所以我個人并沒有去重新思考怎么去解決遺漏Target編譯報錯以及項目配置文件不斷沖突的問題。

觸發(fā)我重新思考是一次機緣, 經(jīng)過花瓣網(wǎng)某iOS研發(fā)高手(我不知道他名字哇)提點, 他問我基于Cocoapods能否有更好的辦法去創(chuàng)建大量相似的App。基于Cocoapods本身就是基于Hook, Hook本身就是動態(tài)修改項目配置項, 換言之, <font color='red'>能否通過動態(tài)修改Target的項目配置項去創(chuàng)建大量相似的App呢</font>?

回到文章前面的基于多Target的應用實踐的5個步驟, 逐一用替換項目的配置文件(pbcproj)的方式去重新審視。

  1. 不需要建立多個Target, 只維護一個Target
  2. 主要是icon和launch image的修改, 有兩種方案:
    • 在image.assert預先放置多個不同名字的資源, 通過修改pbxproj來指定不同的圖片資源
    • 所有的icon和launch image都是用相同名字, 通過腳本動態(tài)替換image.assert中的資源文件(推薦)
  3. 主要針對info.plist和InfoPlist.strings的修改, InfoPlist.string可以通過sed命令去動態(tài)替換, info.plist也可以采取兩種方案來實現(xiàn):
    • 預先防止多個Info.plist文件, 通過修改pbxcproj來指定不同的info.plist文件
    • target永遠指定一個Info.plist, 通過腳本動態(tài)替換修改Info.plist(推薦)
  4. 通過JSON描述特性的文件可以單獨防止在工程里, 通過腳本拷貝替換, 也可以利用cocoapods-keys等工具進行外部注入
  5. 前面的4個步驟都是依賴于基本動態(tài)替換, 自動化構建平臺通過將指定Target的方式, 修改為在編譯器執(zhí)行對應的任務腳本即可完成。

進一步優(yōu)化

重新思考<font color='black'>通過外部修改配置項目和資源文件的方式來實現(xiàn)多個類似應用功能</font>, 省去了維護多個target產(chǎn)生的沖突和配置過大的問題。但是, 外部腳本本身也是一個實現(xiàn)成本, 這里針對替換外部腳本提出一個優(yōu)化策略(不一定最優(yōu))。

  1. 維護每個項目的文件夾

    每一個項目就是指原來的每一個target, 文件夾可以保持和原先的target名字保持同名。該目錄文件夾不參與項目引用, 即不在pbxcproj文件中被描述。該目錄文件夾純粹是提供給外部腳本使用, 與邏輯工程保持獨立。

  2. 在第一步的文件夾中抽離變化項目到同一個JSON文件中

    該json文件中描述了所有需要替換的內容, 包含image.assert的替換規(guī)則以及info.plist替換規(guī)則等等。

  3. 在第一步的文件夾中抽離資源文件

    在該文件夾中防止所有可變化的資源文件, 包含.pnginfo.plist等等所有可變化差異的項目。

配置Configuration的各個xcconfig

在前面三步的基礎下, 主要是為了一個目的, 一行腳本替換所有可變信息。(實際上就是提前將變化項維護在獨立的文件夾中了)

## 動態(tài)變化 demo1 Target
./st_muti_target st_demo1/muti_target.json

## 動態(tài)變化 demo2 Target
./st_muti_target st_demo2/muti_target.json

想要st_muti_target.sh的源碼? 這個自己寫吧。。每個項目都不一樣的。

總結

基于建立多個相似App的需求, 和本人實際在項目應用中遇到的坑, 提出了一種基于腳本不斷替換配置項目和資源文件的解決方案。該方案主要解決了多Target所帶來的配置文件過大和容易沖突的問題, 但是同時又引入了腳本的維護成本。本文也提供了一種降低腳本使用成本和項目耦合的一種方案, 但是仍需要進一步優(yōu)化, 并不是最終的解決方案版本。

多一種方案多一種選擇么, 對于擅長書寫腳本的童鞋們, 用這種方式做大量類似的App(換膚App)可能會是更好的一種選擇喔~

水平有限, 有錯誤之處或者有什么地方?jīng)]有描述清楚, 請大家及時指出哇~

參考文件:

  1. http://blog.devtang.com/blog/2013/10/17/the-tech-detail-of-ape-client-1/
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評論 6 342
  • 前言 在公司發(fā)展過程中,除了開發(fā)維護自有品牌外,針對有實力有潛質的客戶,公司還會接受OEM「貼牌開發(fā)」的合作方式。...
    ChamchamBen閱讀 3,147評論 9 7
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,765評論 25 709
  • 又到一年畢業(yè)季,大四的師妹打電話給我敘了好久的舊,最后問了我一個問題,她說“師姐,我最近越來越清晰地意識到自己將要...
    _大臉貓閱讀 672評論 0 0

友情鏈接更多精彩內容