From 773ccd6a7b6b15adb5c4bcd603f5bfd06711fcc8 Mon Sep 17 00:00:00 2001 From: Jason Praful Date: Fri, 10 Oct 2025 11:00:24 +0100 Subject: [PATCH 1/4] add manual SDK initialization --- README.md | 100 ++++++++++++++++-- .../reactnative/IntercomErrorCodes.java | 1 + android/src/newarch/IntercomModule.java | 17 +++ android/src/oldarch/IntercomModule.java | 17 +++ examples/expo-example/app.json | 4 +- examples/expo-example/app/(tabs)/index.tsx | 47 +++++++- .../expo-example/config/intercom.config.ts | 18 ++++ examples/expo-example/pnpm-lock.yaml | 2 +- ios/IntercomModule.m | 14 +++ package.json | 2 +- src/NativeIntercomSpec.ts | 1 + src/expo-plugins/@types.ts | 22 +++- src/expo-plugins/index.ts | 44 ++++---- src/index.tsx | 23 ++++ 14 files changed, 275 insertions(+), 37 deletions(-) create mode 100644 examples/expo-example/config/intercom.config.ts diff --git a/README.md b/README.md index 39dd3d79..a5a5a1a0 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ ## Installation ```sh -$ npm install @intercom/intercom-react-native +npm install @intercom/intercom-react-native ``` or @@ -61,7 +61,7 @@ If you're using React Native v0.60 or above, the library will be linked automati #### Android: Automatic linking with React Native v0.59 and below ``` -$ react-native link @intercom/intercom-react-native +react-native link @intercom/intercom-react-native ``` #### Android: Manual linking with React Native v0.59 and below @@ -81,6 +81,16 @@ implementation project(':intercom-react-native') #### Android: Setup +You have two options for initializing Intercom: + +**Option 1: Native Initialization (Recommended)** +Initialize at app startup in your native code for the best user experience. + +**Option 2: JavaScript Initialization** +Initialize manually from JavaScript for more control over timing. If you choose this option, skip the native initialization code below and see the [`initialize` method documentation](#intercomintializeapikey-appid) for implementation details. + +**For Native Initialization:** + - Add below lines to `android/app/src/main/java/com/YOUR_APP/app/MainApplication.java` inside `onCreate` method, replacing `apiKey` and `appId` which can be found in your [workspace settings](https://app.intercom.com/a/apps/_/settings/android). ```java @@ -340,6 +350,16 @@ See [How to manually link IOS Intercom SDK](docs/IOS-MANUAL-LINKING.md) #### iOS: Setup +You have two options for initializing Intercom: + +**Option 1: Native Initialization (Recommended)** +Initialize at app startup in your native code for the best user experience. + +**Option 2: JavaScript Initialization** +Initialize manually from JavaScript for more control over timing. If you choose this option, skip the native initialization code below and see the [`initialize` method documentation](#intercomintializeapikey-appid) for implementation details with platform-specific API key handling. + +**For Native Initialization:** + - Open `ios/AppDelegate.m` then add below code: - At the top of file add the following: @@ -359,7 +379,7 @@ See [How to manually link IOS Intercom SDK](docs/IOS-MANUAL-LINKING.md) // ... self.window.rootViewController = rootViewController; - [IntercomModule initialize:@"apiKey" withAppId:@"appId"]; // <-- Add this (Remember to replace strings with your api keys) + [IntercomModule initialize:@"apiKey" withAppId:@"appId"]; // <-- Add this return YES; } @@ -384,7 +404,7 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau .... } - ``` +``` #### iOS: Permissions @@ -518,6 +538,7 @@ The plugin provides props for extra customization. Every time you change the pro - `androidApiKey` (_string_): Android API Key from Intercom. - `iosApiKey` (_string_): iOS API Key from Intercom. - `intercomRegion` (_string_): Region for Intercom `US`, `EU`, `AU`. Optional. Defaults to `US`. +- `useManualInit` (_boolean_): Set to `true` to manually initialize Intercom from JavaScript instead of at app startup. Optional. Defaults to `false`. ```json { @@ -537,6 +558,41 @@ The plugin provides props for extra customization. Every time you change the pro } ``` +#### Manual Initialization with Expo + +If you want to delay Intercom initialization and manually initialize it from JavaScript, you set the `useManualInit` option to `true`: + +```json +{ + "expo": { + "plugins": [ + [ + "@intercom/intercom-react-native", + { + "useManualInit": true + } + ] + ] + } +} +``` + +Then initialize Intercom manually in your JavaScript code with the platform-specific API keys: + +```javascript +import Intercom from '@intercom/intercom-react-native'; +import { Platform } from 'react-native'; + +// You can find your API keys in your Intercom workspace settings +// https://app.intercom.com/a/apps//settings/channels/messenger/install?tab=ios +const apiKey = Platform.select({ + ios: 'ios_sdk-abc123', + android: 'android_sdk-abc123', +}); + +await Intercom.initialize(apiKey, 'abc123'); +``` + #### Expo: Push notifications Add the following configurations into your `app.json` or `app.config.js`: @@ -697,6 +753,36 @@ Sets the user hash necessary for validation when Identity Verification is enable --- +### `Intercom.initialize(apiKey, appId)` + +Initialize the Intercom SDK manually. This is useful when you want to delay initialization until after your app has started, or when using Expo with the `useManualInit` plugin option. + +### Options + +| Name | Type | Required | Description | +| ------ | ------ | -------- | --------------------------------------- | +| apiKey | string | yes | Your Platform-specific Intercom API key | +| appId | string | yes | Your Intercom App ID | + +### Examples + +```javascript +import { Platform } from 'react-native'; + +const apiKey = Platform.select({ + ios: 'ios_sdk-abc123', + android: 'android_sdk-xyz789', +}); + +await Intercom.initialize(apiKey, 'your_app_id'); +``` + +### Returns + +`Promise` + +--- + ### `Intercom.loginUnidentifiedUser()` Login a unidentified user. @@ -1223,9 +1309,9 @@ Data Connectors (e.g., Fin Actions), which use these in `Authorization: Bearer < ### Options -| Name | Type | Required | Description | -| ---------- | ------------------------------- | -------- | --------------------------------------------------- | -| authTokens | `{ [key: string]: string }` | yes | An object with token names as keys and JWT strings as values | +| Name | Type | Required | Description | +| ---------- | --------------------------- | -------- | ------------------------------------------------------------ | +| authTokens | `{ [key: string]: string }` | yes | An object with token names as keys and JWT strings as values | ### Example diff --git a/android/src/main/java/com/intercom/reactnative/IntercomErrorCodes.java b/android/src/main/java/com/intercom/reactnative/IntercomErrorCodes.java index 831b0987..7bde7b81 100644 --- a/android/src/main/java/com/intercom/reactnative/IntercomErrorCodes.java +++ b/android/src/main/java/com/intercom/reactnative/IntercomErrorCodes.java @@ -11,6 +11,7 @@ public class IntercomErrorCodes { public static final String GET_UNREAD_CONVERSATION = "108"; public static final String SET_USER_JWT = "109"; public static final String SET_AUTH_TOKENS = "110"; + public static final String INITIALIZE_ERROR = "111"; public static final String DISPLAY_MESSENGER = "201"; public static final String DISPLAY_MESSENGER_COMPOSER = "202"; public static final String DISPLAY_CONTENT = "203"; diff --git a/android/src/newarch/IntercomModule.java b/android/src/newarch/IntercomModule.java index 6784ead3..2ae7c4c6 100644 --- a/android/src/newarch/IntercomModule.java +++ b/android/src/newarch/IntercomModule.java @@ -626,6 +626,23 @@ public void onFailure(@NonNull IntercomError intercomError) { } } + @ReactMethod + public void initialize(String apiKey, String appId, Promise promise) { + try { + Activity activity = getCurrentActivity(); + if (activity != null) { + IntercomModule.initialize(activity.getApplication(), apiKey, appId); + promise.resolve(true); + } else { + promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, "Activity is null"); + } + } catch (Exception err) { + Log.e(NAME, "initialize error:"); + Log.e(NAME, err.toString()); + promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, err.toString()); + } + } + @ReactMethod public void setNeedsStatusBarAppearanceUpdate(Promise promise) { // iOS-only method, no-op on Android diff --git a/android/src/oldarch/IntercomModule.java b/android/src/oldarch/IntercomModule.java index 871b4ff8..e99e7a9e 100644 --- a/android/src/oldarch/IntercomModule.java +++ b/android/src/oldarch/IntercomModule.java @@ -603,6 +603,23 @@ public void onFailure(@NonNull IntercomError intercomError) { } } + @ReactMethod + public void initialize(String apiKey, String appId, Promise promise) { + try { + Activity activity = getCurrentActivity(); + if (activity != null) { + IntercomModule.initialize(activity.getApplication(), apiKey, appId); + promise.resolve(true); + } else { + promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, "Activity is null"); + } + } catch (Exception err) { + Log.e(NAME, "initialize error:"); + Log.e(NAME, err.toString()); + promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, err.toString()); + } + } + public static synchronized void initialize(Application application, String apiKey, String appId) { String sdkVersion = BuildConfig.INTERCOM_VERSION_NAME; ReactNativeHeaderInterceptor.setReactNativeVersion(application.getApplicationContext(), sdkVersion); diff --git a/examples/expo-example/app.json b/examples/expo-example/app.json index 8137891c..20f479c6 100644 --- a/examples/expo-example/app.json +++ b/examples/expo-example/app.json @@ -39,9 +39,7 @@ [ "@intercom/intercom-react-native", { - "appId": "YOUR_APP_ID", - "androidApiKey": "android_sdk-YOUR_ANDROID_API_KEY", - "iosApiKey": "ios_sdk-YOUR_IOS_API_KEY" + "useManualInit": true } ], "expo-router", diff --git a/examples/expo-example/app/(tabs)/index.tsx b/examples/expo-example/app/(tabs)/index.tsx index 968e543d..26e990c6 100644 --- a/examples/expo-example/app/(tabs)/index.tsx +++ b/examples/expo-example/app/(tabs)/index.tsx @@ -1,11 +1,13 @@ -import React from 'react'; -import { SafeAreaView, ScrollView, StatusBar } from 'react-native'; +import React, { useEffect, useState } from 'react'; +import { SafeAreaView, ScrollView, StatusBar, View, Text } from 'react-native'; import * as Notifications from 'expo-notifications'; import { useIntercom } from '../../hooks/useIntercom'; import { useNotifications } from '../../hooks/useNotifications'; +import { INTERCOM_CONFIG } from '../../config/intercom.config'; import Header from '../../components/Header'; +import Intercom from '@intercom/intercom-react-native'; import AuthenticationSection from '../../components/AuthenticationSection'; import MessagingSection from '../../components/MessagingSection'; import ContentSection from '../../components/ContentSection'; @@ -28,6 +30,33 @@ Notifications.setNotificationHandler({ export default function App() { const intercom = useIntercom(); const notifications = useNotifications(); + const [isInitialized, setIsInitialized] = useState(false); + const [initError, setInitError] = useState(null); + + useEffect(() => { + async function initializeIntercom() { + try { + console.log('Initializing Intercom...'); + if (!INTERCOM_CONFIG.apiKey || !INTERCOM_CONFIG.appId) { + console.error('Intercom API key and app ID are required'); + return; + } + if (!isInitialized) { + await Intercom.initialize( + INTERCOM_CONFIG.apiKey, + INTERCOM_CONFIG.appId + ); + setIsInitialized(true); + console.log('Intercom initialized successfully'); + } + } catch (error) { + console.error('Failed to initialize Intercom:', error); + setInitError(error instanceof Error ? error.message : 'Unknown error'); + } + } + + initializeIntercom(); + }, [isInitialized]); return ( @@ -41,6 +70,20 @@ export default function App() { /> + + + Intercom Status:{' '} + {initError && ( + Failed: {initError} + )} + {isInitialized ? ( + Initialized + ) : ( + Initializing... + )} + + + /settings/channels/messenger/install?tab=ios + * + * Note: iOS and Android require different API keys. + */ +export const INTERCOM_CONFIG = { + appId: '', // Replace with your Intercom App ID + apiKey: Platform.select({ + ios: 'ios_sdk-', // Replace with your iOS API key + android: 'android_sdk-', // Replace with your Android API key + }) as string, +}; diff --git a/examples/expo-example/pnpm-lock.yaml b/examples/expo-example/pnpm-lock.yaml index fcd0f448..2c8b6071 100644 --- a/examples/expo-example/pnpm-lock.yaml +++ b/examples/expo-example/pnpm-lock.yaml @@ -792,7 +792,7 @@ packages: '@intercom/intercom-react-native@file:../..': resolution: {directory: ../.., type: directory} - engines: {node: '>=18', yarn: '>=3'} + engines: {node: '>=18'} peerDependencies: react: '*' react-native: '*' diff --git a/ios/IntercomModule.m b/ios/IntercomModule.m index da8ba910..af690ed3 100644 --- a/ios/IntercomModule.m +++ b/ios/IntercomModule.m @@ -17,6 +17,7 @@ @implementation IntercomModule NSString *UNREAD_CONVERSATION_COUNT = @"107"; NSString *SET_USER_JWT = @"109"; NSString *SET_AUTH_TOKENS = @"110"; +NSString *INITIALIZE_ERROR = @"111"; NSString *SEND_TOKEN_TO_INTERCOM = @"302"; NSString *FETCH_HELP_CENTER_COLLECTIONS = @"901"; NSString *FETCH_HELP_CENTER_COLLECTION = @"902"; @@ -28,6 +29,19 @@ - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } +RCT_EXPORT_METHOD(initialize:(NSString *)apiKey + withAppId:(NSString *)appId + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { + @try { + [IntercomModule initialize:apiKey withAppId:appId]; + resolve(@(YES)); + } @catch (NSException *exception) { + NSLog(@"initialize error: %@", exception.reason); + reject(INITIALIZE_ERROR, @"Failed to initialize Intercom", [self exceptionToError:exception :INITIALIZE_ERROR :@"initialize"]); + } +} + + (void)initialize:(nonnull NSString *)apiKey withAppId:(nonnull NSString *)appId { NSString *version = @"0"; diff --git a/package.json b/package.json index 636f4898..ab68beaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@intercom/intercom-react-native", - "version": "9.1.2", + "version": "9.2.0", "description": "React Native wrapper to bridge our iOS and Android SDK", "source": "./src/index.tsx", "main": "./lib/commonjs/index.js", diff --git a/src/NativeIntercomSpec.ts b/src/NativeIntercomSpec.ts index 22babe5f..6f62da5f 100644 --- a/src/NativeIntercomSpec.ts +++ b/src/NativeIntercomSpec.ts @@ -27,6 +27,7 @@ interface TurboModuleContent { } export interface Spec extends TurboModule { + initialize(apiKey: string, appId: string): Promise; loginUnidentifiedUser(): Promise; loginUserWithUserAttributes(userAttributes: UserAttributes): Promise; logout(): Promise; diff --git a/src/expo-plugins/@types.ts b/src/expo-plugins/@types.ts index cfdda924..db1c377c 100644 --- a/src/expo-plugins/@types.ts +++ b/src/expo-plugins/@types.ts @@ -1,8 +1,24 @@ export type IntercomRegion = 'US' | 'EU' | 'AU'; -export type IntercomPluginProps = { +type BasePluginProps = { + /** Data hosting region for your Intercom workspace. Defaults to 'US' */ + intercomRegion?: IntercomRegion; +}; + +type AutoInitPluginProps = BasePluginProps & { + appId: string; iosApiKey: string; androidApiKey: string; - appId: string; - intercomRegion?: IntercomRegion; + useManualInit?: false | undefined; +}; + +type ManualInitPluginProps = BasePluginProps & { + /** + * When true, prevents automatic SDK initialization at app startup. + * You'll need to manually call Intercom.initialize() in your JavaScript code. + * All initialization parameters (apiKey and appId) should be provided at runtime. + */ + useManualInit: true; }; + +export type IntercomPluginProps = AutoInitPluginProps | ManualInitPluginProps; diff --git a/src/expo-plugins/index.ts b/src/expo-plugins/index.ts index 4678818a..894069b9 100644 --- a/src/expo-plugins/index.ts +++ b/src/expo-plugins/index.ts @@ -37,13 +37,15 @@ const mainApplication: ConfigPlugin = (_config, props) => '' ); - stringContents = appendContentsInsideDeclarationBlock( - stringContents, - 'onCreate', - `IntercomModule.initialize(this, "${props.androidApiKey}", "${ - props.appId - }")${config.modResults.language === 'java' ? ';' : ''}\n` - ); + if (!props.useManualInit) { + stringContents = appendContentsInsideDeclarationBlock( + stringContents, + 'onCreate', + `IntercomModule.initialize(this, "${props.androidApiKey}", "${ + props.appId + }")${config.modResults.language === 'java' ? ';' : ''}\n` + ); + } config.modResults.contents = stringContents; return config; @@ -116,19 +118,21 @@ const appDelegate: ConfigPlugin = (_config, props) => ) .replace(/\s*IntercomModule\.initialize\((.*), withAppId: (.*)\)/g, ''); - stringContents = isSwift - ? insertContentsInsideSwiftFunctionBlock( - stringContents, - 'application(_:didFinishLaunchingWithOptions:)', - `IntercomModule.initialize("${props.iosApiKey}", withAppId: "${props.appId}")`, - { position: 'tailBeforeLastReturn' } - ) - : insertContentsInsideObjcFunctionBlock( - stringContents, - 'application didFinishLaunchingWithOptions:', - `[IntercomModule initialize:@"${props.iosApiKey}" withAppId:@"${props.appId}"];`, - { position: 'tailBeforeLastReturn' } - ); + if (!props.useManualInit) { + stringContents = isSwift + ? insertContentsInsideSwiftFunctionBlock( + stringContents, + 'application(_:didFinishLaunchingWithOptions:)', + `IntercomModule.initialize("${props.iosApiKey}", withAppId: "${props.appId}")`, + { position: 'tailBeforeLastReturn' } + ) + : insertContentsInsideObjcFunctionBlock( + stringContents, + 'application didFinishLaunchingWithOptions:', + `[IntercomModule initialize:@"${props.iosApiKey}" withAppId:@"${props.appId}"];`, + { position: 'tailBeforeLastReturn' } + ); + } config.modResults.contents = stringContents; return config; diff --git a/src/index.tsx b/src/index.tsx index d74e62ec..19d3ad4b 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -67,6 +67,28 @@ export enum Space { } export type IntercomType = { + /** + * Initialize Intercom SDK with API key and App ID. + * This allows manual initialization from React Native instead of requiring native code setup. + * + * For platform-specific API keys, use Platform.select: + * ```typescript + * import { Platform } from 'react-native'; + * + * const apiKey = Platform.select({ + * ios: 'ios_sdk-abc123', + * android: 'android_sdk-xyz789', + * }); + * + * await Intercom.initialize(apiKey, 'your_app_id'); + * ``` + * + * @param apiKey Your Intercom API key + * @param appId Your Intercom App ID + * @return {Promise} A promise that resolves to true if initialization succeeds + */ + initialize: (apiKey: string, appId: string) => Promise; + /** * Login a unidentified user. * This is a user that doesn't have any identifiable information such as a `userId` or `email`. @@ -301,6 +323,7 @@ export type IntercomType = { }; const Intercom: IntercomType = { + initialize: (apiKey, appId) => IntercomModule.initialize(apiKey, appId), loginUnidentifiedUser: () => IntercomModule.loginUnidentifiedUser(), loginUserWithUserAttributes: (userAttributes) => IntercomModule.loginUserWithUserAttributes(userAttributes), From eb6d87e93e2cd795de41979b367f1be2398f3103 Mon Sep 17 00:00:00 2001 From: Jason Praful Date: Fri, 10 Oct 2025 12:11:18 +0100 Subject: [PATCH 2/4] validate api key --- README.md | 2 + android/src/newarch/IntercomModule.java | 2 +- android/src/oldarch/IntercomModule.java | 2 +- examples/expo-example/app/(tabs)/index.tsx | 1 + src/index.tsx | 45 +++++++++++++++++++++- 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5a5a1a0..59a5c4a5 100644 --- a/README.md +++ b/README.md @@ -757,6 +757,8 @@ Sets the user hash necessary for validation when Identity Verification is enable Initialize the Intercom SDK manually. This is useful when you want to delay initialization until after your app has started, or when using Expo with the `useManualInit` plugin option. +**Important:** This method configures the SDK but does NOT validate your credentials with Intercom's servers. Invalid API keys or App IDs will only be detected when you attempt to use Intercom features (e.g., login, show messenger). The method will return `true` if the SDK is successfully configured, regardless of credential validity. + ### Options | Name | Type | Required | Description | diff --git a/android/src/newarch/IntercomModule.java b/android/src/newarch/IntercomModule.java index 2ae7c4c6..c892bd10 100644 --- a/android/src/newarch/IntercomModule.java +++ b/android/src/newarch/IntercomModule.java @@ -630,7 +630,7 @@ public void onFailure(@NonNull IntercomError intercomError) { public void initialize(String apiKey, String appId, Promise promise) { try { Activity activity = getCurrentActivity(); - if (activity != null) { + if (activity != null && activity.getApplication() != null) { IntercomModule.initialize(activity.getApplication(), apiKey, appId); promise.resolve(true); } else { diff --git a/android/src/oldarch/IntercomModule.java b/android/src/oldarch/IntercomModule.java index e99e7a9e..32afd733 100644 --- a/android/src/oldarch/IntercomModule.java +++ b/android/src/oldarch/IntercomModule.java @@ -607,7 +607,7 @@ public void onFailure(@NonNull IntercomError intercomError) { public void initialize(String apiKey, String appId, Promise promise) { try { Activity activity = getCurrentActivity(); - if (activity != null) { + if (activity != null && activity.getApplication() != null) { IntercomModule.initialize(activity.getApplication(), apiKey, appId); promise.resolve(true); } else { diff --git a/examples/expo-example/app/(tabs)/index.tsx b/examples/expo-example/app/(tabs)/index.tsx index 26e990c6..d1a74fa4 100644 --- a/examples/expo-example/app/(tabs)/index.tsx +++ b/examples/expo-example/app/(tabs)/index.tsx @@ -47,6 +47,7 @@ export default function App() { INTERCOM_CONFIG.appId ); setIsInitialized(true); + setInitError(null); console.log('Intercom initialized successfully'); } } catch (error) { diff --git a/src/index.tsx b/src/index.tsx index 19d3ad4b..dd102d7f 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -323,7 +323,50 @@ export type IntercomType = { }; const Intercom: IntercomType = { - initialize: (apiKey, appId) => IntercomModule.initialize(apiKey, appId), + initialize: (apiKey, appId) => { + if (!apiKey || typeof apiKey !== 'string') { + return Promise.reject( + new Error('Intercom: apiKey is required and must be a string') + ); + } + + const isIOS = Platform.OS === 'ios'; + const isAndroid = Platform.OS === 'android'; + + if (isIOS) { + if (!apiKey.startsWith('ios_sdk-')) { + return Promise.reject( + new Error('Intercom: iOS API key must start with "ios_sdk-"') + ); + } + if (apiKey.length < 48) { + return Promise.reject( + new Error('Intercom: iOS API key must be at least 48 characters long') + ); + } + } else if (isAndroid) { + if (!apiKey.startsWith('android_sdk-')) { + return Promise.reject( + new Error('Intercom: Android API key must start with "android_sdk-"') + ); + } + if (apiKey.length < 52) { + return Promise.reject( + new Error( + 'Intercom: Android API key must be at least 52 characters long' + ) + ); + } + } + + if (!appId || typeof appId !== 'string' || appId.trim() === '') { + return Promise.reject( + new Error('Intercom: appId is required and must be a non-empty string') + ); + } + + return IntercomModule.initialize(apiKey, appId); + }, loginUnidentifiedUser: () => IntercomModule.loginUnidentifiedUser(), loginUserWithUserAttributes: (userAttributes) => IntercomModule.loginUserWithUserAttributes(userAttributes), From 033eb8de679e5e5066571f8085758ffce86c8254 Mon Sep 17 00:00:00 2001 From: Jason Praful Date: Fri, 10 Oct 2025 12:22:14 +0100 Subject: [PATCH 3/4] updates --- src/index.tsx | 60 ++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index dd102d7f..856152b1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -324,44 +324,46 @@ export type IntercomType = { const Intercom: IntercomType = { initialize: (apiKey, appId) => { - if (!apiKey || typeof apiKey !== 'string') { + if (!apiKey || typeof apiKey !== 'string' || apiKey.trim() === '') { return Promise.reject( new Error('Intercom: apiKey is required and must be a string') ); } + if (!appId || typeof appId !== 'string' || appId.trim() === '') { + return Promise.reject( + new Error('Intercom: appId is required and must be a string') + ); + } - const isIOS = Platform.OS === 'ios'; - const isAndroid = Platform.OS === 'android'; + const platform = Platform.OS as 'ios' | 'android'; + const platformRules = { + ios: { prefix: 'ios_sdk-', minLength: 48 }, + android: { prefix: 'android_sdk-', minLength: 52 }, + }; - if (isIOS) { - if (!apiKey.startsWith('ios_sdk-')) { - return Promise.reject( - new Error('Intercom: iOS API key must start with "ios_sdk-"') - ); - } - if (apiKey.length < 48) { - return Promise.reject( - new Error('Intercom: iOS API key must be at least 48 characters long') - ); - } - } else if (isAndroid) { - if (!apiKey.startsWith('android_sdk-')) { - return Promise.reject( - new Error('Intercom: Android API key must start with "android_sdk-"') - ); - } - if (apiKey.length < 52) { - return Promise.reject( - new Error( - 'Intercom: Android API key must be at least 52 characters long' - ) - ); - } + const rules = platformRules[platform]; + + if (!rules) { + return Promise.reject( + new Error( + `Intercom: Platform "${platform}" is not supported. Only iOS and Android are supported.` + ) + ); } - if (!appId || typeof appId !== 'string' || appId.trim() === '') { + if (!apiKey.startsWith(rules.prefix)) { + return Promise.reject( + new Error( + `Intercom: ${platform} API key must start with "${rules.prefix}"` + ) + ); + } + + if (apiKey.length < rules.minLength) { return Promise.reject( - new Error('Intercom: appId is required and must be a non-empty string') + new Error( + `Intercom: ${platform} API key must be at least ${rules.minLength} characters long` + ) ); } From 2c74d82f5c2f04aa94269d121d01ea8758578768 Mon Sep 17 00:00:00 2001 From: Jason Praful Date: Fri, 10 Oct 2025 14:12:26 +0100 Subject: [PATCH 4/4] undo version bump - android update will bump it --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ab68beaa..636f4898 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@intercom/intercom-react-native", - "version": "9.2.0", + "version": "9.1.2", "description": "React Native wrapper to bridge our iOS and Android SDK", "source": "./src/index.tsx", "main": "./lib/commonjs/index.js",