ios-sdk静态库framework开发

ios-sdk静态库framework开发


前篇

主要是给 unity 开发 ios 插件, 以 framework 的形式集成到 unity 中, 供 unity 调用 ios 原生接口.


头文件引入方式

  1. 创建模块 UnityApi 时会一起创建一个头文件 UnityApi.h, 这个头文件里用来 import 改模块里的需要导出的 头文件, 如

    • UnityApi.h

      1
      2
      3
      4
      #import <UnityApi/UnityPlugin.h>
      #import <UnityApi/Tools.h>
      #import <UnityApi/Model.h>
      #import <UnityApi/Define.h>

      即使文件存放有目录层级, 但是 import 的时候是没有目录层级, 只有 <模块/头文件>

  2. 文件引入

    • UnityApi 模块内 引入文件内部文件是用到什么就引入什么

    • UnityApi 模块外 的其他模块, 只需要引入 UnityApi.h 即可


创建 静态 framework

  1. 创建 framework, 如: UnityApi

  2. 编译设置

    点击目标工程 >> 选择你创建的 Framework >> 点击工程设置 >> 做出如下修改

    1
    2
    3
    4
    5
    6
    7
    8
    Build Settings >> Dead Code Stripping >> 设置为NO
    Build Settings >> Strip Debug Symbol During Copy >> 全部设置为NO
    Build Settings >> Strip Style >> 设置为Non-Global Symbols
    Build Settings >> Base SDK >> Latest iOS(iOS 选择最新的)
    Build Settings >> Link With Standard Libraries >> 设置为 NO
    Build Settings >> Mach-O Type >> Static Library

    对于Mach-O Type有两种情况:(1)选择 Static Library 打出来的是静态库;(2)选择 Relocatable Object File 打出来是动态库。
  3. 编写代码 并 导出头文件

    外部需要访问的头文件需要导出

    在对应的 target 上, 把头文件拖到 public 下

  4. 构建 真机/模拟器 的 framework

    1. 切到 对应的模块 及 要编译的 真机 (any ios devices) or 模拟器

    2. cmd + b 进行构建

      构建成功后在 products 目录下会显示成 白色.

  5. 合并 真机 和 模拟器 的 framework. 命令: lipo -create (如果只是 真机 或 模拟器 其中一个使用, 就不需要合并了, 直接使用 framework)

    1
    $ lipo -create /Users/wilker/Library/Developer/Xcode/DerivedData/Build/Products/Debug-iphoneos/UnityApi.framework/UnityApi /Users/wilker/Library/Developer/Xcode/DerivedData/Build/Products/Debug-iphonesimulator/UnityApi.framework/UnityApi -output UnityApi

    • 查看合并后支持的架构

      1
      2
      $ lipo -info UnityApi
      Architectures in the fat file: UnityApi are: armv7 x86_64 arm64 // x86_64 就是 模拟器 支持的架构, armv7 arm64 都是真机支持的架构
    • 附: 移除 cpu 架构

      1
      2
      lipo -remove i386 ProjectFramework_SDK -o ProjectFramework_SDK 
      lipo -remove x86_64 ProjectFramework_SDK -o ProjectFramework_SDK
  6. 然后 选择 真机 (或 模拟器 都行) 导出的 framework

    1. 删除原有的 静态库文件 和 _CodeSignature 目录
    2. 将合并后的 静态库文件 拖入 framework 中. 然后就可以使用这个 framework.


bundle 打包资源

  1. 直接创建一个文件加, 重命名为 res.bundle.

    右键 bundle -> show package contents 可以进入到 bundle 里, 然后就可以往里面拖资源

  2. 将 bundle 拖入项目, 会自动引入 bundle 资源

  3. 加载. 因为是 引用资源的方式, 最终 bundle 都是拷贝到 app 的根目录下, 所以加载资源时都是使用相对根目录的资源

    UnityApi 模块中加载代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    +(void)addImgForView:(UIViewController*) ctrl {
    // 方式 1: bundle 内相对路径 (无文件后缀)
    NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"res" ofType:@"bundle"];
    NSBundle *resourceBundle = [NSBundle bundleWithPath:bundlePath];
    NSString* picPath = [resourceBundle pathForResource:@"pic01" ofType:@"png"];
    // UIImage* img = [UIImage imageWithContentsOfFile:picPath];

    // 方式 2: 绝对路径 (有文件后缀)
    UIImage *img = [UIImage imageNamed:@"res.bundle/pic01.png"];

    UIImageView *imageV = [[UIImageView alloc]init];
    imageV.frame = CGRectMake(100, 100, 100, 100);
    imageV.backgroundColor = [UIColor greenColor];
    imageV.image = img;

    [ctrl.view addSubview:imageV];
    }

加载 framework 的资源

bundleForClass 只能是在 动态 framework 中使用, 才能获取到动态库的路径, 而 静态 framework 会返回 app 的根目录.

以加载 UnityApi.framework 库中根目录下的 loading.bundle 为例

  • 动态 framework 获取路径

    1
    2
    3
    NSBundle *fwBundle = [NSBundle bundleForClass:[UnityPlugin class]]; // UnityPlugin 是 UnityApi.framework 中随便的一个可访问的类
    NSString *resPath = [fwBundle pathForResource:@"loading" ofType:@"bundle"];
    NSBundle *resBundle = [NSBundle bundleWithPath:resPath];
  • 静态 framework 获取路径

    1
    2
    3
    NSString *resPath = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:@"UnityApi.framework/loading.bundle"]; // 显式指定 库名
    NSBundle *resBundle = [NSBundle bundleWithPath:resPath];
    // privateFrameworksPath 就是 Frameworks, ios 的 framework 都是放在 Frameworks目录下

以上两个获取到的 resPath 都是 /data/Containers/Bundle/Application/1961B340-16FC-4F38-BBBA-98532919E2EB/MyIosTest.app/Frameworks/UnityApi.framework/loading.bundle


踩坑

build settings 配置要和 引用这个库的 一致

  1. cpu 架构一致, 如: 都是 architecures armv7 arm64, 不然报错: one or more

  2. 目标版本一致, 如: 都是 ios developement target 9.0


framework 添加资源要以 group 方式, 不能是 folder

如果是 folder 方式, 编译会报错: Command CodeSign failed with a nonzero exit code