iOS元件化之具體實現
隨著應用需求逐步迭代,應用的程式碼體積將會越來越大,為了更好的管理應用工程,我們開始藉助CocoaPods版本管理工具對原有應用工程進行拆分。但是僅僅完成程式碼拆分還不足以解決業務之間的程式碼耦合,為了更好的讓拆分出去的業務工程能夠獨立執行,必須進行元件拆分並且實現元件服務化。
1.元件和元件之間沒有明確的約束。
2.元件單獨開發、單獨測試,不能揉入主專案中開發,測試也可以針對性的測試。
由於本人的習慣,喜歡把很複雜的問題大白話化。元件是什麼?它就是通過CocoaPods來管理的幾個檔案,它能實現特定的功能。通常它都採用的私有庫和私有源,不然大夥都可以看到你的程式碼。當然也有的元件本來就是為了開源的,開源的庫通常放在公有源上。
元件化主要為了解決不同app程式碼重複性問題,便於維護,其次為了程式碼功能清晰。當元件更新,各個app只需要執行pod update就把元件的功能程式碼更新了,不用每個app重新匯入或修改相同的程式碼了。新建app只需要配置Podfile檔案,執行pod update命令就能把元件匯入過來大大提高了開發效率。每個元件實現特定的功能,不用在一堆業務程式碼中翻找不同的功能程式碼了,你說程式碼功能能不清晰嗎?
元件主要分三類:基礎功能元件,基礎UI元件,產品業務元件
1.基礎功能元件:(類似於效能統計、Networking、網路診斷、定製Categories安全處理擴充套件類元件等)
按功能分庫,不涉及產品業務需求,跟庫Library類似
通過良好的介面拱上層業務元件呼叫;
不寫入產品定製邏輯,通過擴充套件介面完成定製;
2. 基礎UI元件:(例如下拉重新整理元件、彈出框元件、小菊花元件、選擇框元件等)
產品內通用UI元件;(各個業務模組依賴使用,但需要保持好定製擴充套件的設計)
公共通用UI元件;(不涉及具體產品的視覺設計, 目前較少)
3. 產品業務元件:(例如支付元件、分享元件、頁面管理元件、評價元件、版本更新元件、WebSocket等長連線元件)
業務功能間相對獨立,相互間沒有Model共享的依賴;
業務之間的頁面呼叫只能通過UIBus進行跳轉;
業務之間的邏輯Action呼叫只能通過服務提供;
網路元件可以只包含對AFNetworking的進一步抽象,以便於更簡單的使用。它比使用擴充套件類寫在一個檔案裡的可讀性要強的多。幾個相關的請求在一個類檔案裡比所有的請求都在一個類檔案裡,大家想像就知道那個更合理。
本文主要的內容是元件化的實現,不是講元件化的程式碼具體實現的,關於元件化程式碼實現以後再說。
你可以這樣理解,就是想把幾個.h和.m等檔案怎麼用CocoaPods把它變成私有庫,指定的成員可以下載。大公司都是自己搭建的GitLab伺服器。小公司大都使用的是git伺服器。當然自己搭建的伺服器上傳下載要比git伺服器要快的多。本文主要以git伺服器為示例,所有***需要你換成自己的路徑和檔案,工程名。
以前在大公司都是比人專門建立了私有源和環境,自己上傳元件就可以。當了新公司要當拓荒者一個人實現元件化,遇到問題不是一般的大,一個很小的問題就卡了我兩週。從零開始元件化你才能充分理解元件化的重要和本質。
下面是實現元件化的步驟。
- 你首先要安裝CocoaPods。網上一抓一大把,你慢慢學習去吧!不過我遇到一個奇靶的問題。我以前裝CocoaPods裝了一半失敗了,以後怎麼裝也裝不成功。後來把它解除安裝了再裝才成功。
- 在git伺服器上建立你自己私有源,就是存放podspec檔案的地方。注意:建立時一定要勾選Initialize this repository with a README前面勾選。我就是開始忘記忘記勾選這個選型,上傳了兩週私有源全部失敗。空工程無法使用pod repo push推送本地私有源到遠端私有源。若忘記了,你可以刪除這個私有源再重新建立並勾選這個選項。當然若因為各種原因不能刪除,那麼你就用git下載工程到本地,給它傳一個說明檔案吧!當然你也可以用命令建立。
echo “# TencentBugly” >>
git init
git add README.md
git commit -m “first commit”
git remote add origin https://github.com/****/TencentBugly.git
git push -u origin master
這個TencentBugly是你要建立的私有源的名字,你修改成你自己的私有源的名稱就可以。
- 在git伺服器上建立你自己私有程式碼庫,下載到本地,通常在本地需要建立一個工程,這個工程的主要目的是檢查是否程式碼是否能編譯和執行,當然也可以包含對該模組的測試程式碼。增加***.podspec。注意:配置檔案中不能有中文標點符號,或者會編譯不通過。
- 上傳程式碼到私有庫地址,並且打標籤,注意一定要勾選推送標籤:origin 。
一般一個指定元件都是一個人維護,所以一般都是指直接推送到master主分支。
- 在***.podspec所在檔案路徑下執行程式碼檢查,告警一般可以忽略(–allow-warnings)。例如:pod spec lint ModuleManager.podspec --allow-warnings --use-libraries
注意:若是本元件需要訪問私有源和公有源都需要加上。例如:pod spec lint YXRequestManager.podspec --sources=‘https://github.com/***/***.git,https://github.com/CocoaPods/Specs.git’ --allow-warnings
編譯成功的例子:
podspec --allow-warnings --use-libraries
-> ModuleManager (0.0.1)
Analyzed 1 podspec.
ModuleManager.podspec passed validation.
7. 編譯檢查通過,推送到私有源和私有庫。例如:pod repo push *** ModuleManager.podspec --allow-warnings
注意:若是本元件需要訪問私有源和公有源都需要加上。例如:pod repo push YiXiangSpec YXPayManager.podspec --sources=‘https://github.com/***/***.git,https://github.com/CocoaPods/Specs.git’ --allow-warnings --use-libraries
若你的元件有幾百兆(如通訊基礎元件),可能需要很常時間,畢竟git伺服器在國外,大家耐心等待吧!
上傳成功的例子
jiaguoshangdeMacBook-Air:ModuleManager jiaguoshang$ pod repo push *** ModuleManager.podspec --allow-warnings
Validating spec
-> ModuleManager (0.0.2)
Updating the `***’ repo
Already up to date.
Adding the spec to the `***’ repo
- [Add] ModuleManager (0.0.2)
Pushing the `***’ repo
注意:你下載時,以公有源對映的庫優先,其次是私有源對映的元件。由於共有源上已經有一個ModuleManager的第三方庫,你若你的私有源上的這個元件也叫ModuleManager,那麼你用pod update下載時,下載的事公有源上的那個swift版本的第三方庫。
8. 在專案所在資料夾修改或建立Podfile檔案,增加你的元件。
9.使用pod update更新元件,若你以前已經執行過,只是想對新加的這個三方庫進行下載。可以使用這個命令來提高更新速度:pod update --verbose --no-repo-update。
若有新加的元件或第三方庫,需要關閉工程再開啟工程才能生效。
10.若你已經下載這個第三方庫,有時候你使用pod update命令可能下載的別人的元件是老版本的,更新不到老版本,可以先在Podfile檔案中註釋掉(#pod ‘MLeaksFinder’,‘0.2.1’)對應元件,再pod update --verbose --no-repo-update;再開啟在Podfile檔案中去掉註釋,再pod update --verbose --no-repo-update就能下載別人的元件的最新版本了,估計這個是本地私有源的問題。若這個庫就是在本電腦更新的庫,再更新現在的肯定是最新版本。
下面是包含私有源和公有源的Podfile檔案例子:
Uncomment this line to define a global platform for your project
Uncomment this line if you’re using Swift or would like to use dynamic frameworks
use_frameworks!
Pods for ***
pod 'YXFDCategories'
##################################第三方###########################
#YYModel--陣列轉模型元件
pod 'YYModel', '1.0.4'
#YYCategories--給系統類新增的分類
pod 'YYCategories', '1.0.4'
#記憶體洩漏檢測,正式環境需要註釋下面一行
pod 'MLeaksFinder','0.2.1'
end
下面是一個簡單的一個只包含Classes資料夾下的.h和.m檔案的元件管理元件的配置檔案(ModuleManager.podspec):
Any lines starting with a # are optional, but their use is encouraged
Pod::Spec.new do |s|
s.name = ‘ModuleManager’
s.version = ‘0.0.2’
s.summary = ‘ModuleManager.’
This description is used to generate tags and improve search results.
* Think: What does it do? Why did you write it? What is the focus?
* Try to keep it short, snappy and to the point.
* Write the description between the DESC delimiters below.
* Finally, don’t worry about the indent, CocoaPods strips it!
s.description = <<-DESC
TODO: Add long description of the pod here.
DESC
s.homepage = ‘http://www.baidu.com/’
s.license = { :type => ‘MIT’, :file => ‘LICENSE’ }
s.author = { ‘jiaguoshang’ => ‘**/ModuleManager.git’, :tag => s.version.to_s }
s.social_media_url = ‘https://twitter.com/<TWITTER_USERNAME>’
s.ios.deployment_target = ‘8.0’
s.source_files = 'ModuleManager/Classes/.{h,m}’
#s.source_files = “ModuleManager”, "'ModuleManager/**/.{h,m}"
s.resource_bundles = {
‘ModuleManager’ => [‘ModuleManager/Assets/*.png’]
}
s.public_header_files = ‘Pod/Classes/**/*.h’
s.frameworks = ‘UIKit’, ‘Foundation’
s.dependency ‘AFNetworking’, ‘~> 2.3’
end
下面是一個既依賴私有庫又依賴公有庫的配置檔案(YXRequestManager.podspec):
Be sure to run `pod lib lint YXRequestManager.podspec’ to ensure this is a
valid spec before submitting.
Any lines starting with a # are optional, but their use is encouraged
Pod::Spec.new do |s|
s.name = ‘YXRequestManager’
s.version = ‘1.1.9’
s.summary = ‘YXRequestManager.’
This description is used to generate tags and improve search results.
* Think: What does it do? Why did you write it? What is the focus?
* Try to keep it short, snappy and to the point.
* Write the description between the DESC delimiters below.
* Finally, don’t worry about the indent, CocoaPods strips it!
s.description = <<-DESC
TODO: Add long description of the pod here.
DESC
s.homepage = ‘http://www.baidu.com/’
s.license = { :type => ‘MIT’, :file => ‘LICENSE’ }
s.author = { ‘jiaguoshang’ => ‘***@163.com’ }
s.source = { :git => ‘https://github.com/enjoyor-runlu/YXRequestManager.git’, :tag => s.version.to_s }
s.social_media_url = ‘https://twitter.com/<TWITTER_USERNAME>’
s.ios.deployment_target = ‘8.0’
s.source_files = ‘YXRequestManager/Classes/**/*.{h,m}’
s.source_files = ‘YXCache’, ‘YXRequestManager/Classes/YXCache/*.{h,m}’,
s.source_files = ‘AESCategory’, ‘YXRequestManager/Classes/AESCategory/*.{h,m}’
s.source_files = ‘YXRequest’, ‘YXRequestManager/Classes/YXRequest/*.{h,m}’
#s.source_files = “YXRequestManager”, "YXRequestManager/**/.{h,m}"
s.resource_bundles = {
‘YXRequestManager’ => ['YXRequestManager/Classes/.xcassets’]
}
s.public_header_files = ‘Pod/Classes/**/*.h’
s.frameworks = ‘UIKit’, ‘Foundation’
s.dependency ‘YXFDCategories’
s.dependency ‘AFNetworking’, ‘3.1.0’
s.dependency ‘TMCache’
end