Skip to content

Commit 801570e

Browse files
authored
Merge pull request #799 from Iterable/loren/embedded/SDK-231-ios-add-click-handling-and-track
[SDK-231] Add click handling tracking
2 parents 052450a + 6cf7edb commit 801570e

2 files changed

Lines changed: 62 additions & 0 deletions

File tree

ios/RNIterableAPI/RNIterableAPI.mm

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#if RCT_NEW_ARCH_ENABLED
44
#import "RNIterableAPISpec.h"
5+
#import <string>
56
#endif
67

78
#import <IterableSDK/IterableSDK.h>
@@ -303,6 +304,30 @@ - (void)pauseEmbeddedImpression:(NSString *)messageId {
303304
[_swiftAPI pauseEmbeddedImpression:messageId];
304305
}
305306

307+
- (void)trackEmbeddedClick:(JS::NativeRNIterableAPI::EmbeddedMessage &)message
308+
buttonId:(NSString *_Nullable)buttonId
309+
clickedUrl:(NSString *_Nullable)clickedUrl {
310+
// The TurboModule bridge requires us to use the C++ type in the signature,
311+
// but we need to convert it to NSDictionary to pass to Swift.
312+
// The C++ struct wraps an NSDictionary, and the generated methods already
313+
// return NSString*/NSNumber* types, so we just need to reconstruct the dict.
314+
NSMutableDictionary *messageDict = [NSMutableDictionary new];
315+
316+
// Convert metadata (the accessor methods already return proper ObjC types)
317+
NSMutableDictionary *metadataDict = [NSMutableDictionary new];
318+
metadataDict[@"messageId"] = message.metadata().messageId();
319+
metadataDict[@"placementId"] = @(message.metadata().placementId());
320+
if (message.metadata().campaignId().has_value()) {
321+
metadataDict[@"campaignId"] = @(*message.metadata().campaignId());
322+
}
323+
if (message.metadata().isProof().has_value()) {
324+
metadataDict[@"isProof"] = @(*message.metadata().isProof());
325+
}
326+
messageDict[@"metadata"] = metadataDict;
327+
328+
[_swiftAPI trackEmbeddedClick:messageDict buttonId:buttonId clickedUrl:clickedUrl];
329+
}
330+
306331
- (void)wakeApp {
307332
// Placeholder function -- this method is only used in Android
308333
}
@@ -557,6 +582,10 @@ - (void)wakeApp {
557582
[_swiftAPI pauseEmbeddedImpression:messageId];
558583
}
559584

585+
RCT_EXPORT_METHOD(trackEmbeddedClick : (NSDictionary *)message buttonId : (NSString *_Nullable)buttonId clickedUrl : (NSString *_Nullable)clickedUrl) {
586+
[_swiftAPI trackEmbeddedClick:message buttonId:buttonId clickedUrl:clickedUrl];
587+
}
588+
560589
RCT_EXPORT_METHOD(wakeApp) {
561590
// Placeholder function -- this method is only used in Android
562591
}

ios/RNIterableAPI/ReactIterableAPI.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,39 @@ import React
549549
EmbeddedSessionManager.shared.pauseImpression(messageId: messageId)
550550
}
551551

552+
@objc(trackEmbeddedClick:buttonId:clickedUrl:)
553+
public func trackEmbeddedClick(
554+
message: NSDictionary, buttonId: String?, clickedUrl: String?
555+
) {
556+
ITBInfo()
557+
558+
// Extract message ID from the dictionary
559+
guard let messageDict = message as? [AnyHashable: Any],
560+
let metadataDict = messageDict["metadata"] as? [AnyHashable: Any],
561+
let messageId = metadataDict["messageId"] as? String else {
562+
ITBError("Could not extract messageId from message dictionary")
563+
return
564+
}
565+
566+
// Find the message in the embedded manager's cache
567+
let messages = IterableAPI.embeddedManager.getMessages()
568+
guard let embeddedMessage = messages.first(where: { $0.metadata.messageId == messageId }) else {
569+
ITBError("Could not find embedded message with id: \(messageId)")
570+
return
571+
}
572+
573+
guard let clickedUrl = clickedUrl else {
574+
ITBError("clickedUrl is required for trackEmbeddedClick")
575+
return
576+
}
577+
578+
IterableAPI.track(
579+
embeddedMessageClick: embeddedMessage,
580+
buttonIdentifier: buttonId,
581+
clickedUrl: clickedUrl
582+
)
583+
}
584+
552585
// MARK: Private
553586
private var shouldEmit = false
554587
private let _methodQueue = DispatchQueue(label: String(describing: ReactIterableAPI.self))

0 commit comments

Comments
 (0)