diff --git a/.gitignore b/.gitignore index 39e2442f..302d1ee4 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ local.properties node_modules *.log .nvm +package-lock.json # OS X .DS_Store diff --git a/README.md b/README.md index aed59e75..3f14e4df 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ GoogleTagManager.registerFunctionCallTagHandler( // functionName is passed for convenience. In this example it will be equal to "some_function". // tagArguments is an object and is populated based on Tag configuration in TagManager interface. console.log("Handling Function Call tag:", functionName); - } + } ) ``` diff --git a/android/src/main/java/com/idehub/GoogleAnalyticsBridge/GoogleTagManagerBridge.java b/android/src/main/java/com/idehub/GoogleAnalyticsBridge/GoogleTagManagerBridge.java index 8ec13a35..bc6e3b69 100644 --- a/android/src/main/java/com/idehub/GoogleAnalyticsBridge/GoogleTagManagerBridge.java +++ b/android/src/main/java/com/idehub/GoogleAnalyticsBridge/GoogleTagManagerBridge.java @@ -80,6 +80,16 @@ public void onResult(ContainerHolder containerHolder) { }, 2000, TimeUnit.MILLISECONDS); } + @ReactMethod + public void refreshContainer(final Promise promise){ + if (mContainerHolder != null && mContainerHolder.getContainer() != null) { + mContainerHolder.refresh(); + promise.resolve(true); + } else { + promise.reject(E_CONTAINER_NOT_OPENED, new Throwable("The container has not been opened. You must call openContainerWithId(..)")); + } + } + @ReactMethod public void booleanForKey(final String key, final Promise promise){ if (mContainerHolder != null && mContainerHolder.getContainer() != null) { diff --git a/ios/RCTGoogleAnalyticsBridge/RCTGoogleAnalyticsBridge/RCTGoogleTagManagerBridge.m b/ios/RCTGoogleAnalyticsBridge/RCTGoogleAnalyticsBridge/RCTGoogleTagManagerBridge.m index ee5ddac5..6dd8dea7 100644 --- a/ios/RCTGoogleAnalyticsBridge/RCTGoogleAnalyticsBridge/RCTGoogleTagManagerBridge.m +++ b/ios/RCTGoogleAnalyticsBridge/RCTGoogleAnalyticsBridge/RCTGoogleTagManagerBridge.m @@ -47,6 +47,18 @@ @implementation RCTGoogleTagManagerBridge notifier:self]; } +RCT_REMAP_METHOD(refreshContainer, + refreshContainerWithResolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + if (self.container != nil) { + [self.container refresh]; + resolve(@YES); + } else { + reject(E_CONTAINER_NOT_OPENED, nil, RCTErrorWithMessage(@"The container has not been opened. You must call openContainerWithId(..)")); + } +} + RCT_EXPORT_METHOD(stringForKey:(NSString *)key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) @@ -123,8 +135,10 @@ @implementation RCTGoogleTagManagerBridge - (void)containerAvailable:(TAGContainer *)container { dispatch_async(_methodQueue, ^{ self.container = container; - self.openContainerResolver(@YES); - self.openContainerResolver = nil; + if (self.openContainerResolver) { + self.openContainerResolver(@YES); + self.openContainerResolver = nil; + } }); } diff --git a/src/GoogleTagManager.ts b/src/GoogleTagManager.ts index 25c01814..eba179da 100644 --- a/src/GoogleTagManager.ts +++ b/src/GoogleTagManager.ts @@ -24,6 +24,18 @@ class GoogleTagManager { return TagManagerBridge.openContainerWithId(containerId); } + /** + * Refreshes the GTM container. + * According to Tag Manager documentations for Android can be called once every 15 minutes. + * No such limitations has been mentioned for iOS containers, though. + * @example + * GoogleTagManager.refreshContainer().then((..) => ..) + * @returns {Promise} + */ + static refreshContainer(): Promise { + return TagManagerBridge.refreshContainer(); + } + /** * Retrieves a boolean value with the given key from the opened container. * @example GoogleTagManager.boolForKey("key").then(val => console.log(val)); diff --git a/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerAndroid.ts b/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerAndroid.ts index 95f8ba24..4fd51493 100644 --- a/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerAndroid.ts +++ b/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerAndroid.ts @@ -19,7 +19,15 @@ export default (functionName: string, handler: Handler): Promise => { return TagManagerBridge.registerFunctionCallTagHandler(functionName).then( () => { DeviceEventEmitter.addListener(event, payload => { - handler(functionName, payload); + try { + handler(functionName, payload); + } catch (e) { + console.error( + `Unhandled exception in FunctionCallTag handler: ${e.stack}`, + `\nFunction Name: ${functionName}`, + `\nPayload: ${JSON.stringify(payload)}` + ); + } }); return true; } diff --git a/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerIOS.ts b/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerIOS.ts index 6775303f..2ac19092 100644 --- a/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerIOS.ts +++ b/src/Helpers/FunctionCallTagHandler/FunctionCallTagHandlerIOS.ts @@ -22,9 +22,6 @@ const functionCallTagEventEmitter = new NativeEventEmitter(TagManagerBridge); const listeners: Array = []; let listenerRegistered = false; -// tagEventEmmiter is used to handle callbacks in JS -let jsEventEmitter; - export default (functionName: string, handler: Handler): Promise => { if (!listenerRegistered) { // Register a global listener for Function Tag events @@ -33,10 +30,17 @@ export default (functionName: string, handler: Handler): Promise => { ({ _fn, payload }) => { // Pass on the event to listeners // _fn is basically the same as functionName - jsEventEmitter.emit(_fn, payload); listeners.forEach(listener => { if (listener.functionName === _fn) { - handler(_fn, payload); + try { + handler(_fn, payload); + } catch (e) { + console.error( + `Unhandled exception in FunctionCallTag handler: ${e.stack}`, + `\nFunction Name: ${_fn}`, + `\nPayload: ${JSON.stringify(payload)}` + ); + } } }); } diff --git a/src/NativeBridges.ts b/src/NativeBridges.ts index 57ad0fc8..176e5dfe 100644 --- a/src/NativeBridges.ts +++ b/src/NativeBridges.ts @@ -67,6 +67,7 @@ export interface IGoogleAnalyticsBridge { export interface IGoogleTagManagerBridge extends EventSubscriptionVendor { openContainerWithId(containerId: string): Promise; + refreshContainer(): Promise; booleanForKey(key: string): Promise; stringForKey(key: string): Promise; doubleForKey(key: any): Promise;