notify_mvp 1.0.1 copy "notify_mvp: ^1.0.1" to clipboard
notify_mvp: ^1.0.1 copied to clipboard

Official Flutter SDK for NotifyMVP — a OneSignal-like push notification platform. Handles FCM token registration, auto-refresh, and device identification with zero boilerplate.

notify_mvp — Flutter SDK #

Official Flutter SDK for NotifyMVP — a self-hosted push notification platform.

What it does #

  • Requests FCM (Firebase Cloud Messaging) permission
  • Registers the device token with your NotifyMVP backend
  • Auto re-registers when the FCM token refreshes
  • Persists a stable deviceId across app restarts using secure storage
  • Retries failed registrations with exponential backoff

Installation #

Add to your app's pubspec.yaml:

dependencies:
  notify_mvp: ^1.0.0
  firebase_core: ^3.0.0
  firebase_messaging: ^15.0.0

Run:

flutter pub get

Setup #

1. Configure Firebase #

Follow the FlutterFire setup guide to:

  1. Create a Firebase project
  2. Add your Android/iOS apps
  3. Download google-services.json (Android) and GoogleService-Info.plist (iOS)
  4. Run flutterfire configure to generate firebase_options.dart

2. Android — android/app/build.gradle (or build.gradle.kts) #

A. Apply Google Services Plugin:

plugins {
    id 'com.google.gms.google-services'
}

B. Enable Core Library Desugaring (Required for High-Priority Notifications):

Why is this required?
NotifyMVP Flutter SDK delivers high-priority Heads-Up system notifications (pop-up banner with sound & vibration) using Java 8+ Android APIs. Enabling core library desugaring allows older Android versions to process these APIs without crashing.

If using Groovy (build.gradle):

android {
    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
        coreLibraryDesugaringEnabled true
    }
}

dependencies {
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
}

If using Kotlin DSL (build.gradle.kts):

android {
    ...
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
        isCoreLibraryDesugaringEnabled = true
    }
}

dependencies {
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
}

C. Add Default Notification Channel to android/app/src/main/AndroidManifest.xml:

Inside your <application> tag, add this <meta-data> entry so Android FCM assigns background notifications to the High-Priority Pop-up Channel (enabling top pop-up banners on mobile home screen):

<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="notifymvp_heads_up_channel" />

3. iOS — ios/Runner/Info.plist #

Add background modes for push notifications:

<key>UIBackgroundModes</key>
<array>
    <string>fetch</string>
    <string>remote-notification</string>
</array>

Usage #

Initialize in main.dart #

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:notify_mvp/notify_mvp.dart';

/// Background message handler for FCM — must be a top-level function
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  try {
    await Firebase.initializeApp();
  } catch (_) {}
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 1. Initialize Firebase & FCM Background Handler
  try {
    await Firebase.initializeApp();
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    // 2. Initialize NotifyMVP SDK
    await NotifyMVP.initialize(
      appId: 'app_your_app_id',         // From dashboard → Projects
      apiKey: 'your_api_key_here',      // From dashboard → Projects
      baseUrl: 'https://notify.earnslash.com', // Your NotifyMVP URL
      debugLogging: false,              // Set true in development
    );
  } catch (e) {
    debugPrint('NotifyMVP / Firebase init info: $e');
  }

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'NotifyMVP App',
      theme: ThemeData.dark(useMaterial3: true),
      home: const HomeScreen(),
    );
  }
}

Handle foreground notifications #

@override
void initState() {
  super.initState();

  // Foreground messages
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print('Title: ${message.notification?.title}');
    print('Body:  ${message.notification?.body}');
  });
}

External User ID (OneSignal-style User Linking) #

Link a user ID (e.g., Firebase Auth UID, User Database ID) to target specific users in your notifications:

// Option A: Pass externalUserId on initialize
await NotifyMVP.initialize(
  appId: 'app_a3f9bc12',
  apiKey: 'your_api_key',
  baseUrl: 'https://your-app.vercel.app',
  externalUserId: 'user_12345', // Link user immediately
);

// Option B: Link user after login
await NotifyMVP.login('user_12345'); // or NotifyMVP.setExternalUserId('user_12345')

// Unlink user on logout
await NotifyMVP.logout();

Dashboard Launch URL arrives as data['url'].

// Cold start (app was killed)
final initial = await NotifyMVP.getInitialNotification();
if (initial?.url != null) {
  // GoRouter.of(context).go(initial!.url!);
}

// Background → tap
NotifyMVP.onNotificationOpened().listen((payload) {
  if (payload.url != null) {
    // navigate using payload.url
  }
});

Manual registration #

// Re-register (e.g. after permissions change)
final result = await NotifyMVP.register();

if (result.isSuccess) {
  print('Registered! deviceId: ${result.data?['deviceId']}');
} else {
  print('Failed: ${result.error}');
}

API Reference #

NotifyMVP.initialize(...) #

Parameter Type Required Default Description
appId String ✅ — Your NotifyMVP App ID
apiKey String ✅ — Your NotifyMVP API Key
baseUrl String ✅ — NotifyMVP deployment URL
externalUserId String? ❌ null Optional User ID (Firebase UID / DB ID)
debugLogging bool ❌ false Enable console logs
autoRegister bool ❌ true Register on init

Returns NotifyResult — check .isSuccess and .error.

NotifyMVP.login(userId) / setExternalUserId(userId) #

Link this device subscription to a user ID for targeted pushes.

NotifyMVP.logout() #

Unlink user ID from this device subscription.

NotifyMVP.register() #

Manually register or re-register the device. Returns NotifyResult.

NotifyMVP.fcmToken #

String? — the current FCM token. Null until initialized.

NotifyMVP.isInitialized #

bool — whether the SDK has been initialized.


NotifyConfig (advanced) #

Pass a custom config object for fine-grained control:

final config = NotifyConfig(
  appId: 'app_a3f9bc12',
  apiKey: 'your_api_key',
  baseUrl: 'https://your-app.vercel.app',
  debugLogging: true,
  requestTimeout: const Duration(seconds: 15),
  maxRetries: 3,
);

await NotifyMVP.initialize(
  appId: config.appId,
  apiKey: config.apiKey,
  baseUrl: config.baseUrl,
  config: config,
);

How it works #

Flutter App                    NotifyMVP Backend            Firebase FCM
    │                                  │                         │
    │── NotifyMVP.initialize() ───────►│                         │
    │                                  │                         │
    │◄── Request FCM permission ───────┤                         │
    │                                  │                         │
    │── getToken() ────────────────────┼────────────────────────►│
    │◄── FCM token ────────────────────┼─────────────────────────│
    │                                  │                         │
    │── POST /api/device/register ────►│                         │
    │   { appId, apiKey, fcmToken,     │                         │
    │     deviceId, platform }         │                         │
    │◄── { success: true } ────────────│                         │
    │                                  │                         │
    │                           Token saved in DB                │
    │                                  │                         │
    │  [later — dashboard send]        │                         │
    │                                  │── FCM multicast ───────►│
    │◄── Push notification ────────────┼─────────────────────────│

Security notes #

  • The apiKey is embedded in your app binary — this is expected and intentional (same model as OneSignal, Firebase, etc.)
  • The API key only allows device registration — it cannot read data, send notifications, or access other projects
  • Sending notifications requires the dashboard (server-side only) — the apiKey alone cannot trigger sends
  • deviceId is stored in encrypted secure storage (flutter_secure_storage)

Platform support #

Platform Status
Android ✅
iOS ✅
Flutter Web ❌ (web push not in scope for MVP)
macOS ⚠️ (untested)
Windows/Linux ❌ (FCM not supported)

Troubleshooting #

"FCM token unavailable — notification permission may be denied" → User denied notification permission. Show a rationale UI and call NotifyMVP.register() again after they grant permission.

"Invalid appId or apiKey" → Double-check your App ID and API Key in the NotifyMVP dashboard → Projects.

"Request failed after 3 attempts" → Check your baseUrl is correct and the server is reachable.

Token not refreshing → The SDK listens to FirebaseMessaging.instance.onTokenRefresh automatically. Make sure NotifyMVP.initialize() is called before runApp().

1
likes
0
points
63
downloads

Publisher

unverified uploader

Weekly Downloads

Official Flutter SDK for NotifyMVP — a OneSignal-like push notification platform. Handles FCM token registration, auto-refresh, and device identification with zero boilerplate.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

device_info_plus, firebase_core, firebase_messaging, flutter, flutter_local_notifications, flutter_secure_storage, http, package_info_plus, uuid

More

Packages that depend on notify_mvp