How do you integrate the Genuin React Native SDK into your application?

The Genuin React Native SDK enables brands to seamlessly integrate a full-featured Community Media Network experience directly into their mobile applications.

Use this when:

  • You want to embed short-form video feeds, carousels, or community content inside your app
  • You need SSO-enabled, deeply integrated media experiences
  • You want to drive engagement, retention, and monetization through native app experiences

This matters because:

  • It eliminates the need to build video infrastructure from scratch
  • Ensures brand-safe, moderated, and scalable content delivery
  • Supports deep linking, push notifications, and personalization
  • Enables faster go-to-market with plug-and-play embeds

Guide (Step-by-Step Setup & Integration)

1. Install the SDK

Run the following command:

index.html
npm install genuin-react-native

Android Setup

Step 1: Minimum SDK Configuration

Update android/app/build.gradle:

build.gradle
android {
    defaultConfig {
        minSdk = 24
    }
}

Step 2: Update Android Manifest

Add internet permission and required flags (android/app/src/main/AndroidManifest.xml):

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<!-- 1. Add tools:remove="android:taskAffinity"
     2. Add android:allowBackup="false" -->
<application
    android:name=".MainApplication"
    android:label="@string/app_name"
    android:icon="@mipmap/ic_launcher"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:allowBackup="false"
    android:theme="@style/AppTheme"
    tools:remove="android:taskAffinity"
    android:supportsRtl="true">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
</manifest>

Step 3: Apply Material Theme

Update styles.xml (located at android/app/src/main/res/values/styles.xml):

The SDK requires Material Components; ensure your application utilizes a material theme as demonstrated in the example below to maintain compatibility.

index.html
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
    <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
        <!-- Show a splash screen on the activity. Automatically removed when
             the Flutter engine draws its first frame -->
        <item name="android:windowBackground">@drawable/launch_background</item>
    </style>
</resources>

Step 4: Add ProGuard Rules

Create proguard-rules.pro and add the following lines:

proguard-rules.pro
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:
-dontwarn com.facebook.imagepipeline.nativecode.WebpTranscoder
-keep class com.bumptech.glide.**{*;}
-keep public class * {
    public *;
    protected *;
}

# Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and
# EnclosingMethod is required to use InnerClasses.
-keepattributes Signature, InnerClasses, EnclosingMethod

# Retrofit does reflection on method and parameter annotations.
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**

# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit

# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.KotlinExtensions
-dontwarn java.lang.reflect.AnnotatedType
-dontwarn com.google.api.client.http.GenericUrl
-dontwarn com.google.api.client.http.HttpHeaders
-dontwarn com.google.api.client.http.HttpRequest
-dontwarn com.google.api.client.http.HttpRequestFactory
-dontwarn com.google.api.client.http.HttpResponse
-dontwarn com.google.api.client.http.HttpTransport
-dontwarn com.google.api.client.http.javanet.NetHttpTransport$Builder
-dontwarn com.google.api.client.http.javanet.NetHttpTransport
-dontwarn com.squareup.picasso.Picasso
-dontwarn com.squareup.picasso.RequestCreator
-dontwarn java.awt.image.BufferedImage
-dontwarn javax.imageio.ImageIO
-dontwarn org.joda.time.Instant
-dontwarn org.junit.Assert
-dontwarn org.slf4j.impl.StaticLoggerBinder
-dontwarn org.slf4j.impl.StaticMDCBinder
-dontwarn org.slf4j.impl.StaticMarkerBinder

# With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy
# and replaces all potential values with null. Explicitly keeping the interfaces prevents this.
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>

##---------------Begin: proguard configuration for Gson  ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature

# For using GSON @Expose annotation
-keepattributes *Annotation*

# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }

# Application classes that will be serialized/deserialized over Gson
-keep class com.begenuin.begenuin.data.model.** { <fields>; }
-keep class com.begenuin.begenuin.vo.** { <fields>; }

# RenderScript
-keepclasseswithmembernames class * {
native <methods>;
}
-keep class androidx.renderscript.** { *; }
-keepattributes *Annotation*
-keep class com.giphy.sdk.core.models.** { *; }
-keep class com.giphy.sdk.ui.views.** { *; }
-keep public class * implements java.lang.reflect.Type
-keep class com.google.mediapipe.solutioncore.** {*;}
-keep class com.google.protobuf.** {*;}
-dontwarn com.begenuin.sdk.BR
-dontwarn com.google.android.play.core.splitcompat.SplitCompatApplication
-dontwarn com.google.android.play.core.splitinstall.SplitInstallManager
-dontwarn com.google.android.play.core.splitinstall.SplitInstallManagerFactory
-dontwarn com.google.android.play.core.splitinstall.SplitInstallRequest$Builder
-dontwarn com.google.android.play.core.splitinstall.SplitInstallRequest
-dontwarn com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener
-dontwarn com.google.android.play.core.tasks.OnFailureListener
-dontwarn com.google.android.play.core.tasks.OnSuccessListener
-dontwarn com.google.android.play.core.tasks.Task
-dontwarn com.google.mediapipe.proto.CalculatorProfileProto$CalculatorProfile
-dontwarn com.google.mediapipe.proto.GraphTemplateProto$CalculatorGraphTemplate
-dontwarn javax.lang.model.AnnotatedConstruct
-dontwarn javax.lang.model.SourceVersion
-dontwarn javax.lang.model.element.AnnotationMirror
-dontwarn javax.lang.model.element.AnnotationValue
-dontwarn javax.lang.model.element.AnnotationValueVisitor
-dontwarn javax.lang.model.element.Element
-dontwarn javax.lang.model.element.ElementKind
-dontwarn javax.lang.model.element.ElementVisitor
-dontwarn javax.lang.model.element.ExecutableElement
-dontwarn javax.lang.model.element.Name
-dontwarn javax.lang.model.element.NestingKind
-dontwarn javax.lang.model.element.PackageElement
-dontwarn javax.lang.model.element.QualifiedNameable
-dontwarn javax.lang.model.element.TypeElement
-dontwarn javax.lang.model.element.TypeParameterElement
-dontwarn javax.lang.model.element.VariableElement
-dontwarn javax.lang.model.type.ArrayType
-dontwarn javax.lang.model.type.DeclaredType
-dontwarn javax.lang.model.type.ErrorType
-dontwarn javax.lang.model.type.ExecutableType
-dontwarn javax.lang.model.type.IntersectionType
-dontwarn javax.lang.model.type.NoType
-dontwarn javax.lang.model.type.NullType
-dontwarn javax.lang.model.type.PrimitiveType
-dontwarn javax.lang.model.type.TypeKind
-dontwarn javax.lang.model.type.TypeMirror
-dontwarn javax.lang.model.type.TypeVariable
-dontwarn javax.lang.model.type.TypeVisitor
-dontwarn javax.lang.model.type.WildcardType
-dontwarn javax.lang.model.util.AbstractElementVisitor8
-dontwarn javax.lang.model.util.ElementFilter
-dontwarn javax.lang.model.util.Elements
-dontwarn javax.lang.model.util.SimpleAnnotationValueVisitor8
-dontwarn javax.lang.model.util.SimpleElementVisitor8
-dontwarn javax.lang.model.util.SimpleTypeVisitor8
-dontwarn javax.lang.model.util.Types
-dontwarn javax.tools.Diagnostic$Kind
-dontwarn javax.tools.JavaFileObject$Kind
-dontwarn javax.tools.JavaFileObject
-dontwarn javax.tools.SimpleJavaFileObject

Want to override our default loader?

The SDK utilizes Lottie animations for the loading experience. To integrate a custom loader, place your Lottie animation file named loader_mix.json in the android/app/src/main/res/raw directory. It is critical to ensure the filename matches exactly as specified for proper integration.

Quick Start

1. Initialize SDK

index.html
import android.content.Intent
import android.os.Bundle
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import com.genuinsdk.GenuinSDKPluginModule
class MainActivity : ReactActivity() {
    /**
     * Returns the name of the main component registered from JavaScript. This is used to schedule
     * rendering of the component.
     */
    override fun getMainComponentName(): String = "YourApp"
    /**
     * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
     * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
     */
    override fun createReactActivityDelegate(): ReactActivityDelegate =
        DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GenuinSDKPluginModule.initSDK(application, "YOUR_API_KEY")
    }
}

2. Configure Deep Linking

To properly handle deep links, incorporate the following configuration into your android/app/src/main/AndroidManifest.xml file:

AndroidManifest.xml
<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
    android:launchMode="singleTask"
    android:windowSoftInputMode="adjustResize"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:host="YOUR_WHITE-LABELLED_DOMAIN" android:scheme="https" />
    </intent-filter>
</activity>
index.html
import android.content.Intent
import android.os.Bundle
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import com.genuinsdk.GenuinSDKPluginModule
class MainActivity : ReactActivity() {
    /**
     * Returns the name of the main component registered from JavaScript. This is used to schedule
     * rendering of the component.
     */
    override fun getMainComponentName(): String = "YourApp"
    /**
     * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
     * which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
     */
    override fun createReactActivityDelegate(): ReactActivityDelegate =
        DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GenuinSDKPluginModule.initSDK(application, "YOUR_API_KEY")
        if (intent != null && intent.data != null) {
            handleDeepLink(intent)
        }
    }
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleDeepLink(intent)
    }
    private fun handleDeepLink(intent: Intent?) {
        intent?.data?.let {
            GenuinSDKPluginModule.handleDeepLink(this@MainActivity, intent)
        }
    }
}

3. Configuring Push Notifications

To enable push notification functionality, insert the following code snippet into your android/app/build.gradle file:

build.gradle
buildscript {
    dependencies {
        classpath("com.google.gms:google-services:4.4.2") 
    }
}

iOS Setup

Step 1: iOS Configuration

In ios/Podfile:

ios/Podfile
ENV['USE_FRAMEWORKS'] = 'dynamic'

# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
  'require.resolve(
    "react-native/scripts/react_native_pods.rb",
    {paths: [process.argv[1]]},
  )', __dir__]).strip
platform :ios, min_ios_version_supported
prepare_react_native_project!
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end
target 'YourApp' do
  config = use_native_modules!
  use_react_native!(
    :path => config[:reactNativePath],
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )
  pre_install do |installer|
      installer.pod_targets.each do |pod|
        if pod.name.eql?('RNReanimated')
          def pod.build_type
          Pod::BuildType.static_library
        end
      end
    end
  end
  post_install do |installer|
    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false,
      # :ccache_enabled => true
    )
    installer.pods_project.targets.each do |target|
      if target.name == 'Giphy'
        `xcrun -sdk iphoneos bitcode_strip -r Pods/Giphy/GiphySDK/GiphyUISDK.xcframework/ios-arm64_armv7/GiphyUISDK.framework/GiphyUISDK -o Pods/Giphy/GiphySDK/GiphyUISDK.xcframework/ios-arm64_armv7/GiphyUISDK.framework/GiphyUISDK`
      end
      target.build_configurations.each do |config|
        config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.1'
        config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
      end
    end
  end
end

Quick Start

1. Initialize SDK

index.html
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import Firebase
@main
class AppDelegate: RCTAppDelegate, UNUserNotificationCenterDelegate {
  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    self.moduleName = "YourApp"
    self.dependencyProvider = RCTAppDependencyProvider()
    if FirebaseApp.app() == nil {
      FirebaseApp.configure()
    }
    UNUserNotificationCenter.current().delegate = self
    UIApplication.shared.registerForRemoteNotifications()

    // You can add your custom initial props in the dictionary below.
    // They will be passed down to the ViewController used by React Native.
    self.initialProps = [:]
    GenuinModuleObjCWrapper.initSDK("YOUR_API_KEY", loaderName: "YOUR_LOTTIE_LOADER_NAME", showNavigationBar: nil)
    addNavVC()
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  func addNavVC(){
    DispatchQueue.main.async {
      if let rootVC = self.window.rootViewController {
        self.window.rootViewController = nil
        let navVC = GenuinModuleObjCWrapper.getGenuinNavigationController(rootVC)
        navVC?.setNavigationBarHidden(true, animated: true);
        self.window.rootViewController = navVC
        self.window.makeKeyAndVisible()
      }
    }
  }
  override func sourceURL(for bridge: RCTBridge) -> URL? {
    self.bundleURL()
  }
  override func bundleURL() -> URL? {
#if DEBUG
    RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
    Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
  }
}

If your project includes an AppDelegate.swift file, you must implement the following Objective-C wrapper classes to facilitate communication with the Genuin React Native module:

  1. GenuinModuleObjCWrapper.h
index.html
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface GenuinModuleObjCWrapper : NSObject
+ (void)initSDK:(NSString *_Nullable)apiKey loaderName:(NSString *_Nullable)loaderName showNavigationBar:(BOOL *_Nullable)showNavigationBar;
+ (BOOL)application:(UIApplication *_Nullable)application continueUserActivity:(NSUserActivity *_Nullable)userActivity restorationHandler:(void (^_Nullable)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler;
+ (BOOL)handleDeepLink:(NSURL * _Nullable)dlURL controller:(UIViewController * _Nullable)controller;
+ (void)handleForegroundNotification:(NSDictionary *)notificationData;
+ (UINavigationController*_Nullable)getGenuinNavigationController:(UIViewController*)viewController;
@end
NS_ASSUME_NONNULL_END

2. GenuinModuleObjCWrapper.mm

index.html
#import "GenuinModuleObjCWrapper.h"
#import "GenuinSDKPlugin.h"
@implementation GenuinModuleObjCWrapper
+ (void)initSDK:(NSString *_Nullable)apiKey loaderName:(NSString *_Nullable)loaderName showNavigationBar:(BOOL *_Nullable)showNavigationBar {
  [GenuinSDKPlugin initSDK:apiKey loaderName:loaderName showNavigationBar:showNavigationBar];
}
+ (BOOL)application:(UIApplication *_Nullable)application continueUserActivity:(NSUserActivity *_Nullable)userActivity restorationHandler:(void (^_Nullable)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
  return [GenuinSDKPlugin application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
}
+ (BOOL)handleDeepLink:(NSURL * _Nullable)dlURL controller:(UIViewController * _Nullable)controller {
  return [GenuinSDKPlugin handleDeepLink:dlURL controller:controller];
}
+ (void)handleForegroundNotification:(NSDictionary *)notificationData {
  [GenuinSDKPlugin handleForegroundNotification:notificationData];
}
+ (UINavigationController*_Nullable)getGenuinNavigationController:(UIViewController*)viewController {
  return [GenuinSDKPlugin getGenuinNavigationController: viewController];
}
@end

3. YourApp-Bridging-Header.h

index.html
#import "GenuinModuleObjCWrapper.h"

2. Configure Deep Linking

To properly handle deep links, incorporate the following configuration into your AppDelegate.swift file:

Prerequisite step: Link

Update AppDelegate.swift:

AppDelegate.swift
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import Firebase
@main
class AppDelegate: RCTAppDelegate, UNUserNotificationCenterDelegate {
  override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
    let result = GenuinModuleObjCWrapper.application(application, continue: userActivity, restorationHandler: restorationHandler)
    if GenuinModuleObjCWrapper.handleDeepLink(userActivity.webpageURL, controller: window.rootViewController) {
        return true
    }
    return result
  }
}

3. Configuring Push Notifications

To implement push notification handling, add the following code block to your AppDelegate.swift file:

AppDelegate.swift
import UIKit
import React
import React_RCTAppDelegate
import ReactAppDependencyProvider
import Firebase
@main
class AppDelegate: RCTAppDelegate, UNUserNotificationCenterDelegate {
  override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    Messaging.messaging().apnsToken = deviceToken
    print("deviceToken", deviceToken)
  }
  override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
      print("\(userInfo )")
      completionHandler(.newData)
  }
  override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: any Error) {
  }
  func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.list, .banner, .badge, .sound])
  }
  func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    if response.notification.request.trigger == nil {
      let notificationData = ["data": response.notification.request.content.userInfo]        GenuinModuleObjCWrapper.handleForegroundNotification(notificationData)
    }
    completionHandler()
  }
}

Web Setup

Web Configuration

Follow these steps to integrate the genuin-react-native SDK into your application:

  1. Import the Feed Component: Within your app.jsx file, import the Feed component from the genuin-react-native SDK.
  2. Obtain Your API Key: Reach out to the Genuin team to secure your unique API_KEY, which is required to authenticate your application.
  3. Implement the Feed Component: Embed the Feed component in your app and pass the API_KEY as a prop, as shown in the example below:
javascript
import React from "react";
import Feed from "genuin-react-native";
export default function App() {
  return <Feed apiKey="API_KEY" />;
}

Carousel

javascript
import React from "react";
import Carousel from "genuin-react-native";
export default function App() {
  return <Carousel apiKey="API_KEY" />;
}

Example Implementation

The following code snippet demonstrates a complete implementation of the app.jsx file within your application:

javascript
import React from "react";
import { SafeAreaView, StyleSheet, Text } from "react-native";
import Feed from "genuin-react-native";
export default function App() {
  return (
    <SafeAreaView style={styles.container}>
      <Text style={styles.header}>Welcome to the Genuin Feed</Text>
      <Feed apiKey="YOUR_API_KEY_HERE" />
    </SafeAreaView>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#F5FCFF",
  },
  header: {
    fontSize: 20,
    textAlign: "center",
    margin: 10,
  },
});

Additional Information

Handling Errors: Ensure you handle any potential errors gracefully. The Feed component can throw errors if the API key is invalid or if there are network issues. Implement error handling in your component as needed to maintain a smooth user experience.

Styling the Feed: You can style the Feed component using standard React Native styling techniques. Customize it to fit the design and aesthetics of your application.

Updating the API Key: If you need to update your API key, simply modify the apiKey prop passed to the Feed component. Ensure your application is reloaded to apply the changes effectively.

React Native

1. Load Carousel Embed View

index.html
import React, { useRef } from 'react';
import { Carousel, PlayPauseRef } from 'genuin-react-native';
export default function App() {
  const carouselRef = useRef<PlayPauseRef>(null);
  return <Carousel ref={carouselRef} style={{height:400, width:'100%'}} embedId='YOUR_EMBED_ID' uniqueId='UNIQUE_ID' ssoToken='YOUR_SSO_TOKEN' isShowProfileEnabled={false} isDirectDeepLinkEnabled={false}  />;
}

1. You can customize the height and width of the Carousel as per your requirements. 2. To programmatically control playback, utilize carouselRef.current?.pause() and carouselRef.current?.resume() to pause and resume video within the Carousel.

Configure EmbedParams by passing the following values based on your use case:

embedId: The unique identifier for the embed you wish to load.

uniqueId: An optional parameter required when the same embedId appears multiple times within a single screen or across multiple screens.

ssoToken: An optional parameter to enable auto-login functionality. Pass a valid SSO token to implement deeply integrated media experiences.

interactionDeepLink: An optional custom redirect URL. If provided, all fullscreen interactions will redirect to this URL. Ensure the URL is valid to prevent redirection failures.

isDirectDeepLinkEnabled: A boolean (default: false). When enabled, fullscreen interactions redirect directly to the video in your white-labelled app, overriding any value in interactionDeepLink.

Using isDirectDeepLinkEnabled requires a configured white-labelled domain and proper deep link handling within your host application.

isShowProfileEnabled: A boolean (default: false). If enabled for authenticated users, the profile picture will appear in the top-right corner, providing access to account settings and logout.

2. Load Standard Wall Embed View

index.html
import React, { useRef } from 'react';
import { PlayPauseRef, StandardWall } from 'genuin-react-native';
export default function App() {
  const standardWallRef = useRef<PlayPauseRef>(null);
  return <StandardWall ref={standardWallRef} style={{height:'100%', width:'100%'}} embedId='YOUR_EMBED_ID' uniqueId='UNIQUE_ID' ssoToken='YOUR_SSO_TOKEN' isShowProfileEnabled={false} isDirectDeepLinkEnabled={false}  />;
}

1. You can customize the height and width of the StandardWall as per your requirements. 2. To programmatically control playback, utilize standardWallRef.current?.pause() and standardWallRef.current?.resume() to pause and resume video within the StandardWall.

Configure EmbedParams by passing the following values based on your use case:

embedId: The unique identifier for the embed you wish to load.

uniqueId: An optional parameter required when the same embedId appears multiple times within a single screen or across multiple screens.

ssoToken: An optional parameter to enable auto-login functionality. Pass a valid SSO token to implement deeply integrated media experiences.

interactionDeepLink: An optional custom redirect URL. If provided, all fullscreen interactions will redirect to this URL. Ensure the URL is valid to prevent redirection failures.

isDirectDeepLinkEnabled: A boolean (default: false). When enabled, fullscreen interactions redirect directly to the video in your white-labelled app, overriding any value in interactionDeepLink.

Using isDirectDeepLinkEnabled requires a configured white-labelled domain and proper deep link handling within your host application.

isShowProfileEnabled: A boolean (default: false). If enabled for authenticated users, the profile picture will appear in the top-right corner, providing access to account settings and logout.

3. Load FullScreen Embed View

index.html
import React, { useRef } from 'react';
import { Feed, PlayPauseRef } from 'genuin-react-native';
export default function App() {
  const feedRef = useRef<PlayPauseRef>(null);
  return <Feed ref={feedRef} style={{height:'100%', width:'100%'}} embedId='YOUR_EMBED_ID' uniqueId='UNIQUE_ID' ssoToken='YOUR_SSO_TOKEN' isShowProfileEnabled={false} isDirectDeepLinkEnabled={false}  />;
}

1. You can customize the height and width of the Feed as per your requirements. 2. To programmatically control playback, utilize feedRef.current?.pause() and feedRef.current?.resume() to pause and resume video within the Feed.

Configure EmbedParams by passing the following values based on your use case:

embedId: The unique identifier for the embed you wish to load.

uniqueId: An optional parameter required when the same embedId appears multiple times within a single screen or across multiple screens.

ssoToken: An optional parameter to enable auto-login functionality. Pass a valid SSO token to implement deeply integrated media experiences.

interactionDeepLink: An optional custom redirect URL. If provided, all fullscreen interactions will redirect to this URL. Ensure the URL is valid to prevent redirection failures.

isDirectDeepLinkEnabled: A boolean (default: false). When enabled, fullscreen interactions redirect directly to the video in your white-labelled app, overriding any value in interactionDeepLink.

Using isDirectDeepLinkEnabled requires a configured white-labelled domain and proper deep link handling within your host application.

isShowProfileEnabled: A boolean (default: false). If enabled for authenticated users, the profile picture will appear in the top-right corner, providing access to account settings and logout.

4. Load HomeFeed View (Android Specific)

index.html
import React, { useRef } from 'react';
import { HomeFeed, PlayPauseRef } from 'genuin-react-native';
export default function App() {
  const homeFeedRef = useRef<PlayPauseRef>(null);
  return <HomeFeed ref={homeFeedRef} style={{height:'100%', width:'100%'}}  />;
}

1. You can customize the height and width of the HomeFeed as per your requirements. 2. To programmatically control playback, utilize homeFeedRef.current?.pause() and homeFeedRef.current?.resume() to pause and resume video within the HomeFeed.

5. Handling Push Notifications

Prerequisite:

Create a Firebase project and integrate it into your application by following the official documentation at https://firebase.google.com/docs/flutter/setup.

Step 1: Create firebase_options.dart within the lib folder and incorporate the following configuration details into that file.

index.html
import 'package:firebase_core/firebase_core.dart';
class DefaultFirebaseOptions {
  static FirebaseOptions get currentPlatform {
    if (Platform.isAndroid) {
      return const FirebaseOptions(
        apiKey: 'YOUR-ANDROID-API-KEY',
        appId: 'YOUR-ANDROID-APP-ID',
        messagingSenderId: 'YOUR-SENDER-ID',
        projectId: 'YOUR-PROJECT-ID',
        storageBucket: 'YOUR-STORAGE-BUCKET',
      );
    }else{
      return const FirebaseOptions(
        apiKey: 'YOUR-IOS-API-KEY',
        appId: 'YOUR-IOS-APP-ID',
        messagingSenderId: 'YOUR-SENDER-ID',
        projectId: 'YOUR-PROJECT-ID',
        storageBucket: 'YOUR-STORAGE-BUCKET',
      );
    }
  }
}

Step 2: Handling background/foreground notifications

For Android integration, you must provide a small notification icon using the “icon” key for foreground notifications. It is critical to ensure this icon is present within both your Flutter and Android directories to maintain consistent notification behavior.

index.html
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:genuin_sdk/genuin_sdk.dart';
import 'firebase_options.dart';

// This method will be called when app is in background and push received
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
}
final _genuinSdkPlugin = GenuinSdk();
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    name: 'YOUR_FIREBASE_PROJECT_NAME',
    options: DefaultFirebaseOptions.currentPlatform,
  );
  final messaging = FirebaseMessaging.instance;

  // Asking push notification permission
  final settings = await messaging.requestPermission(
    alert: true,
    announcement: false,
    badge: true,
    carPlay: false,
    criticalAlert: false,
    provisional: false,
    sound: true,
  );

  // If permission is granted than get firebase token and register it with Genuin SDK
  if (settings.authorizationStatus == AuthorizationStatus.authorized) {
    String? token = await messaging.getToken();
    if (token != null) {
      await _genuinSdkPlugin.registerFCMToken(token);
    }
  }

  // Check for initial notification that opened the app
  RemoteMessage? initialMessage =
  await FirebaseMessaging.instance.getInitialMessage();
  if (initialMessage != null) {
    // Handle navigation or actions
    final notificationData = {
      'title': initialMessage.notification?.title,
      'body': initialMessage.notification?.body,
      'data': initialMessage.data,
    };
    var willHandleNotification = await _genuinSdkPlugin
        .willHandleBackgroundNotifications(notificationData);
    if (willHandleNotification == true) {
      _genuinSdkPlugin.handleBackgroundNotifications(notificationData);
    } else {
      // Your notification handling
    }
  }

  // This method will be called when app is in foreground and push received
  FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
    if (kDebugMode) {
      print('Handling a foreground message: ${message.messageId}');
      print('Message data: ${message.data}');
      print('Message notification: ${message.notification?.title}');
      print('Message notification: ${message.notification?.body}');
    }
    final notificationData = {
      'title': message.notification?.title,
      'body': message.notification?.body,
      'data': message.data,
      'icon': 'mipmap/ic_notification'
      // OR 'icon':'drawable/ic_notification'[if image put under drawable folder]
    };
    var willHandleNotification = await _genuinSdkPlugin
        .willHandleForegroundNotifications(notificationData);
    if (willHandleNotification == true) {
      _genuinSdkPlugin.handleForegroundNotifications(notificationData);
    } else {
      // Your notification handling
    }
  });
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  //This method will be called when user clicked on notification[Push notification is received when app is in background/killed]
  FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
    final notificationData = {
      'title': message.notification?.title,
      'body': message.notification?.body,
      'data': message.data,
    };
    var willHandleNotification = await _genuinSdkPlugin
        .willHandleBackgroundNotifications(notificationData);
    if (willHandleNotification == true) {
      _genuinSdkPlugin.handleBackgroundNotifications(notificationData);
    } else {
      // Your notification handling
    }
  });
  runApp(const MyApp());
}

5. Handle SSO Login Explicitly in SDK

To enable auto-login functionality within the SDK, invoke the following method whenever a user authenticates within your application.

Invocation of this method is not required if you have already implemented Embed with SSO.

index.html
import 'package:genuin_sdk/genuin_sdk.dart';
final _genuinSdkPlugin = GenuinSdk();
await _genuinSdkPlugin.ssoLogin("YOUR_SSO_TOKEN");

6. Handle SSO Logout in SDK

index.html
import 'package:genuin_sdk/genuin_sdk.dart';
final _genuinSdkPlugin = GenuinSdk();
await _genuinSdkPlugin.ssoLogout();

Embed Views (Core SDK Components)

1. Carousel Embed

Best for: Horizontal scrolling video discovery

index.html
<Carousel embedId="YOUR_EMBED_ID" />

2. Standard Wall

Best for: Grid-based browsing

index.html
<StandardWall embedId="YOUR_EMBED_ID" />

3. Fullscreen Feed

Best for: TikTok/Reels-like experience

index.html
<Feed embedId="YOUR_EMBED_ID" />

4. Home Feed (Android)

Native feed experience:

index.html
<HomeFeed />

Key Configuration Parameters

ParameterDescription
embedIdUnique ID of the embed
uniqueIdRequired when same embed appears multiple times
ssoTokenEnables auto-login
interactionDeepLinkCustom redirect URL
isDirectDeepLinkEnabledRedirects to native app video
isShowProfileEnabledShows user profile in UI

Specs & Limitations

System Behaviour

  • SDK initializes at app launch using API key
  • Supports real-time content rendering
  • Handles deep links and push notifications natively
  • Provides playback controls (pause/resume)

Validation Rules

  • Valid API key is mandatory
  • Deep linking requires white-labelled domain
  • SSO token must be secure and user-specific
  • Firebase setup required for push notifications

Limitations

  • Minimum Android SDK: 24
  • iOS deployment target: 15.1+
  • Material theme required for Android
  • Duplicate embed instances require uniqueId
  • Deep link redirection depends on proper configuration

Example Scenarios

Scenario 1: Retail App Engagement

A fashion brand embeds a carousel on the homepage to showcase trending looks and drive product discovery.

Scenario 2: OTT / Media App

A publisher integrates a fullscreen feed to deliver short-form content alongside long-form streaming.

Scenario 3: Community Platform

A brand enables SSO-based feeds where logged-in users can interact, comment, and engage seamlessly.

FAQs

1. Do I need separate setups for Android and iOS?

Yes. Both platforms require platform-specific configurations.

2. Can I customize the UI?

Yes. Use React Native styling and configuration parameters.

3. How does SSO work?

Pass a valid ssoToken to auto-authenticate users inside the SDK.

4. What happens if deep linking is not configured?

The SDK falls back to default navigation behavior.

5. Can I pause videos programmatically?

Yes. Use PlayPauseRef to control playback.

Related Articles

Genuin Footer