Skip to content
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,6 @@ docs/
# Local Netlify folder
.netlify
.metals/

# Agents
.pi/
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## Unreleased

### Updates
- Added `Iterable.registerDeviceToken(token)` to re-enable push for the current device.
- Android accepts an FCM token string.
- iOS accepts a continuous hex string representation of the APNS token.

## 3.0.0

### Updates
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@ public void disableDeviceForCurrentUser() {
IterableApi.getInstance().disablePush();
}

public void registerDeviceToken(String token) {
IterableLogger.v(TAG, "registerDeviceToken");
IterableApi.getInstance().registerDeviceToken(token);
}

public void handleAppLink(String uri, Promise promise) {
IterableLogger.printInfo();
promise.resolve(IterableApi.getInstance().handleAppLink(uri));
Expand Down
5 changes: 5 additions & 0 deletions android/src/newarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ public void disableDeviceForCurrentUser() {
moduleImpl.disableDeviceForCurrentUser();
}

@Override
public void registerDeviceToken(String token) {
moduleImpl.registerDeviceToken(token);
}

@Override
public void handleAppLink(String uri, Promise promise) {
moduleImpl.handleAppLink(uri, promise);
Expand Down
5 changes: 5 additions & 0 deletions android/src/oldarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ public void disableDeviceForCurrentUser() {
moduleImpl.disableDeviceForCurrentUser();
}

@ReactMethod
public void registerDeviceToken(String token) {
moduleImpl.registerDeviceToken(token);
}

@ReactMethod
public void handleAppLink(String uri, Promise promise) {
moduleImpl.handleAppLink(uri, promise);
Expand Down
5 changes: 2 additions & 3 deletions example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
77E3B5772EA71A4B001449CE /* IterableJwtGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77E3B5742EA71A4B001449CE /* IterableJwtGenerator.swift */; };
77E3B5782EA71A4B001449CE /* JwtTokenModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77E3B5752EA71A4B001449CE /* JwtTokenModule.mm */; };
77E3B5792EA71A4B001449CE /* JwtTokenModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77E3B5762EA71A4B001449CE /* JwtTokenModule.swift */; };
7C8CB9778D44155D232C3690 /* libPods-ReactNativeSdkExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8A71BC6B8F9B2B3CF98A77 /* libPods-ReactNativeSdkExample.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
A3A40C20801B8F02005FA4C0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 1FC6B09E65A7BD9F6864C5D8 /* PrivacyInfo.xcprivacy */; };
DDD9C96E1785FEF10EEE61A5 /* libPods-ReactNativeSdkExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 627B7C7165CE568DB5CB8F50 /* libPods-ReactNativeSdkExample.a */; };
Expand Down Expand Up @@ -439,7 +438,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = iterable.reactnativesdk.example;
PRODUCT_BUNDLE_IDENTIFIER = com.iterable.reactnativesdk.example;
PRODUCT_NAME = ReactNativeSdkExample;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SWIFT_OBJC_BRIDGING_HEADER = "ReactNativeSdkExample-Bridging-Header.h";
Expand Down Expand Up @@ -470,7 +469,7 @@
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = iterable.reactnativesdk.example;
PRODUCT_BUNDLE_IDENTIFIER = com.iterable.reactnativesdk.example;
PRODUCT_NAME = ReactNativeSdkExample;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SWIFT_OBJC_BRIDGING_HEADER = "ReactNativeSdkExample-Bridging-Header.h";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>
8 changes: 8 additions & 0 deletions ios/RNIterableAPI/RNIterableAPI.mm
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ - (void)disableDeviceForCurrentUser {
[_swiftAPI disableDeviceForCurrentUser];
}

- (void)registerDeviceToken:(NSString *)token {
[_swiftAPI registerDeviceToken:token];
}

- (void)getLastPushPayload:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject {
[_swiftAPI getLastPushPayload:resolve rejecter:reject];
Expand Down Expand Up @@ -512,6 +516,10 @@ - (void)wakeApp {
[_swiftAPI disableDeviceForCurrentUser];
}

RCT_EXPORT_METHOD(registerDeviceToken : (NSString *)token) {
[_swiftAPI registerDeviceToken:token];
}

RCT_EXPORT_METHOD(getLastPushPayload : (RCTPromiseResolveBlock)
resolve reject : (RCTPromiseRejectBlock)reject) {
[_swiftAPI getLastPushPayload:resolve rejecter:reject];
Expand Down
22 changes: 22 additions & 0 deletions ios/RNIterableAPI/ReactIterableAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ import React
IterableAPI.disableDeviceForCurrentUser()
}

@objc(registerDeviceToken:)
public func registerDeviceToken(token: String) {
ITBInfo()
guard let tokenData = data(fromHex: token) else {
ITBError("Could not convert token to Data: invalid hex string")
return
}
IterableAPI.register(token: tokenData)
}

@objc(getLastPushPayload:rejecter:)
public func getLastPushPayload(resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock)
{
Expand Down Expand Up @@ -599,6 +609,18 @@ import React

private let inboxSessionManager = InboxSessionManager()

private func data(fromHex hex: String) -> Data? {
var data = Data()
var chars = hex.makeIterator()
while let high = chars.next(), let low = chars.next() {
guard let highValue = high.hexDigitValue, let lowValue = low.hexDigitValue else {
return nil
}
data.append(UInt8(highValue << 4 | lowValue))
}
return data
}

@objc func initialize(
withApiKey apiKey: String,
config configDict: NSDictionary,
Expand Down
4 changes: 4 additions & 0 deletions src/__mocks__/MockRNIterableAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export class MockRNIterableAPI {

static disableDeviceForCurrentUser = jest.fn();

static registerDeviceToken = jest.fn((token: string): void => {
MockRNIterableAPI.token = token;
});

static trackPushOpenWithCampaignId = jest.fn();

static updateCart = jest.fn();
Expand Down
1 change: 1 addition & 0 deletions src/api/NativeRNIterableAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export interface Spec extends TurboModule {

// Device management
disableDeviceForCurrentUser(): void;
registerDeviceToken(token: string): void;
getLastPushPayload(): Promise<{
[key: string]: string | number | boolean;
} | null>;
Expand Down
11 changes: 11 additions & 0 deletions src/core/classes/Iterable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ describe('Iterable', () => {
});
});

describe('registerDeviceToken', () => {
it('should register the device token for the current user', () => {
// GIVEN a device token
const token = 'test-device-token';
// WHEN Iterable.registerDeviceToken is called
Iterable.registerDeviceToken(token);
// THEN corresponding method is called on RNIterableAPI
expect(MockRNIterableAPI.registerDeviceToken).toBeCalledWith(token);
});
});

describe('getLastPushPayload', () => {
it('should return the last push payload', async () => {
const result = { var1: 'val1', var2: true };
Expand Down
20 changes: 20 additions & 0 deletions src/core/classes/Iterable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,26 @@ export class Iterable {
IterableApi.disableDeviceForCurrentUser();
}

/**
* Register the device's token for the current user, re-enabling push notifications.
*
* @param token - The device token to register.
* On Android, pass the Firebase Cloud Messaging (FCM) token string.
* On iOS, pass the Apple Push Notification service (APNS) token as a continuous hex string.
*
* @example
* ```typescript
* // Android
* Iterable.registerDeviceToken('fcm-token-string');
*
* // iOS
* Iterable.registerDeviceToken('abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234');
* ```
*/
static registerDeviceToken(token: string) {
IterableApi.registerDeviceToken(token);
}

/**
* Get the payload of the last push notification with which the user
* opened the application (by clicking an action button, etc.).
Expand Down
13 changes: 13 additions & 0 deletions src/core/classes/IterableApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,19 @@ describe('IterableApi', () => {
});
});

describe('registerDeviceToken', () => {
it('should call RNIterableAPI.registerDeviceToken with the token', () => {
// GIVEN a device token
const token = 'test-device-token';

// WHEN registerDeviceToken is called
IterableApi.registerDeviceToken(token);

// THEN RNIterableAPI.registerDeviceToken is called with the token
expect(MockRNIterableAPI.registerDeviceToken).toBeCalledWith(token);
});
});

describe('updateUser', () => {
it('should call RNIterableAPI.updateUser with data fields and merge flag', () => {
// GIVEN data fields and merge flag
Expand Down
10 changes: 10 additions & 0 deletions src/core/classes/IterableApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,16 @@ export class IterableApi {
return RNIterableAPI.disableDeviceForCurrentUser();
}

/**
* Register the device token for the current user, re-enabling push notifications.
*
* @param token - On Android, the FCM token string. On iOS, a continuous hex string representation of the APNS token.
*/
static registerDeviceToken(token: string) {
IterableLogger.log('registerDeviceToken');
return RNIterableAPI.registerDeviceToken(token);
}

/**
* Save data to the current user's Iterable profile.
*
Expand Down
Loading