Swift 呼叫 OC 實用技巧

語言: CN / TW / HK

Swift App

混入OC/C/C++程式碼

方法一

使用橋接檔案。

方法二

使用.modulemap

  1. Swift App專案,引入OC/C/C++檔案。
  2. 建立檔名必須為module 字尾為.modulemap的檔案。

image.png

  1. 配置工程BuildSettingSwift Compiler - Search Paths選項,值為module.modulemap檔案所在的目錄路徑或其上層目錄路徑。

image.png 此處可為: sh ${SRCROOT}/MixFrameworkTest ${SRCROOT}/MixFrameworkTest/ObjcInSwitApp 如果這裡的路徑配置不正確便會報錯:error build: No such module '*'

4.配置module.modulemap內容 js module OcInApp { // 所引入標頭檔案相對於`.modulemap`的路徑; "./OcClassInApp.h"也可以 header "OcClassInApp.h" export * } 5. import匯入使用 swift import OcInApp class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() OcClassInApp.description() } }

混入OC Framework

如果引入的OC FrameWork中含有Modules/module.modulemap檔案,則直接拖入Swift工程中,使用import引入並進行呼叫即可。

如果OC FrameWork不支援modulemap(沒有module.modulemap檔案),則有兩種方法:

方法一

建立橋接檔案,按需匯入標頭檔案

方法二

基於OC FrameWork/Modules/module.modulemap路徑,建立module.modulemap檔案,並輸入以下內容並儲存,之後便可使用import引入並進行呼叫。 js // 按需匯入 framework module SameAsFrameWorkName { //必須與匯入的`OC Framework`同名 header "A.h" header "B.h" header "b.h" //.. export * } ``js ///遞迴匯入 framework module SameAsFrameWorkName { //必須與匯入的OC Framework`同名 umbrella header "SameAsFrameWorkName.h" //SDK對外標頭檔案,包含SDK對外暴露的諸多.h檔案

export * module * { export * } } ```

混入OC xcframework

與混入OC framework操作基本一致,如果引入的OC xcframework下不同的架構檔案下的framework中含有Modules/module.modulemap檔案,則直接拖入Swift工程中,使用import引入並進行呼叫即可。

如果OC xcframework不支援modulemap,也是有兩種方法:

方法一

建立橋接檔案,按需匯入標頭檔案。

方法二

OC xcframework下不同架構framework,參考混入OC framework的方法二,即可呼叫。

Swift Framework

Swift Framework僅有Swift類時,如果是需要SDK外部使用的ClassMethod,則只需要使用publicopen修飾。

image.pngSwift工程匯入Swift Framework後,直接在Swift的工程中使用即可。 swift import RadarSDK class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() RadarEntry.start() } } 注意:Swift Framework中是不支援使用橋接檔案的,不然的話會報錯:

image.png

混入OC/C/C++程式碼

示例工程結構如下:

image.png

內部使用 OC

SDK內部的Swift類,不能直接使用OC的程式碼,並且不支援橋接檔案。因此只能使用module.modulemap檔案

  1. 建立檔名必須為module 字尾為.modulemap的檔案。
  2. 配置工程BuildSettingSwift Compiler - Search Paths選項,值為module.modulemap檔案所在的目錄路徑或其上層目錄路徑,此處可為:

sh ${SRCROOT}/SwiftMixSDK/ObjcSources ${SRCROOT}/SwiftMixSDK 3. 配置module.modulemap內容

js module ObjcInFramwork { header "ObjcClassA.h" header "ObjcClassB.h" export * } 4. 使用 swift import ObjcInFramwork public class SwiftMixTest: NSObject { public static func mixTest() { ObjcClassA.description() print("Swift MixIn OC") } }

外部使用OC

如果Swift Framework外部需要呼叫混入的OC,有兩種方法:

方法一

Swift Framework外接.h標頭檔案以#import <SwiftMixSDK/PublicHeader.h>的方法對外公開需要使用的OC標頭檔案。

  1. 配置 Frame Targetbuild Phases,使得OC標頭檔案公開

image.pngimage.png 2. 在Swift Framework外接.h檔案import需要公開的OC標頭檔案 image.png

  1. 使用

swift import UIKit import SwiftMixSDK class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() SwiftMixTest.mixTest() ObjcClassA.description() ObjcClassB.description() } } 4. 編譯最終產物對外暴露的標頭檔案

image.pngimage.png

方法二

自定義Swift Framework.modulemap檔案。

  1. 自定義module.modulemap檔案;此處的檔名不強制module,但建議用module,因為編譯器最終會合並自定義的檔案,最終匯出module.modulemap檔案。
  2. 配置 Frame Targetbuild Setting,保證Define ModuleYES; Module Map File 為自定義.modulemap檔案的路徑。

image.png

  1. 配置module.modulemap內容

js framework module SwiftMixSDK { umbrella header "SwiftMixSDK.h" export * module * {export *} module ObjcInFramwork { header "/Users/*/Desktop/*/SwiftSDKExample/SwiftMixSDK/ObjcSources/ObjcClassA.h" header "/Users/*/Desktop/*/SwiftSDKExample/SwiftMixSDK/ObjcSources/ObjcClassB.h" export * } } 最終SDKmodulemap:

image.png 值得注意的是,此處的header,只能使用絕對路徑,否則會出錯。 stackoverflow此問題的QA

  1. 使用

swift import UIKit import SwiftMixSDK.ObjcInFramwork class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() SwiftMixTest.mixTest() ObjcClassA.description() ObjcClassB.description() } } 5. 編譯最終產物對外暴露的標頭檔案

image.png

小結

綜上可以看出,兩種方法編譯的最終產物存在差異:

方法一會暴露OC標頭檔案的;方法二會隱藏OC的標頭檔案。 多人協作開發Swift Framework時,方法二會存在頻繁修改.modulemap檔案檔案。因此實際開發中還得基於專案決定方案。

混入OC Framework

OC Framework不支援Module時,有兩種方式混入OC Framework

方法一

通過使用.modulemap檔案,實現對OC Framework呼叫。即:OC Framework支援(自動或者手動)module

方法二

參考上述 混入OC/C/C++程式碼 —— 內部使用OC ,建立module.modulemap檔案,配置相關Building Setting。配置module.modulemap內容如下: js module ObjcFramwork { ///相對於module.modulemap的相對路徑 umbrella header "../ObjcFramwork.framework/Headers/ObjcFramwork.h" export * module * { export * } } 最後在Swift檔案中import ObjcFramwork,即可呼叫。

混入OC xcframework

OC xcframework不支援Module時,有兩種方式混入OC xcframework

方法一OC xcframework下不同架構framework,參考混入OC Framework方法一,進行操作後即可呼叫。

方法二

參考上述 混入OC/C/C++程式碼 —— 內部使用OC ,建立module.modulemap檔案,配置相關Building Setting

這些操作與混入OC Framework方法二一致,唯一有區別在於:OC xcframework包含多種架構的Framework

image.png

因此不能通過相對路徑直接引入,因為不同架構路徑下的同一個標頭檔案會相互覆蓋而報錯;

image.png

如何解決呢?我們可以通過新建一個ObjcXCFramwork-umbrella.h檔案(可以是其它名稱),並在其中引入xcframework的標頭檔案: ```objc

import

然後配置`module.modulemap`內容如下:js module ObjcXCFramwork { umbrella header "ObjcXCFramwork-umbrella.h"

export * module * { export * } } `` 最後在Swift檔案中import ObjcXCFramwork`,即可呼叫。