Skip to content

fix(ios): let pods depending on core resolve ReactNativeHealthkitCore_Private - #395

Merged
robertherber merged 2 commits into
kingstinct:masterfrom
enavermate:fix/core-private-module-include-path
Oct 6, 2026
Merged

robertherber merged 2 commits into
kingstinct:masterfrom
enavermate:fix/core-private-module-include-path

Conversation

@enavermate

Copy link
Copy Markdown
Contributor

Fixes #391.

The problem

Since 16.0.0, ReactNativeHealthkitCore imports its private Objective-C module:

// packages/core/ios/Exceptions.swift
internal import ReactNativeHealthkitCore_Private

The module map is made findable through the core pod's own pod_target_xcconfig (SWIFT_INCLUDE_PATHS => $(PODS_TARGET_SRCROOT)/ios), which applies to that pod only. The core module is built without library evolution, so an internal import does not hide the dependency from clients: whenever another pod loads ReactNativeHealthkitCore, that import has to resolve there too. With explicit module builds the dependency scanner of ReactNativeHealthkit (and of ReactNativeHealthkitHealthRecords) looks for it and fails:

error: Unable to resolve module dependency: 'ReactNativeHealthkitCore_Private' (in target 'ReactNativeHealthkit' from project 'Pods')

Reproduction

A blank Expo app (SDK 57, React Native 0.86.3, Xcode 27.0, iOS simulator), @kingstinct/react-native-healthkit@16.0.0 from npm:

expo-build-properties ios Result
defaults builds
useFrameworks: "static" builds
useFrameworks: "static" + buildReactNativeFromSource: true fails with the error above

The last combination is common in apps using React Native Firebase, which is where I hit it. The monorepo's example app doesn't use it, which is likely why it didn't show up there.

The fix

The two pods that depend on core (ReactNativeHealthkit, ReactNativeHealthkitHealthRecords) add the core's ios/ directory to their own SWIFT_INCLUDE_PATHS. The path is resolved the way Node resolves the dependency (require.resolve('@react-native-healthkit/core/package.json'), the same technique React Native's podspecs use) and written relative to $(PODS_TARGET_SRCROOT), so it works in the monorepo (../core/ios), a flat node_modules (../../@react-native-healthkit/core/ios) and a nested one, without absolute paths in the generated xcconfig.

I also tried switching the import to @_implementationOnly import: it builds, but the compiler warns that it is unsafe without library evolution (#ImplementationOnlyDeprecated), so I kept your internal import and fixed the search path instead.

Verification

  • Same app and failing configuration, with the patched podspec: Release build for the simulator succeeds, the app launches and isHealthDataAvailable() returns true.
  • In the monorepo the podspec evaluates to SWIFT_INCLUDE_PATHS = $(inherited) "$(PODS_TARGET_SRCROOT)/../core/ios".

Note on health-records

ReactNativeHealthkitHealthRecords fails with the same private-module error in that configuration, and this change gets it past it. In my app it then stops on a different, unrelated error: 'AuthorizationRequestStatus.hpp' file not found from its nitrogen bridge header. Both @kingstinct/react-native-healthkit and @react-native-healthkit/health-records generate a header with that name, in different namespaces. I left that out of this PR and can open a separate issue for it if that helps.

@changeset-bot

changeset-bot Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 37a2c04

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@kingstinct/react-native-healthkit Patch
@react-native-healthkit/health-records Patch
@react-native-healthkit/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@enavermate
enavermate force-pushed the fix/core-private-module-include-path branch from 81d894c to f8059bb Compare October 2, 2026 00:41
@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@react-native-healthkit/core@395
npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@react-native-healthkit/health-records@395
npm i https://pkg.pr.new/kingstinct/react-native-healthkit/@kingstinct/react-native-healthkit@395

commit: 37a2c04

@robertherber
robertherber enabled auto-merge (squash) October 6, 2026 19:43
@robertherber
robertherber merged commit 9854ae3 into kingstinct:master Oct 6, 2026
12 checks passed
FDOTPike added a commit to FDOTPike/athlete-kinetics that referenced this pull request Oct 9, 2026
…(Xcode 27)

The tester's second run on Xcode 27 (issue #38) confirmed the
deployment-target fix and then failed in the ReactNativeHealthkit pod:
"Unable to resolve module dependency: 'ReactNativeHealthkitCore_Private'".
The pinned core (16.0.0) puts its ios/ directory, which holds that
module map, on SWIFT_INCLUDE_PATHS for its own target only; with
explicit module builds a dependent pod must resolve the module too.
Upstream fixes this in 16.1.0 (kingstinct/react-native-healthkit#395).

The Podfile post_install now adds the core's ios/ directory to
SWIFT_INCLUDE_PATHS of the pods that depend on the core, as upstream
does. It applies to exactly 16.0.0 and fails closed if the module map
is missing. The binding's version is unchanged. Podfile.lock carries
the new Podfile checksum.

verify:native-config gains a check, watched failing with the call
removed. typecheck and verify:native-config pass. Not yet run on any
Mac: CI covers Xcode 26; Xcode 27 needs another run by the tester.

Ledger: Entry 0201 output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

16.0.0: dependent pod cannot resolve ReactNativeHealthkitCore_Private (SWIFT_INCLUDE_PATHS is not inherited)

2 participants