Summary
BackgroundDeliveryManager (and presumably other native APIs meant to be called directly from AppDelegate/native code, per the README's "Usage from AppDelegate.swift" section) cannot actually be used from outside the ReactNativeHealthkit CocoaPods target. Importing the module from a plain Objective-C++ (.mm) file — the standard way to consume a Swift module from native code without forcing a target-wide Swift/C++ interop mode change — fails because the library's auto-generated Swift-to-C++ compatibility header (ReactNativeHealthkit-Swift.h) references multiple margelo::nitro::* types without itself importing NitroModules, and an explicit @import NitroModules; placed before @import ReactNativeHealthkit; in the consuming file does not fix it.
This makes the documented BackgroundDeliveryManager.shared.setupBackgroundObservers() AppDelegate integration effectively unusable from any file outside the library's own pod target.
Environment
- @kingstinct/react-native-healthkit: 14.0.2
- react-native-nitro-modules: 0.35.9
- react-native: 0.85.3
- expo: 56.0.12
- Xcode: 26.5 (Build 17F42)
- Swift: 6.3.2 (swiftlang-6.3.2.1.108 clang-2100.1.1.101)
- iOS SDK: iphonesimulator26.5
- CocoaPods, default use_frameworks! off (static libraries)
Minimal reproduction
A two-file Objective-C++ bridge added to the main app target (not the library's own pod target):
HealthKitBackgroundDeliveryBridge.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface HealthKitBackgroundDeliveryBridge : NSObject
+ (void)setupBackgroundObservers;
@end
NS_ASSUME_NONNULL_END
HealthKitBackgroundDeliveryBridge.mm
#import "HealthKitBackgroundDeliveryBridge.h"
@import NitroModules;
@import ReactNativeHealthkit;
@implementation HealthKitBackgroundDeliveryBridge
+ (void)setupBackgroundObservers {
[[BackgroundDeliveryManager shared] setupBackgroundObservers];
}
@end
Build settings applied to the consuming app target only (confirmed necessary, not the issue):
CLANG_ENABLE_MODULES = YES
OTHER_CPLUSPLUSFLAGS = $(inherited) -fcxx-modules
HEADER_SEARCH_PATHS includes $(PODS_ROOT)/Headers/Private/NitroModules
Actual error
Why this looks like a module-dependency declaration issue, not a consumer-side config problem
chrono_time (NitroModules/DateToChronoDate.hpp) and SharedAnyMap (NitroModules/AnyMapUtils.hpp) are both simple, unconditional using type aliases in the margelo::nitro namespace:
// AnyMapUtils.hpp
#include "AnyMap.hpp"
namespace margelo::nitro {
using SharedAnyMap = std::shared_ptr<AnyMap>;
...
}
// DateToChronoDate.hpp
#include "NitroTypeInfo.hpp"
#include <chrono>
namespace margelo::nitro {
using chrono_time = std::chrono::system_clock::time_point;
...
}
Both headers correctly #include their own dependencies and are both listed in NitroModules-umbrella.h. Ruled out before filing this:
- Not a stale build/cache issue — reproduces after a full DerivedData wipe and a clean
pod install.
- Not a missing header search path —
Pods/Headers/Private/NitroModules (where the sibling headers these files include live) is explicitly added; a different, earlier "file not found" error for JSIConverter+AnyMap.hpp was fixed by adding that path, and disappeared. This is a different, later error.
- Not a missing @import —
@import NitroModules; is present, and ordered before @import ReactNativeHealthkit; specifically to rule out an ordering issue.
- Not file-extension/language-mode related —
.mm files are unambiguously Objective-C++ regardless of any target-wide Swift interop setting, and -fcxx-modules/CLANG_ENABLE_MODULES are both set.
Two different, unrelated symbols from two different headers fail identically despite a structurally correct import. The most plausible explanation: Clang modules are built and cached independently per-module. ReactNativeHealthkit's own Clang module is apparently compiled in a way that doesn't itself resolve its dependency on NitroModules's types when that compilation is triggered from a context outside ReactNativeHealthkit's own CocoaPods target — so an @import NitroModules; in the consuming file doesn't retroactively make those types visible inside ReactNativeHealthkit's own module build. This would point to ReactNativeHealthkit's module map (or whatever generates/wraps ReactNativeHealthkit-Swift.h) not declaring NitroModules as a dependency in a way that survives external consumption — possibly fine when the module is only ever consumed from within its own pod target (where build order/precompiled context happens to make the types available incidentally) but breaking for the documented AppDelegate-integration use case, which is inherently external.
Impact
The documented background-delivery AppDelegate integration (BackgroundDeliveryManager.shared.setupBackgroundObservers()) cannot currently be wired up at all from a project using static libraries (no use_frameworks!) without hitting this — whether called directly from Swift (which has its own, separate problems with target-wide interop mode breaking React Native's own headers) or from an Objective-C++ bridge (this issue). Happy to provide a full minimal reproduction repo if useful.
Summary
BackgroundDeliveryManager (and presumably other native APIs meant to be called directly from AppDelegate/native code, per the README's "Usage from AppDelegate.swift" section) cannot actually be used from outside the ReactNativeHealthkit CocoaPods target. Importing the module from a plain Objective-C++ (.mm) file — the standard way to consume a Swift module from native code without forcing a target-wide Swift/C++ interop mode change — fails because the library's auto-generated Swift-to-C++ compatibility header (ReactNativeHealthkit-Swift.h) references multiple margelo::nitro::* types without itself importing NitroModules, and an explicit
@import NitroModules;placed before@import ReactNativeHealthkit;in the consuming file does not fix it.This makes the documented
BackgroundDeliveryManager.shared.setupBackgroundObservers()AppDelegate integration effectively unusable from any file outside the library's own pod target.Environment
Minimal reproduction
A two-file Objective-C++ bridge added to the main app target (not the library's own pod target):
HealthKitBackgroundDeliveryBridge.h
HealthKitBackgroundDeliveryBridge.mm
Build settings applied to the consuming app target only (confirmed necessary, not the issue):
CLANG_ENABLE_MODULES = YESOTHER_CPLUSPLUSFLAGS = $(inherited) -fcxx-modulesHEADER_SEARCH_PATHSincludes$(PODS_ROOT)/Headers/Private/NitroModulesActual error
Why this looks like a module-dependency declaration issue, not a consumer-side config problem
chrono_time(NitroModules/DateToChronoDate.hpp) andSharedAnyMap(NitroModules/AnyMapUtils.hpp) are both simple, unconditional using type aliases in themargelo::nitronamespace:Both headers correctly
#includetheir own dependencies and are both listed inNitroModules-umbrella.h. Ruled out before filing this:pod install.Pods/Headers/Private/NitroModules(where the sibling headers these files include live) is explicitly added; a different, earlier "file not found" error forJSIConverter+AnyMap.hppwas fixed by adding that path, and disappeared. This is a different, later error.@import NitroModules;is present, and ordered before@import ReactNativeHealthkit;specifically to rule out an ordering issue..mmfiles are unambiguously Objective-C++ regardless of any target-wide Swift interop setting, and-fcxx-modules/CLANG_ENABLE_MODULESare both set.Two different, unrelated symbols from two different headers fail identically despite a structurally correct import. The most plausible explanation: Clang modules are built and cached independently per-module. ReactNativeHealthkit's own Clang module is apparently compiled in a way that doesn't itself resolve its dependency on NitroModules's types when that compilation is triggered from a context outside ReactNativeHealthkit's own CocoaPods target — so an
@import NitroModules;in the consuming file doesn't retroactively make those types visible inside ReactNativeHealthkit's own module build. This would point to ReactNativeHealthkit's module map (or whatever generates/wrapsReactNativeHealthkit-Swift.h) not declaring NitroModules as a dependency in a way that survives external consumption — possibly fine when the module is only ever consumed from within its own pod target (where build order/precompiled context happens to make the types available incidentally) but breaking for the documented AppDelegate-integration use case, which is inherently external.Impact
The documented background-delivery AppDelegate integration (
BackgroundDeliveryManager.shared.setupBackgroundObservers()) cannot currently be wired up at all from a project using static libraries (nouse_frameworks!) without hitting this — whether called directly from Swift (which has its own, separate problems with target-wide interop mode breaking React Native's own headers) or from an Objective-C++ bridge (this issue). Happy to provide a full minimal reproduction repo if useful.