iOS - 建立大量相似App的另外一種選擇
本篇文章主要針對iOS應用開發中, 針對需要建立許多相似的應用App提出一種新穎的解決方案。
關於如何建立大量相似的App,iOS大神@唐巧曾在他的博文《猿題庫iOS客戶端的技術細節(一):使用多target來構建大量相似App》提出了一種可行性非常高的解決方案。我本人也將該實現方案應用到了某二手車應用開發中, 通過建立多個target的方式建立了N個某某拍的應用。但是這種方案真的適用於所有場景麼? 除了使用這種方案能否有其它的方式去解決這個問題呢?
基於多Target的應用實踐
我剛開始接觸到開發多個相似App應用的需求的時候, 也採用了多個target的解決方案。主要做了以下工作:
- 建立多個Target (通過Duplicate行為)
- 為每一個Target指定LaunchImage和IconImage, LauchImage和IconImage由同一個image assert管理
- 為每一個Target指定了Info.Plist和InfoPlist.strings, InfoPlist.strings的作用僅僅是為了指定CFBundleDisplayName
- 為每一個Target建立了一個用於配置應用特徵的JSON描述檔案, 用於對每個Target的特徵進行配置修改。
- 部署自動化打包平臺,防止有N個Target就手動打N次包。
在上述工作中, 1、2、3均和配置項有關, 5與專案開發無關, 4是和具體的開發業務相關的。每一項的配置都沒有什麼技術深度和難度, 4的實現和具體需求相關, 對於極度相似的應用更多的行為是換膚和換key。
這裡稍微提以下關於InfoPlist.strings的指定, 每一個Target只能識別一個InfoPlist.strings, 而且還不能重新命名。需要為每一個Target建立一個物理資料夾, 然後在對應的資料夾下放置InfoPlist.strings防止命名衝突, 每一個InfoPlist.strings只能指定唯一識別的Target物件。(原理我還沒有找到, 找到我就更新下博文哈~)
差異性較大的Target處理
什麼? 差異性大你還放在一個工程裡? 架構就有問題。是的, 差異性較大的工程就應該拆分成不同的工程, 然後共享的程式碼通過framework以及靜態庫引用的方式抽離出去。<font color='orange'>但是, 時間是道坎!</font> 假如你時間很緊怎麼辦? 本文給出一種時間很緊時候的<font color='red'>臨時</font>解決方案(注意: 決必是臨時的, 時間是海綿, 需要去擠的!)
在時間非常緊的情況下, 可以通過拆分AppDelegate來實現(代價其實非常沉重, 會link好多無用的類)。拆分AppDelegate其實就要在main.m裡面賦值不同的AppDelegate即可實現。main函式中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實現的好處
-
直觀
一目瞭然, 可以看到所有已建立的Target醒目的列在Build列表中。每一個Target都有對應的Tagret配置介面可以看到每一個專案配置圖示以及Info.plist對應資訊。
-
靈活性高
可以根據專案需要Link需要的類, 根據Target來指定連結不同的類和資原始檔, 而不用一口氣全部都Link進來。
基於多Target遇到的坑
如果沒有遇到坑, 那就不會去重新尋找一個更好的解決方案了。基於多Target的方式去建立大量相似的App的坑主要提現在多人協作上。
個人之前在實現多Target專案的時候遇到的問題不多, 但是隨著時間推移, 維護開發遇到了兩個比較明顯的問題:
-
類的Target指定遺漏
在多個Target的環境下, 我們每新建一個類檔案都要給類檔案指定對應的Target, 如果不小心忘記指定對應的Target, 則會會在編譯階段報錯。
-
配置檔案描述龐大, 難以修改
多個Target會導致專案的pbxproj臃腫, 因為pbxproj檔案維護了專案的所有檔案id和group層級關係, 多一個target就幾乎多了一倍的描述資訊, 可想而知, 這個pbxporj檔案是有多龐大。
光檔案龐大頂多引起Xcode專案的配置檔案載入慢, 但是遇到衝突的時候可就頭疼了, 幾萬行的描述檔案。
配置檔案修改不同步
配置檔案修改不同步是基於已建立N個Target的前提下, 因為專案的推進, 需要對每一個專案檔案進行固定的修改, 但是存在修改遺漏的情況。
對於這種場景, 有一種比較好的方案是自己動手寫指令碼來替換編譯配置項, 保證每一個Target的配置專案均被替換。Mac開發工具中自帶的PlistBuddy在處理配置專案替換上絕對是個神器。
重新思考
雖然在專案中遇到了不少坑,但是解決這些坑並不需要大量的時間(那是因為時間被打散了, 組合起來估計也不少了),所以我個人並沒有去重新思考怎麼去解決遺漏Target編譯報錯以及專案配置檔案不斷衝突的問題。
觸發我重新思考是一次機緣, 經過花瓣網某iOS研發高手(我不知道他名字哇)提點, 他問我基於Cocoapods能否有更好的辦法去建立大量相似的App。基於Cocoapods本身就是基於Hook, Hook本身就是動態修改專案配置項, 換言之, <font color='red'>能否通過動態修改Target的專案配置項去建立大量相似的App呢</font>?
回到文章前面的基於多Target的應用實踐
的5個步驟, 逐一用替換專案的配置檔案(pbcproj)的方式去重新審視。
- 不需要建立多個Target, 只維護一個Target
- 主要是icon和launch image的修改, 有兩種方案:
- 在image.assert預先放置多個不同名字的資源, 通過修改pbxproj來指定不同的圖片資源
- 所有的icon和launch image都是用相同名字, 通過指令碼動態替換image.assert中的資原始檔(推薦)
- 主要針對info.plist和InfoPlist.strings的修改, InfoPlist.string可以通過
sed
命令去動態替換, info.plist也可以採取兩種方案來實現:- 預先防止多個Info.plist檔案, 通過修改pbxcproj來指定不同的info.plist檔案
- target永遠指定一個Info.plist, 通過指令碼動態替換修改Info.plist(推薦)
- 通過JSON描述特性的檔案可以單獨防止在工程裡, 通過指令碼拷貝替換, 也可以利用
cocoapods-keys
等工具進行外部注入 - 前面的4個步驟都是依賴於基本動態替換, 自動化構建平臺通過將指定Target的方式, 修改為在編譯器執行對應的任務指令碼即可完成。
進一步優化
重新思考<font color='black'>通過外部修改配置專案和資原始檔的方式來實現多個類似應用功能</font>, 省去了維護多個target產生的衝突和配置過大的問題。但是, 外部指令碼本身也是一個實現成本, 這裡針對替換外部指令碼提出一個優化策略(不一定最優)。
-
維護每個專案的資料夾
每一個專案就是指原來的每一個target, 資料夾可以保持和原先的target名字保持同名。該目錄資料夾不參與專案引用, 即不在pbxcproj檔案中被描述。該目錄資料夾純粹是提供給外部指令碼使用, 與邏輯工程保持獨立。
-
在第一步的資料夾中抽離變化專案到同一個JSON檔案中
該json檔案中描述了所有需要替換的內容, 包含image.assert的替換規則以及info.plist替換規則等等。
-
在第一步的資料夾中抽離資原始檔
在該資料夾中防止所有可變化的資原始檔, 包含
.png
、info.plist
等等所有可變化差異的專案。
在前面三步的基礎下, 主要是為了一個目的, 一行指令碼替換所有可變資訊。(實際上就是提前將變化項維護在獨立的資料夾中了)
## 動態變化 demo1 Target
./st_muti_target st_demo1/muti_target.json
## 動態變化 demo2 Target
./st_muti_target st_demo2/muti_target.json
想要st_muti_target.sh
的原始碼? 這個自己寫吧。。每個專案都不一樣的。
總結
基於建立多個相似App的需求, 和本人實際在專案應用中遇到的坑, 提出了一種基於指令碼不斷替換配置專案和資原始檔的解決方案。該方案主要解決了多Target所帶來的配置檔案過大和容易衝突的問題, 但是同時又引入了指令碼的維護成本。本文也提供了一種降低指令碼使用成本和專案耦合的一種方案, 但是仍需要進一步優化, 並不是最終的解決方案版本。
多一種方案多一種選擇麼, 對於擅長書寫指令碼的童鞋們, 用這種方式做大量類似的App(換膚App)可能會是更好的一種選擇喔~
水平有限, 有錯誤之處或者有什麼地方沒有描述清楚, 請大家及時指出哇~
參考檔案:
相關文章
- SAP QM 04型別檢驗批的另外一種建立方式型別
- 開窗函式的另外一種方式函式
- 探探社交、一對一交友APP不是偶然的選擇,而是社交市場的選擇APP
- 家屬感言:選擇程式設計師,就是選擇一種生活程式設計師
- iOS選擇器元件iOS元件
- oracle手動建立另外一個例項Oracle
- Cordova學習----iOS建立第一個appiOSAPP
- iOS 一個滑動選擇控制元件iOS控制元件
- 8 種基本軟體開發模型:選擇哪一種?模型
- [譯] iOS App 上一種靈活的路由方式iOSAPP路由
- 31種選擇器的應用
- 選擇 Java 編寫 iOS 與 安卓 App的八大理由JavaiOS安卓APP
- RIS,建立 React 應用的新選擇React
- java中寫建構函式的另外一種方式Java函式
- 《大教堂與集市》:軟體工程的另一種選擇軟體工程
- uniapp 檔案選擇APP
- jquery另外一種類似tab切換效果jQuery
- 非空+預設值——一種選擇方案思路
- iOS App中可拆卸一個framework的兩種方式iOSAPPFramework
- 創業者談:做微信還是做APP,兩種選擇的不同風險創業APP
- HTM – JSX 的替代品?還是另一種選擇?JS
- HTM - JSX 的替代品?還是另一種選擇?JS
- 啟動另外的一個應用程式的Activity(三種方式)
- ios蘋果企業開發者賬號與蘋果另外兩種賬號的區別iOS蘋果
- PostgreSQL相似人群圈選,人群擴選,向量相似使用實踐-cubeSQL
- 選擇一種安裝方法安裝Linux(轉)Linux
- 利用memcached配置session一致性另外一種方案Session
- iOS倒數計時的探究與選擇iOS
- iOS 單張及多張照片的選擇iOS
- React 的幾種條件渲染以及選擇React
- HTML5新增的3種選擇器HTML
- css 選擇器效能的取捨。和大量標籤帶有都是classCSS
- iOS開發圖片格式選擇iOS
- 仿微信iOS相簿選擇 MTImagePickeriOS
- iOS簡易時間選擇器iOS
- iOS開發之城市選擇器iOS
- iOS筆記--PickView選擇國家iOS筆記View
- iOS APP建立桌面快捷方式iOSAPP