iOS開發(fā),組件本地化管理

項(xiàng)目背景需求:

  1. 本地創(chuàng)建一個(gè)靜態(tài)庫(kù),靜態(tài)庫(kù)封裝RTC三方庫(kù)的調(diào)用方式以及接收三方庫(kù)的回調(diào)方法。此靜態(tài)庫(kù)與主工程完全獨(dú)立開,主工程可以通過pods集成,也可以通過本地關(guān)聯(lián)進(jìn)行開發(fā)。
  2. 將此靜態(tài)庫(kù)上傳到公司GitLab倉(cāng)庫(kù)
  3. 其他成員可以git克隆代碼,交付團(tuán)隊(duì)也可以pods引入。

整個(gè)過程可以分為創(chuàng)建靜態(tài)庫(kù)、配置Pod并上傳Git、使用私有庫(kù)三個(gè)主要階段。

??? 第一步:創(chuàng)建靜態(tài)庫(kù)項(xiàng)目

首先,我們需要在Xcode中創(chuàng)建一個(gè)靜態(tài)庫(kù)項(xiàng)目并編寫代碼。

  1. 新建項(xiàng)目:打開Xcode,選擇 File → New → Project,然后選擇 Framework & Library 下的 Static Library,語言選擇 Objective-C。

  2. 編寫代碼:在項(xiàng)目中添加或修改你的類。例如,創(chuàng)建一個(gè)MyCalculator類,對(duì)外提供簡(jiǎn)單的加法功能。

// MyCalculator.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface MyCalculator : NSObject
- (NSInteger)addA:(NSInteger)a toB:(NSInteger)b;
@end

NS_ASSUME_NONNULL_END
// MyCalculator.m
#import "MyCalculator.h"

@implementation MyCalculator
- (NSInteger)addA:(NSInteger)a toB:(NSInteger)b {
    return a + b;
}
@end
  1. 配置項(xiàng)目:在 Build Settings 中,確保 Architectures 設(shè)置正確(通常包括 arm64, x86_64),以便庫(kù)能同時(shí)支持真機(jī)和模擬器。Build Active Architecture Only 在Debug模式下設(shè)為YES可以加快編譯速度,Release模式下設(shè)為NO以構(gòu)建全架構(gòu)版本

  2. 暴露公共頭文件:在 Build PhasesCopy Files 中,添加需要暴露給使用者的頭文件(如 MyCalculator.h),目標(biāo)選擇 Public Headers 并設(shè)置好路徑。

  3. 設(shè)置為靜態(tài)庫(kù):在 Build Settings 中,設(shè)置Mach-O TypeStatic Library 。Dynamic 表示動(dòng)態(tài)庫(kù)。

?? 第二步:配置CocoaPods并上傳至Git

這是最關(guān)鍵的一步,我們需要?jiǎng)?chuàng)建podspec文件,并將代碼與描述文件分別管理。

  1. 創(chuàng)建Podspec文件:在靜態(tài)庫(kù)項(xiàng)目的根目錄下,打開終端,運(yùn)行以下命令生成一個(gè)模板文件:
pod spec create MyStaticLibrary
  1. 編輯Podspec文件:使用文本編輯器打開該文件,根據(jù)你的項(xiàng)目修改關(guān)鍵配置。一個(gè)精簡(jiǎn)且完整的示例如下:
Pod::Spec.new do |s|
  # 基礎(chǔ)信息
  s.name             = 'MyStaticLibrary'      # 庫(kù)的名稱
  s.version          = '0.1.0'                # 版本號(hào),必須與git tag一致
  s.summary          = '一個(gè)簡(jiǎn)單的計(jì)算器靜態(tài)庫(kù)' # 簡(jiǎn)短描述
  s.description      = '這是一個(gè)使用Objective-C編寫的靜態(tài)庫(kù),提供了基礎(chǔ)的加法運(yùn)算功能,用于演示私有庫(kù)的創(chuàng)建流程。'
  s.homepage         = 'https://github.com/your-username/MyStaticLibrary' # 倉(cāng)庫(kù)主頁(yè)
  s.license          = { :type => 'MIT', :file => 'LICENSE' }              # 開源協(xié)議,通常附帶LICENSE文件
  s.author           = { 'Your Name' => '[email protected]' }             # 作者信息
  s.social_media_url = 'https://twitter.com/your-username'                 # 可選

  # 平臺(tái)信息
  s.platform         = :ios, '9.0'              # 最低支持版本
  s.requires_arc     = true                     # 是否使用ARC

  # 源代碼配置(核心)
  s.source           = { :git => 'https://github.com/your-username/MyStaticLibrary.git', :tag => "#{s.version}" } # 代碼倉(cāng)庫(kù)地址

  # 源文件路徑配置
  # 如果你的所有代碼都在一個(gè)文件夾下,可以這樣寫
  s.source_files     = 'MyStaticLibrary/**/*.{h,m}' 

  # 如果有公開的頭文件需要單獨(dú)指定,可以用public_header_files
  # s.public_header_files = 'MyStaticLibrary/**/*.h'

  # 如果你的庫(kù)依賴了其他第三方庫(kù),在這里聲明
  # s.dependency 'AFNetworking', '~> 4.0'

  # 如果你的庫(kù)包含了資源文件(如xib、圖片等),需要這樣配置
  # s.resource_bundles = {
  #   'MyStaticLibrary' => ['MyStaticLibrary/Assets/*.png']
  # }
end
    • 特別注意s.source中的git地址必須正確,且tag必須與后續(xù)你打的標(biāo)簽版本號(hào)#{s.version}一致。s.source_files的路徑要精確匹配你的代碼所在位置。
  1. 上傳代碼到Git倉(cāng)庫(kù):
  • 在GitHub、GitLab或碼云上創(chuàng)建一個(gè)新的倉(cāng)庫(kù)(注意:這個(gè)倉(cāng)庫(kù)用來存放你的源代碼,可以設(shè)為私有)。
  • 在本地項(xiàng)目根目錄下,初始化Git并提交代碼:
git init
git add .
git commit -m "Initial commit with library source"
git remote add origin https://github.com/your-username/MyStaticLibrary.git
git push -u origin main
  • 打上版本標(biāo)簽:這一步至關(guān)重要,CocoaPods通過標(biāo)簽來定位特定版本的代碼。
git tag 0.1.0
git push --tags
  1. 驗(yàn)證Podspec文件:
    在終端中,確保你仍在項(xiàng)目根目錄,運(yùn)行以下命令來驗(yàn)證你的.podspec文件配置是否正確。
pod lib lint

如果驗(yàn)證成功,你會(huì)看到 -> MyStaticLibrary (0.1.0)MyStaticLibrary passed validation. 的提示

第三步:讓其他端可以通過Pods拉取

完成了上面的步驟,你的私有庫(kù)已經(jīng)準(zhǔn)備好被其他人使用了。

方法一:直接指定Git地址(最簡(jiǎn)單)

對(duì)于私有庫(kù),最直接的方式是在使用方的Podfile中直接指定git地址。這是最靈活且推薦的方式。

# 使用方的 Podfile
platform :ios, '9.0'

target 'YourAppTarget' do
  use_frameworks! # 如果項(xiàng)目中使用了Swift或者需要framework,則開啟

  # 直接指定私有庫(kù)的Git倉(cāng)庫(kù)地址和版本
  pod 'MyStaticLibrary', :git => 'https://github.com/your-username/MyStaticLibrary.git', :tag => '0.1.0'
  # 或者使用 :branch => 'main' 來跟蹤某個(gè)分支

  # 也可以同時(shí)使用其他公開庫(kù)
  # pod 'AFNetworking'
end

然后在終端運(yùn)行pod install即可拉取并集成你的靜態(tài)庫(kù)。

方法二:clone代碼到本地

對(duì)于團(tuán)隊(duì)間的共同開發(fā),需要clone下原始代碼,方便團(tuán)隊(duì)間一起協(xié)作開發(fā),此庫(kù)大家都有可能去修改。當(dāng)將代碼克隆下來后,需要將此庫(kù)引入到主工程中。

  1. 點(diǎn)擊Xcode的左下角+號(hào)按鈕,Add Files to 你的工程名,找到你剛clone下來的靜態(tài)庫(kù)工程,選擇xxx.xcodeproj。這樣就可以在主工程下看到你的開發(fā)靜態(tài)庫(kù)。
    image.png
  2. 點(diǎn)擊主工程,在Target下找到General設(shè)置項(xiàng),在Frameworks,Libraries,and Embedded Content下,點(diǎn)擊添加按鈕,輸入MyStaticLibrary,找到此庫(kù),點(diǎn)擊添加,并設(shè)置為Do Not Embed

靜態(tài)庫(kù)工程點(diǎn)擊運(yùn)行后,找不到.framework

這是因?yàn)?Apple 為了簡(jiǎn)化項(xiàng)目導(dǎo)航,默認(rèn)隱藏了編譯產(chǎn)物文件夾。我們有兩種辦法可以找到它,你可以根據(jù)自己的習(xí)慣來選擇。

?? 方法一:最簡(jiǎn)單直接——通過菜單找到它

這是最快速的方法,無需任何配置,可以直接定位到你的靜態(tài)庫(kù)文件。

  1. 在 Xcode 中,點(diǎn)擊菜單欄的 Product

  2. 按住鍵盤上的 Option 鍵(也叫 Alt 鍵)。

  3. 這時(shí)菜單里的 Clean Build Folder 會(huì)變成 Show Build Folder in Finder,點(diǎn)擊它。

  4. Finder 會(huì)直接打開你項(xiàng)目的編譯文件目錄。你需要的靜態(tài)庫(kù)(.a 文件)通常位于 Products 文件夾下的 Debug-iphoneos(真機(jī))或 Debug-iphonesimulator(模擬器)文件夾中。

??? 方法二:如果你希望恢復(fù)“Product”文件夾

如果你還是更習(xí)慣在 Xcode 左側(cè)看到“Product”文件夾,可以通過一個(gè)小技巧把它找回來。

  1. 在 Finder 中,找到你的工程文件(.xcodeproj),右鍵點(diǎn)擊它,選擇 “顯示包內(nèi)容”。

  2. 在打開的文件夾里,找到 project.pbxproj 文件,用文本編輯器打開它。

  3. 搜索 productRefGroup 這個(gè)詞。

  4. 你會(huì)看到類似 productRefGroup = ___ 的一行代碼。將它等號(hào)后面的值,替換為它上面 mainGroup = 后面的那一長(zhǎng)串值。

    • 修改前: mainGroup = 1234567890ABCDEF; ... productRefGroup = ;

    • 修改后: mainGroup = 1234567890ABCDEF; ... productRefGroup = 1234567890ABCDEF;

  5. 保存文件,然后重新打開你的 Xcode 項(xiàng)目。你會(huì)發(fā)現(xiàn)“Product”文件夾又回來了!

靜態(tài)庫(kù)里集成動(dòng)態(tài)庫(kù)

??問題現(xiàn)象:靜態(tài)庫(kù)里集成了動(dòng)態(tài)庫(kù),編譯生成的framework包里面還包含了framework文件夾。

這個(gè)現(xiàn)象確實(shí)是靜態(tài)庫(kù)(.a 或靜態(tài) .framework)在打包時(shí)的一個(gè)常見問題。當(dāng)你的靜態(tài)庫(kù)依賴了外部的動(dòng)態(tài)庫(kù)(.framework 或 .dylib),并且構(gòu)建配置不正確時(shí),Xcode 可能會(huì)錯(cuò)誤地將這些依賴的動(dòng)態(tài)庫(kù)原樣打包進(jìn)你生成的靜態(tài)庫(kù)包體內(nèi),形成了“包里套包”的結(jié)構(gòu)。

核心原因在于 iOS 系統(tǒng)的安全機(jī)制和靜態(tài)庫(kù)的本質(zhì)

  1. iOS 不允許嵌套動(dòng)態(tài)庫(kù):iOS 有嚴(yán)格的安全限制,一個(gè) .framework 包內(nèi)不能嵌套包含另一個(gè)動(dòng)態(tài)庫(kù) 。如果你的靜態(tài)庫(kù)工程配置不當(dāng),Xcode 在編譯時(shí)試圖將依賴的動(dòng)態(tài)庫(kù)“復(fù)制”進(jìn)產(chǎn)物中,就會(huì)產(chǎn)生你看到的“包含 framework 文件夾”的無效結(jié)構(gòu)。
  2. 靜態(tài)庫(kù) vs 動(dòng)態(tài)庫(kù):你自己創(chuàng)建的 .framework 通常是靜態(tài)庫(kù)(Mach-O Type 為 Static Library)。它本質(zhì)上是一個(gè)“打包好的文件夾”,包含了二進(jìn)制文件和頭文件。它不應(yīng)該、也無法“容納”另一個(gè)動(dòng)態(tài)庫(kù)并使其正常工作。

? 解決方案:明確“不嵌入”依賴的動(dòng)態(tài)庫(kù)

要解決這個(gè)問題,核心是讓 Xcode 明確:依賴的動(dòng)態(tài)庫(kù)屬于最終 App,而不屬于你這個(gè)靜態(tài)庫(kù)包本身。 你需要將依賴關(guān)系改為“鏈接但不嵌入”。

具體操作步驟如下:

  1. 打開你的靜態(tài)庫(kù)工程,在 Xcode 左側(cè)選中你的靜態(tài)庫(kù) Target。

  2. 點(diǎn)擊上方的 Build Phases 標(biāo)簽頁(yè)。

  3. 展開 Link Binary With Libraries 階段。

  4. 找到你集成的那個(gè)動(dòng)態(tài)庫(kù)(.framework)。

  5. 在 Xcode 較新的版本中(特別是針對(duì)動(dòng)態(tài)庫(kù)),你還需要檢查 General 標(biāo)簽頁(yè)。點(diǎn)擊你的靜態(tài)庫(kù) Target,然后在 General -> Frameworks, Libraries, and Embedded Content 中找到這個(gè)動(dòng)態(tài)庫(kù)。

  6. 最關(guān)鍵的一步:將它右側(cè)的 Embed 選項(xiàng)設(shè)置為 Do Not Embed

    • Embed & Sign / Embed Without Signing:表示將這個(gè)庫(kù)復(fù)制到最終產(chǎn)品的包體(.app)里。對(duì)于你正在構(gòu)建的靜態(tài)庫(kù)來說,這是錯(cuò)誤的,因?yàn)樗鼤?huì)導(dǎo)致庫(kù)被錯(cuò)誤地打包進(jìn)靜態(tài)庫(kù)內(nèi)部 。

    • Do Not Embed:表示只鏈接,不復(fù)制。這正是靜態(tài)庫(kù)所需要的——告訴 Xcode:“這個(gè)庫(kù)是我的依賴,編譯時(shí)需要鏈接它的符號(hào),但請(qǐng)不要把它打包進(jìn)我的 .framework 里,最終 App 會(huì)負(fù)責(zé)包含它?!?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容