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

Flutter plugin for xNotify/XPush push notifications, in-app notifications, unread counts, Android notification tap handling, and deep linking.

XPush Flutter SDK #

Flutter plugin for integrating xNotify/XPush push notifications, in-app notifications, notification center, unread notification count, Android notification tap handling, app lifecycle handling, user session handling, and deep linking.

⚠️ Android 13+ requires runtime notification permission.

The XPush Flutter SDK does not request notification permission automatically. The host application is responsible for requesting and managing notification permission before initializing the SDK.


Features #

  • Android push notification support
  • In-app notification popup support
  • Notification center support
  • Unread notification count support
  • Foreground, background, and terminated state handling
  • Notification tap handling
  • Deep linking support
  • User login/contact update support
  • Logout/session clearing support
  • Android 13+ notification permission compatible, host app managed

Installation #

Add the package in the host Flutter app pubspec.yaml:

dependencies:
  xpush_flutter: ^1.0.0

Then run:

flutter pub get

Android Setup #

1. Add JitPack Repository #

Open:

android/settings.gradle

Add JitPack inside both repository blocks:

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { url 'https://jitpack.io' }
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

For older Android projects, add JitPack in:

android/build.gradle
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}

2. Kotlin SDK Dependency #

The native Android SDK dependency used by this Flutter plugin is:

implementation("com.github.dilawarabbas1:kotlin-sdk-v2:stg-4.2.0")

This dependency should be added inside the plugin Android module:

android/build.gradle

Example:

dependencies {
    implementation("com.github.dilawarabbas1:kotlin-sdk-v2:stg-4.2.0")
}

3. Android Permissions #

Open:

android/app/src/main/AndroidManifest.xml

Add these permissions above the <application> tag:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

POST_NOTIFICATIONS is required for Android 13 and above.


4. Android 13+ Notification Permission #

Android 13, API level 33, requires runtime notification permission before push notifications can be displayed.

The XPush Flutter SDK does not request notification permission automatically.

The host application is responsible for:

  • Requesting notification permission
  • Handling permission denial
  • Redirecting users to settings if permission is permanently denied

Example using permission_handler

Add this dependency in the host app:

dependencies:
  permission_handler: ^11.3.1

Import:

import 'package:permission_handler/permission_handler.dart';

Create this method:

Future<void> requestNotificationPermission() async {
  final status = await Permission.notification.request();

  if (status.isGranted) {
    debugPrint("Notification permission granted");
  } else {
    debugPrint("Notification permission denied");
  }
}

Call it before SDK initialization:

Future<void> initializeApp() async {
  await requestNotificationPermission();

  await XpushSdkController.initializeSdk();

  await XpushSdkController.onForeground();
}

Important: If notification permission is not granted on Android 13+, push notifications may not be displayed even though the SDK is initialized correctly.


5. MainApplication Setup #

Create or update:

android/app/src/main/kotlin/YOUR_PACKAGE_NAME/MainApplication.kt

Example:

package YOUR_PACKAGE_NAME

import android.app.Application
import com.tencent.mmkv.MMKV

class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        MMKV.initialize(this)
    }
}

Register it in:

android/app/src/main/AndroidManifest.xml

Inside the <application> tag:

<application
    android:name=".MainApplication"
    android:label="@string/app_name"
    android:icon="@mipmap/ic_launcher">
</application>

6. Firebase Messaging Service #

Inside the <application> tag in:

android/app/src/main/AndroidManifest.xml

Add:

<service
    android:name="com.xpush.sdk.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

This service is required for receiving push notifications from Firebase Cloud Messaging.


7. MainActivity Setup #

In:

android/app/src/main/AndroidManifest.xml

Make sure MainActivity uses:

android:launchMode="singleTop"

Example:

<activity
    android:name=".MainActivity"
    android:exported="true"
    android:launchMode="singleTop"
    android:theme="@style/LaunchTheme"
    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

</activity>

singleTop is required so notification tap and deep link intents can be handled correctly through the existing activity.


Flutter Usage #

Import the SDK controller.

For the package/example project:

import 'package:xpush_flutter_example/sdk/xpush_sdk_controller.dart';

For pub.dev package usage, the recommended import should be:

import 'package:xpush_flutter/sdk/xpush_sdk_controller.dart';

Note: Before publishing, make sure xpush_sdk_controller.dart is available inside the package lib/ folder and not only inside the example/ app.


SDK Initialization #

Initialize the SDK after app startup or after splash:

await XpushSdkController.initializeSdk();

Example:

Future<void> initSdk() async {
  try {
    await XpushSdkController.initializeSdk();
    await XpushSdkController.onForeground();
  } catch (e) {
    debugPrint("XPush SDK init failed: $e");
  }
}

Recommended flow:

await requestNotificationPermission();
await XpushSdkController.initializeSdk();
await XpushSdkController.onForeground();

Contact Update After Login #

After user login, call contactUpdate with the user's phone number:

await XpushSdkController.contactUpdate(phoneNumber);

Example:

if (isLoggedIn && phoneNumber != null) {
  await XpushSdkController.contactUpdate(phoneNumber);
}

This links the current device/subscriber with the logged-in user.


Open Notification Center #

To open the SDK notification center:

await XpushSdkController.openNotifications();

Example:

IconButton(
  icon: const Icon(Icons.notifications),
  onPressed: () async {
    await XpushSdkController.openNotifications();
  },
)

Get Unread Notification Count #

To get unread notification count:

final unreadCount = await XpushSdkController.getUnreadCount();

Example:

int unreadCount = 0;

Future<void> refreshUnreadCount() async {
  final count = await XpushSdkController.getUnreadCount();

  setState(() {
    unreadCount = count;
  });
}

Example badge UI:

Stack(
  children: [
    IconButton(
      icon: const Icon(Icons.notifications),
      onPressed: () async {
        await XpushSdkController.openNotifications();
        await refreshUnreadCount();
      },
    ),
    if (unreadCount > 0)
      Positioned(
        right: 6,
        top: 6,
        child: Container(
          padding: const EdgeInsets.all(4),
          decoration: const BoxDecoration(
            color: Colors.red,
            shape: BoxShape.circle,
          ),
          child: Text(
            unreadCount.toString(),
            style: const TextStyle(
              color: Colors.white,
              fontSize: 10,
            ),
          ),
        ),
      ),
  ],
)

App Lifecycle Handling #

The host Flutter app should notify the SDK when the app enters foreground or background.

Example:

class XBankApp extends StatefulWidget {
  const XBankApp({super.key});

  @override
  State<XBankApp> createState() => _XBankAppState();
}

class _XBankAppState extends State<XBankApp> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addObserver(this);

    Future.microtask(() async {
      await requestNotificationPermission();
      await XpushSdkController.initializeSdk();
      await XpushSdkController.onForeground();
    });
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      XpushSdkController.onForeground();
    } else if (state == AppLifecycleState.paused ||
        state == AppLifecycleState.inactive ||
        state == AppLifecycleState.detached) {
      XpushSdkController.onBackground();
    }
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

Deep Linking Setup #

The SDK sends deep link events from native Android/iOS to Flutter through this MethodChannel:

MethodChannel('xpush_flutter_deeplink')

Native channel name:

let deepLinkChannel = FlutterMethodChannel(
    name: "xpush_flutter_deeplink",
    binaryMessenger: registrar.messenger()
)

Add the MethodChannel handler inside your main Flutter app widget.

Example:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:xpush_flutter/sdk/xpush_sdk_controller.dart';

import 'deep_link_router.dart';
import 'screens/splash_screen.dart';
import 'screens/login_screen.dart';
import 'screens/dashboard_screen.dart';
import 'screens/payment_screen.dart';

class XBankApp extends StatefulWidget {
  const XBankApp({super.key});

  static final GlobalKey<NavigatorState> navigatorKey =
      GlobalKey<NavigatorState>();

  @override
  State<XBankApp> createState() => _XBankAppState();
}

class _XBankAppState extends State<XBankApp> with WidgetsBindingObserver {
  static const MethodChannel _deepLinkChannel =
      MethodChannel('xpush_flutter_deeplink');

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

    WidgetsBinding.instance.addObserver(this);

    _deepLinkChannel.setMethodCallHandler((call) async {
      if (call.method == 'routeDeepLink') {
        final args = Map<String, dynamic>.from(call.arguments ?? {});

        final deepLink = args['deepLink']?.toString();
        final messageId = args['messageId']?.toString();

        if (deepLink != null && deepLink.isNotEmpty) {
          DeepLinkRouter.route(
            navigatorKey: XBankApp.navigatorKey,
            deepLink: deepLink,
            messageId: messageId,
          );
        }
      }
    });

    Future.microtask(() async {
      try {
        await requestNotificationPermission();
        await XpushSdkController.initializeSdk();
        await XpushSdkController.onForeground();
      } catch (e) {
        debugPrint("XPush SDK init failed: $e");
      }
    });
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      XpushSdkController.onForeground();
    } else if (state == AppLifecycleState.paused ||
        state == AppLifecycleState.inactive ||
        state == AppLifecycleState.detached) {
      XpushSdkController.onBackground();
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: XBankApp.navigatorKey,
      debugShowCheckedModeBanner: false,
      home: const SplashScreen(),
      routes: {
        '/login': (_) => const LoginScreen(),
        '/dashboard': (_) => const DashboardScreen(),
        '/payment': (_) => const PaymentScreen(),
      },
    );
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

DeepLinkRouter Example #

Create:

lib/deep_link_router.dart

Add:

import 'package:flutter/material.dart';

class DeepLinkRouter {
  static void route({
    required GlobalKey<NavigatorState> navigatorKey,
    required String deepLink,
    String? messageId,
  }) {
    final uri = Uri.tryParse(deepLink);

    if (uri == null) return;

    if (uri.scheme == 'xpush' && uri.host == 'pay') {
      final paymentId = uri.queryParameters['id'];

      navigatorKey.currentState?.pushNamed(
        '/payment',
        arguments: {
          'paymentId': paymentId,
          'messageId': messageId,
        },
      );

      return;
    }

    if (uri.scheme == 'xpush' && uri.host == 'notifications') {
      navigatorKey.currentState?.pushNamed('/dashboard');
      return;
    }
  }
}

Example deep link:

xpush://pay?id=12

This navigates to:

/payment

with arguments:

{
  "paymentId": "12",
  "messageId": "MESSAGE_ID"
}

Logout #

On logout, call:

await XpushSdkController.logout();

Example:

Future<void> logout() async {
  await XpushSdkController.logout();

  Navigator.pushReplacementNamed(context, '/login');
}

This clears the current user session and prevents notifications from being shown for the logged-out user.


Notification Tap Handling #

Android notification tap handling is managed by the SDK.

The SDK handles:

  • App foreground state
  • App background state
  • App terminated state
  • Notification body tap
  • Notification action button tap
  • Deep link payload
  • Dialog fallback when no valid deep link exists

If a valid deep link is received, it is sent to Flutter through:

MethodChannel('xpush_flutter_deeplink')

If no valid deep link exists, the SDK opens the notification dialog.


Required SDK Methods #

Method Description
initializeSdk() Initializes XPush SDK
contactUpdate(phoneNumber) Updates logged-in user/contact
openNotifications() Opens notification center
getUnreadCount() Returns unread notification count
onForeground() Sets app state as foreground
onBackground() Sets app state as background
logout() Clears user/session data
restartSocket() Restarts socket if required
handlePushTap() Handles Android notification tap

App Start #

await requestNotificationPermission();
await XpushSdkController.initializeSdk();
await XpushSdkController.onForeground();

User Login #

await XpushSdkController.contactUpdate(phoneNumber);

Open Notification Center #

await XpushSdkController.openNotifications();

Refresh Unread Count #

final count = await XpushSdkController.getUnreadCount();

App Resume #

await XpushSdkController.onForeground();

App Background #

await XpushSdkController.onBackground();

Logout #

await XpushSdkController.logout();

Troubleshooting #

Push notification is not received on Android 13+ #

Check that this permission exists:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

Also make sure runtime notification permission is requested and granted.

await Permission.notification.request();

Notification tap opens app but does not route #

Check that MainActivity has:

android:launchMode="singleTop"

Also check that the Flutter app has registered:

MethodChannel('xpush_flutter_deeplink')

Make sure the app has a valid navigatorKey:

static final GlobalKey<NavigatorState> navigatorKey =
    GlobalKey<NavigatorState>();

And pass it to MaterialApp:

MaterialApp(
  navigatorKey: XBankApp.navigatorKey,
)

Unread count is always zero #

Make sure contactUpdate(phoneNumber) is called after login:

await XpushSdkController.contactUpdate(phoneNumber);

Also refresh unread count when app resumes:

await XpushSdkController.getUnreadCount();

In-app notification appears on login screen after logout #

Make sure logout is called:

await XpushSdkController.logout();

Also clear the local login session from the host app.


Package Publishing Checklist #

Before publishing to pub.dev, make sure the package root contains:

README.md
CHANGELOG.md
LICENSE
pubspec.yaml
lib/
android/
ios/
example/

Run:

flutter pub get
dart pub publish --dry-run

If dry run succeeds:

dart pub publish

License #

This package is distributed under the license mentioned in the LICENSE file.

0
likes
140
points
95
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for xNotify/XPush push notifications, in-app notifications, unread counts, Android notification tap handling, and deep linking.

Homepage
Repository

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on xpush_flutter

Packages that implement xpush_flutter