diff --git a/ios/RNMParticle/RNMPRokt.mm b/ios/RNMParticle/RNMPRokt.mm index fbae339..b7cc060 100644 --- a/ios/RNMParticle/RNMPRokt.mm +++ b/ios/RNMParticle/RNMPRokt.mm @@ -19,6 +19,7 @@ #import #import #import +#import #import "RoktEventManager.h" #ifdef RCT_NEW_ARCH_ENABLED @@ -26,6 +27,25 @@ #import #endif // RCT_NEW_ARCH_ENABLED +// os_log for [mParticle-Rokt] diagnostics: visible in production (Console.app, device logs) +// and does not trigger RCT LogBox/warning UI in debug. +static os_log_t _rokt_os_log(void) { + static os_log_t log; + static dispatch_once_t once; + dispatch_once(&once, ^{ + log = os_log_create("com.mparticle.react-native", "rokt"); + }); + return log; +} + +static void _rokt_log(NSString *format, ...) { + va_list args; + va_start(args, format); + NSString *msg = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + os_log_with_type(_rokt_os_log(), OS_LOG_TYPE_INFO, "%{public}s", [msg UTF8String]); +} + @interface RNMPRokt () @property (nonatomic, nullable) RoktEventManager *eventManager; @@ -43,11 +63,15 @@ + (NSString *)moduleName { } + (void)load { + _rokt_log(@"[mParticle-Rokt] RNMPRokt module load"); RCTRegisterModule(self); } - (dispatch_queue_t)methodQueue { + BOOL bridgeNil = (self.bridge == nil); + BOOL uiManagerNil = (self.bridge.uiManager == nil); + _rokt_log(@"[mParticle-Rokt] methodQueue called, bridge %@, uiManager %@", bridgeNil ? @"nil" : @"non-nil", uiManagerNil ? @"nil" : @"non-nil"); return self.bridge.uiManager.methodQueue; } @@ -65,8 +89,10 @@ - (void)setMethodQueue:(dispatch_queue_t)methodQueue static NSDictionary * __attribute__((optnone)) safeExtractRoktConfigDict( JS::NativeMPRokt::RoktConfigType &roktConfig) { if (&roktConfig == nullptr) { + _rokt_log(@"[mParticle-Rokt] safeExtractRoktConfigDict: roktConfig ref is nullptr, returning nil"); return nil; } + _rokt_log(@"[mParticle-Rokt] safeExtractRoktConfigDict: extracting config"); NSMutableDictionary *roktConfigDict = [[NSMutableDictionary alloc] init]; if (roktConfig.cacheConfig().has_value()) { NSMutableDictionary *cacheConfigDict = [[NSMutableDictionary alloc] init]; @@ -78,7 +104,11 @@ - (void)setMethodQueue:(dispatch_queue_t)methodQueue cacheConfigDict[@"cacheAttributes"] = cacheConfig.cacheAttributes(); } roktConfigDict[@"cacheConfig"] = cacheConfigDict; + _rokt_log(@"[mParticle-Rokt] safeExtractRoktConfigDict: cacheConfig present, keys: %lu", (unsigned long)roktConfigDict.count); + } else { + _rokt_log(@"[mParticle-Rokt] safeExtractRoktConfigDict: cacheConfig has no value"); } + _rokt_log(@"[mParticle-Rokt] safeExtractRoktConfigDict: returning dict with %lu keys", (unsigned long)roktConfigDict.count); return roktConfigDict; } @@ -89,6 +119,7 @@ - (void)selectPlacements:(NSString *)identifer roktConfig:(JS::NativeMPRokt::RoktConfigType &)roktConfig fontFilesMap:(NSDictionary *)fontFilesMap { + _rokt_log(@"[mParticle-Rokt] New Architecture Implementation"); NSMutableDictionary *finalAttributes = [self convertToMutableDictionaryOfStrings:attributes]; NSDictionary *roktConfigDict = safeExtractRoktConfigDict(roktConfig); @@ -97,51 +128,73 @@ - (void)selectPlacements:(NSString *)identifer // Old Architecture Implementation RCT_EXPORT_METHOD(selectPlacements:(NSString *) identifer attributes:(NSDictionary *)attributes placeholders:(NSDictionary * _Nullable)placeholders roktConfig:(NSDictionary * _Nullable)roktConfig fontFilesMap:(NSDictionary * _Nullable)fontFilesMap) { + _rokt_log(@"[mParticle-Rokt] Old Architecture Implementation"); NSMutableDictionary *finalAttributes = [self convertToMutableDictionaryOfStrings:attributes]; MPRoktConfig *config = [self buildRoktConfigFromDict:roktConfig]; #endif + _rokt_log(@"[mParticle-Rokt] selectPlacements called with identifier: %@, attributes count: %lu", identifer, (unsigned long)finalAttributes.count); + [MParticle _setWrapperSdk_internal:MPWrapperSdkReactNative version:@""]; // Create callback implementation MPRoktEventCallback *callbacks = [[MPRoktEventCallback alloc] init]; - __weak __typeof__(self) weakSelf = self; callbacks.onLoad = ^{ - [self.eventManager onRoktCallbackReceived:@"onLoad"]; + _rokt_log(@"[mParticle-Rokt] onLoad"); + [weakSelf.eventManager onRoktCallbackReceived:@"onLoad"]; }; callbacks.onUnLoad = ^{ - [self.eventManager onRoktCallbackReceived:@"onUnLoad"]; - RCTLogInfo(@"unloaded"); + _rokt_log(@"[mParticle-Rokt] onUnLoad"); + [weakSelf.eventManager onRoktCallbackReceived:@"onUnLoad"]; }; callbacks.onShouldShowLoadingIndicator = ^{ - [self.eventManager onRoktCallbackReceived:@"onShouldShowLoadingIndicator"]; + _rokt_log(@"[mParticle-Rokt] onShouldShowLoadingIndicator"); + [weakSelf.eventManager onRoktCallbackReceived:@"onShouldShowLoadingIndicator"]; }; callbacks.onShouldHideLoadingIndicator = ^{ - [self.eventManager onRoktCallbackReceived:@"onShouldHideLoadingIndicator"]; + _rokt_log(@"[mParticle-Rokt] onShouldHideLoadingIndicator"); + [weakSelf.eventManager onRoktCallbackReceived:@"onShouldHideLoadingIndicator"]; }; callbacks.onEmbeddedSizeChange = ^(NSString *placementId, CGFloat height) { - [self.eventManager onWidgetHeightChanges:height placement:placementId]; + _rokt_log(@"[mParticle-Rokt] onEmbeddedSizeChange"); + [weakSelf.eventManager onWidgetHeightChanges:height placement:placementId]; }; - if (self.bridge == nil || self.bridge.uiManager == nil) { - NSLog(@"[mParticle-Rokt] addUIBlock skipped: self.bridge%@ is nil. selectPlacements will not be called. This can occur in New Architecture bridgeless production builds.", self.bridge == nil ? @"" : @".uiManager"); + BOOL bridgeNil = (self.bridge == nil); + BOOL uiManagerNil = (self.bridge.uiManager == nil); + _rokt_log(@"[mParticle-Rokt] bridge %@, uiManager %@", bridgeNil ? @"nil" : @"non-nil", uiManagerNil ? @"nil" : @"non-nil"); + + if (bridgeNil || uiManagerNil) { + _rokt_log(@"[mParticle-Rokt] addUIBlock skipped: self.bridge%@ is nil. selectPlacements will not be called. This can occur in New Architecture bridgeless production builds.", bridgeNil ? @"" : @".uiManager"); + } else { + _rokt_log(@"[mParticle-Rokt] queuing addUIBlock for identifier: %@", identifer); } [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - NSMutableDictionary *nativePlaceholders = [self getNativePlaceholders:placeholders viewRegistry:viewRegistry]; + __strong __typeof__(weakSelf) strongSelf = weakSelf; + _rokt_log(@"[mParticle-Rokt] addUIBlock executing for identifier: %@, viewRegistry count: %lu", identifer, (unsigned long)viewRegistry.count); - [self subscribeViewEvents:identifer]; + NSMutableDictionary *nativePlaceholders = strongSelf ? [strongSelf getNativePlaceholders:placeholders viewRegistry:viewRegistry] : [NSMutableDictionary dictionary]; + + if (strongSelf) { + [strongSelf subscribeViewEvents:identifer]; + } + id mpInstance = [MParticle sharedInstance]; + id roktKit = mpInstance ? [mpInstance rokt] : nil; + _rokt_log(@"[mParticle-Rokt] MParticle sharedInstance %@, rokt kit %@", mpInstance ? @"non-nil" : @"nil", roktKit ? @"non-nil" : @"nil"); + _rokt_log(@"[mParticle-Rokt] calling mParticle Core selectPlacements for: %@", identifer); [[[MParticle sharedInstance] rokt] selectPlacements:identifer attributes:finalAttributes embeddedViews:nativePlaceholders config:config callbacks:callbacks]; }]; + _rokt_log(@"[mParticle-Rokt] addUIBlock enqueued for identifier: %@", identifer); } RCT_EXPORT_METHOD(purchaseFinalized : (NSString *)placementId catalogItemId : ( @@ -180,6 +233,7 @@ - (MPColorMode)stringToColorMode:(NSString*)colorString } - (MPRoktConfig *)buildRoktConfigFromDict:(NSDictionary *)configMap { + _rokt_log(@"[mParticle-Rokt] buildRoktConfigFromDict: configMap %@", configMap == nil ? @"nil" : [NSString stringWithFormat:@"non-nil (%lu keys)", (unsigned long)configMap.count]); MPRoktConfig *config = [[MPRoktConfig alloc] init]; BOOL isConfigEmpty = YES; @@ -212,11 +266,13 @@ - (MPRoktConfig *)buildRoktConfigFromDict:(NSDictionary *)config config.cacheDuration = cacheDuration; } + _rokt_log(@"[mParticle-Rokt] buildRoktConfigFromDict: returning %@", isConfigEmpty ? @"nil" : @"config"); return isConfigEmpty ? nil : config; } - (void)subscribeViewEvents:(NSString* _Nonnull) viewName { + _rokt_log(@"[mParticle-Rokt] subscribeViewEvents for viewName: %@", viewName); if (self.eventManager == nil) { self.eventManager = [RoktEventManager allocWithZone: nil]; } @@ -227,6 +283,7 @@ - (void)subscribeViewEvents:(NSString* _Nonnull) viewName - (NSMutableDictionary *)getNativePlaceholders:(NSDictionary *)placeholders viewRegistry:(NSDictionary *)viewRegistry { + _rokt_log(@"[mParticle-Rokt] getNativePlaceholders: placeholders %lu, viewRegistry %lu", (unsigned long)placeholders.count, (unsigned long)viewRegistry.count); NSMutableDictionary *nativePlaceholders = [[NSMutableDictionary alloc]initWithCapacity:placeholders.count]; for(id key in placeholders){ @@ -248,12 +305,14 @@ - (NSMutableDictionary *)getNativePlaceholders:(NSDictionary *)placeholders view #endif // RCT_NEW_ARCH_ENABLED } + _rokt_log(@"[mParticle-Rokt] getNativePlaceholders: resolved %lu native placeholder(s)", (unsigned long)nativePlaceholders.count); return nativePlaceholders; } #ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params { self.bridge = params.instance.bridge; + _rokt_log(@"[mParticle-Rokt] getTurboModule: bridge set to %@", self.bridge == nil ? @"nil" : @"non-nil"); return std::make_shared(params); } #endif // RCT_NEW_ARCH_ENABLED diff --git a/ios/RNMParticle/RoktEventManager.m b/ios/RNMParticle/RoktEventManager.m index 5369324..a9b211a 100644 --- a/ios/RNMParticle/RoktEventManager.m +++ b/ios/RNMParticle/RoktEventManager.m @@ -1,5 +1,23 @@ #import "RoktEventManager.h" #import +#import + +static os_log_t _rokt_events_os_log(void) { + static os_log_t log; + static dispatch_once_t once; + dispatch_once(&once, ^{ + log = os_log_create("com.mparticle.react-native", "rokt-events"); + }); + return log; +} + +static void _rokt_events_log(NSString *format, ...) { + va_list args; + va_start(args, format); + NSString *msg = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + os_log_with_type(_rokt_events_os_log(), OS_LOG_TYPE_INFO, "%{public}s", [msg UTF8String]); +} @implementation RoktEventManager { @@ -13,17 +31,20 @@ + (id)allocWithZone:(NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [super allocWithZone:zone]; + _rokt_events_log(@"[mParticle-Rokt] RoktEventManager module alloc"); }); return sharedInstance; } // Will be called when this module's first listener is added. -(void)startObserving { + _rokt_events_log(@"[mParticle-Rokt] RoktEventManager startObserving (JS listener added)"); hasListeners = YES; } // Will be called when this module's last listener is removed, or on dealloc. -(void)stopObserving { + _rokt_events_log(@"[mParticle-Rokt] RoktEventManager stopObserving (no JS listeners)"); hasListeners = NO; } @@ -51,6 +72,7 @@ - (void)onFirstPositiveResponse - (void)onRoktCallbackReceived:(NSString*)eventValue { + _rokt_events_log(@"[mParticle-Rokt] RoktEventManager onRoktCallbackReceived: %@", eventValue ?: @"(nil)"); if (hasListeners) { [self sendEventWithName:@"RoktCallback" body:@{@"callbackValue": eventValue}]; } @@ -58,6 +80,8 @@ - (void)onRoktCallbackReceived:(NSString*)eventValue - (void)onRoktEvents:(MPRoktEvent * _Nonnull)event viewName:(NSString * _Nullable)viewName { + NSString *eventClass = event ? NSStringFromClass([event class]) : @"nil"; + _rokt_events_log(@"[mParticle-Rokt] RoktEventManager onRoktEvents: %@ viewName: %@", eventClass, viewName ?: @"(nil)"); if (hasListeners) { NSString *placementId; NSString *eventName = @"";