Skip to main content

Intervengine React Native SDK

React Native wrapper for the Intervengine Mobile SDK, built with Expo Modules and Kotlin Multiplatform (KMP).

Overview

This SDK provides a React Native interface to the Intervengine platform, enabling mobile apps to:

  • Authenticate users and manage sessions
  • Fetch and display embeddable cards
  • Listen to real-time updates via Server-Sent Events (SSE)
  • Manage user context and state

Architecture

The SDK consists of three main layers:

React Native SDK Architecture
React Native SDK Architecture

How It Works

  1. TypeScript SDK (IntervengineSdk.tsx): High-level API that React Native apps use
  2. Native Modules: Platform-specific bridge code (Swift for iOS, Kotlin for Android)
  3. KMP Shared Library: Cross-platform business logic written in Kotlin

The native modules use Expo Modules API, which provides:

  • Automatic type conversion between native and JavaScript
  • Promise-based async functions
  • Event emitters for native → JavaScript communication
  • No need to write JSI/JNI code manually

Installation (NPM package not published yet)

npm install intervengine-rn-sdk

Usage

Basic Setup

import { IntervengineSdk } from 'intervengine-rn-sdk';

// Initialize the SDK
const sdk = await IntervengineSdk.initialize({
apiUrl: '<https://your-api-url.com>',
apiKey: 'your-api-key',
appId: 'your-app-id',
appSecret: 'your-app-secret',
initialPageSize: 20,
enableLogging: true,
});

// Start listening for events
await sdk.start('participant', 'user-123');

Listening to Auth State Changes

import { useEffect, useState } from 'react';

function MyComponent() {
const [authState, setAuthState] = useState('loading');

useEffect(() => {
if (!sdk) return;

// Get current auth state
sdk.getCurrentAuthState().then((state) => {
setAuthState(state.state);
});

// Listen for auth state changes
const subscription = sdk.addAuthStateListener((state) => {
console.log('Auth state:', state.state);
console.log('Access token:', state.accessToken);
setAuthState(state.state);
});

return () => subscription.remove();
}, [sdk]);

return <Text>Auth State: {authState}</Text>;
}

Fetching Cards

// Fetch embeddable cards
const cards = await sdk.getEmbeddableCards(1, 20); // page, perPage

cards.forEach((card) => {
console.log('Card:', card.title, card.url);
});

Listening to Card Updates

useEffect(() => {
if (!sdk) return;

const subscription = sdk.addCardsUpdateListener((update) => {
console.log('New cards received:', update.newCards);
// Refresh your cards list
});

return () => subscription.remove();
}, [sdk]);

Getting User Context

const context = await sdk.getUserContext();
console.log('User ID:', context.userId);
console.log('Access Token:', context.accessToken);

Complete Example

import React, { useEffect, useState } from 'react';
import { View, Text, FlatList } from 'react-native';
import { IntervengineSdk } from 'intervengine-rn-sdk';

function App() {
const [sdk, setSdk] = useState(null);
const [authState, setAuthState] = useState('loading');
const [cards, setCards] = useState([]);

useEffect(() => {
// Initialize SDK
IntervengineSdk.initialize({
apiUrl: '<https://api.example.com>',
apiKey: 'your-key',
appId: 'your-app-id',
appSecret: 'your-secret',
}).then(async (sdkInstance) => {
setSdk(sdkInstance);

// Start listening for events
await sdkInstance.start('participant', 'user-123');

// Fetch initial cards
const initialCards = await sdkInstance.getEmbeddableCards(1, 20);
setCards(initialCards);
});
}, []);

useEffect(() => {
if (!sdk) return;

// Listen for auth state changes
const authSub = sdk.addAuthStateListener((state) => {
setAuthState(state.state);
});

// Listen for new cards
const cardsSub = sdk.addCardsUpdateListener(async () => {
const updatedCards = await sdk.getEmbeddableCards(1, 20);
setCards(updatedCards);
});

return () => {
authSub.remove();
cardsSub.remove();
};
}, [sdk]);

return (
<View>
<Text>Status: {authState}</Text>
<FlatList
data={cards}
renderItem={({ item }) => (
<View>
<Text>{item.title}</Text>
<Text>{item.descriptionText}</Text>
</View>
)}
keyExtractor={(item) => item.id}
/>
</View>
);
}

API Reference

IntervengineSdk.initialize(config)

Initialize the SDK with configuration.

Parameters:

  • config.apiUrl: API endpoint URL
  • config.apiKey: API key
  • config.appId: Application ID
  • config.appSecret: Application secret
  • config.initialPageSize: Initial page size for cards (default: 10)
  • config.enableLogging: Enable debug logging (default: false)

Returns: Promise<IntervengineSdk>

sdk.start(userType, userId)

Start listening for Server-Sent Events (SSE).

Parameters:

  • userType: 'participant' or 'external'
  • userId: User identifier

Returns: Promise<void>

sdk.stop()

Stop listening for SSE events.

Returns: Promise<void>

sdk.signOut()

Sign out and clear SDK state.

Returns: Promise<void>

sdk.getEmbeddableCards(page, perPage)

Fetch embeddable cards.

Parameters:

  • page: Page number (default: 1)
  • perPage: Items per page (default: 10)

Returns: Promise<EmbeddableCard[]>

sdk.getUserContext()

Get current user context.

Returns: Promise<{ userId: string, accessToken: string }>

sdk.getCurrentAuthState()

Get current authentication state.

Returns: Promise<AuthStatePayload>

sdk.addAuthStateListener(callback)

Listen for authentication state changes.

Parameters:

  • callback: (state: AuthStatePayload) => void

Returns: { remove: () => void }

sdk.addCardsUpdateListener(callback)

Listen for card updates.

Parameters:

  • callback: (update: CardsUpdatePayload) => void

Returns: { remove: () => void }

Types

AuthStatePayload

type AuthStatePayload = {
state: 'authenticated' | 'unauthenticated' | 'loading' | 'error';
accessToken?: string; // Present when state is 'authenticated'
error?: string; // Present when state is 'error'
};

EmbeddableCard

type EmbeddableCard = {
id: string;
url: string;
activityPlanType: string;
title: string;
descriptionText: string;
imageUrl: string;
isOneOff: boolean;
scheduledAt: string;
reportedAt: string;
};

CardsUpdatePayload

type CardsUpdatePayload = {
newCards: EmbeddableCard[];
};