Migration Guide — React Native to Native iOS/Android SDKs
This guide helps developers move from @hoberhq/react-native-sdk to the native HoberKit (iOS) or hober-android-sdk (Android) SDKs.
When to Choose Native vs React Native
| Scenario | Recommendation |
|---|---|
| Greenfield native iOS or Android app | Use the native SDK |
| Existing full Swift/Kotlin codebase | Migrate to native SDK |
| Performance-sensitive app (games, media) | Use the native SDK to avoid the React Native bridge overhead |
| Cross-platform product sharing JS business logic | Stay on @hoberhq/react-native-sdk |
| Expo managed workflow (cannot eject) | Use @hoberhq/react-native-sdk (Expo bare) or the Hober REST API |
In short: choose the native SDK when your app is written primarily in Swift or Kotlin and you want to eliminate the JavaScript bridge. Stick with @hoberhq/react-native-sdk for cross-platform React Native apps where the React component model provides value.
API Comparison
The table below maps each @hoberhq/react-native-sdk API to its native iOS and Android equivalent.
| React Native SDK | Native iOS (HoberKit) | Native Android (hober-android-sdk) |
|---|---|---|
<HoberProvider sdkKey channelId> (JSX wrapper) | Hober.configure(sdkKey:channelId:) in AppDelegate | Hober.init(context, sdkKey, channelId) in Application.onCreate() |
useHober() hook | N/A — use Hober.* class methods directly | N/A — use Hober.* companion object methods directly |
requestPermission() → Promise<boolean> | await Hober.requestPermission() → Bool | Runtime POST_NOTIFICATIONS permission request (Android 13+) |
identifySubscriber({ externalId, email }) | Hober.identifySubscriber(externalId:email:attributes:) | Hober.identifySubscriber(externalId, email, attributes, callback) |
registerDevice() (auto via HoberProvider) | Hober.registerDevice(token:) in didRegisterForRemoteNotificationsWithDeviceToken | Hober.registerDevice(token) via HoberFirebaseMessagingService.onNewToken |
| Foreground handling via React component re-render | UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:) | Override onMessageReceived in your FirebaseMessagingService |
| Background/silent push via JS handler | application(_:didReceiveRemoteNotification:fetchCompletionHandler:) — content-available: 1 | onMessageReceived when app is backgrounded |
API surface gaps
@hoberhq/react-native-sdk exposes a unified JS interface over both iOS and Android. The native SDKs have full API parity for all production features — configure/init, requestPermission, identifySubscriber, and registerDevice are all available on both platforms. There is no feature exclusive to the React Native SDK that is unavailable in the native SDKs.
The one difference is paradigm: the React Native SDK wraps both platforms behind a single useHober() hook, while each native SDK uses the platform's own lifecycle hooks and class APIs.
Paradigm Shift: Declarative to Imperative
The React Native SDK uses React's component model — you wrap your app in HoberProvider and call methods from useHober():
// React Native — declarative / hook-based
import { HoberProvider, useHober } from '@hoberhq/react-native-sdk';
export default function App() {
return (
<HoberProvider sdkKey="YOUR_SDK_KEY" channelId="default">
<PushSetup />
</HoberProvider>
);
}
function PushSetup() {
const { requestPermission, identifySubscriber, registerDevice } = useHober();
// ...
}
The native SDKs use imperative APIs tied to platform lifecycle methods. There is no JSX, no hook, and no provider context — you call Hober.* static methods directly at the right lifecycle points.
From React Native to Native iOS
Step 1 — Remove the React Native SDK
npm uninstall @hoberhq/react-native-sdk
cd ios && pod install
Remove the <HoberProvider> wrapper from your root component and delete all useHober() imports.
Step 2 — Install HoberKit via Swift Package Manager
In Xcode, go to File > Add Package Dependencies… and enter:
https://github.com/hoberhq/hober-ios-sdk.git
Choose Up to Next Major Version from 1.0.0 and add the HoberKit target.
Step 3 — Configure in AppDelegate
Replace the HoberProvider initialisation with Hober.configure(sdkKey:channelId:) inside application(_:didFinishLaunchingWithOptions:):
import UIKit
import HoberKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Hober.configure(sdkKey: "YOUR_SDK_KEY", channelId: "YOUR_CHANNEL_ID")
UNUserNotificationCenter.current().delegate = self
return true
}
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Hober.registerDevice(token: deviceToken)
}
}
Step 4 — Request Permission
Replace the useHober().requestPermission() call with the native equivalent:
// React Native (before)
// const { requestPermission } = useHober();
// const granted = await requestPermission();
// Native iOS (after)
let granted = await Hober.requestPermission()
Call this at a meaningful moment in your onboarding flow — not immediately on launch.
Step 5 — Identify a Subscriber
// After user login/sign-in
Task {
try await Hober.identifySubscriber(
externalId: user.id,
email: user.email
)
}
Step 6 — Handle Foreground Notifications
Add UNUserNotificationCenterDelegate to display banners while the app is in the foreground:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .sound, .badge])
}
}
Token Lifecycle in Native iOS
In @hoberhq/react-native-sdk the token refresh is handled internally — you never see didRegisterForRemoteNotificationsWithDeviceToken. With HoberKit, token refresh is automatic via the same delegate method: whenever iOS rotates the APNs token, didRegisterForRemoteNotificationsWithDeviceToken is called and Hober.registerDevice(token:) forwards it to Hober. No extra code is needed beyond the boilerplate above.
From React Native to Native Android
Step 1 — Remove the React Native SDK
npm uninstall @hoberhq/react-native-sdk
Remove the <HoberProvider> wrapper from your root component and delete all useHober() imports. Clean up the React Native bridge references in android/.
Step 2 — Add the Gradle Dependency
In your project-level build.gradle, ensure mavenCentral() is listed:
repositories {
mavenCentral()
google()
}
In your app-level build.gradle, add:
dependencies {
implementation("io.hober:sdk:1.0.0")
implementation("com.google.firebase:firebase-messaging:24.0.0")
}
Step 3 — Initialise in Application.onCreate()
Create an Application subclass (if you don't already have one) and replace the HoberProvider initialisation with Hober.init():
import android.app.Application
import io.hober.sdk.Hober
import io.hober.sdk.android.AppContextImpl
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
Hober.init(
context = AppContextImpl(this),
sdkKey = "YOUR_SDK_KEY",
channelId = "default"
)
}
}
Register MyApplication in AndroidManifest.xml:
<application android:name=".MyApplication" ...>
Step 4 — Request POST_NOTIFICATIONS Permission (Android 13+)
The React Native SDK's requestPermission() handled this for you. In the native Android SDK you must request the POST_NOTIFICATIONS permission directly:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
Declare the permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Step 5 — Set Up HoberFirebaseMessagingService
Extend HoberFirebaseMessagingService to handle token updates automatically:
import io.hober.sdk.fcm.HoberFirebaseMessagingService
class MyFirebaseService : HoberFirebaseMessagingService()
Register it in AndroidManifest.xml:
<service android:name=".MyFirebaseService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Step 6 — Identify a Subscriber
// After user logs in
Hober.identifySubscriber(
externalId = user.id,
email = user.email
) { result -> /* handle result */ }
Token Lifecycle in Native Android
In @hoberhq/react-native-sdk the FCM token is obtained and refreshed internally. With hober-android-sdk, HoberFirebaseMessagingService overrides onNewToken and forwards the new token to Hober automatically. If you need manual control, call Hober.registerDevice(token) directly — for example, inside your own FirebaseMessagingService.onNewToken:
override fun onNewToken(token: String) {
super.onNewToken(token)
Hober.registerDevice(token = token)
}
Behavioural Differences Summary
| Behaviour | React Native SDK | Native iOS (HoberKit) | Native Android (hober-android-sdk) |
|---|---|---|---|
| Initialisation | <HoberProvider> JSX wrapper (component mount) | Hober.configure(sdkKey:channelId:) in didFinishLaunchingWithOptions | Hober.init(...) in Application.onCreate() |
| Permission request | requestPermission() — unified cross-platform | Hober.requestPermission() — async/await | Manual POST_NOTIFICATIONS runtime request (Android 13+) |
| Token registration | Automatic inside HoberProvider | Hober.registerDevice(token:) in didRegisterForRemoteNotificationsWithDeviceToken | Automatic via HoberFirebaseMessagingService.onNewToken |
| Token refresh | Handled internally | iOS calls didRegisterForRemoteNotificationsWithDeviceToken automatically | FCM calls onNewToken automatically |
| Foreground handling | React state / JS event listener | UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:) | FirebaseMessagingService.onMessageReceived while foregrounded |
| Background/silent push | JS handler registered via HoberProvider | application(_:didReceiveRemoteNotification:fetchCompletionHandler:) — content-available: 1 | onMessageReceived (FCM handles wake-up) |
| Subscriber identification | identifySubscriber({ externalId, email }) | Hober.identifySubscriber(externalId:email:attributes:) | Hober.identifySubscriber(externalId, email, attributes, callback) |