Skip to content

Use -core modules for lightweight location/forms#312

Merged
evan-masseau merged 15 commits intorel/2.3.0from
ecm/core-modules
Feb 20, 2026
Merged

Use -core modules for lightweight location/forms#312
evan-masseau merged 15 commits intorel/2.3.0from
ecm/core-modules

Conversation

@evan-masseau
Copy link
Contributor

@evan-masseau evan-masseau commented Feb 19, 2026

Description

Replace unconditional location and forms dependencies with configurable toggles using -core modules. When opted out, only a lightweight -core module is included — providing the API surface (compiles) but no implementation (no-ops at runtime). This avoids pulling in heavy transitive dependencies like Google Play Services Location or the forms WebView engine.

Supersedes #308 which used the location-no-permissions approach.

Due Diligence

  • I have tested this on a simulator/emulator or a physical device, on iOS and Android (if applicable).
  • I have added sufficient unit/integration tests of my changes.
  • I have adjusted or added new test cases to team test docs, if applicable.
  • I am confident these changes are implemented with feature parity across iOS and Android (if applicable).

Release/Versioning Considerations

  • Patch Contains internal changes or backwards-compatible bug fixes.
  • Minor Contains changes to the public API.
  • Major Contains breaking changes.
  • Contains readme or migration guide changes.
  • This is planned work for an upcoming release.

Changelog / Code Overview

Android

  • android/build.gradle: Add klaviyoIncludeLocation and klaviyoIncludeForms gradle property toggles (default true). When false, swap the full location/forms dependency for its -core counterpart.
  • android/settings.gradle + example/android/settings.gradle: Add forms-core and location-core dependency substitution rules for local composite builds.
  • KlaviyoReactNativeSdkModule.kt: Expose FORMS_AVAILABLE and LOCATION_AVAILABLE native constants via Registry.isRegistered<FormsProvider>() and Registry.isRegistered<GeofencingProvider>() for runtime detection.

iOS

  • klaviyo-react-native-sdk.podspec: Make KlaviyoForms and KlaviyoLocation pod dependencies conditional on KLAVIYO_INCLUDE_FORMS and KLAVIYO_INCLUDE_LOCATION env vars (included by default, set to 'false' to exclude).
  • example/ios/Podfile: Demonstrate env var usage with both set to 'true'.
  • KlaviyoBridge.swift: Wrap all forms/location API calls in #if canImport(KlaviyoForms) / #if canImport(KlaviyoLocation) guards. Add isFormsAvailable and isLocationAvailable computed properties.
  • KlaviyoReactNativeSdk.mm: Expose FORMS_AVAILABLE and LOCATION_AVAILABLE constants via constantsToExport.

TypeScript / React Native

  • src/index.tsx: Add isFormsAvailable() and isLocationAvailable() guard functions that check the native constants. When a module is unavailable, logs console.error with platform-specific setup instructions and returns early (no-op) — no exceptions thrown, preventing host app crashes.
  • src/tests/index.test.tsx: Add tests verifying the no-op + console.error behavior when modules are unavailable, and that native bridge methods are not called.

Documentation

  • README.md: Add "Module Configuration" subsections to both In-App Forms and Geofencing sections with iOS (Podfile env var) and Android (gradle.properties) instructions for opting out. Includes a note that Location module will be excluded by default in the next major version.

Test Plan

  • Build with default flags (both true) — full location + forms
  • Build with klaviyoIncludeLocation=false — no location permissions in merged manifest
  • Build with klaviyoIncludeForms=false — forms no-op
  • Example app builds in all configurations
  • Local composite build with new substitutions works
  • TypeScript unit tests pass (23/23)

Note: This PR depends on the Android SDK -core modules being available via JitPack. Until those land, builds against JitPack will fail on the new module coordinates.

Related Issues/Tickets

🤖 Generated with Claude Code

@evan-masseau evan-masseau marked this pull request as ready for review February 19, 2026 19:24
@evan-masseau evan-masseau requested a review from a team as a code owner February 19, 2026 19:24
@belleklaviyo belleklaviyo changed the base branch from master to rel/2.3.0 February 19, 2026 21:03
@evan-masseau evan-masseau requested a review from a team as a code owner February 19, 2026 21:04
@evan-masseau evan-masseau changed the base branch from rel/2.3.0 to bl/make-podspec-modular February 19, 2026 21:27
Base automatically changed from bl/make-podspec-modular to rel/2.3.0 February 19, 2026 21:43
belleklaviyo and others added 9 commits February 19, 2026 16:56
Replace unconditional location and forms dependencies with conditional
toggles controlled by gradle properties. When klaviyoIncludeLocation or
klaviyoIncludeForms is set to false, only the lightweight -core module
is included — providing the API surface but no-oping at runtime.

- Add includeLocation/includeForms flags to android/build.gradle
- Add forms-core and location-core dependency substitutions for local
  composite builds in both android/ and example/android/ settings.gradle
- Document the new Android Module Configuration section in README

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The docs claimed calls would "be no-ops and log a warning" but the actual
behavior is that the SDK catches the missing implementation gracefully via
safeApply and logs at error level. Updated both location and forms sections
to accurately describe the mechanism.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exception handling now lives in the native Android SDK's -core
extension functions via safeApply, so the RN bridge no longer
needs its own try/catch wrapper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The config parsing (getDouble) could throw, and this runs on the UI
thread. Wrapping in try/catch prevents an unhandled crash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… merged

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Uses Registry.isRegistered<FormsProvider>() and
Registry.isRegistered<GeofencingProvider>() to expose module
availability to the JS layer, matching the iOS approach in PR #313.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
evan-masseau and others added 2 commits February 19, 2026 18:50
…ming

- Restore original Rich Push description mentioning video support for iOS
  and using "media" instead of "images"
- Rename ENABLE_KLAVIYO_LOCATIONS -> ENABLE_KLAVIYO_LOCATION (singular)
  to match pod name KlaviyoLocation, consistent with ENABLE_KLAVIYO_FORMS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change requireFormsAvailable/requireLocationAvailable from throwing to
  returning boolean (isFormsAvailable/isLocationAvailable), preventing
  host app crashes when optional modules are excluded
- Add platform-specific setup instructions to error messages
- Fix unregisterFromInAppForms arrow function to method shorthand
- Fix KlaviyoBridge.swift indentation on isFormsAvailable @objc
- Revert Rich Push README wording back to master (unintentional change)
- Update tests to match the new no-throw behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@evan-masseau
Copy link
Contributor Author

bugbot run

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

- Rename ENABLE_KLAVIYO_FORMS → KLAVIYO_INCLUDE_FORMS
- Rename ENABLE_KLAVIYO_LOCATION → KLAVIYO_INCLUDE_LOCATION
- Switch from opt-out (!=false) to opt-in (==true) semantics, matching Flutter convention
- Revert Rich Push README wording change (not part of this PR)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
evan-masseau and others added 2 commits February 20, 2026 14:35
…ssages

- Add "Module Configuration" sections to README for Forms and Geofencing
  with iOS (Podfile) and Android (gradle.properties) instructions
- Note that Location module default will flip to excluded in next major version
- Change podspec to included-by-default (!=false) for both modules
- Update error messages with platform-specific remediation instructions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Safety net in case the TS no-op guards are bypassed — catches
MissingKlaviyoModule on registerForInAppForms, unregisterFromInAppForms,
registerGeofencing, and unregisterGeofencing to prevent native crashes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

const constants = KlaviyoReactNativeSdk.getConstants?.() ?? {};
if (constants.FORMS_AVAILABLE === false) {
console.error(`[Klaviyo] ${FORMS_UNAVAILABLE_MESSAGE}`);
throw new Error(FORMS_UNAVAILABLE_MESSAGE);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This throw would crash the app in production. I dont think we need to be that noisy. console.error is still quite loud and in your face on RN, including a little red error in the app's UI during development.

Prevents callers from being left in a permanently pending state
(e.g. loading spinner that never resolves).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@amber-klaviyo amber-klaviyo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good as far as my understanding goes!

@evan-masseau evan-masseau merged commit 48230cb into rel/2.3.0 Feb 20, 2026
13 checks passed
@evan-masseau evan-masseau deleted the ecm/core-modules branch February 20, 2026 22:42
belleklaviyo added a commit that referenced this pull request Mar 6, 2026
* Make Forms and Location pods optional, true on default (#313)

* Make Forms and Location pods optional, true on default

* Add compiler flag wraps

* Remove README updates (for now)

* Surface missing module to ts error

* Use no-op approach to make forms and location optional modules (#312)

Make Forms and Location native modules optional with graceful degradation                                                      
                                                                                                                                 
  iOS: KLAVIYO_INCLUDE_FORMS/KLAVIYO_INCLUDE_LOCATION Podfile ENV vars control pod inclusion                                     
  Android: FORMS_AVAILABLE/LOCATION_AVAILABLE constants, MissingKlaviyoModule catches in bridge
  JS: Module unavailability logs console.error and no-ops (no throw, no crash)

* Bump to 2.3.0 | Swift 5.2.1 | Android 4.3.0 (#317)

* Bump to 5.2.1

* unversion pods for testing for now

* Point to android release branch

* Point to Swift SDK 5.2.1, Android SDK 4.3.0

* Unversion readme links

* Run pod install

---------

Co-authored-by: Evan C Masseau <5167687+evan-masseau@users.noreply.github.com>
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.

4 participants