1. iOS SDK开发基础认知在移动开发领域SDKSoftware Development Kit是每个开发者必须掌握的核心技能。以iOS平台为例一个设计良好的SDK能够帮助团队实现代码复用、功能模块化并显著提升开发效率。不同于普通应用开发SDK开发需要特别关注接口设计、兼容性和依赖管理。重要提示在开始制作SDK前请确保已更新至最新版Xcode当前稳定版本为15.0并准备好开发者账号。虽然测试阶段可以暂不配置Team但最终发布到App Store必须完成证书配置。1.1 开发环境准备清单硬件要求必须使用Mac设备建议macOS Ventura 13.5基础工具链Xcode 15.0包含iOS 17 SDKCocoaPods 1.12.0用于依赖管理Git 2.40版本控制可选工具Jazzy文档生成工具SwiftLint代码规范检查在实际操作中我发现很多开发者会忽略开发环境的版本一致性。曾经有个团队因为CocoaPods版本差异导致编译失败花费两天时间排查才发现是环境问题。建议使用.ruby-version文件锁定Ruby版本并通过Gemfile固定CocoaPods版本。2. 创建SDK工程框架2.1 项目初始化步骤启动Xcode选择菜单栏File - New - Project在模板选择界面选择Framework语言选择Objective-C/Swift取消勾选Include Tests初期可跳过测试项目配置关键参数Product Name:YourSDKName建议使用反向域名格式Organization Identifier:com.yourcompanyLanguage: 根据团队技术栈选择这里有个容易踩的坑Bundle Identifier不要包含下划线等特殊字符否则可能导致后续的代码签名问题。我推荐使用com.companyname.sdkname这样的标准格式。2.2 关键编译设置进入Build Settings进行以下必要配置配置项推荐值说明Mach-O TypeStatic Library生成静态库Build Active Architecture OnlyNo支持全架构Enable BitcodeNo避免兼容问题iOS Deployment Target11.0最低支持版本特别提醒在Deployment Info中需要移除iPad和Mac的支持除非你的SDK需要跨平台否则会增加不必要的体积。曾经有个SDK因为保留了Mac支持导致最终体积多了30%这在移动端是完全不必要的开销。3. SDK核心代码开发3.1 类与接口设计创建一个示例类NetworkManager来演示SDK开发规范// NetworkManager.h #import Foundation/Foundation.h NS_ASSUME_NONNULL_BEGIN interface NetworkManager : NSObject /// 单例实例 (instancetype)shared; /** 发起GET请求 param url 请求地址 param completion 回调block */ - (void)get:(NSString *)url completion:(void(^)(NSData * _Nullable data, NSError * _Nullable error))completion; end NS_ASSUME_NONNULL_END对应的实现文件// NetworkManager.m #import NetworkManager.h implementation NetworkManager (instancetype)shared { static NetworkManager *instance nil; static dispatch_once_t onceToken; dispatch_once(onceToken, ^{ instance [[self alloc] init]; }); return instance; } - (void)get:(NSString *)url completion:(void (^)(NSData * _Nullable, NSError * _Nullable))completion { NSURLSessionTask *task [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { dispatch_async(dispatch_get_main_queue(), ^{ if (completion) completion(data, error); }); }]; [task resume]; } end设计经验SDK接口应该遵循最小暴露原则只公开必要的方法和属性。内部实现细节应该放在.m文件中或者使用NS_ASSUME_NONNULL宏来明确标注可空性。3.2 头文件管理在SDK的主头文件通常命名为YourSDKName.h中集中导入所有公开头文件// YourSDKName.h #import Foundation/Foundation.h //! Project version number for YourSDKName. FOUNDATION_EXPORT double YourSDKNameVersionNumber; //! Project version string for YourSDKName. FOUNDATION_EXPORT const unsigned char YourSDKNameVersionString[]; // 公开头文件 #import YourSDKName/NetworkManager.h #import YourSDKName/Utility.h4. 多架构编译与合并4.1 创建Aggregate Target新建TargetFile - New - Target...选择Aggregate命名为UniversalFramework添加Run Script Phase4.2 合并脚本详解以下是我优化过的通用合并脚本增加了架构检查和错误处理#!/bin/sh set -e # 配置参数 TARGET_NAME${PROJECT_NAME} OUTPUT_DIR${SRCROOT}/Output CONFIGURATION${CONFIGURATION:-Release} # 清理旧构建 rm -rf ${OUTPUT_DIR} mkdir -p ${OUTPUT_DIR} # 构建真机版本 echo Building for device... xcodebuild -target ${TARGET_NAME} \ -configuration ${CONFIGURATION} \ -sdk iphoneos \ BUILD_DIR${BUILD_DIR} \ BUILD_ROOT${BUILD_ROOT} \ clean build | xcpretty # 构建模拟器版本 echo Building for simulator... xcodebuild -target ${TARGET_NAME} \ -configuration ${CONFIGURATION} \ -sdk iphonesimulator \ BUILD_DIR${BUILD_DIR} \ BUILD_ROOT${BUILD_ROOT} \ clean build | xcpretty # 检查构建产物 DEVICE_FRAMEWORK${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework SIMULATOR_FRAMEWORK${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework if [ ! -d ${DEVICE_FRAMEWORK} ] || [ ! -d ${SIMULATOR_FRAMEWORK} ]; then echo Error: Build products not found! exit 1 fi # 创建通用框架目录 UNIVERSAL_FRAMEWORK${OUTPUT_DIR}/${TARGET_NAME}.framework mkdir -p ${UNIVERSAL_FRAMEWORK} # 拷贝基础文件 cp -R ${DEVICE_FRAMEWORK}/ ${UNIVERSAL_FRAMEWORK}/ # 合并二进制文件 echo Creating universal binary... lipo -create \ ${DEVICE_FRAMEWORK}/${TARGET_NAME} \ ${SIMULATOR_FRAMEWORK}/${TARGET_NAME} \ -output ${UNIVERSAL_FRAMEWORK}/${TARGET_NAME} # 验证架构 echo Architectures in the universal binary: lipo -info ${UNIVERSAL_FRAMEWORK}/${TARGET_NAME} # 拷贝Swift模块如果存在 if [ -d ${SIMULATOR_FRAMEWORK}/Modules/${TARGET_NAME}.swiftmodule ]; then cp -R \ ${SIMULATOR_FRAMEWORK}/Modules/${TARGET_NAME}.swiftmodule/ \ ${UNIVERSAL_FRAMEWORK}/Modules/${TARGET_NAME}.swiftmodule/ fi echo Universal framework created at: ${UNIVERSAL_FRAMEWORK} open ${OUTPUT_DIR}这个脚本相比基础版本有几个重要改进增加了错误检查set -e使用xcpretty美化构建日志自动处理Swift模块完善的路径检查5. 常见问题解决方案5.1 架构支持问题症状Undefined symbol for architecture arm64解决方案检查Build Settings - Excluded Architectures是否为空确认VALID_ARCHS包含arm64 arm64e armv7 armv7s对于模拟器构建需要额外包含x86_645.2 符号可见性问题症状Symbol not found when linking解决方案在Build Settings中设置Symbols Hidden by Default为NO对于需要导出的符号使用__attribute__((visibility(default)))或者在Build Settings中添加-fvisibilitydefault5.3 资源打包问题症状图片/资源文件无法加载解决方案确保资源文件在Copy Bundle Resources构建阶段使用[NSBundle bundleForClass:[self class]]加载资源对于xcassets需要确保在Build Settings中启用了Asset Catalog Compiler6. 进阶技巧与优化6.1 减小SDK体积使用strip命令移除调试符号strip -x -S ${UNIVERSAL_FRAMEWORK}/${TARGET_NAME}设置Optimization Level为-Os启用Dead Code Stripping6.2 版本管理策略推荐使用语义化版本控制SemVerMAJOR不兼容的API修改MINOR向下兼容的功能新增PATCH向下兼容的问题修正在代码中通过以下方式暴露版本信息// Version.h extern NSString * const YourSDKVersion; // Version.m NSString * const YourSDKVersion 1.0.0;6.3 文档自动生成使用Jazzy生成API文档安装gem install jazzy配置.jazzy.yamlmodule: YourSDKName author: YourName author_url: https://yourwebsite.com github_url: https://github.com/yourrepo运行jazzy我在实际项目中发现良好的文档可以减少80%以上的集成问题。建议至少包含快速开始指南API参考文档常见问题解答变更日志7. 本地测试与验证7.1 创建测试工程新建Single View App工程手动添加framework拖拽framework到Embedded Binaries确保Copy items if needed被选中导入头文件#import YourSDKName/YourSDKName.h7.2 集成测试要点测试时特别注意以下场景多次初始化SDK网络权限提示如有网络操作低版本iOS兼容性内存警告处理后台运行行为建议编写自动化测试脚本可以使用Fastlane实现持续集成lane :test_sdk do scan( workspace: YourSDK.xcworkspace, scheme: YourSDK, devices: [iPhone 12, iPad Pro (12.9-inch)], clean: true ) end8. 发布准备与注意事项8.1 最终检查清单[ ] 移除所有调试日志[ ] 验证所有公开API的文档注释[ ] 检查所有第三方依赖的许可证[ ] 更新CHANGELOG.md[ ] 版本号更新8.2 分发方式选择根据使用场景选择合适的分发渠道分发方式适用场景优点缺点直接提供.framework内部使用简单直接难以更新CocoaPods开源项目依赖管理方便需要公开源码Swift Package ManageriOS 13项目官方支持兼容性要求高私有仓库企业SDK可控性强维护成本高对于大多数团队我建议从CocoaPods开始当SDK成熟后再支持SPM。创建podspec的基本模板Pod::Spec.new do |s| s.name YourSDK s.version 1.0.0 s.summary A short description of YourSDK. s.homepage https://github.com/your/YourSDK s.license { :type MIT, :file LICENSE } s.author { YourName youremail.com } s.source { :git https://github.com/your/YourSDK.git, :tag s.version.to_s } s.ios.deployment_target 11.0 s.vendored_frameworks YourSDK.framework s.frameworks Foundation, UIKit end在开发过程中我发现很多团队会忽视符号冲突的问题。建议为所有公开符号添加前缀如公司缩写比如ABCNetworkManager而不是简单的NetworkManager。这样可以有效避免与用户代码或其他第三方库的命名冲突。