iOS SDK开发(静态SDK)
静态方式开发,一直是iOS SDK开发的主流方式。百度地图、高德地图等大型三方SDK均是采用静态的方式开发。也有采用动态的方式开发SDK的如:环信。
静态方式和动态方式比较:
- 静态SDK不能嵌套。见iOS中Framework Library嵌套使用。因此,当SDK需要引用其他SDK,且不希望暴露给用户时,只能采用动态库的开发方式。
- 若SDK和项目中用到相同的三方库(如:AFNetworking)。动态库:工程和项目中可以存在2份AFNetworking,因此开发方便。静态库只会存在一份,因此开发相对复杂,但减少了代码的冗余。
现以SDK和项目中都需要用到相同的三方库(如AFNetWorking)为例,介绍静态库开发和使用。Demo见https://github.com/wutao23yzd/SDKDemo, StaticSDK目录下。
本文分为开发和使用2个部分:
开发:
- 静态SDK的创建和配置
- 利用workspace将sdk和Demo工程建立关联
- SDK中Bundle和脚本的配置和使用
- SDK中断点调试
使用:
- SDK和项目共用一份AFNetworking
- 利用.spec的方式安装SDK和相关依赖。
前期准备
- 开发环境:
- Xcode 10
- cocoaPods version:
1.6.0.beta.2
- 当为Xcode10时,需要升级cocoaPods为最新,否则会报错
RuntimeError - [!] Xcodeproj doesn't know about the following attributes {"inputFileListPaths"=>[], "outputFileListPaths"=>[]} for the 'PBXShellScriptBuildPhase' isa.
- 升级cocoaPods
// 升级
sudo gem install cocoapods --pre -n /usr/local/bin
// 查看版本
pod --version
2.知识储备:了解 Xcode中的 workspace, project, target, scheme区别
开发
创建SDK工程和Demo工程
将SDK和Demo工程用一个workspace管理。
创建SDK
-
创建SDK工程
取名为HelloSDK,并做如下配置。
创建SDK
- 配置
Deployment Target
iOS 9.0- Mach-O Type
Static Library
- Enable Bitcode
No
- Edit Scheme - Run - Info - Build Configuration
Release
- 在SDK工程中创建Bundle。
SDK 中xib,图片等一切资源都需要添加到Bundle中
依次选择,file
-New
-Target
-macOS
- Bundle
;取名为 HelloSDKBundle。并做如下配置。
- Build Settings - Base SDK - iOS
- Deployment Target -9.0
- Enable Bitcode 设置为NO
- 清除Build settings - Installation Directory路径信息
- COMBINE_HIDPI_IMAGES设置为NO
- Edit Scheme - Run - Info - Build Configuration
Release
- 在SDK工程中创建脚本。
SDK以模拟器编译时,会生成对应模拟器架构的SDK( i386,x86_64);以Generic iOS Device编译时,会生成真机架构的SDK(arm7,arm64)。脚本的作用是将这两个sdk合成一个,使的同时适用于真机和模拟器。
file
-New
- Target
-Cross
-platform
- Aggregate
;取名为 CommonStatic
。
- Run Script中添加以下脚本
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
#open "${DEVICE_DIR}"
#open "${SRCROOT}/Products"
fi
- 在其
Build Phases
-Target Dependencies
中,添加Hello SDK
。
点击+号,选择New run Script添加脚本
为脚本Target做如下配置
- Enable Bitcode 设置为NO
- Edit Scheme - Run - Info - Build Configuration
Release
创建Demo工程
在HelloSDK同目录下,创建StaticSDKDemo工程。
创建工程
并做如下设置
- Enable Bitcode 设置为NO
- Deployment Target -9.0
创建workspace
打开终端, cd 到 StaticSDKDemo目录下,执行pod init,在工程目录下会生成Podfile文件。打开Podfile,输入以下。
# platform :ios, '9.0'
workspace 'StaticSDKDemo'
def shared_pods
pod 'AFNetworking'
end
target 'StaticSDKDemo' do
project 'StaticSDKDemo'
shared_pods
end
target 'HelloSDK' do
project '../HelloSDK/HelloSDK'
shared_pods
end
在终端种执行pod install,打开生成的workspace。此时可见
现在Demo工程和SDK在一个workspace中,已建立了关联,并可共用一个
AFNetworking
(其他三方库,在 podfile中的 shared_pods
中添加即可)。
现在SDK工程和Demo工程已创建完毕。
开发
SDK中添加代码
在HelloSDK中创建HSViewController
,并编写如下代码。
设置SDK公开头文件
在上图中每设置一个公开头文件,都在下图中的
.h
文件中,都需要引入该头文件。设置公开头文件步骤二
删掉SDK中的资源,后续Bundle中会包含。
删掉资源
编译SDK,并将SDK导入到Demo工程中
- 切换Target为HelloSDK,选中一款模拟器,
comand
+B
,编译
编译SDK这里选择模拟器,是为了方便用模拟器演示功能。当然也可以选择
Generic iOS Device
使之适用于真机。当利用模拟器和Generic iOS Device
分别编译后,再利用之前创建的CommonStatic
编译(选择Generic iOS Device
),便会生成同时适用于真机和模拟器的SDK。
- 编译好后,在Demo工程中,添加SDK
选中StaticSDKDemo
Target,依次选择Build Phases
-Link Binary With Libraries
,点击+
号,添加SDK
编译Bundle,并将Bundle导入到Demo工程中
- 在
HelloSDK
工程中,选中HelloSDKBundle
,在其copy Bundle Resources
中,点击+
号,添加资源
添加资源 - 编译Bundle,并在其
products
目录中,show in finder
找到,复制到Demo工程目录
编译Bundle
复制到Demo工程目录 - 在Demo 工程的
Copy Bundle Resources
中,点击+
号引入Bundle(在弹出的框中,可不选复制)
引入Bundle
在Demo工程中,添加代码查看效果
添加如下代码,运行模拟器,便查看到效果了。
添加代码
效果图
同时,当我们在SDK里面的点击事件里,设置断点时,是有效的,这就方便我们的调试。
设置断点
当我们在SDK里更改了代码时,需要编译一遍SDK,在Demo工程中
Link Binary With Libraries
,点击-
去掉SDK,直接运行Demo工程就有效果了;如果再次更改,点击+
添加SDK,运行工程就有效果(原因未知)。如果更改了xib
.新增了图片时,就必须重新编译Bundle,并用新的覆盖掉原来老的,才会产生效果。
以上便是SDK静态库开发的全部内容。
使用
AFNetWorking应用
在SDK中新建AFAppDotNetAPIClient
.m文件代码
在
HSViewController
中添加如下代码,网络请求
编译SDK,并按照上面说的,在Demo工程中Link Binary With Libraries
,点击-
去掉SDK,直接运行Demo工程便见到Label上显示了一句古诗。
SDK脚本导出
分别将sdk在模拟器(随便选一款模拟器)和Generic iOS Device
下编译 (选择该target,command + B
)。这会编译生成2个SDK,一个适用于模拟器,一个适用于真机。
Generic iOS Device编译
选择Target选为
CommonStatic
编译,这会将上面生成的2个SDK合成一个,编译完成后,会发现在项目根目录会生成Products文件夹,便是所制作的sdk脚本编译
生成最终SDK
利用spec文件安装SDK及其依赖
现在SDK已经开发完了,需要交给客户的开发人员使用了。且我们的SDK需要依赖AFNetWorking。
-
创建名为
创建客户工程cusProject
工程,假定为客户的项目工程,且采用CocoPods管理。注意修改其Deployment Target
和bit code
-
在工程目录下新建
SDK和BundleHelloSDK
文件夹,并将上面脚本生成的SDK拷贝到该文件夹下,编译Bundle也拷贝到该文件夹下。
-
打开终端,cd到
HelloSDK
文件夹下,执行如下命令,创建spec文件。
pod spec create HelloSDK
- 打开生成的
podspec
文件,删除里面的全部内容,并添加如下:
Pod::Spec.new do |spec|
spec.name = "HelloSDK"
spec.version = "1.0.0"
spec.summary = "A short description of HelloSDk"
spec.description = <<-DESCRIPTION
pod spec create xx
DESCRIPTION
spec.homepage = "http://www.baidu.com"
spec.license = "None"
spec.author = { "wutao" => "359424792@qq.com" }
spec.source = { :path => '/'}
spec.static_framework = true
spec.requires_arc = true
spec.platform = :ios, '9.0'
spec.ios.vendored_frameworks = 'HelloSDK.framework'
spec.resource = "HelloSDKBundle.bundle"
spec.dependency 'AFNetworking'
end
编写spec文件,ruby语言下图中
spec.name = "HelloSDk"
,k应该改为大写的K
- 打开
cusProject
工程,在Podfile文件中按图示添加:
打开终端,cd到项目目录下,执行pod install
;现在HelloSDK
和AFNetworking
都添加到项目中了。此时HelloSDK
和客户的项目就可以共用一份AFNetworking
- 在主项目中编写代码测试。
在ViewController
中添加如下代码,运行模拟器。
vc中逻辑
以上便是SDK使用的全过程,我们已实现了SDK和项目主工程共用一份AFNetworing,且SDK和Bundle交由Pods管理。
开发SDK是选择动态库还是静态库呢?
- 静态SDK不能嵌套。见iOS中Framework Library嵌套使用。因此,当SDK需要引用其他SDK,且不希望暴露给用户时,只能采用动态库的开发方式。
- 静态库开发需要编写spec文件,且需要告诉客户如何导入,若嫌其麻烦时可采用动态库开发。
- 动态库上架需要删除其X86,i386模拟器架构,若嫌其麻烦可采用静态库开发。
- 若SDK和项目中用到相同的三方库(如:AFNetworking)。动态库:工程和项目中可以存在2份AFNetworking,静态库只会存在一份,若嫌2份代码重复占存储资源时,可采用静态库开发。
- 主流SDK均采用静态库开发。环信采用动态库开发。
区分一个sdk是动态库还是静态库?
在项目中, 以
Embedded Binaries
方式导入为动态库;以Link Binary With Libraries
方式导入为静态库。