diff --git a/CHANGELOG.md b/CHANGELOG.md index 0336d6cf8..476661592 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 2.2.0-alpha.2 + +### Updates +* Changed `onJWTError` to `onJwtError` +* Changed `IterableRetryBackoff` enum keys to be lowercase for consistency + across application + +### Fixes +* Fixed Android `retryInterval` not being updated on re-initialization. + ## 2.2.0-alpha.1 ### Updates @@ -6,7 +16,6 @@ ### Fixes * [SDK-151] Fixed "cannot read property authtoken of undefined" error - ## 2.2.0-alpha.0 ### Updates diff --git a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java index 57cf9a0b8..98340a1f7 100644 --- a/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java +++ b/android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java @@ -24,6 +24,7 @@ import com.iterable.iterableapi.IterableActionContext; import com.iterable.iterableapi.IterableApi; import com.iterable.iterableapi.IterableAuthHandler; +import com.iterable.iterableapi.IterableAuthManager; import com.iterable.iterableapi.IterableConfig; import com.iterable.iterableapi.IterableCustomActionHandler; import com.iterable.iterableapi.IterableAttributionInfo; @@ -88,7 +89,36 @@ public void initializeWithApiKey(String apiKey, ReadableMap configReadableMap, S configBuilder.setAuthHandler(this); } - IterableApi.initialize(reactContext, apiKey, configBuilder.build()); + IterableConfig config = configBuilder.build(); + IterableApi.initialize(reactContext, apiKey, config); + + // Update retry policy on existing authManager if it was already created + // This fixes the issue where retryInterval is not respected after + // re-initialization + // TODO [SDK-197]: Fix the root cause of this issue, instead of this hack + try { + // Use reflection to access package-private fields and methods + java.lang.reflect.Field configRetryPolicyField = config.getClass().getDeclaredField("retryPolicy"); + configRetryPolicyField.setAccessible(true); + Object retryPolicy = configRetryPolicyField.get(config); + + if (retryPolicy != null) { + java.lang.reflect.Method getAuthManagerMethod = IterableApi.getInstance().getClass().getDeclaredMethod("getAuthManager"); + getAuthManagerMethod.setAccessible(true); + IterableAuthManager authManager = (IterableAuthManager) getAuthManagerMethod.invoke(IterableApi.getInstance()); + + if (authManager != null) { + // Update the retry policy field on the authManager + java.lang.reflect.Field authRetryPolicyField = authManager.getClass().getDeclaredField("authRetryPolicy"); + authRetryPolicyField.setAccessible(true); + authRetryPolicyField.set(authManager, retryPolicy); + IterableLogger.d(TAG, "Updated retry policy on existing authManager"); + } + } + } catch (Exception e) { + IterableLogger.e(TAG, "Failed to update retry policy: " + e.getMessage()); + } + IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); IterableApi.getInstance().getInAppManager().addListener(this); @@ -122,7 +152,36 @@ public void initialize2WithApiKey(String apiKey, ReadableMap configReadableMap, // override in the Android SDK. Check with @Ayyanchira and @evantk91 to // see what the best approach is. - IterableApi.initialize(reactContext, apiKey, configBuilder.build()); + IterableConfig config = configBuilder.build(); + IterableApi.initialize(reactContext, apiKey, config); + + // Update retry policy on existing authManager if it was already created + // This fixes the issue where retryInterval is not respected after + // re-initialization + // TODO [SDK-197]: Fix the root cause of this issue, instead of this hack + try { + // Use reflection to access package-private fields and methods + java.lang.reflect.Field configRetryPolicyField = config.getClass().getDeclaredField("retryPolicy"); + configRetryPolicyField.setAccessible(true); + Object retryPolicy = configRetryPolicyField.get(config); + + if (retryPolicy != null) { + java.lang.reflect.Method getAuthManagerMethod = IterableApi.getInstance().getClass().getDeclaredMethod("getAuthManager"); + getAuthManagerMethod.setAccessible(true); + IterableAuthManager authManager = (IterableAuthManager) getAuthManagerMethod.invoke(IterableApi.getInstance()); + + if (authManager != null) { + // Update the retry policy field on the authManager + java.lang.reflect.Field authRetryPolicyField = authManager.getClass().getDeclaredField("authRetryPolicy"); + authRetryPolicyField.setAccessible(true); + authRetryPolicyField.set(authManager, retryPolicy); + IterableLogger.d(TAG, "Updated retry policy on existing authManager"); + } + } + } catch (Exception e) { + IterableLogger.e(TAG, "Failed to update retry policy: " + e.getMessage()); + } + IterableApi.getInstance().setDeviceAttribute("reactNativeSDKVersion", version); IterableApi.getInstance().getInAppManager().addListener(this); diff --git a/example/src/hooks/useIterableApp.tsx b/example/src/hooks/useIterableApp.tsx index 9f72f0cf8..0022fdb4c 100644 --- a/example/src/hooks/useIterableApp.tsx +++ b/example/src/hooks/useIterableApp.tsx @@ -89,6 +89,8 @@ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const getIsEmail = (id: string) => EMAIL_REGEX.test(id); +let lastTimeStamp = 0; + export const IterableAppProvider: FunctionComponent< React.PropsWithChildren > = ({ children }) => { @@ -141,9 +143,7 @@ export const IterableAppProvider: FunctionComponent< const initialize = useCallback( (navigation: Navigation) => { - if (getUserId()) { - login(); - } + logout(); const config = new IterableConfig(); @@ -151,7 +151,7 @@ export const IterableAppProvider: FunctionComponent< config.retryPolicy = { maxRetry: 5, - retryInterval: 10, + retryInterval: 5, retryBackoff: IterableRetryBackoff.linear, }; @@ -199,8 +199,16 @@ export const IterableAppProvider: FunctionComponent< process.env.ITBL_JWT_SECRET ) { config.authHandler = async () => { + console.group('authHandler'); + const now = Date.now(); + if (lastTimeStamp !== 0) { + console.log('Time since last call:', now - lastTimeStamp); + } + lastTimeStamp = now; + console.groupEnd(); + + // return 'InvalidToken'; // Uncomment this to test the failure callback const token = await getJwtToken(); - // return 'SomethingNotValid'; // Uncomment this to test the failure callback return token; }; } @@ -219,6 +227,10 @@ export const IterableAppProvider: FunctionComponent< .then((isSuccessful) => { setIsInitialized(isSuccessful); + if (isSuccessful && getUserId()) { + return login(); + } + if (!isSuccessful) { return Promise.reject('`Iterable.initialize` failed'); } @@ -242,6 +254,8 @@ export const IterableAppProvider: FunctionComponent< const logout = useCallback(() => { Iterable.setEmail(null); Iterable.setUserId(null); + Iterable.logout(); + lastTimeStamp = 0; setIsLoggedIn(false); }, []);