Skip to main content

React Native

The Sukko TypeScript SDK works in React Native out of the box. No separate native SDK needed — @sukko/sdk and @sukko/websocket run on React Native's JavaScript runtime, and @sukko/react hooks work identically to web React.

Same SDK, same API

React Native uses the exact same packages as web React. If you've already integrated Sukko in a web app, the code is identical.

Install​

npm install @sukko/sdk @sukko/websocket @sukko/react

Setup Provider​

// App.tsx
import { SukkoProvider } from '@sukko/react';
import { WebSocketTransport } from '@sukko/websocket';

export default function App() {
return (
<SukkoProvider
options={{
transport: new WebSocketTransport({ url: 'ws://your-gateway:3000' }),
getToken: async () => {
const res = await fetch('https://your-api.com/auth/sukko-token');
return res.text();
},
}}
>
<ChatScreen />
</SukkoProvider>
);
}

Subscribe and Display Messages​

useSubscription takes an array of channels and returns the latest message; accumulate a list with onMessage for a scrollback view:

import { useState } from 'react';
import { useSubscription, useConnectionState, type TypedMessage } from '@sukko/react';
import { View, Text, FlatList } from 'react-native';

function ChatScreen() {
const [messages, setMessages] = useState<TypedMessage[]>([]);
const { state } = useConnectionState();

useSubscription({
channels: ['general.chat'],
onMessage: (msg) => setMessages((prev) => [...prev, msg]),
});

return (
<View>
<Text>Status: {state}</Text>
<FlatList
data={messages}
keyExtractor={(_, i) => String(i)}
renderItem={({ item }) => <Text>{JSON.stringify(item.data)}</Text>}
/>
</View>
);
}

Publish a Message​

import { useSukkoClient } from '@sukko/react';
import { TouchableOpacity, Text } from 'react-native';

function SendButton() {
const client = useSukkoClient();

return (
<TouchableOpacity onPress={() => client.publish('general.chat', { text: 'Hello from RN!' })}>
<Text>Send</Text>
</TouchableOpacity>
);
}

Platform Notes​

  • WebSocket — React Native includes a built-in WebSocket implementation. The @sukko/websocket transport uses it automatically.
  • Background — WebSocket connections are closed when the app is backgrounded on iOS/Android. The SDK auto-reconnects when the app returns to the foreground and automatically replays any Kafka messages missed while offline — no manual call. Where a replay can't be confirmed the SDK surfaces a possible_gap marker on the client's messages() stream instead of dropping silently (see Automatic Recovery). The per-channel pos cursor is held in memory, so it persists across background/foreground cycles within the same app session.
  • Client ID persistence — Unlike web, React Native has no localStorage. The SDK generates a fresh client_id each time the app cold-starts, so gap-free replay does not persist across app restarts on React Native. Replay still works within the same app session (across background/foreground cycles).
  • Token refresh — The getToken callback is called automatically before token expiry, same as web.

Push Notifications ENTERPRISE​

Mobile push (FCM/APNs) is an Enterprise feature — registering android/ios devices below Enterprise is rejected with 403 EDITION_LIMIT. (Web Push, used by browser apps, is Pro — see the push notifications guide.)

Register a device for push with @sukko/react-native. It bundles no push library — you provide a small MessagingAdapter over whatever your app already uses (@react-native-firebase/messaging, expo-notifications, …), and the SDK registers the device token with the gateway and re-registers automatically when it rotates.

npm install @sukko/react-native
import { enableMobilePush, type MessagingAdapter } from '@sukko/react-native';
import { Platform } from 'react-native';
import messaging from '@react-native-firebase/messaging';

// A thin adapter over your app's messaging library — the SDK depends on none directly.
const adapter: MessagingAdapter = {
requestPermission: async () => {
const status = await messaging().requestPermission();
return status === messaging.AuthorizationStatus.AUTHORIZED;
},
getToken: () => messaging().getToken(),
onTokenRefresh: (cb) => messaging().onTokenRefresh(cb),
};

const registration = await enableMobilePush(client, adapter, {
platform: Platform.OS === 'ios' ? 'ios' : 'android',
channels: ['acme.alerts'],
onError: (err) => console.warn('push re-registration failed', err),
});

// registration.deviceId — persist it (it rotates when the token refreshes).
// Later: await registration.disable();

The SDK is a push registrar, not a receiver — the device receives notifications through the OS (FCM/APNs) and your app's own handler, never over the Sukko socket.

iOS via Firebase is not supported

The gateway routes push by platform (ios → APNs). An iOS app using Firebase holds an FCM token that platform: "ios" can't express — use APNs directly on iOS, and FCM on Android.

Next Steps​