阅读视图

发现新文章,点击刷新页面。

Swift组件:使用第三方静态库

最近在做的项目,使用了组件化方案,组件都是用Swift编写。在做用户组件的时候,用到了微信登录SDK,该SDK是一个使用OC编写的静态库,文件只有.a和.h文件,通过CocoaPods引入到项目后,尝试导入,结果报错找不到该库。

为什么找不到静态库?

明明导入了SDK,为什么找不到?

很简单,因为OC代码没有暴露给Swift。

在常规Swift项目中,创建OC文件时Xcode会自动帮我们创建桥接文件Xx-Bridging-Header.h,供Swift使用OC代码,同时也会创建Xx-Swift.h文件,供OC使用Swift代码,以达到混合开发的目的。

但是,组件是不允许使用桥接文件的。

怎么办?

我们来看下Cocoapods的做法。 比如在Swift项目中导入OC库MJRefresh。 安装到项目后,会看到在该库的Support Files文件夹中多了MJRefresh-umbrella.h和MJRefresh.modulemap文件。

MJRefresh-umbrella.h文件导入了所有OC头文件:

#import "MJRefreshAutoFooter.h"
#import "MJRefreshBackFooter.h"
#import "MJRefreshComponent.h"
...

MJRefresh.modulemap文件声明了Swift可以导入的库名MJRefresh

framework module MJRefresh {
  umbrella header "MJRefresh-umbrella.h"
  export *
  module * { export * }
}

这一套下来,Swift就知道可以导入哪个OC库,里边有哪些OC类可以用。

但是,为什么导入微信提供的开源库之后,没有自动生成上面说的这些文件?

因为微信开源库提供的文件不是源码,而是打包好的静态库和头文件。CocoaPods不会自动创建这些文件。

怎样才能让CocoaPods生成桥接文件?

把SDK包装成一个本地组件!

参考项目:gitee.com/style_tende…

我们先看下微信开源库有哪些文件:

libWechatOpenSDK.a
WechatAuthSDK.h
WXApi.h
WXApiObject.h

创建文件夹和配置文件,目录如下:

WechatOpenSDK

  • WechatOpenSDK
    • libWechatOpenSDK.a
    • WechatAuthSDK.h
    • WXApi.h
    • WXApiObject.h
  • WechatOpenSDK.podspec

配置文件的内容如下:

Pod::Spec.new do |s|
  s.name         = 'WechatOpenSDK'
  s.version      = '2.0.4'
  s.summary      = '本地集成的微信 OpenSDK'
  s.homepage     = 'https://open.weixin.qq.com'
  s.license      = { :type => 'Commercial' }
  s.author       = { 'WeChat' => 'wechat@tencent.com' }
  s.source       = { :path => '.' }

  s.ios.deployment_target = '9.0'
  s.swift_version = '5.0'
  s.requires_arc = true
  s.static_framework = true
  
  s.source_files         = 'WechatOpenSDK/*'
  s.vendored_libraries   = 'WechatOpenSDK/*.a'
  
  # SDK依赖
  s.libraries = 'c++'}
  
end

注意:s.source_files需把.a文件也包括在内,否则CocoaPods不会生成桥接文件。

怎么使用本地组件?

1、在组件库的配置文件中依赖该组件:

s.dependency 'WechatOpenSDK'

2、在Podfile文件中指定该组件的路径:

pod 'WechatOpenSDK', :path => '../WechatOpenSDK'

3、在Swift文件中导入头文件

import WechatOpenSDK

其他

问题一:组件为什么不能使用桥接文件?

  1. Bridging-Header 只对主 Target 有效

Bridging-Header 是通过主 App 的 Build Settings 中 Objective-C Bridging Header 设置路径生效的。 这个设置不会自动传递给子模块(比如 Pod 或 Framework)。

  1. Swift 模块之间是隔离的

Swift Framework 被设计为 模块化的独立单元,不能通过 Bridging-Header 暴露 OC 给 Swift。 如果允许使用 Bridging-Header,模块之间的隔离性就被破坏了,会出现冲突、依赖混乱等问题。

问题二:为什么 CocoaPods 对静态库没有自动生成 umbrella header (umbrella.h) 和 module.modulemap 文件?

Umbrella Header 和 modulemap 是为动态 Framework(modular framework)服务的,而不是为传统的静态库(.a)服务的。

  1. 静态库(Static Library)本身不支持模块化特性

静态库(.a 文件)是预编译的二进制文件,不具备模块边界、命名空间,本质上只能通过头文件路径手动 #import 来暴露接口。所以CocoaPods 默认不会为 .a 文件创建模块相关的 umbrella header 或 modulemap。

  1. CocoaPods 默认是非模块化集成方式

CocoaPods 默认行为(不启用 use_frameworks! 或 modular_headers):不开启模块化编译,不生成 module.modulemap,不要求每个 Pod 是一个独立模块。这样做的原因是为了兼容所有 Objective-C 传统项目(非 Swift 项目)。

❌