Skip to content

Commit ca6466f

Browse files
committed
add manual SDK initialization
1 parent 58e312c commit ca6466f

File tree

13 files changed

+274
-36
lines changed

13 files changed

+274
-36
lines changed

README.md

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
## Installation
4646

4747
```sh
48-
$ npm install @intercom/intercom-react-native
48+
npm install @intercom/intercom-react-native
4949
```
5050

5151
or
@@ -61,7 +61,7 @@ If you're using React Native v0.60 or above, the library will be linked automati
6161
#### Android: Automatic linking with React Native v0.59 and below
6262

6363
```
64-
$ react-native link @intercom/intercom-react-native
64+
react-native link @intercom/intercom-react-native
6565
```
6666

6767
#### Android: Manual linking with React Native v0.59 and below
@@ -81,6 +81,16 @@ implementation project(':intercom-react-native')
8181

8282
#### Android: Setup
8383

84+
You have two options for initializing Intercom:
85+
86+
**Option 1: Native Initialization (Recommended)**
87+
Initialize at app startup in your native code for the best user experience.
88+
89+
**Option 2: JavaScript Initialization**
90+
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.
91+
92+
**For Native Initialization:**
93+
8494
- 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).
8595

8696
```java
@@ -340,6 +350,16 @@ See [How to manually link IOS Intercom SDK](docs/IOS-MANUAL-LINKING.md)
340350

341351
#### iOS: Setup
342352

353+
You have two options for initializing Intercom:
354+
355+
**Option 1: Native Initialization (Recommended)**
356+
Initialize at app startup in your native code for the best user experience.
357+
358+
**Option 2: JavaScript Initialization**
359+
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.
360+
361+
**For Native Initialization:**
362+
343363
- Open `ios/AppDelegate.m` then add below code:
344364

345365
- 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)
359379
// ...
360380
self.window.rootViewController = rootViewController;
361381

362-
[IntercomModule initialize:@"apiKey" withAppId:@"appId"]; // <-- Add this (Remember to replace strings with your api keys)
382+
[IntercomModule initialize:@"apiKey" withAppId:@"appId"]; // <-- Add this
363383

364384
return YES;
365385
}
@@ -384,7 +404,7 @@ func application(_ application: UIApplication, didFinishLaunchingWithOptions lau
384404
....
385405
}
386406

387-
```
407+
```
388408

389409
#### iOS: Permissions
390410

@@ -518,6 +538,7 @@ The plugin provides props for extra customization. Every time you change the pro
518538
- `androidApiKey` (_string_): Android API Key from Intercom.
519539
- `iosApiKey` (_string_): iOS API Key from Intercom.
520540
- `intercomRegion` (_string_): Region for Intercom `US`, `EU`, `AU`. Optional. Defaults to `US`.
541+
- `useManualInit` (_boolean_): Set to `true` to manually initialize Intercom from JavaScript instead of at app startup. Optional. Defaults to `false`.
521542

522543
```json
523544
{
@@ -537,6 +558,41 @@ The plugin provides props for extra customization. Every time you change the pro
537558
}
538559
```
539560

561+
#### Manual Initialization with Expo
562+
563+
If you want to delay Intercom initialization and manually initialize it from JavaScript, you set the `useManualInit` option to `true`:
564+
565+
```json
566+
{
567+
"expo": {
568+
"plugins": [
569+
[
570+
"@intercom/intercom-react-native",
571+
{
572+
"useManualInit": true
573+
}
574+
]
575+
]
576+
}
577+
}
578+
```
579+
580+
Then initialize Intercom manually in your JavaScript code with the platform-specific API keys:
581+
582+
```javascript
583+
import Intercom from '@intercom/intercom-react-native';
584+
import { Platform } from 'react-native';
585+
586+
// You can find your API keys in your Intercom workspace settings
587+
// https://app.intercom.com/a/apps/<your-app-id>/settings/channels/messenger/install?tab=ios
588+
const apiKey = Platform.select({
589+
ios: 'ios_sdk-abc123',
590+
android: 'android_sdk-abc123',
591+
});
592+
593+
await Intercom.initialize(apiKey, 'abc123');
594+
```
595+
540596
#### Expo: Push notifications
541597

542598
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
697753

698754
---
699755

756+
### `Intercom.initialize(apiKey, appId)`
757+
758+
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.
759+
760+
### Options
761+
762+
| Name | Type | Required | Description |
763+
| ------ | ------ | -------- | --------------------------------------- |
764+
| apiKey | string | yes | Your Platform-specific Intercom API key |
765+
| appId | string | yes | Your Intercom App ID |
766+
767+
### Examples
768+
769+
```javascript
770+
import { Platform } from 'react-native';
771+
772+
const apiKey = Platform.select({
773+
ios: 'ios_sdk-abc123',
774+
android: 'android_sdk-xyz789',
775+
});
776+
777+
await Intercom.initialize(apiKey, 'your_app_id');
778+
```
779+
780+
### Returns
781+
782+
`Promise<boolean>`
783+
784+
---
785+
700786
### `Intercom.loginUnidentifiedUser()`
701787

702788
Login a unidentified user.
@@ -1223,9 +1309,9 @@ Data Connectors (e.g., Fin Actions), which use these in `Authorization: Bearer <
12231309
12241310
### Options
12251311
1226-
| Name | Type | Required | Description |
1227-
| ---------- | ------------------------------- | -------- | --------------------------------------------------- |
1228-
| authTokens | `{ [key: string]: string }` | yes | An object with token names as keys and JWT strings as values |
1312+
| Name | Type | Required | Description |
1313+
| ---------- | --------------------------- | -------- | ------------------------------------------------------------ |
1314+
| authTokens | `{ [key: string]: string }` | yes | An object with token names as keys and JWT strings as values |
12291315
12301316
### Example
12311317

android/src/main/java/com/intercom/reactnative/IntercomErrorCodes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class IntercomErrorCodes {
1111
public static final String GET_UNREAD_CONVERSATION = "108";
1212
public static final String SET_USER_JWT = "109";
1313
public static final String SET_AUTH_TOKENS = "110";
14+
public static final String INITIALIZE_ERROR = "111";
1415
public static final String DISPLAY_MESSENGER = "201";
1516
public static final String DISPLAY_MESSENGER_COMPOSER = "202";
1617
public static final String DISPLAY_CONTENT = "203";

android/src/newarch/IntercomModule.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,23 @@ public void onFailure(@NonNull IntercomError intercomError) {
626626
}
627627
}
628628

629+
@ReactMethod
630+
public void initialize(String apiKey, String appId, Promise promise) {
631+
try {
632+
Activity activity = getCurrentActivity();
633+
if (activity != null) {
634+
IntercomModule.initialize(activity.getApplication(), apiKey, appId);
635+
promise.resolve(true);
636+
} else {
637+
promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, "Activity is null");
638+
}
639+
} catch (Exception err) {
640+
Log.e(NAME, "initialize error:");
641+
Log.e(NAME, err.toString());
642+
promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, err.toString());
643+
}
644+
}
645+
629646
@ReactMethod
630647
public void setNeedsStatusBarAppearanceUpdate(Promise promise) {
631648
// iOS-only method, no-op on Android

android/src/oldarch/IntercomModule.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,23 @@ public void onFailure(@NonNull IntercomError intercomError) {
603603
}
604604
}
605605

606+
@ReactMethod
607+
public void initialize(String apiKey, String appId, Promise promise) {
608+
try {
609+
Activity activity = getCurrentActivity();
610+
if (activity != null) {
611+
IntercomModule.initialize(activity.getApplication(), apiKey, appId);
612+
promise.resolve(true);
613+
} else {
614+
promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, "Activity is null");
615+
}
616+
} catch (Exception err) {
617+
Log.e(NAME, "initialize error:");
618+
Log.e(NAME, err.toString());
619+
promise.reject(IntercomErrorCodes.INITIALIZE_ERROR, err.toString());
620+
}
621+
}
622+
606623
public static synchronized void initialize(Application application, String apiKey, String appId) {
607624
String sdkVersion = BuildConfig.INTERCOM_VERSION_NAME;
608625
ReactNativeHeaderInterceptor.setReactNativeVersion(application.getApplicationContext(), sdkVersion);

examples/expo-example/app.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,7 @@
3939
[
4040
"@intercom/intercom-react-native",
4141
{
42-
"appId": "YOUR_APP_ID",
43-
"androidApiKey": "android_sdk-YOUR_ANDROID_API_KEY",
44-
"iosApiKey": "ios_sdk-YOUR_IOS_API_KEY"
42+
"useManualInit": true
4543
}
4644
],
4745
"expo-router",

examples/expo-example/app/(tabs)/index.tsx

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import React from 'react';
2-
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';
1+
import React, { useEffect, useState } from 'react';
2+
import { SafeAreaView, ScrollView, StatusBar, View, Text } from 'react-native';
33
import * as Notifications from 'expo-notifications';
44

55
import { useIntercom } from '../../hooks/useIntercom';
66
import { useNotifications } from '../../hooks/useNotifications';
7+
import { INTERCOM_CONFIG } from '../../config/intercom.config';
78

89
import Header from '../../components/Header';
10+
import Intercom from '@intercom/intercom-react-native';
911
import AuthenticationSection from '../../components/AuthenticationSection';
1012
import MessagingSection from '../../components/MessagingSection';
1113
import ContentSection from '../../components/ContentSection';
@@ -28,6 +30,33 @@ Notifications.setNotificationHandler({
2830
export default function App() {
2931
const intercom = useIntercom();
3032
const notifications = useNotifications();
33+
const [isInitialized, setIsInitialized] = useState(false);
34+
const [initError, setInitError] = useState<string | null>(null);
35+
36+
useEffect(() => {
37+
async function initializeIntercom() {
38+
try {
39+
console.log('Initializing Intercom...');
40+
if (!INTERCOM_CONFIG.apiKey || !INTERCOM_CONFIG.appId) {
41+
console.error('Intercom API key and app ID are required');
42+
return;
43+
}
44+
if (!isInitialized) {
45+
await Intercom.initialize(
46+
INTERCOM_CONFIG.apiKey,
47+
INTERCOM_CONFIG.appId
48+
);
49+
setIsInitialized(true);
50+
console.log('Intercom initialized successfully');
51+
}
52+
} catch (error) {
53+
console.error('Failed to initialize Intercom:', error);
54+
setInitError(error instanceof Error ? error.message : 'Unknown error');
55+
}
56+
}
57+
58+
initializeIntercom();
59+
}, []);
3160

3261
return (
3362
<ErrorBoundary>
@@ -41,6 +70,20 @@ export default function App() {
4170
/>
4271

4372
<ScrollView className="flex-1 px-6 py-4">
73+
<View className="mb-4 p-3 rounded-lg bg-gray-100">
74+
<Text className="text-sm font-semibold text-gray-700">
75+
Intercom Status:{' '}
76+
{initError && (
77+
<Text className="text-red-600">Failed: {initError}</Text>
78+
)}
79+
{isInitialized ? (
80+
<Text className="text-green-600">Initialized</Text>
81+
) : (
82+
<Text className="text-yellow-600">Initializing...</Text>
83+
)}
84+
</Text>
85+
</View>
86+
4487
<AuthenticationSection
4588
loggedUser={intercom.loggedUser}
4689
email={intercom.email}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Platform } from 'react-native';
2+
3+
/**
4+
* Intercom configuration
5+
*
6+
* Replace these values with your actual Intercom credentials.
7+
* You can find your API keys and App ID in your Intercom workspace settings:
8+
* https://app.intercom.com/a/apps/<your-app-id>/settings/channels/messenger/install?tab=ios
9+
*
10+
* Note: iOS and Android require different API keys.
11+
*/
12+
export const INTERCOM_CONFIG = {
13+
appId: '<your-app-id>', // Replace with your Intercom App ID
14+
apiKey: Platform.select({
15+
ios: 'ios_sdk-<your-ios-api-key>', // Replace with your iOS API key
16+
android: 'android_sdk-<your-android-api-key>', // Replace with your Android API key
17+
}) as string,
18+
};

examples/expo-example/pnpm-lock.yaml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ios/IntercomModule.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ @implementation IntercomModule
1717
NSString *UNREAD_CONVERSATION_COUNT = @"107";
1818
NSString *SET_USER_JWT = @"109";
1919
NSString *SET_AUTH_TOKENS = @"110";
20+
NSString *INITIALIZE_ERROR = @"111";
2021
NSString *SEND_TOKEN_TO_INTERCOM = @"302";
2122
NSString *FETCH_HELP_CENTER_COLLECTIONS = @"901";
2223
NSString *FETCH_HELP_CENTER_COLLECTION = @"902";
@@ -28,6 +29,19 @@ - (dispatch_queue_t)methodQueue {
2829
return dispatch_get_main_queue();
2930
}
3031

32+
RCT_EXPORT_METHOD(initialize:(NSString *)apiKey
33+
withAppId:(NSString *)appId
34+
resolver:(RCTPromiseResolveBlock)resolve
35+
rejecter:(RCTPromiseRejectBlock)reject) {
36+
@try {
37+
[IntercomModule initialize:apiKey withAppId:appId];
38+
resolve(@(YES));
39+
} @catch (NSException *exception) {
40+
NSLog(@"initialize error: %@", exception.reason);
41+
reject(INITIALIZE_ERROR, @"Failed to initialize Intercom", [self exceptionToError:exception :INITIALIZE_ERROR :@"initialize"]);
42+
}
43+
}
44+
3145
+ (void)initialize:(nonnull NSString *)apiKey withAppId:(nonnull NSString *)appId {
3246
NSString *version = @"0";
3347

src/NativeIntercomSpec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface TurboModuleContent {
2727
}
2828

2929
export interface Spec extends TurboModule {
30+
initialize(apiKey: string, appId: string): Promise<boolean>;
3031
loginUnidentifiedUser(): Promise<boolean>;
3132
loginUserWithUserAttributes(userAttributes: UserAttributes): Promise<boolean>;
3233
logout(): Promise<boolean>;

0 commit comments

Comments
 (0)