Skip to content

Commit 37673e3

Browse files
[SDK-363] Expose register device token (#877)
* chore: ignore coding agent specifics in version control * chore: ios build update * fix: updated PRODUCT_BUNDLE_IDENTIFIER to the correct one. * feat(SDK-363): expose registerDeviceToken in React Native bridge - Add Iterable.registerDeviceToken(token) public API - Add IterableApi.registerDeviceToken bridge proxy - Add TurboModule spec entry in NativeRNIterableAPI.ts - Add iOS Swift/Obj-C++ glue with hex-to-Data conversion for APNS tokens - Add Android impl + old/new architecture stubs for FCM token pass-through - Update MockRNIterableAPI and unit tests - Add CHANGELOG entry under Unreleased * chore: update .gitignore * fix(iOS): guard registerDeviceToken hex token parsing for empty/odd-length strings --------- Co-authored-by: Joao Dordio <joaodordio@icloud.com>
1 parent 5c4690c commit 37673e3

15 files changed

Lines changed: 125 additions & 5 deletions

File tree

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,9 @@ docs/
9494
# Local Netlify folder
9595
.netlify
9696
.metals/
97+
98+
# Agents
99+
.agent/
100+
.claude/
101+
.cursor/
102+
.pi/

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## Unreleased
2+
3+
### Updates
4+
5+
- Added `Iterable.registerDeviceToken(token)` to re-enable push for the current device.
6+
- Android accepts an FCM token string.
7+
- iOS accepts a continuous hex string representation of the APNS token.
8+
19
## 3.0.1
210

311
### Updates
@@ -402,4 +410,3 @@ To use this version of Iterable's React Native SDK, you'll need to update your n
402410
```java
403411
IterableApi.setContext(this);
404412
```
405-

android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,11 @@ public void disableDeviceForCurrentUser() {
373373
IterableApi.getInstance().disablePush();
374374
}
375375

376+
public void registerDeviceToken(String token) {
377+
IterableLogger.v(TAG, "registerDeviceToken");
378+
IterableApi.getInstance().registerDeviceToken(token);
379+
}
380+
376381
public void handleAppLink(String uri, Promise promise) {
377382
IterableLogger.printInfo();
378383
promise.resolve(IterableApi.getInstance().handleAppLink(uri));

android/src/newarch/java/com/RNIterableAPIModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ public void disableDeviceForCurrentUser() {
137137
moduleImpl.disableDeviceForCurrentUser();
138138
}
139139

140+
@Override
141+
public void registerDeviceToken(String token) {
142+
moduleImpl.registerDeviceToken(token);
143+
}
144+
140145
@Override
141146
public void handleAppLink(String uri, Promise promise) {
142147
moduleImpl.handleAppLink(uri, promise);

android/src/oldarch/java/com/RNIterableAPIModule.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ public void disableDeviceForCurrentUser() {
138138
moduleImpl.disableDeviceForCurrentUser();
139139
}
140140

141+
@ReactMethod
142+
public void registerDeviceToken(String token) {
143+
moduleImpl.registerDeviceToken(token);
144+
}
145+
141146
@ReactMethod
142147
public void handleAppLink(String uri, Promise promise) {
143148
moduleImpl.handleAppLink(uri, promise);

example/ios/ReactNativeSdkExample.xcodeproj/project.pbxproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
77E3B5772EA71A4B001449CE /* IterableJwtGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77E3B5742EA71A4B001449CE /* IterableJwtGenerator.swift */; };
1414
77E3B5782EA71A4B001449CE /* JwtTokenModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = 77E3B5752EA71A4B001449CE /* JwtTokenModule.mm */; };
1515
77E3B5792EA71A4B001449CE /* JwtTokenModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77E3B5762EA71A4B001449CE /* JwtTokenModule.swift */; };
16-
7C8CB9778D44155D232C3690 /* libPods-ReactNativeSdkExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8A71BC6B8F9B2B3CF98A77 /* libPods-ReactNativeSdkExample.a */; };
1716
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
1817
A3A40C20801B8F02005FA4C0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 1FC6B09E65A7BD9F6864C5D8 /* PrivacyInfo.xcprivacy */; };
1918
DDD9C96E1785FEF10EEE61A5 /* libPods-ReactNativeSdkExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 627B7C7165CE568DB5CB8F50 /* libPods-ReactNativeSdkExample.a */; };
@@ -439,7 +438,7 @@
439438
"-ObjC",
440439
"-lc++",
441440
);
442-
PRODUCT_BUNDLE_IDENTIFIER = iterable.reactnativesdk.example;
441+
PRODUCT_BUNDLE_IDENTIFIER = com.iterable.reactnativesdk.example;
443442
PRODUCT_NAME = ReactNativeSdkExample;
444443
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
445444
SWIFT_OBJC_BRIDGING_HEADER = "ReactNativeSdkExample-Bridging-Header.h";
@@ -470,7 +469,7 @@
470469
"-ObjC",
471470
"-lc++",
472471
);
473-
PRODUCT_BUNDLE_IDENTIFIER = iterable.reactnativesdk.example;
472+
PRODUCT_BUNDLE_IDENTIFIER = com.iterable.reactnativesdk.example;
474473
PRODUCT_NAME = ReactNativeSdkExample;
475474
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
476475
SWIFT_OBJC_BRIDGING_HEADER = "ReactNativeSdkExample-Bridging-Header.h";
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
33
<plist version="1.0">
4-
<dict/>
4+
<dict>
5+
<key>aps-environment</key>
6+
<string>development</string>
7+
</dict>
58
</plist>

ios/RNIterableAPI/RNIterableAPI.mm

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ - (void)disableDeviceForCurrentUser {
230230
[_swiftAPI disableDeviceForCurrentUser];
231231
}
232232

233+
- (void)registerDeviceToken:(NSString *)token {
234+
[_swiftAPI registerDeviceToken:token];
235+
}
236+
233237
- (void)getLastPushPayload:(RCTPromiseResolveBlock)resolve
234238
reject:(RCTPromiseRejectBlock)reject {
235239
[_swiftAPI getLastPushPayload:resolve rejecter:reject];
@@ -512,6 +516,10 @@ - (void)wakeApp {
512516
[_swiftAPI disableDeviceForCurrentUser];
513517
}
514518

519+
RCT_EXPORT_METHOD(registerDeviceToken : (NSString *)token) {
520+
[_swiftAPI registerDeviceToken:token];
521+
}
522+
515523
RCT_EXPORT_METHOD(getLastPushPayload : (RCTPromiseResolveBlock)
516524
resolve reject : (RCTPromiseRejectBlock)reject) {
517525
[_swiftAPI getLastPushPayload:resolve rejecter:reject];

ios/RNIterableAPI/ReactIterableAPI.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ import React
144144
IterableAPI.disableDeviceForCurrentUser()
145145
}
146146

147+
@objc(registerDeviceToken:)
148+
public func registerDeviceToken(token: String) {
149+
ITBInfo()
150+
guard let tokenData = data(fromHex: token) else {
151+
ITBError("Could not convert token to Data: invalid hex string")
152+
return
153+
}
154+
IterableAPI.register(token: tokenData)
155+
}
156+
147157
@objc(getLastPushPayload:rejecter:)
148158
public func getLastPushPayload(resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock)
149159
{
@@ -599,6 +609,19 @@ import React
599609

600610
private let inboxSessionManager = InboxSessionManager()
601611

612+
private func data(fromHex hex: String) -> Data? {
613+
guard !hex.isEmpty, hex.count.isMultiple(of: 2) else { return nil }
614+
var data = Data(capacity: hex.count / 2)
615+
var chars = hex.makeIterator()
616+
while let high = chars.next(), let low = chars.next() {
617+
guard let highValue = high.hexDigitValue, let lowValue = low.hexDigitValue else {
618+
return nil
619+
}
620+
data.append(UInt8(highValue << 4 | lowValue))
621+
}
622+
return data
623+
}
624+
602625
@objc func initialize(
603626
withApiKey apiKey: String,
604627
config configDict: NSDictionary,

src/__mocks__/MockRNIterableAPI.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export class MockRNIterableAPI {
3434

3535
static disableDeviceForCurrentUser = jest.fn();
3636

37+
static registerDeviceToken = jest.fn((token: string): void => {
38+
MockRNIterableAPI.token = token;
39+
});
40+
3741
static trackPushOpenWithCampaignId = jest.fn();
3842

3943
static updateCart = jest.fn();

0 commit comments

Comments
 (0)