iOS關於模塊化開發解決方案(純乾貨)

来源:http://www.cnblogs.com/wujy/archive/2016/09/29/5919105.html
-Advertisement-
Play Games

關於iOS模塊化開發解決方案網上也有一些介紹,但真正落實在在具體的實例卻很少看到,計劃編寫系統文章來介紹關於我對模塊化解決方案的理解,裡面會有包含到一些關於解耦、路由、封裝、私有Pod管理等內容;並編寫的一個實例項目放在git進行開源[jiaModuleDemo],裡面現在已經放著一些封裝的功能模塊 ...


關於iOS模塊化開發解決方案網上也有一些介紹,但真正落實在在具體的實例卻很少看到,計劃編寫系統文章來介紹關於我對模塊化解決方案的理解,裡面會有包含到一些關於解耦、路由、封裝、私有Pod管理等內容;並編寫的一個實例項目放在git進行開源[jiaModuleDemo],裡面現在已經放著一些封裝的功能模塊;會不斷的進行更新,假如你感興趣可以Star一下,項目也不斷的更新完善優化;如果你有更好的方案或者說好的建議可以lssues,我會在短時間進行更新並修改相應的問題;

一:項目中存在的問題

1:當公司裡面有多個項目同時進行,並且有可能是多個人分別不同項目時,就會存在如上圖出現的情況,其實每個APP中都是有很多共同的模塊,當然有可能你會把相同功能模塊代碼複製一份在新項目中,但這其實並不是最好的方式,在後期不斷迭代過程中,不同的人會往裡面增加很多帶有個人色彩的代碼;這樣就像相同的模塊項目後期對於多個項目統一管理也是災難性,有可能會失控,哪怕項目轉移別人接手也會無形中浪費很多時間,增加維護成本,所以實例中更註重對於一些相同模塊進行提取,求同存異;而模塊化結合私有Pods進行管理,對於常用功能的封裝,只要開放出一些簡單開關配置方式,就可以實現一個功能,比如日誌記錄、網路請求模塊、網路狀態變化提示等;

 

2:對於頁面之間相互耦合,而頁面之間的傳參也各不相同,由於不同的開發人員或者簡便方式等原因,傳參的類型都有差異,包含如實體、簡單基本類型等,先前項目對於路由方式也不支持,導致要實現收到消息推送進行不同的頁面跳轉存在硬編碼情況,對於功能擴展存在相當大的問題;而右邊則是模塊化後頁面之間的交互方式;頁面之間也不存在耦合關係,都只跟JiaMediator這個中介者相依賴;而傳參都統一成以字典的形式;雖然可能犧牲一些方便跟隨意,卻可以解耦模塊化;並且加入對路由方式的處理;約定好相關的協議進行交互;用這種路由方式代替那些第三方的路由插件則是因為它的靈活性,最主要還是省去了第三方路由插件在啟動時要註冊路由的問題;

 

二:解決方案實現之模塊化

1:JiaCore(基礎功能封裝)

JiaCore是整個APP最基礎模塊,所有的模塊化都要依賴,主要包含一些全局的功能模塊,比如JiaBaseViewController、JiaAppDelegate等;目前已經把一些預設的功能進行集成在裡面,包含網路狀態變化判斷及提示、日誌記錄功能等;並把一些相關配置的內容用JiaCoreConfigManager這個管理類進行統一設置,比如是否打開日誌記錄功能;JiaCoreConfigManager類則是開放給具體APP設置全局的相關配置;下麵就以其中一個日誌記錄功能進行講解:

//JiaCore基礎模塊相關配置
JiaCoreConfigManager *jiaCoreConfig=[JiaCoreConfigManager sharedInstance];
jiaCoreConfig.recordlogger=YES;

然後具體APP的PrefixHeader.pch引入命名空間併進行設置記錄日誌的等級:

#import "JiaCocoaLumberjack.h"

//DDLog等級
static const int ddLogLevel = DDLogLevelVerbose;

這樣就完成的一個APP對於日誌記錄模塊的引入,JiaCore已經幫你完成的關於日誌記錄的相關配置,並且錯誤內容以一種可讀性較好的格式記錄到file文件中,而且這些file文件生成規則也都定義好了,當然如何時你要是在Xcode控制台顯示不同等級色彩,只要安裝XcodeColors插件並簡單進行設置就可以了,對於不同等級不同色彩都已經在JiaCore配置完成;

2:JSPatch熱更新功能

JiaCore裡面也預設集成了熱更新的功能,只要傳入簡單的對象數組就會啟動熱更新;其中JiaPathchModel已經是定義好的模型,在APP中把介面請求轉化成模型數組,其中patchId是唯一值名稱、md5則是JS文件的MD5值、url是JS的下載路徑、ver則是對哪個版本起作用;因為一般我們在外面的APP都是多版本共存,熱更新也要進行版本區分,只下載與本版本相對應的熱更新JS文件載入;而MD5值則是為了增加安全性,避免JS文件被別人進行修改而影響APP的運行,在JiaCore會對下載後的JS文件進行MD5計算並比較;對於沒有在jSPatchMutableArray以前的JS文件會被刪除;

//熱更新內容
JiaPathchModel *sample=[[JiaPathchModel alloc]init];
sample.patchId = @"patchId_sample1";
sample.md5 = @"2cf1c6f6c5632dc21224bf42c698706b";
sample.url = @"http://test.qshmall.net:9090/demo1.js";
sample.ver = @"1";

JiaPathchModel *sample1=[[JiaPathchModel alloc]init];
sample1.patchId = @"patchId_sample2";
sample1.md5 = @"e8a4eaeadce5a4598fb9a868e09c75fd";
sample1.url = @"http://test.qshmall.net:9090/demo2.js";
sample1.ver = @"1";

//JiaCore基礎模塊相關配置
JiaCoreConfigManager *jiaCoreConfig=[JiaCoreConfigManager sharedInstance];
jiaCoreConfig.jSPatchMutableArray=[@[sample,sample1] mutableCopy];

3:JiaGT模塊(個推封裝)

消息推送對於一個APP是相當重要性,一般是採用第三方的SDK進行集成,其實大部分的SDK處理代碼都是差不多,在這實例中對差異化的內容進行提取,實例中將以個推進行模塊化,因為消息推送的大部分代碼都集中在AppDelegate中,造成的一大堆雜亂代碼,當然也有一部分人對AppDelegate進行擴展分類進行移除代碼,實例中將採用另外一種解決方案進行抽取,可以達到完全解耦,在具體的APP裡面將不會再出現個推SDK相關內容,只要簡單進行配置跟處理消息就可以,下麵只是簡單的列出部分代碼,其它封裝代碼見源代碼;

//設置個推模塊的配置
jiaGTConfigManager *gtConfig=[jiaGTConfigManager sharedInstance];
gtConfig.jiaGTAppId=@"0uuwznWonIANoK07JeRWgAs";
gtConfig.jiaGTAppKey=@"26LeO4stbrA7TeyMUJdXlx3";
gtConfig.jiaGTAppSecret=@"2282vl0IwZd9KL3ZpDyoUL7";
#pragma mark 消息推送相關處理

/**
 *  @author wujunyang, 16-07-07 16:07:25
 *
 *  @brief  處理個推消息
 *
 *  @param NotificationMessage
 */
-(void)gtNotification:(NSDictionary *)NotificationMessage
{
    NSLog(@"%@",NotificationMessage[@"payload"]);
    NSLog(@"-----接收到個推通知------");
}


/**
 *  @author wujunyang, 16-07-07 16:07:40
 *
 *  @brief  處理遠程蘋果通知
 *
 *  @param RemoteNotificationMessage
 */
-(void)receiveRemoteNotification:(NSDictionary *)RemoteNotificationMessage
{
    NSLog(@"%@",RemoteNotificationMessage[@"message"]);
    NSLog(@"-----接收到蘋果通知------");
}

/**
 *  @author wujunyang, 16-09-21 14:09:33
 *
 *  @brief 獲得註冊成功時的deviceToken 可以在裡面做一些綁定操作
 *
 *  @param deviceToken <#deviceToken description#>
 */
-(void)receiveDeviceToken:(NSString *)deviceToken
{
    NSLog(@"-----當前deviceToken:%@------",deviceToken);
}

4:JiaAnalytics模塊(友盟統計封裝)

JiaAnalytics模塊是在友盟統計SDK跟Aspect相結合基礎上完成,對於頁面的進出統計採用Aop切麵方式進行,把原本應該在每個頁面生命周期的統計代碼移除,App運用只要簡單配置友盟相對應的信息,也可以設置要統計頁面的過濾條件,目前已經有三種如要統計的開頭頁面的首碼字元串數組、要統計的頁面名稱字元串數組、不統計的頁面名稱字元串數組;可以結合使用,達到精確統計頁面的目的;而且把統計的代碼放在非同步線程進行,不會影響主線程的響應;

__weak typeof(self) ws = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [UIViewController aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> info, BOOL animated){
            UIViewController *controller = [info instance];
            BOOL filterResult=[ws fileterWithControllerName:NSStringFromClass([controller class])];
            if (filterResult) {
                [ws beginLogPageView:[controller class]];
            }
        } error:NULL];

        [UIViewController aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo> info, BOOL animated){
            UIViewController *controller = [info instance];
            BOOL filterResult=[ws fileterWithControllerName:NSStringFromClass([controller class])];
            if (filterResult) {
                [ws endLogPageView:[controller class]];
            }
        } error:NULL];
    });

三:解決方案實現之頁面解耦

JiaMediator起到一個中介的作用,所有的模塊間響應交互都是通過它進行,每個模塊都會對它進行擴展分類(例如:JiaMediator+模塊A),分類主要是為了用於本地間調用而又不想用路由的方式,若要用路由的方式則要註意關於路由約束準確編寫,它將會直接影響到能否正確響應到目標;實例中也有關於使用通知的方式進行回調參數的回傳問題;

 

實例代碼如下:

NSDictionary *curParams=@{kDesignerModuleActionsDictionaryKeyName:@"wujunyang",kDesignerModuleActionsDictionaryKeyID:@"1001",kDesignerModuleActionsDictionaryKeyImage:@"designerImage"};
    switch (indexPath.row) {
        case 0:
        {
            UIViewController *viewController=[[JiaMediator sharedInstance]JiaMediator_Designer_viewControllerForDetail:curParams];
            [self presentViewController:viewController animated:YES completion:nil];
            break;
        }
        case 1:
        {
            UIViewController *viewController=[[JiaMediator sharedInstance]JiaMediator_Designer_viewControllerForDetail:curParams];
            [self.navigationController pushViewController:viewController animated:YES];
            break;
        }
        case 2:
        {
            NSString *curRoue=@"jiaScheme://Designer/nativeFetchDetailViewController?name=wujunyang&ID=1001&image=designerImage";
            UIViewController *viewController=[[JiaMediator sharedInstance]performActionWithUrl:[NSURL URLWithString:curRoue] completion:^(NSDictionary *info) {
                
            }];
            [self.navigationController pushViewController:viewController animated:YES];
            break;
        }
        case 3:
        {
            NSDictionary *userParaDictionary=@{kUserModuleActionsDictionaryKeyID:@"1"};
            UIViewController *viewController=[[JiaMediator sharedInstance] JiaMediator_User_viewControllerForDetail:userParaDictionary];
            [self.navigationController pushViewController:viewController animated:YES];
            break;
        }
        default:
            break;
    }

四:模塊化結合私有Pods方案

實例中只是把相關模塊化的提取都在一個工程進行體現,最後還是要落實結合Pods進行管理,把每個模塊分開管理,不同的APP可以簡單通過Pods指令就可以達到引入模塊的效果,對於一些相同模塊可以在不同的APP重覆引用,減小重覆開發成本;

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文接著實現輪播圖廣告的監聽滾動 本文地址:http://www.cnblogs.com/wuyudong/p/5920757.html,轉載請註明源地址。 首先添加佈局文件,實現小白點 shape_bg_point_enable.xml shape_bg_point_disable.xml 再添加 ...
  • addSubview: Adds a view to the end of the receiver’s list of subviews. 譯:增加一個視圖到接收者的子視圖列表中。 - (void)addSubview:(UIView *)view Parameters view The view ...
  • 安卓已經出來很長時間了,網上的教程也有很多,怕以後忘記,就把網上大牛們的分享的知識自己在學習一下,也記錄一下,如果能幫到別人,那是更好不過的! 鑒於現在的IDE工具來說,IDEA已經占據了java的半壁江山,Android Studio也漸漸的成為了Android開發的首選工具,筆者學習的時候就選擇 ...
  • 只有一個方法。 ...
  • PhotoKit 是一套比 AssetsLibrary 更新更完整也更高效的ios照片處理庫,對資源的處理跟 AssetsLibrary 有很大的不同。下麵簡單介紹下PhotoKit的幾個基本概念 PHAsset:代表照片庫中的特定資源,PHAsset對象來表示存儲在照片應用程式中或雲端的一個圖片或 ...
  • 1,模擬機上在創建地圖的xml的時候不能創建<MapView>,需要創建<TexturemapView>。 2,在獲取百度地圖的key的時候需要註意獲取的SHA1和包名的時候需要註意的是與創建的包名一致,在android Studio中因為包名可以進行修改,需要到build.Gradle中去查看 紅 ...
  • 一、添加自定義字體 1.把字體文件拖到工程中。 2.plist 文件中添加欄位:<Array>Fonts provided by application</Array> 把字體文件全名添加到數組中。 3.使用以下代碼找出添加的字體名稱。 4.使用 [UIFont fontWithName] 方法獲取 ...
  • Android中Listview點擊item不變顏色以及設置listselector 無效 這是同一個問題,Listview中點擊item是會變顏色的,因為listview設置了預設的listselector,有一個預設的顏色,同理如果點擊沒顏色變化我們怎麼設置listselector也不會變顏色的 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...