-
Notifications
You must be signed in to change notification settings - Fork 134
Adding Objective C code to Swift framework (SPM, Carthage, Cocoa Pods)
In PR #64 we added Objective-C module to our Swift SDK.
The goal was to:
- write Objective-C code and use it from Swift;
- do not expose Objective-C code to SDK users (make it internal);
- make it work with SPM, Carthage and Cocoapods.
At the end, all was achieved with small issue on module public visibility. We managed to hide it from Xcode import
autocompletion, but it can be still imported explicitly. Good enough 🥈.
First, no Xcode target is required ✋. A private module is defined only by module.private.modulemap
.
All .m
and .h
files should be put inside single folder, DatadogPrivate/*
.
The module.private.modulemap
file is required. It should name the private module and list all the headers. It should be put inside DatadogPrivate/include/
(the include
folder is required by Xcode 11.3
, but not 11.4
).
Next, depending on dependency manager the .modulemap
and headers are discovered differently:
For Carthage, SWIFT_INCLUDE_PATHS
build setting should be set to DatadogPrivate/**
and all .h
files should be added to Build Phases > Headers > Project
build phase of Swift target;
For Cocoapods, the podspec should list source files, paths to preserve and SWIFT_INCLUDE_PATHS
build setting:
s.source_files = "Sources/Datadog/**/*.swift", "Datadog/DatadogPrivate/*.m"
s.preserve_paths = "Datadog/DatadogPrivate/*.h", "Datadog/DatadogPrivate/include/*.modulemap"
s.pod_target_xcconfig = {
"SWIFT_INCLUDE_PATHS" => "$(PODS_ROOT)/DatadogSDK/Datadog/DatadogPrivate/** $(PODS_TARGET_SRCROOT)/DatadogSDK/Datadog/DatadogPrivate/**"
}
For Swift Package Manager, all header files must be put inside DatadogPrivate/include/
. As we store them in DatadogPrivate/
, we just added single SPMHeaders.h
umbrella header with parent imports:
// SPMHeaders.h
#import "../Header1.h"
#import "../Header2.h"
#import "../Header3.h"
Then, in Package.swift
we just defined the target and SPM does the rest by discovering the include/*.modulemap
under given path
:
.target(
name: "_Datadog_Private",
path: "Datadog/DatadogPrivate"
),