前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OC framework 与 Swift 混编

OC framework 与 Swift 混编

作者头像
韦弦zhy
发布2023-10-16 16:44:22
6490
发布2023-10-16 16:44:22
举报

在模块化,组件化的热潮下,不管是真的因为业务复杂或者是对于未来业务的提前规划还是只是被这股热潮裹挟着,我们手上不少项目都已经完成了组件化或者正在实现。当历史模块需要修改时,直接使用OC进行是一个很正确的选择,但是某些时候,引入 Swift 也是其中一个选择。

最近也往一个在工作空间直接管理的一个OC模块中引入了Swift,也遇到了一些问题与此记录,以备日后查阅。

1、 项目中混编 OC 和 Swift

Swift 通过 ProjectName-Bridging-Header.h 引入需要的 OC 头文件调用 OC, OC 则通过 引入 ProjectName-swift.h 调用 Swift。

  • Xcode 会提示创建桥接文件,点击创建就行,此时会自动生成ProjectName-Bridging-Header.hProjectName-swift.h
  • 如果选错了则可以手动创建一个HeaderFile 文件,命名:ProjectName-Bridging-Header.h ProjectName 为项目名称,然后在 Build Settings 中,找到 Swift Compiler - General 中的 Objective-C Bridging Header, 输入HeaderFile.h 的路径就行,同样 ProjectName-swift.h 会自动生成,如图可见系统通过 $(SWIFT_MODULE_NAME)-Swift.h 自动进行命名。

Build Settings - Swift Compiler - General - Objective-C Bridging Header

2、OC framework 与 Swift 混编

主要参考 Swift framework 与 OC 混编 及其Demo GitHub - smallyou/swift-oc-interpolation

在任意位置新建一个 modulemap 文件夹,并在其中新增一个 module.modulemap 文件

注意:

  • 该文件的名称一定是 module.modulemap,否则 XCode 无法 import 进来;
  • 该文件的位置与 OC 源代码/头文件的位置不做要求,仅仅需要注意的是 modulemap 文件内部引用头文件一定是 OC 头文件的相对位置。

modulemap 文件内容如下, 具体语法格式见:Modules — Clang 18.0.0git documentation (llvm.org)

代码语言:javascript
复制
module ModuleName [extern_c] {

    // 相对路径
    umbrella header "../ModuleName_Private.h"

    export *
    module * { export * }
}

ModuleName_Private.h 是一个 OC 的头文件,里面 import 需要开放给 Swift 使用的 OC 头文件。

最开始参考参考demo想多引入其他OC文件时发现报错:

Umbrella for module '********' already covers this directory

Umbrella for module '*****' already covers this directory

然后就需要配置多个 modulemap 来处理,那无疑是不太现实的处理方式,尝试之后采用头文件方式,同时此处 ModuleName 就是这个模块导出的名字,不要自定义命名,否则该 framework 编译正常,后面导出的时候会有问题。

然后在OC 的 framework 的 Build Settings 中,将 Packaging 的 Defines Module 为 Yes:

Build Settings 中,Packaging - Defines Module

接下来,在 OC 的 framework target 中设置 Build Settings, Swift Compiler 的 Import Paths 属性,将其设置为 module.modulemap 的文件路径:

Build Settings, Swift Compiler - Import Paths

接下里在工程任意位置新建一个与 target 同名的 modulemap 文件。

注意:

  • 新建的 modulemap 文件存放的路径任意
  • modulemap 文件的名称一定要与 target 的产物名称一致

modulemap 文件内容如下, 具体语法格式见:Modules — Clang 18.0.0git documentation (llvm.org)

代码语言:javascript
复制
// ModuleName.modulemap
framework module ModuleName {
    // 此处引用你的 umbrella 文件,无需配置路径,直接名称即可。
    // 需要注意的是,ModuleName.h  需要在 Build Phases 的 Header 中设置为 Public
  umbrella header "../ModuleName.h"

  export *
  module * { export * }
}

上文提到 module.modulemap 中提到 module 的名字就设置为 ModuleName, 如果不这样设置,此处 umbrella header 会提示 ModuleName 这个module 找不到 Umbrella header '../ModuleName.h' not found

最后 在 Build Settings 的 Packaging 中设置 Module Map File 为当前 modulemap 的路径。

Build Settings - Packaging - Module Map File

此时,万事大吉。workSpaces 项目可以正常运行了。

3、 OC framework 与 Swift 混编后需要导入 Swift 三方库

原项目使用 CocoaPods 管理,配置的 #use_frameworks!, 并且因为某些原因,该项目不能直接改成 use_frameworks! 了事。

如果可以改,直接改了就不会有其他问题!

此时,在 ModelTarget 导入 Swift 库 pod 'SnapKit', '~> 5.6.0' 然后 使用如下脚本配置该库需要编译成动态库:

代码语言:javascript
复制
dynamic_frameworks = ['SnapKit'] # <- swift libraries names
# Make all the other frameworks into dynamic frameworks by overriding the dynamic_framework? function to return true
pre_install do |installer|
  installer.pod_targets.each do |pod|
    if dynamic_frameworks.include?(pod.name)
      puts "Overriding the dynamic_framework? method for #{pod.name}"
      def pod.dynamic_framework?;
        true
      end
      def pod.build_type;
        Pod::BuildType.dynamic_framework
      end
    end
  end
end

pod install 之后正常编译。

随后开始运行项目报错,程序卡死在启动页: ` dyld[44691]: Library not loaded: @rpath/SnapKit.framework/SnapKit

Referenced from: <4B87D787-447E-33D1-B3A1-C8A1A70BBF95> /private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/ProjectName

Reason: tried: '/usr/lib/swift/SnapKit.framework/SnapKit' (no such file, not in dyld cache), '/private/preboot/Cryptexes/OS/usr/lib/swift/SnapKit.framework/SnapKit' (no such file), '/usr/lib/swift/SnapKit.framework/SnapKit' (no such file, not in dyld cache), '/private/preboot/Cryptexes/OS/usr/lib/swift/SnapKit.framework/SnapKit' (no such file), '/private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/Frameworks/SnapKit.framework/SnapKit' (no such file), '/private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/Frameworks/SnapKit.framework/SnapKit' (no such file), '/private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/Frameworks/SnapKit.framework/SnapKit' (no such file), '/usr/lib/swift/SnapKit.framework/SnapKit' (no such file, not in dyld cache), '/private/preboot/Cryptexes/OS/usr/lib/swift/SnapKit.framework/SnapKit' (no such file), '/usr/lib/swift/SnapKit.framework/SnapKit' (no such file, not in dyld cache), '/private/preboot/Cryptexes/OS/usr/lib/swift/SnapKit.framework/SnapKit' (no such file), '/private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/Frameworks/SnapKit.framework/SnapKit' (no such file), '/private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/Frameworks/SnapKit.framework/SnapKit' (no such file), '/private/var/containers/Bundle/Application/7BBAB1C0-064B-460F-BC39-01061BBA2F30/ProjectName.app/Frameworks/SnapKit.framework/SnapKit' (no such file), '/System/Library/Frameworks/SnapKit.framework/SnapKit' (no such file, not in dyld cache) ` 随后通过 PodFile 的主工程中也引入该库解决,可以自定义 Swift 库引入模块,然后同时在主工程和模块内引入:

代码语言:javascript
复制
def dependencies_swift_third_party
  pod 'SnapKit', '~> 5.6.0'
end

target 'Project' do
  platform :ios, '12.0'
  ...

  dependencies_swift_third_party
end

target 'Module' do
  platform :ios, '12.0'
  ...

  dependencies_swift_third_party
end

Done!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-08-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、 项目中混编 OC 和 Swift
  • 2、OC framework 与 Swift 混编
  • 3、 OC framework 与 Swift 混编后需要导入 Swift 三方库
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档