Integrate the Genuin SDK with Flutter apps
Add the genuin_sdk plugin to a Flutter project and configure the Android and iOS hosts it needs.
The Genuin Flutter SDK is the genuin_sdk plugin, version 1.0.1 on pub.dev. It wraps the native Genuin SDKs: genuin_android_sdk 1.1.9.3 on Android and the GenuinSDK 1.1.9.1 pod on iOS. The plugin gives you four embed widgets and a GenuinSdk class for sign-in, push notifications, and playback control.
This page gets the project to build: the dependency, the Android and iOS host configuration, and the permissions the native SDKs bring with them. When the project builds, continue with Initialize the Genuin SDK and load a feed in Flutter to initialize the SDK and render your first embed.
Requirements
| Minimum | |
|---|---|
| Flutter | 3.24.4. The plugin requires Dart ^3.5.4, and Flutter 3.24.4 is the first stable release that ships it. |
| Android | API 24 (Android 7.0), compileSdk 34, Android Gradle Plugin 8.1.0, Kotlin 1.8.22. The launcher activity must extend FlutterFragmentActivity. |
| iOS | 13.0, Swift 5, CocoaPods. The plugin's example app builds for iOS 15.0. |
| Native SDKs | Fixed by the plugin: org.bitbucket.genuindev:genuin_android_sdk:1.1.9.3 from JitPack, and the GenuinSDK CocoaPod at ~> 1.1.9.1. |
| Orientation | Portrait. The native Android screens lock to portrait. |
| Devices | Phones with a camera, a front camera, and a microphone. The Android SDK declares all three as required hardware. |
You also need an API key for your brand and at least one embed ID, both from Brand Control Center. The key is the same one the Android, iOS, and Web SDKs use.
Note: The plugin pins native SDK 1.1.9.x. Integrate the Genuin Android SDK and Integrate the Genuin iOS SDK describe version 2.1.5, which has features the Flutter plugin doesn't expose, such as placements, contextual parameters, and event callbacks.
Step 1: Add the dependency
- Add the package to
pubspec.yaml:
dependencies:
flutter:
sdk: flutter
genuin_sdk: ^1.0.1- Run
flutter pub get.
The package has one library per widget. package:genuin_sdk/genuin_sdk.dart exports only the GenuinSdk class. The widgets come from genuin_carousel_embed_view.dart, genuin_feed_embed_view.dart, genuin_standard_wall_view.dart, and genuin_feed_view.dart. The initialization page lists the import for each widget.
Step 2: Configure the Android project
Add the JitPack repository
The native Android SDK is published on JitPack, not Maven Central. In android/build.gradle, add JitPack for every project:
allprojects {
repositories {
google()
mavenCentral()
maven { url "https://jitpack.io" }
}
}If Gradle reports Could not find org.bitbucket.genuindev:genuin_android_sdk:1.1.9.3, this repository is missing.
Set the minimum SDK version
The plugin declares minSdk 24, which is higher than the Flutter template default. In android/app/build.gradle:
android {
compileSdk = flutter.compileSdkVersion // 34 or later
defaultConfig {
minSdk = 24
targetSdk = flutter.targetSdkVersion
}
}Make sure android/gradle.properties contains android.useAndroidX=true and android.enableJetifier=true. The plugin's example app sets both.
Update the manifest
Make three changes to the Flutter template. Replace the SDK's android:label, and give the activity singleTask launch mode so deep links reach the running activity. Remove android:taskAffinity="" if the template added it.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:label="{{APP_NAME}}"
android:icon="@mipmap/ic_launcher"
tools:replace="android:label">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>tools:replace="android:label" is required because the SDK's own manifest sets android:label, and the manifest merger refuses two different values.
Tip: The plugin's README recommends android:windowSoftInputMode="adjustPan" for smoother SDK screens. The example app ships with adjustResize; both work.
Register your white-labelled domain (Optional)
To open Genuin links in your app, add an https intent filter for your white-labelled domain inside the same <activity>:
<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_DOMAIN}}" android:scheme="https" />
</intent-filter>autoVerify needs a Digital Asset Links file on your domain. Genuin serves it from your brand's configuration once you send your package name and signing fingerprints; Handle Genuin deep links in your app covers the request. The code that hands the link to the SDK is on the initialization page.
Use a Material theme
The native SDK is built on Material Components, and its views throw when the host theme isn't a Material Components theme. Change the two styles in android/app/src/main/res/values/styles.xml, and make the same change in values-night/styles.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>The .Bridge variants keep AppCompat attributes working, so the rest of your app doesn't need to change.
Add ProGuard rules
The Android SDK ships no consumer rules: the proguard.txt inside its AAR is empty. Release builds shrink with R8, and without rules they strip classes the SDK reaches through reflection. Flutter adds android/app/proguard-rules.pro to release builds when the file exists, so create it with these rules:
-keep class com.bumptech.glide.** { *; }
-keep public class * { public *; protected *; }
-keepattributes Signature, InnerClasses, EnclosingMethod, *Annotation*
-keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
-if interface * { @retrofit2.http.* <methods>; }
-keep,allowobfuscation interface <1>
-keep class com.begenuin.begenuin.data.model.** { <fields>; }
-keep class com.begenuin.begenuin.vo.** { <fields>; }
-keep class com.giphy.sdk.core.models.** { *; }
-keep class com.giphy.sdk.ui.views.** { *; }
-keep class com.google.mediapipe.solutioncore.** { *; }
-keep class com.google.protobuf.** { *; }
-keep public class * implements java.lang.reflect.Type
-dontwarn com.begenuin.sdk.BRThese are the keep rules. The full file also carries about 100 -dontwarn lines for optional dependencies. Copy it from the plugin's example app, at example/android/app/proguard-rules.pro inside the genuin_sdk-1.0.1 folder of your pub cache.
Caution: -keep public class * { public *; protected *; } keeps every public class in your app, which disables most of R8's obfuscation. Narrow it to the SDK's packages only after testing a release build with the narrower rule.
Replace the loading animation (Optional)
The SDK shows a Lottie animation named loader_mix while content loads. To use your own, save a Lottie file as android/app/src/main/res/raw/loader_mix.json. A resource with that exact name overrides the SDK's.
Step 3: Configure the iOS project
Set the platform and build settings in the Podfile
The plugin's example app pins the platform to iOS 15.0 and adds a post_install hook. In ios/Podfile:
platform :ios, '15.0'
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(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.0'
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
endThen run pod install in the ios folder.
The hook does two things. The bitcode_strip command removes bitcode from the Giphy framework that the Genuin SDK uses, because App Store Connect rejects uploads that contain bitcode since Xcode 14. The two build settings apply to every pod; keep them as the example app has them.
Both the genuin_sdk and GenuinSDK podspecs allow iOS 13.0. You can lower both 15.0 values to 13.0 if you support iOS 13 and 14, but the plugin's example app is configured for 15.0.
Add usage descriptions to Info.plist
The native iOS SDK includes recording, upload, contacts, and location flows, and iOS terminates an app that reaches a protected resource without the matching Info.plist key. The plugin's example app declares none, so add the keys for the features your embeds enable:
| Key | Add it when |
|---|---|
| NSCameraUsageDescription | Viewers record video posts or video comments |
| NSMicrophoneUsageDescription | Viewers record video or voice comments |
| NSPhotoLibraryUsageDescription | Viewers upload from, or save videos to, their photo library |
| NSSpeechRecognitionUsageDescription | Voice comments are transcribed |
| NSContactsUsageDescription | Viewers add contacts as community or group members |
| NSLocationWhenInUseUsageDescription | Location-based community suggestions are on |
| NSUserTrackingUsageDescription | Your brand runs ads in embeds |
The wording the Genuin iOS team uses for each key is in Integrate the Genuin iOS SDK.
Enable universal links (Optional)
Genuin links use your white-labelled domain. For iOS to hand them to your app, add the Associated Domains capability in Xcode with applinks:{{YOUR_DOMAIN}}. Then send your Team ID and bundle ID to your Genuin contact, who adds your app to the apple-app-site-association file Genuin serves on that domain. Handle Genuin deep links in your app covers the request. The AppDelegate code that passes the link to the SDK is on the initialization page.
Add a custom loader (Optional)
On iOS the loading animation is chosen at initialization. Add a Lottie JSON file to the Runner target so it's copied into the main bundle, and pass its name as loaderName when you call GenuinSdkPlugin.initialize.
Permissions
Android
The native SDK's manifest declares every permission it uses, and the manifest merger copies them into your app. You don't add any yourself, but they appear in your Play Console listing, so know what each one is for:
| Permission | Used for |
|---|---|
| INTERNET, ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE, WAKE_LOCK, VIBRATE | Loading and playing video, notifications |
| POST_NOTIFICATIONS | Push notifications on Android 13 and later |
| CAMERA, RECORD_AUDIO | Recording video posts and voice comments |
| READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE (API 28 and below) | Uploading from the gallery and saving videos |
| READ_CONTACTS | Adding contacts as community and group members |
| ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION | Location-based community suggestions |
| READ_PHONE_STATE, WRITE_SETTINGS | Declared by the SDK; Genuin hasn't documented what uses them |
| com.google.android.gms.permission.AD_ID | The advertising ID for monetization. Google Play requires an advertising ID declaration in Play Console; see the Android SDK guide. |
The SDK asks for the runtime permissions when a viewer reaches the feature. The one exception is POST_NOTIFICATIONS, which your Flutter code requests through firebase_messaging as shown on the initialization page.
The SDK also declares the camera, front camera, microphone, and OpenGL ES 2.0 as required hardware features. Google Play hides the app from devices without them. To stay available on such devices, override the flag in your own manifest and confirm the result in Android Studio's Merged Manifest tab:
<uses-feature
android:name="android.hardware.camera"
android:required="false"
tools:replace="android:required" />Repeat for android.hardware.camera.front and android.hardware.microphone. Recording then fails on devices without the hardware, but browsing and playback work.
iOS
iOS has no manifest permissions. Add the usage descriptions from Step 3 and iOS asks the viewer at first use.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Could not find org.bitbucket.genuindev:genuin_android_sdk:1.1.9.3 | The JitPack repository isn't declared | Add maven { url "https://jitpack.io" } to allprojects.repositories in android/build.gradle. |
| uses-sdk:minSdkVersion 21 cannot be smaller than version 24 declared in library | minSdk is below 24 | Set minSdk = 24 in android/app/build.gradle. |
| Manifest merger failed : Attribute application@label value=... is also present at [...] | The SDK's manifest sets its own android:label | Add xmlns:tools and tools:replace="android:label" to <application>. |
| Embeds render blank on Android, and Logcat shows ClassCastException: MainActivity cannot be cast to androidx.fragment.app.FragmentActivity | MainActivity extends FlutterActivity | Extend FlutterFragmentActivity. The plugin hosts the native feeds in fragments. |
| Crash when an SDK screen opens: The style on this component requires your app theme to be Theme.MaterialComponents | The app theme isn't a Material Components theme | Use Theme.MaterialComponents.Light.NoActionBar.Bridge as in Step 2. |
| Release build crashes in com.begenuin classes or feeds load empty, while the debug build works | R8 removed classes the SDK reaches by reflection, and the AAR ships no consumer rules | Add android/app/proguard-rules.pro as in Step 2. |
| pod install fails: Specs satisfying the GenuinSDK (~> 1.1.9.1) dependency were found, but they required a higher minimum deployment target | platform :ios is below 13.0 | Set platform :ios to 13.0 or higher. |
| App Store Connect rejects the upload: ITMS-90482: Invalid Executable ... contains bitcode | The Giphy framework contains bitcode | Keep the bitcode_strip command in post_install and rebuild. |
Limitations
- Native versions are fixed: The plugin pins
genuin_android_sdk1.1.9.3 andGenuinSDK1.1.9.1. You can't move to a newer native SDK from Flutter; a new plugin release is needed. - Production only: There's no environment setting. The native Android SDK calls
https://api.begenuin.com, so a key issued for another environment doesn't work. FlutterFragmentActivityonly: The plugin casts the launcher activity toFragmentActivity; a plainFlutterActivityrenders empty embeds.- Required hardware: Camera, front camera, and microphone are required features unless you override them as shown in Permissions.
- Portrait phones: The SDK isn't laid out for landscape or tablets.
- Size: The Android AAR is 21 MB before its dependencies, which include FFmpegKit, MediaPipe, CameraX, Media3, and Giphy. The iOS pod brings FFmpegKit, MediaPipe, Giphy, and the Google IMA SDK. On Android, build with
flutter build appbundleor--split-per-abito keep downloads small. - GPL component: Both native SDKs link the GPL build of FFmpegKit (
ffmpeg-kit-min-gpl6.0). - No consumer ProGuard rules: Release builds need the rules from Step 2.

