Flutter SDK integration
Add BNotify to any Flutter app with the bnotify_flutter package. After setup, devices register automatically and can receive pushes plus in-app campaigns on Android and iOS. Web is not supported.
Before Dart setup, create a project, register Android and iOS apps, and download bnotify-config.json plus bnotify-config.plist. Package name and bundle id must match the Flutter app.
What you get after integration
| Capability | Result |
|---|---|
| Device registration | Device appears in the BNotify dashboard after initialize + permission |
| Push notifications | System notifications on Android and iOS |
| Background / killed app | Notifications can still arrive after the first successful init |
| Notification tap | Dart BNotify.onClick with a screen value you can route on |
| In-app messages | Native in-app UI when Console campaigns match events you log |
| Device token | Dart BNotify.onToken |
The Flutter SDK does not send campaigns. Create and send messages from the BNotify dashboard. The SDK registers the device, displays messages, and reports engagement.
Prerequisites
| Requirement | Notes |
|---|---|
| Flutter 3.24+ / Dart 3.13+ | Matches the plugin pubspec.yaml |
| Android + iOS only | No web implementation |
| BNotify Console account | Project + Android app + iOS app |
Android minSdk 24 | Required |
| iOS 13.0+ | Required |
| Physical devices | Recommended for push testing |
Integration checklist
- 1Register Android and iOS apps in Console with the exact
applicationId/ bundle id - 2Download
bnotify-config.jsonandbnotify-config.plist - 3Add
bnotify_flutter: ^0.1.2and runflutter pub get - 4Place JSON as a Flutter asset and at
android/app/bnotify-config.json - 5Android: JitPack, minSdk 24,
BNotifyFlutterActivity,singleTask, AppCompat themes - 6iOS: plist on Runner, Push capability, optional Notification Service Extension
- 7Dart: subscribe to streams,
initialize, thenrequestPermission - 8Send a test campaign from the Console
Step 1 — Console
Open the BNotify Console. Create a project, then register:
- An Android app whose package name equals
applicationIdinandroid/app/build.gradle.kts - An iOS app whose bundle id equals the Runner bundle identifier
Download bnotify-config.json and bnotify-config.plist. Do not commit real keys to a public repository. Full walkthrough: Create a project.
Step 2 — Add the package
Install from pub.dev.
dependencies:
bnotify_flutter: ^0.1.2
flutter:
assets:
- assets/bnotify-config.json
Then run flutter pub get. Copy the Console files to:
assets/bnotify-config.jsonandroid/app/bnotify-config.json(same JSON — required so Android can start when a notification creates the process)ios/Runner/bnotify-config.plist
Install from pub.dev only. The plugin source repository is private (not open source).
Step 3 — Dart initialize, permission, and listeners
Subscribe to streams before initialize so you do not miss a token or a cold-start tap.
import 'package:bnotify_flutter/bnotify_flutter.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
BNotify.onToken.listen((token) {
debugPrint('BNotify token: $token');
});
BNotify.onMessage.listen((message) {
debugPrint('BNotify message: ${message.title} ${message.body}');
});
BNotify.onClick.listen((click) {
debugPrint('BNotify click screen=${click.screen}');
});
await BNotify.initialize(
configAsset: 'assets/bnotify-config.json',
);
runApp(const MyApp());
}
After the first frame (or from a settings screen), request notification permission:
await BNotify.requestPermission();
| API | When to call |
|---|---|
BNotify.initialize | Once per process, after ensureInitialized |
BNotify.requestPermission | Android 13+ / iOS notification permission |
BNotify.logEvent('…') | Match an in-app campaign trigger |
BNotify.onToken | Device token stream |
BNotify.onMessage | Incoming payload (optional if system UI is on) |
BNotify.onClick | Route after a notification tap |
BNotify.setAutoNotifications | Android only: system tray vs custom UI |
configAsset is read on Android. iOS uses ios/Runner/bnotify-config.plist. Pass configAsset anyway so one initialize call works on both platforms.
Hot reload does not re-run native Kotlin/Swift. After changing MainActivity, manifests, or the plist, do a full restart.
Step 4 — Android host setup
Do every item in this section. Skipping the Activity or theme steps is the usual reason in-app messages never appear.
JitPack + minSdk 24
Add JitPack in android/settings.gradle.kts (pluginManagement.repositories) and in android/build.gradle.kts repositories:
maven { url = uri("https://jitpack.io") }
defaultConfig {
applicationId = "com.example.my_app" // must match Console
minSdk = 24
}
Copy config into Android assets
Keep android/app/bnotify-config.json. Add this above the android { } block in android/app/build.gradle.kts:
val bnotifyConfigFile = file("bnotify-config.json")
val bnotifyAssetsDir = file("src/main/assets")
tasks.register<Copy>("copyBnotifyConfigAsset") {
from(bnotifyConfigFile)
into(bnotifyAssetsDir)
onlyIf { bnotifyConfigFile.exists() }
}
tasks.matching { it.name == "preBuild" }.configureEach {
dependsOn("copyBnotifyConfigAsset")
}
MainActivity must extend BNotifyFlutterActivity
Do not extend FlutterActivity or FlutterFragmentActivity.
import com.convex.bnotify_flutter.BNotifyFlutterActivity
class MainActivity : BNotifyFlutterActivity()
Manifest and themes
Use android:launchMode="singleTask". Do not set android:taskAffinity="" (that creates two Recents cards). LaunchTheme and NormalTheme must use Theme.AppCompat.* (for example Theme.AppCompat.Light.NoActionBar).
Call BNotify.requestPermission() at runtime on Android 13+. Keep the INTERNET permission.
Step 5 — iOS host setup
- Copy
bnotify-config.plisttoios/Runner/bnotify-config.plistand enable Target Membership → Runner. - In Xcode → Signing & Capabilities, add Push Notifications.
- Minimum iOS 13. If you use Flutter’s Swift Package Manager path:
flutter config --enable-swift-package-manager.
A stock FlutterAppDelegate is enough. You do not need to call native BNotify APIs from AppDelegate for basic push.
Notification Service Extension (images)
To show images in the banner, add a Notification Service Extension, add the iOS SDK (bnotifyiossdk, product BNotify), enable the same App Group on Runner and the extension, then call:
BNotifyExtensionSafe.prepareNotificationContent(
request,
appGroupId: bnotifyAppGroupId
) { content in
contentHandler(content)
}
Without an extension, text notifications still work. See the iOS NSE section for the full native pattern.
In-app campaigns
In the Console, create an in-app campaign whose trigger name matches a string you log (for example app_open):
await BNotify.logEvent('app_open');
The name must match the Console trigger exactly. Android in-app UI requires BNotifyFlutterActivity and AppCompat themes.
Notification tap routing
Listen to BNotify.onClick and use click.screen (set on the campaign in the Console) to navigate. Subscribe in main() before initialize so a tap that opened a killed app still reaches Dart.
BNotify.onClick.listen((click) {
final screen = click.screen;
if (screen == null || screen.isEmpty) return;
navigatorKey.currentState?.pushNamed(screen);
});
Optional: await BNotify.setAutoNotifications(false) on Android to draw your own UI from onMessage. iOS always uses the system notification UI.
Verification
Use a physical device and real Console files (not placeholders).
| # | Test | Expected |
|---|---|---|
| 1 | Cold start, initialize | No exception; onToken prints a token |
| 2 | requestPermission | System dialog; user allows |
| 3 | Console device list | This install appears |
| 4 | Send a push, app backgrounded or swiped away | Tray / banner notification |
| 5 | Tap the notification | onClick fires; one Recents card |
| 6 | logEvent with a matching campaign | In-app UI appears |
Troubleshooting
| Symptom | What to check |
|---|---|
initialize throws missing config | Asset listed in pubspec.yaml; iOS plist on the Runner target |
| No token | Permission denied; package/bundle ≠ Console; placeholder keys |
| Pushes only while the UI is open | Android JSON not packaged as an asset; first init never succeeded |
| Two Recents cards | Remove empty taskAffinity; use singleTask |
| In-app never shows (Android) | MainActivity still extends FlutterActivity; themes not AppCompat; full rebuild |
| Launch crash (Android theme) | LaunchTheme / NormalTheme must use Theme.AppCompat.* |
Gradle cannot find bnotifysdk | JitPack missing from Gradle repositories |
minSdk error | Set minSdk = 24 in the app module |
| iOS images missing | No Notification Service Extension / App Group |
Pin bnotify_flutter: ^0.1.2, keep Console files out of public git, test onClick from a killed app, and complete APNs / Play signing as usual.