Swift SDK 开发详解

前言

日常的开发中,我们经常会遇到这样的开发需求。比如 不能提供源码,暴露部分接口出去、 项目功能组件模块化等。这个时候,我们一般就想到了sdk开发。在OC的开发中,我们涉及到的一般是静态库(.a)或者动态库(.framework)。(注:不是所有的.framework就一定是动态库)。之前,使用OC尝试过SDk的开发,感觉还是比较繁琐,接下来我们就使用Swift进行SDK开发。


开发准备

静态库和动态库的对比,我们在这里就不论述了。想要了解,可以查看 What are Frameworks,下面进行SDK开发。

新建一个framework工程

1、打开Xcode, command+shift+N
Swift SDK 开发详解_第1张图片

2、工程配置
Swift SDK 开发详解_第2张图片
3、工程目录
Swift SDK 开发详解_第3张图片
4、开发SDK示例
我们在项目工程中,开始我们的开发工作。
假如我们要实现一个类文件,暴露出去一个方法 对输入的名字 添加一个简单的描述。
Swift SDK 开发详解_第4张图片

在上面的代码中,我们可以看到 open class 和 open func.
这是在swift 的sdk开发中,我们不用再像OC那样选择头文件暴露出去。我们可以通过open 和 public 来处理我们需要暴露出来给外界访问的类或者方法等。

关于在开发中,我们是使用public还是open.

public:可以在任何地方访问。但其他 module 中不可以被 override 和继承,而在 module 内可以被 override 和继承。
open: 可以在任何地方访问到,同时可以被继承和 override 。

简单的配置sdk

Swift SDK 开发详解_第5张图片


调试framework

1、拖拽引入项目(不推荐)

将Products 下的.framework 拖拽添到我们需要的项目工程中。这个虽然可以,但是调试起来比较麻烦,稍有改动,我们就要删除之前的,重新引入新版本的.framework.

2、创建workspace
1、我们新建一个项目工程用来测试我们开发的SDK

Swift SDK 开发详解_第6张图片

2、将我们的SDK工程文件拖进到我们新建的测试工程文件中

Swift SDK 开发详解_第7张图片

3、打开新建的测试工程引入sdk工程

Swift SDK 开发详解_第8张图片

此时我们可以发现在导航栏里面 我们有了两个build target
Swift SDK 开发详解_第9张图片
此时我们可以随时切换编译的目标,方便我们在开发中测试。

4、在测试工程中,引入sdk,并使用。

Swift SDK 开发详解_第10张图片

扩展

在上面文章中,我们简单的了解到了如何开发sdk,怎么简单有效的测试。但是这样就足够了吗? 显示是不够的。
我们通常还会有以下的使用场景需要处理。

  1. 开发的sdk怎么同时支持模拟器和真机?
  2. 开发的sdk,有时候不仅仅是功能的封装,有时候会有UI的封装。例如:我们常见的IMSDK等。这个时候,牵扯到的资源文件怎么处理?
  3. 我们开发的sdk,功能比较复杂,引用了一些开源库,我们在sdk中怎么处理?

首先我们来处理第一个问题。

常见的处理方式呢 就是使用lipo 命令。
找到products下文件夹 打开然后将debug 和release 的 frame合并

查看sdk的架构

lipo -info xxx

合并sdk

lipo -create  a路径 b路径 -output c路径

添加脚本处理

添加target

Swift SDK 开发详解_第11张图片
Swift SDK 开发详解_第12张图片

#添加运行脚本

Swift SDK 开发详解_第13张图片

编写脚本

Swift SDK 开发详解_第14张图片

脚本的全部代码,粘贴进去即可。

#!/bin/sh

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"

# Step 1. Build Device and Simulator versions
xcodebuild -target ${PROJECT_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target ${PROJECT_NAME} -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"

# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi

# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"

# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"

# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"

到此,合并sdk就到此结束。

处理第二个问题:资源文件

在提供sdk开发的时候,我的建议是把我们所使用的资源文件,使用bundle的形式提供。具体的可参照我们经常使用的sdk,如:友盟分享sdk等。
建议bundle的命名跟sdk的名字保持一致,减少图片重名冲突的可能性。
1、bundle的创建
bundle的创建是很简单的,我们直接新建一个文件夹,将资源文件放进去,文件件名称后缀改成.bundle即可。
2、sdk中访问bundle的资源
在sdk中,我们就不能再直接的访问图片资源了,需要加上图片的资源路径。
代码示例:

import UIKit

open class SwiftSDKClass: NSObject {
    open func test(name:String)-> String{
        return self.addName(name: name)
    }
    open func getImage(name:String)->UIImage{
        let path = Bundle.main.resourcePath ?? ""
        let bundle = Bundle(path:path + "/SwiftSDK.bundle");
         if let currentbundle =  bundle {
            let imagePath = "\(currentbundle.resourcePath!)/\(name)"
            return UIImage.init(contentsOfFile: imagePath)!;
         }else{
            print("bundle 资源路径不存在");
            return UIImage();
        }
    }
    func addName(name:String)->String{
        return "我的名字是\(name)";
    }
}

访问资源的路径

Swift SDK 开发详解_第15张图片
获取到bundle的资源文件
Swift SDK 开发详解_第16张图片

到此,第二个问题,算是解决。将代码和资源文件做了分离。当然,并不是所有的资源文件一定要这么做。如果资源很少也比较小,也可以直接打包在sdk中。

处理最后一个问题:第三库的引入问题

在我们进行sdk开发时,有时难免设计到一些功能或者业务逻辑使用到第三方开源库。
我的建议是不要在sdk工程中直接引用,建议使用cocoapods或者其他第三库管理工具。在我们的sdk的引入指南中,告诉引入的工程目录集成 sdk中所使用的第三方开源库及其版本。

你可能感兴趣的:(Swift)