Skip to content

package:ios --add-spm-package: allow project-declared extra XCFrameworks as binary targets #468

Description

@malopezr7

Summary

brownfield package:ios --add-spm-package generates a local Swift package whose binary targets are fixed: the app framework, Hermes, ReactBrownfield, Brownie/BrownfieldNavigation, and the Expo support list in emitExpoSupportXcframeworks.ts. There is no way for a project to declare an additional XCFramework that the host must import directly.

Problem

Some Swift modules cannot be fused into the packaged RN framework: the host app has to link and import them itself (the same reason ExpoModulesCore is shipped as a separate XCFramework instead of inside BrownfieldLib). Today the host ends up with two integration paths: the generated SPM package for RN, plus a hand-added local Swift package or a manually dragged XCFramework for the extra module. --add-spm-package promises “one Add Local”; that promise breaks as soon as a project has one such module.

Dropping an extra *.xcframework into the package dir is not a workaround: createLocalSpmPackage.resolveAppFrameworkName treats any non-reserved XCFramework as an app-framework candidate, so without --scheme it either fails with “multiple candidates” or picks the wrong one.

Proposal (opt-in, additive)

// brownfield.config.js
module.exports = {
  ios: {
    extraSpmXcframeworks: [
      { name: 'MyHostModule', path: './artifacts/MyHostModule.xcframework' },
    ],
  },
};
  • Default [] → byte-identical to current behavior.
  • Only consumed when --add-spm-package is set.
  • Each name is added to RESERVED_FRAMEWORK_NAMES for that run, so it never competes with app-framework resolution.
  • Copied into spm-artifacts/ with normalizeCopiedXcframework, emitted as one more .binaryTarget and listed in the library product.
  • Not linked into BrownfieldLib; no Podfile or Xcode project changes.
  • Missing path → hard error naming the entry. No silent skip.
  • Schema: BrownfieldIosConfig.extraSpmXcframeworks (array of { name, path }), same shape family as extraParams.

Why here and not in the consumer

The host has no Node toolchain; the point of package:ios is that the RN side owns packaging. A per-project list keeps that contract instead of pushing a second package onto every host.

Context

Hit this with a C++-free Swift API that must live beside (not inside) the RN framework so the host can provide() native implementations before startReactNative. Any analytics / design-system / internal SDK the host must import has the same shape.

Happy to send a PR against createLocalSpmPackage.ts + schema.json if the direction is acceptable.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions