iOS开发,组件本地化管理

项目背景需求:

  1. 本地创建一个静态库,静态库封装RTC三方库的调用方式以及接收三方库的回调方法。此静态库与主工程完全独立开,主工程可以通过pods集成,也可以通过本地关联进行开发。
  2. 将此静态库上传到公司GitLab仓库
  3. 其他成员可以git克隆代码,交付团队也可以pods引入。

整个过程可以分为创建静态库、配置Pod并上传Git、使用私有库三个主要阶段。

🏗️ 第一步:创建静态库项目

首先,我们需要在Xcode中创建一个静态库项目并编写代码。

  1. 新建项目:打开Xcode,选择 File → New → Project,然后选择 Framework & Library 下的 Static Library,语言选择 Objective-C

  2. 编写代码:在项目中添加或修改你的类。例如,创建一个MyCalculator类,对外提供简单的加法功能。

// 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. 配置项目:在 Build Settings 中,确保 Architectures 设置正确(通常包括 arm64, x86_64),以便库能同时支持真机和模拟器。Build Active Architecture Only 在Debug模式下设为YES可以加快编译速度,Release模式下设为NO以构建全架构版本

  2. 暴露公共头文件:在 Build PhasesCopy Files 中,添加需要暴露给使用者的头文件(如 MyCalculator.h),目标选择 Public Headers 并设置好路径。

  3. 设置为静态库:在 Build Settings 中,设置Mach-O TypeStatic LibraryDynamic 表示动态库。

⚙️ 第二步:配置CocoaPods并上传至Git

这是最关键的一步,我们需要创建podspec文件,并将代码与描述文件分别管理。

  1. 创建Podspec文件:在静态库项目的根目录下,打开终端,运行以下命令生成一个模板文件:
pod spec create MyStaticLibrary
  1. 编辑Podspec文件:使用文本编辑器打开该文件,根据你的项目修改关键配置。一个精简且完整的示例如下:
Pod::Spec.new do |s|
  # 基础信息
  s.name             = 'MyStaticLibrary'      # 库的名称
  s.version          = '0.1.0'                # 版本号,必须与git tag一致
  s.summary          = '一个简单的计算器静态库' # 简短描述
  s.description      = '这是一个使用Objective-C编写的静态库,提供了基础的加法运算功能,用于演示私有库的创建流程。'
  s.homepage         = 'https://github.com/your-username/MyStaticLibrary' # 仓库主页
  s.license          = { :type => 'MIT', :file => 'LICENSE' }              # 开源协议,通常附带LICENSE文件
  s.author           = { 'Your Name' => '[email protected]' }             # 作者信息
  s.social_media_url = 'https://twitter.com/your-username'                 # 可选

  # 平台信息
  s.platform         = :ios, '9.0'              # 最低支持版本
  s.requires_arc     = true                     # 是否使用ARC

  # 源代码配置(核心)
  s.source           = { :git => 'https://github.com/your-username/MyStaticLibrary.git', :tag => "#{s.version}" } # 代码仓库地址

  # 源文件路径配置
  # 如果你的所有代码都在一个文件夹下,可以这样写
  s.source_files     = 'MyStaticLibrary/**/*.{h,m}' 

  # 如果有公开的头文件需要单独指定,可以用public_header_files
  # s.public_header_files = 'MyStaticLibrary/**/*.h'

  # 如果你的库依赖了其他第三方库,在这里声明
  # s.dependency 'AFNetworking', '~> 4.0'

  # 如果你的库包含了资源文件(如xib、图片等),需要这样配置
  # s.resource_bundles = {
  #   'MyStaticLibrary' => ['MyStaticLibrary/Assets/*.png']
  # }
end
    • 特别注意s.source中的git地址必须正确,且tag必须与后续你打的标签版本号#{s.version}一致s.source_files的路径要精确匹配你的代码所在位置
  1. 上传代码到Git仓库:
  • 在GitHub、GitLab或码云上创建一个新的仓库(注意:这个仓库用来存放你的源代码,可以设为私有)。
  • 在本地项目根目录下,初始化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
  • 打上版本标签:这一步至关重要,CocoaPods通过标签来定位特定版本的代码。
git tag 0.1.0
git push --tags
  1. 验证Podspec文件:
    在终端中,确保你仍在项目根目录,运行以下命令来验证你的.podspec文件配置是否正确。
pod lib lint

如果验证成功,你会看到 -> MyStaticLibrary (0.1.0)MyStaticLibrary passed validation. 的提示

第三步:让其他端可以通过Pods拉取

完成了上面的步骤,你的私有库已经准备好被其他人使用了。

方法一:直接指定Git地址(最简单)

对于私有库,最直接的方式是在使用方的Podfile中直接指定git地址。这是最灵活且推荐的方式。

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

target 'YourAppTarget' do
  use_frameworks! # 如果项目中使用了Swift或者需要framework,则开启

  # 直接指定私有库的Git仓库地址和版本
  pod 'MyStaticLibrary', :git => 'https://github.com/your-username/MyStaticLibrary.git', :tag => '0.1.0'
  # 或者使用 :branch => 'main' 来跟踪某个分支

  # 也可以同时使用其他公开库
  # pod 'AFNetworking'
end

然后在终端运行pod install即可拉取并集成你的静态库。

方法二:clone代码到本地

对于团队间的共同开发,需要clone下原始代码,方便团队间一起协作开发,此库大家都有可能去修改。当将代码克隆下来后,需要将此库引入到主工程中。

  1. 点击Xcode的左下角+号按钮,Add Files to 你的工程名,找到你刚clone下来的静态库工程,选择xxx.xcodeproj。这样就可以在主工程下看到你的开发静态库。
    image.png
  2. 点击主工程,在Target下找到General设置项,在Frameworks,Libraries,and Embedded Content下,点击添加按钮,输入MyStaticLibrary,找到此库,点击添加,并设置为Do Not Embed

静态库工程点击运行后,找不到.framework

这是因为 Apple 为了简化项目导航,默认隐藏了编译产物文件夹。我们有两种办法可以找到它,你可以根据自己的习惯来选择。

🧭 方法一:最简单直接——通过菜单找到它

这是最快速的方法,无需任何配置,可以直接定位到你的静态库文件。

  1. 在 Xcode 中,点击菜单栏的 Product

  2. 按住键盘上的 Option 键(也叫 Alt 键)。

  3. 这时菜单里的 Clean Build Folder 会变成 Show Build Folder in Finder,点击它。

  4. Finder 会直接打开你项目的编译文件目录。你需要的静态库(.a 文件)通常位于 Products 文件夹下的 Debug-iphoneos(真机)或 Debug-iphonesimulator(模拟器)文件夹中

🛠️ 方法二:如果你希望恢复“Product”文件夹

如果你还是更习惯在 Xcode 左侧看到“Product”文件夹,可以通过一个小技巧把它找回来

  1. 在 Finder 中,找到你的工程文件(.xcodeproj),右键点击它,选择 “显示包内容”

  2. 在打开的文件夹里,找到 project.pbxproj 文件,用文本编辑器打开它。

  3. 搜索 productRefGroup 这个词。

  4. 你会看到类似 productRefGroup = ___ 的一行代码。将它等号后面的值,替换为它上面 mainGroup = 后面的那一长串值。

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

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

  5. 保存文件,然后重新打开你的 Xcode 项目。你会发现“Product”文件夹又回来了!

静态库里集成动态库

🌿问题现象:静态库里集成了动态库,编译生成的framework包里面还包含了framework文件夹。

这个现象确实是静态库(.a 或静态 .framework)在打包时的一个常见问题。当你的静态库依赖了外部的动态库(.framework 或 .dylib),并且构建配置不正确时,Xcode 可能会错误地将这些依赖的动态库原样打包进你生成的静态库包体内,形成了“包里套包”的结构。

核心原因在于 iOS 系统的安全机制和静态库的本质

  1. iOS 不允许嵌套动态库:iOS 有严格的安全限制,一个 .framework 包内不能嵌套包含另一个动态库 。如果你的静态库工程配置不当,Xcode 在编译时试图将依赖的动态库“复制”进产物中,就会产生你看到的“包含 framework 文件夹”的无效结构。
  2. 静态库 vs 动态库:你自己创建的 .framework 通常是静态库(Mach-O Type 为 Static Library)。它本质上是一个“打包好的文件夹”,包含了二进制文件和头文件。它不应该、也无法“容纳”另一个动态库并使其正常工作。

✅ 解决方案:明确“不嵌入”依赖的动态库

要解决这个问题,核心是让 Xcode 明确:依赖的动态库属于最终 App,而不属于你这个静态库包本身。 你需要将依赖关系改为“链接但不嵌入”。

具体操作步骤如下:

  1. 打开你的静态库工程,在 Xcode 左侧选中你的静态库 Target。

  2. 点击上方的 Build Phases 标签页。

  3. 展开 Link Binary With Libraries 阶段。

  4. 找到你集成的那个动态库(.framework)。

  5. 在 Xcode 较新的版本中(特别是针对动态库),你还需要检查 General 标签页。点击你的静态库 Target,然后在 General -> Frameworks, Libraries, and Embedded Content 中找到这个动态库。

  6. 最关键的一步:将它右侧的 Embed 选项设置为 Do Not Embed

    • Embed & Sign / Embed Without Signing:表示将这个库复制到最终产品的包体(.app)里。对于你正在构建的静态库来说,这是错误的,因为它会导致库被错误地打包进静态库内部

    • Do Not Embed:表示只链接,不复制。这正是静态库所需要的——告诉 Xcode:“这个库是我的依赖,编译时需要链接它的符号,但请不要把它打包进我的 .framework 里,最终 App 会负责包含它。”

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容