iOS 同一個工程下 使用多target來構建大量相似App

前言

本人今年主要在負責猿題庫iOS客戶端的開發,本文旨在通過分享猿題庫iOS客戶端開發過程中的技術細節,達到總結和交流的目的。

這是本技術分享系列文章的第一篇。本文涉及的技術細節是:採用多Target編譯方案來實現多個相似App的開發,以保證我們能夠快速地推出多個相似課程的客戶端。

問題描述

今年春節後,我們對外發布了應用“猿題庫-公務員考試行測”,接着我們就開始一個個發佈猿題庫系列課程應用。到現在半年多過去了,我們一共對外發布了8款應用(如下圖所示)。

這些課程,隨了“猿題庫-公務員考試申論”和其它課程不一樣之外,另外7個課程都有着相似,但是又不完全相同的功能和界面。

這些應用的相同點包括:

  1. 基本相同的註冊和登錄以及首頁邏輯和界面(只是背景圖片不一樣而已)。
  2. 相同的做題邏輯和界面。
  3. 基本相同的答題報告顯示界面。
  4. 基本相同的能力評估報告界面。

不同點主要包括:

  1. 應用圖標,啓動畫面,應用啓動後的首頁都不一樣。
  2. 有些課程(例如公務員考試和高考)是有目標考試的概念,不同的目標考試大綱是不一樣的。拿高考來舉例,北京的高考和上海的高考,就有着完全不一樣的考試大綱。高考的文科和理科,又有着完全不同的考試科目。
  3. 有些課程會有一些自定義的界面,例如高考的應用可以設置暱稱,有些課程的真題練習中是有推薦真題模塊的,而有些課程又沒有。
  4. 有些課程有掃描答題卡功能,有些課程有考前衝刺功能,有些課程有大題專項查看功能,而有些課程又沒有上述功能。另外還有一些微小細節,但是解決方法和類似,所以就不一一展開說明。

技術解決方案

我們的技術解決方案主要說來分4步:

  1. 通過抽取子項目,構建可複用的大模塊。
  2. 通過多Target編譯的方式,不同課程的在編譯時,採用不同的資源文件和源文件。
  3. 在第2步的基礎上,在項目中創建配置用的Config類,然後在不同Target各自的配置文件中設置不同的Config值。實現課程的差異化界面。
  4. 從不同的xib中加載界面。

抽取子項目

我們首先做的是抽取子項目,從“猿題庫司法考試客戶端”開始,我們將可以重用的模塊一一抽取出來,以git submodule的形式組織到項目中。這個抽取過程在開發完猿題庫司法考試客戶端之後,基本成型了。我們抽取的submodule主要分爲4部分:

  1. UI Common,涉及可複用的登錄界面,註冊界面,付費界面,NPS界面,意見反饋界面,關於界面,掃描答題卡界面。另外,我們將一些可複用的UI風格控件也抽取成了相應的靜態工廠方法,用於生成統一風格的按鈕、背景以及狀態欄等。
  2. Core Common,涉及可複用的底層模塊。包括網絡請求模塊,自己封裝的Core Text渲染引擎,緩存模塊,一些靜態util方法等。
  3. Lib Common,所有第三方的開源庫依賴,有部分代碼根據我們的需求做了修改和定製。
  4. Scan Common, 答題卡掃描識別算法模塊,實現核心的掃描算法。

以上只是粗粒度劃分,這些模塊化的子項目可能在以後被重用,例如Core Common完全就可以複用在任何其它項目中。

構造多個編譯Target

抽取完子項目以後,我們採用多target的方式,將不同課程中的同名資源文件打包進各自的Target中,最後所有課程在一個工程項目中,如下圖所示:

先簡單介紹一下Xcode中target的概念,蘋果在文檔中寫道:

Targets that define the products to build. A target organizes the files and instructions needed to build a product into a sequence of build actions that can be taken.”

在Xcode的一個項目中,可以允許建立多個編譯的target,每個target代表着最終編譯出來的一個App文件,在每個target中,可以添加不同的編譯源文件和資源文件。最終,通過我們在不同target之間,修改其 Copy Bundle Resources 和 Compile Sources 配置,使課程之間的差異性得到實現。我們具體的配置方案如下:

  1. 我們的每個課程的資源文件都具有相同的文件名,例如首頁背景都叫 HomeBackgroundBg.png ,由於每個課程背景不一樣,所以我們在工程中,每一個課程target下,通過修改Copy Bundle Resources,使其都配置有不同的(但是同名) HomeBackgroundBg.png 。這樣的好處是,在代碼邏輯層面,我們可以完全不用處理課程間資源文件的差異性問題。資源文件的差異性都是通過配置文件來保證的。

  2. 對於文案一類的差別,我們通過修改Compile Sources,使不同的課程有着不同的文案定義文件。通過這樣,我們使不同課程有了不同的文案。另外包括後臺網絡接口的差異性問題,統計項的差異性問題,也都是這樣處理的。

Config類

最後,我們使用Config類來完成交互和頁面UI組件差異性問題。拿能力評估報告頁面來說,不同的課程的頁面都有一些差異。我們在公共層的代碼中將這些邏輯全部實現,具體的UI在呈現時,通過讀取相關的Config類來決定具體如何展示。這樣,我們只需要在第2步提供的各個課程的差異性源文件中,完成Config類的配置即可。

從不同的xib中加載界面

有些時候,我們僅僅需要的是UI界面排列方式不一樣,其它交互邏輯完全一樣。對於這種需求,我們嘗試同一個view對應有多個xib,然後通過上一步的Config類的信息,來加載不同的xib界面。這樣所有的差異性都在不同的xib中解決了,對controller層可以完全透明。

下圖是我們報告頁面的xib界面,分爲:高考課程、有目標考試的課程、沒有目標考試的課程三種。由於這3個界面的後臺邏輯和交互邏輯都一樣,我們通過3個xib來實現它們之間差異性的部分。

以下是view加載對應的xib的代碼邏輯:

+ (IPadAbilityReportHeaderView *)loadFromNib:(IPadAbilityReportHeaderViewType)type {

    NSString *nibFileName;

    switch (type) {

        case IPadAbilityReportHeaderViewTypeWithQuiz:

            nibFileName = @"IPadAbilityReportHeaderViewWithQuiz";

            break;

        case IPadAbilityReportHeaderViewTypeWithoutQuiz:

            nibFileName = @"IPadAbilityReportHeaderViewWithoutQuiz";

            break;

        case IPadAbilityReportHeaderViewTypeGaokao:

            nibFileName = @"IPadAbilityReportHeaderViewInGaokao";

            break;

        default:

            break;

    }

    NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:nibFileName owner:nil options:nil];

    if (nibArray.count > 0) {

        return [nibArray lastObject];

    } else {

        return nil;

    }

}


總結

通過多target編譯方案,我們可以很方便的實現多個相似App的開發,以保證我們能夠快速地推出多個相似課程的客戶端。同時,由於在一個工程中,我們也可以方便地測試新的代碼邏輯在各個課程下是否正常。

該方案可以用來解決“維護大量邏輯相似但是又有細微不同的應用”的需求,希望本文能給業界同行一些幫助。

 Oct 17th, 2013  iOS

原文地址 : http://blog.devtang.com/blog/2013/10/17/the-tech-detail-of-ape-client-1/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章