Skip to content

feat: implement support for React Native's new architecture with TurboModules and update configuration #676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions NEW_ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# React Native New Architecture Support

This document explains the setup for React Native's new architecture (Fabric and TurboModules) for the Iterable React Native SDK.

## Overview

The new architecture introduces:
- **TurboModules**: A new way to create native modules with better performance
- **Fabric**: A new rendering system for React Native components
- **Codegen**: Automatic code generation from TypeScript spec files

## Spec Files Created

### 1. TypeScript Spec (`src/RNIterableSpec.ts`)
This file defines the interface between JavaScript and native code. It includes:
- All method signatures with proper TypeScript types
- Promise-based async methods
- Proper null handling for optional parameters

### 2. Android Spec (`android/src/main/java/com/iterable/reactnative/RNIterableAPISpec.java`)
This abstract class defines the interface for the Android implementation:
- Extends `TurboModule` instead of `ReactContextBaseJavaModule`
- Contains abstract method declarations for all native methods
- Properly typed parameters and return values

### 3. C++ Spec (`cpp/RNIterableAPISpec.h`)
This header file defines the C++ interface for the new architecture:
- Uses JSI (JavaScript Interface) for direct JavaScript-C++ communication
- Defines virtual methods for all native functionality
- Part of the TurboModule system

## Configuration Updates

### Package.json Changes
The `codegenConfig` has been updated to include:
- Spec file references for both iOS and Android
- Proper module naming and type definitions
- Platform-specific configurations

## Migration Steps

### 1. Update Native Modules
- Android: `RNIterableAPIModule` now extends `RNIterableAPISpec`
- iOS: The existing implementation will work with the new spec
- Remove `getName()` method from Android module (not needed in new architecture)

### 2. Build Configuration
To enable the new architecture:

```bash
# For Android
cd android && ./gradlew clean && cd ..
npx react-native run-android --new-arch

# For iOS
cd ios && xcodebuild clean && cd ..
npx react-native run-ios --new-arch
```

### 3. Metro Configuration
Ensure Metro is configured for the new architecture:

```javascript
// metro.config.js
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const config = {
resolver: {
unstable_enableSymlinks: true,
},
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
```

## Benefits of New Architecture

1. **Better Performance**: Direct JSI communication reduces bridge overhead
2. **Type Safety**: Strong typing between JavaScript and native code
3. **Code Generation**: Automatic code generation reduces manual work
4. **Future-Proof**: Aligns with React Native's roadmap

## Testing

To test the new architecture:

1. Build the library with new architecture enabled
2. Test all existing functionality
3. Verify performance improvements
4. Check for any breaking changes

## Troubleshooting

### Common Issues

1. **Build Errors**: Ensure all spec files are properly configured
2. **Type Errors**: Check TypeScript spec file for correct types
3. **Runtime Errors**: Verify native implementations match spec interfaces

### Debugging

- Use React Native's debugging tools
- Check Metro bundler logs
- Verify codegen output in build directories

## Next Steps

1. Test thoroughly with the new architecture
2. Update documentation for users
3. Consider adding Fabric components if needed
4. Monitor performance improvements
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class RNIterableAPIModule extends ReactContextBaseJavaModule implements IterableUrlHandler, IterableCustomActionHandler, IterableInAppHandler, IterableAuthHandler, IterableInAppManager.Listener {
public class RNIterableAPIModule extends RNIterableAPISpec implements IterableUrlHandler, IterableCustomActionHandler, IterableInAppHandler, IterableAuthHandler, IterableInAppManager.Listener {
private final ReactApplicationContext reactContext;
private static String TAG = "RNIterableAPIModule";

Expand All @@ -70,11 +70,6 @@ public RNIterableAPIModule(ReactApplicationContext reactContext) {
// ---------------------------------------------------------------------------------------
// region IterableSDK calls

@Override
public String getName() {
return "RNIterableAPI";
}

@ReactMethod
public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, String version, Promise promise) {
IterableLogger.d(TAG, "initializeWithApiKey: " + apiKey);
Expand Down
118 changes: 118 additions & 0 deletions android/src/main/java/com/iterable/reactnative/RNIterableAPISpec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.iterable.reactnative;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import java.util.Map;

public abstract class RNIterableAPISpec extends TurboModule {
public RNIterableAPISpec(ReactApplicationContext reactContext) {
super(reactContext);
}

// MARK: - Native SDK Functions

public abstract void initializeWithApiKey(
String apiKey, ReadableMap config, String version, Promise promise);

public abstract void initialize2WithApiKey(
String apiKey, ReadableMap config, String apiEndPointOverride, String version, Promise promise);

public abstract void setEmail(@Nullable String email, @Nullable String authToken);

public abstract void getEmail(Promise promise);

public abstract void setUserId(@Nullable String userId, @Nullable String authToken);

public abstract void getUserId(Promise promise);

// MARK: - Iterable API Request Functions

public abstract void disableDeviceForCurrentUser();

public abstract void setInAppShowResponse(int inAppShowResponse);

public abstract void getLastPushPayload(Promise promise);

public abstract void getAttributionInfo(Promise promise);

public abstract void setAttributionInfo(@Nullable ReadableMap attributionInfo);

public abstract void trackPushOpenWithCampaignId(
int campaignId,
int templateId,
String messageId,
boolean appAlreadyRunning,
@Nullable ReadableMap dataFields);

public abstract void updateCart(@Nullable ReadableArray items);

public abstract void trackPurchase(
double total, @Nullable ReadableArray items, @Nullable ReadableMap dataFields);

public abstract void trackInAppOpen(@Nullable String messageId, int location);

public abstract void trackInAppClick(String messageId, int location, String clickedUrl);

public abstract void trackInAppClose(
String messageId, int location, int source, @Nullable String clickedUrl);

public abstract void inAppConsume(String messageId, int location, int source);

public abstract void trackEvent(String name, @Nullable ReadableMap dataFields);

public abstract void updateUser(ReadableMap dataFields, boolean mergeNestedObjects);

public abstract void updateEmail(String email, @Nullable String authToken);

public abstract void handleAppLink(String appLink, Promise promise);

public abstract void updateSubscriptions(
@Nullable ReadableArray emailListIds,
@Nullable ReadableArray unsubscribedChannelIds,
@Nullable ReadableArray unsubscribedMessageTypeIds,
@Nullable ReadableArray subscribedMessageTypeIds,
int campaignId,
int templateId);

// MARK: - SDK In-App Manager Functions

public abstract void getInAppMessages(Promise promise);

public abstract void getHtmlInAppContentForMessage(String messageId, Promise promise);

public abstract void getInboxMessages(Promise promise);

public abstract void getUnreadInboxMessagesCount(Promise promise);

public abstract void showMessage(String messageId, boolean consume, Promise promise);

public abstract void removeMessage(String messageId, int location, int source);

public abstract void setReadForMessage(String messageId, boolean read);

public abstract void setAutoDisplayPaused(boolean paused);

// MARK: - SDK Inbox Session Tracking Functions

public abstract void startSession(ReadableArray visibleRows);

public abstract void endSession();

public abstract void updateVisibleRows(ReadableArray visibleRows);

// MARK: - SDK Auth Manager Functions

public abstract void passAlongAuthToken(@Nullable String authToken);

// MARK: - Event Emitter Methods

public abstract void addListener(String eventName);

public abstract void removeListeners(int count);
}
Loading
Loading