diff --git a/CodePush.podspec b/CodePush.podspec index 53716c7a..e3e0aac5 100644 --- a/CodePush.podspec +++ b/CodePush.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| s.preserve_paths = '*.js' s.libraries = 'z', 'bz2' s.source_files = [ - 'ios/CodePush/*.{h,m,swift}', + 'ios/CodePush/*.{h,m}', 'ios/CodePushCore/Sources/CodePushCore/**/*.swift', 'shared/diffpatch/*.{c,h}', 'shared/third_party/hdiffpatch/libHDiffPatch/HPatch/patch.{c,h}', diff --git a/Package.swift b/Package.swift new file mode 100644 index 00000000..a24bfea0 --- /dev/null +++ b/Package.swift @@ -0,0 +1,77 @@ +// swift-tools-version:5.9 +import PackageDescription + +// How this package finds React Native's header products (ReactHeaders etc.). +// +// `react-native spm scaffold` emits this same path, and react-native-screens, reanimated and +// Sentry ship this same pattern. +// RN generates these products in a local package inside each app, at +// /ios/build/xcframeworks, and gives a hand-written manifest no way to locate the app. The +// path works because the autolinker loads this manifest through a symlink at +// /ios/build/generated/autolinking/libs/CodePush, and SwiftPM resolves relative paths from +// that symlink, not from node_modules. Shipping no manifest is not an option: the autolinker +// rejects a dependency without one. +// +// It breaks in remote mode (RN_SPM_REMOTE_URL) and with a custom `--xcframeworks-path`. +// RN's documented contract for hand-written manifests is a remote package dependency instead, +// which RN doesn't publish as of 0.88: +// https://github.com/react/react-native/blob/v0.88.0/packages/react-native/scripts/spm/__docs__/spm-header-paths-contract.md#hand-authored-community-library-contract +let reactNativePackagePath = "../../../../xcframeworks" + +let package = Package( + name: "CodePush", + platforms: [ + .iOS("15.5"), + .tvOS("15.5"), + ], + products: [ + .library(name: "CodePush", targets: ["CodePush"]), + ], + dependencies: [ + .package(name: "ReactNative", path: reactNativePackagePath), + .package(url: "https://github.com/ZipArchive/ZipArchive", .upToNextMinor(from: "2.5.5")), + ], + targets: [ + .target( + name: "CodePush", + dependencies: [ + "CodePushCore", + "CodePushHDiffPatch", + .product(name: "ZipArchive", package: "ZipArchive"), + .product(name: "ReactHeaders", package: "ReactNative"), + .product(name: "ReactNativeHeaders", package: "ReactNative"), + .product(name: "ReactNativeDependenciesHeaders", package: "ReactNative"), + ], + path: "ios/CodePush", + publicHeadersPath: "include" + ), + .target( + name: "CodePushCore", + path: "ios/CodePushCore/Sources/CodePushCore" + ), + .target( + name: "CodePushHDiffPatch", + path: "shared", + sources: [ + "diffpatch/bspatch_bridge.c", + "third_party/hdiffpatch/libHDiffPatch/HPatch/patch.c", + "third_party/hdiffpatch/bsdiff_wrapper/bspatch_wrapper.c", + "third_party/hdiffpatch/file_for_patch.c", + ], + publicHeadersPath: "diffpatch", + cSettings: [ + // Keep in sync with CodePush.podspec and android/app/src/main/cpp/CMakeLists.txt. + .define("_IS_NEED_BLOCK_DEV", to: "0"), + .define("_IS_USED_MULTITHREAD", to: "0"), + .define("_IS_NEED_DIR_DIFF_PATCH", to: "0"), + .headerSearchPath("."), + .headerSearchPath("third_party/hdiffpatch"), + .headerSearchPath("third_party/hdiffpatch/libHDiffPatch/HPatch"), + ], + linkerSettings: [ + .linkedLibrary("z"), + .linkedLibrary("bz2"), + ] + ), + ] +) diff --git a/ios/CodePush/CodePushPackage.m b/ios/CodePush/CodePushPackage.m index 3b1c21d8..1dc03395 100644 --- a/ios/CodePush/CodePushPackage.m +++ b/ios/CodePush/CodePushPackage.m @@ -2,7 +2,11 @@ #import "CodePushDiffManifest.h" #import "CodePushErrorUtils.h" #import "CodePushBinaryDiffPatcher.h" +#if SWIFT_PACKAGE +@import ZipArchive; +#else #import +#endif @implementation CodePushPackage diff --git a/ios/CodePush/CodePushUpdateUtils.m b/ios/CodePush/CodePushUpdateUtils.m index eb7a2aee..4846157f 100644 --- a/ios/CodePush/CodePushUpdateUtils.m +++ b/ios/CodePush/CodePushUpdateUtils.m @@ -2,9 +2,11 @@ #import "CodePushErrorUtils.h" #import "CodePushSha256.h" -// Cocoapods static library vs framework interop: the generated header lives at a different -// path depending on whether the pod is built as a static library or as a framework. -#if __has_include() +// SwiftPM builds the Swift sources as a separate module. In CocoaPods they are part of the +// CodePush module, and the generated header path depends on static library vs framework linkage. +#if SWIFT_PACKAGE +@import CodePushCore; +#elif __has_include() #import #else #import "CodePush-Swift.h" diff --git a/ios/CodePush/include/CodePush/CodePush.h b/ios/CodePush/include/CodePush/CodePush.h new file mode 100644 index 00000000..a5c88bc3 --- /dev/null +++ b/ios/CodePush/include/CodePush/CodePush.h @@ -0,0 +1,3 @@ +// SwiftPM exposes only include/ to dependents, so this gives them `#import `. +// SwiftPM also generates the CodePush module map from this umbrella header. +#import "../../CodePush.h" diff --git a/package.json b/package.json index 680bac34..a94255b3 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,9 @@ "type": "git", "url": "https://github.com/bitrise-io/react-native-code-push" }, + "swiftpmConfig": { + "name": "CodePush" + }, "dependencies": { "hoist-non-react-statics": "^3.3.2" },