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

Flutter SDK for NotifySphere (notifysphere.net) to monitor push notification delivery confirmations, click tracking, and user subscriptions on Android and iOS.

Flutter NotifySphere (flutter_notify_sphere) #

pub package License: MIT Platform

Official Flutter SDK for NotifySphere. Easily monitor and track push notification delivery confirmation, click rates, and subscriber metadata across Android and iOS in real-time.


Features #

  • 🚀 Accurate Delivery Tracking: Confirms delivery when notifications arrive in the foreground, background isolate, or terminated state (via iOS Notification Service Extension).
  • 🖱️ Click & Open Analytics: Tracks user clicks across foreground heads-up notifications, background resumes, and cold starts from terminated state.
  • 📱 Device & Subscriber Synchronization: Automatically collects and updates FCM/APNs tokens, device model, OS version, app version, network connectivity type, timezone, and optional geolocation.
  • 🖼️ Rich Notifications: Native support for expandable images (Android BigPictureStyle and iOS UNNotificationAttachment).
  • 🔔 Custom Notification Sounds: Custom notification channels and sounds supported on both platforms.
  • 🔄 Offline Pending Queue: Delivery and click events received while offline or before initial registration are queued securely and flushed automatically once registration completes.

Architecture Flow #

flowchart TD
    subgraph Client ["Client Application (Flutter & Native iOS)"]
        Init["FlutterNotifySphere.initialize()"]
        Reg["FlutterNotifySphere.registerUser()"]
        FG["Foreground: FirebaseMessaging.onMessage"]
        BG["Background: notifyBackgroundHandler"]
        Cold["Cold Start: getInitialMessage()"]
        Ext["iOS Service Extension: NotifySphereExtension.didReceive()"]
    end

    subgraph Backend ["NotifySphere Panel (notifysphere.net)"]
        API_Reg["POST /client/{appId}/users"]
        API_Deliv["POST /client/{appId}/delivery/confirm"]
        API_Click["POST /client/{appId}/onpress/handle"]
    end

    Reg -->|Device Metadata + FCM Token| API_Reg
    FG -->|Delivery Confirmation| API_Deliv
    BG -->|Background Delivery Confirmation| API_Deliv
    Ext -->|Silent Delivery Confirmation| API_Deliv
    Cold -->|Click Event Tracking| API_Click

1. NotifySphere Panel Setup (notifysphere.net) #

  1. Sign Up / Log In:
  2. Create an Application:
    • Navigate to Applications > Create New Application.
    • Enter your application name and package/bundle ID.
    • Note down your Application ID (appId) and API Key (apiKey).
  3. Configure Firebase Cloud Messaging (FCM):
    • In the Firebase Console, open your project settings > Service Accounts.
    • Click Generate new private key and download the JSON file.
    • In the NotifySphere dashboard, open your Application Settings and upload the Firebase Service Account JSON.
  4. Configure Apple Push Notification service (APNs) (for iOS):
    • In Firebase Console > Project Settings > Cloud Messaging, upload your Apple Push Notifications Authentication Key (.p8) and team ID.

2. Installation #

Add flutter_notify_sphere along with Firebase dependencies to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  flutter_notify_sphere: ^1.0.0
  firebase_core: ^3.10.0
  firebase_messaging: ^15.2.0

Run:

flutter pub get

3. Android Setup #

3.1 Firebase Configuration #

  1. Download google-services.json from your Firebase project.
  2. Place it into android/app/google-services.json.
  3. Add the Google Services plugin to your Gradle configuration:
    • In android/build.gradle (or android/settings.gradle):
      plugins {
          id 'com.google.gms.google-services' version '4.4.2' apply false
      }
      
    • In android/app/build.gradle:
      plugins {
          id 'com.android.application'
          id 'com.google.gms.google-services'
      }
      

3.2 Permissions (AndroidManifest.xml) #

In android/app/src/main/AndroidManifest.xml, add the following permissions inside the <manifest> tag:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Required permissions -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <uses-permission android:name="android.permission.VIBRATE"/>

    <!-- Optional: Only if useLocationData: true is passed to registerUser() -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    <application ...>
        <!-- Optional default notification icon & color -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@mipmap/ic_launcher" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="notify_sphere_channel" />
        ...
    </application>
</manifest>

3.3 Custom Notification Sound (Android) #

  1. Place your audio file (e.g. custom_sound.mp3 or .wav) into:
    android/app/src/main/res/raw/custom_sound.mp3
    
  2. When creating a notification in the NotifySphere dashboard, enter custom_sound (without the file extension) in the sound field.

3.4 Rich Images (Android) #

Images sent in the notification (imageUrl or image in data payload) are automatically downloaded and displayed as BigPictureStyle notifications.


4. iOS Setup #

4.1 Firebase Configuration #

  1. Download GoogleService-Info.plist from your Firebase Console.
  2. Open your project in Xcode (open ios/Runner.xcworkspace).
  3. Drag and drop GoogleService-Info.plist into the Runner folder (ensure Copy items if needed is checked).

4.2 Xcode Capabilities #

In Xcode, select the Runner target > Signing & Capabilities:

  1. Click + Capability and add Push Notifications.
  2. Click + Capability and add Background Modes. Check:
    • ✅ Remote notifications
    • ✅ Background fetch
  3. Click + Capability and add App Groups:
    • Add an App Group named: group.<your.bundle.id> (e.g. group.com.example.myapp).

4.3 iOS Notification Service Extension (Background Delivery & Image Tracking) #

Important

iOS does not execute Flutter/Dart code when the app is in the background or terminated upon receiving a notification. To track delivery confirmations and show rich image attachments when the app is closed, you must configure an iOS Notification Service Extension.

Step 1: Create the Extension Target

  1. In Xcode, choose File > New > Target....
  2. Select Notification Service Extension and click Next.
  3. Name the extension (e.g. ImageNotification), ensure language is Swift, and click Finish.
  4. When prompted to activate scheme, click Cancel.

Step 2: Configure the App Group on the Extension

  1. Select your new ImageNotification target > Signing & Capabilities.
  2. Click + Capability > App Groups.
  3. Check the exact same App Group you created for the Runner target (group.<your.bundle.id>).

Step 3: Add NotifySphereExtension.swift

Inside your extension folder (e.g. ios/ImageNotification/), create a new Swift file named NotifySphereExtension.swift and paste the following code:

import Foundation
import UserNotifications
import os.log

public class NotifySphereExtension {
    
    /// Called inside the Notification Service Extension to confirm delivery with NotifySphere
    public static func didReceive(_ request: UNNotificationRequest, completion: @escaping () -> Void) {
        let userInfo = request.content.userInfo
        
        // Extract required notification identifier
        guard let notificationId = userInfo["notification_id"] as? String ?? userInfo["gcm.message_id"] as? String else {
            completion()
            return
        }
        
        // Dynamically resolve the parent App Group suite
        guard let extensionBundleId = Bundle.main.bundleIdentifier else {
            completion()
            return
        }
        
        let components = extensionBundleId.components(separatedBy: ".")
        guard components.count >= 2 else {
            completion()
            return
        }
        let parentBundleId = components.dropLast().joined(separator: ".")
        let dynamicAppGroup = "group.\(parentBundleId)"
        
        guard let groupDefaults = UserDefaults(suiteName: dynamicAppGroup) else {
            completion()
            return
        }
        
        // Retrieve credentials saved by flutter_notify_sphere
        let appId = groupDefaults.string(forKey: "app_id") ?? ""
        let apiKey = groupDefaults.string(forKey: "api_key") ?? ""
        let subscriptionId = groupDefaults.string(forKey: "subscription_id") ?? ""
        
        guard !appId.isEmpty else {
            completion()
            return
        }
        
        // Construct delivery confirmation endpoint
        let urlString = "https://api.notifysphere.in/client/\(appId)/delivery/confirm"
        guard let url = URL(string: urlString) else {
            completion()
            return
        }
        
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "POST"
        urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
        if !apiKey.isEmpty {
            urlRequest.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        }
        
        let body: [String: Any] = [
            "notification_id": notificationId,
            "subscription_id": subscriptionId,
            "platform": "ios"
        ]
        
        urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: body)
        
        let task = URLSession.shared.dataTask(with: urlRequest) { _, _, _ in
            completion()
        }
        task.resume()
    }
}

Step 4: Implement NotificationService.swift

In the same extension folder, replace the contents of NotificationService.swift with:

import UIKit
import UserNotifications
import os.log

class NotificationService: UNNotificationServiceExtension {
    
    private var contentHandler: ((UNNotificationContent) -> Void)?
    private var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(
        _ request: UNNotificationRequest,
        withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
    ) {
        self.contentHandler = contentHandler
        bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
        
        guard let bestAttemptContent = bestAttemptContent else {
            contentHandler(request.content)
            return
        }

        let userInfo = request.content.userInfo

        // 1. Confirm delivery with NotifySphere
        NotifySphereExtension.didReceive(request) {
            NSLog("NotifySphere delivery confirmed in extension")
        }

        // 2. Custom Sound
        if let aps = userInfo["aps"] as? [String: Any],
           let soundName = aps["sound"] as? String {
            bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName))
        } else if let soundName = userInfo["sound"] as? String {
            bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: soundName))
        } else {
            bestAttemptContent.sound = .default
        }

        // 3. Expandable Image Attachment
        if let imageUrl = userInfo["imageUrl"] as? String ?? userInfo["image"] as? String,
           let url = URL(string: imageUrl) {
            downloadImage(from: url) { attachment in
                if let attachment = attachment {
                    bestAttemptContent.attachments = [attachment]
                }
                contentHandler(bestAttemptContent)
            }
        } else {
            contentHandler(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler,
           let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

    private func downloadImage(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) {
        URLSession.shared.downloadTask(with: url) { location, _, _ in
            guard let location = location else {
                completion(nil)
                return
            }
            let tempDir = URL(fileURLWithPath: NSTemporaryDirectory())
            let fileURL = tempDir.appendingPathComponent(UUID().uuidString + ".jpg")
            try? FileManager.default.moveItem(at: location, to: fileURL)

            let attachment = try? UNNotificationAttachment(
                identifier: UUID().uuidString,
                url: fileURL,
                options: nil
            )
            completion(attachment)
        }.resume()
    }
}

4.4 Custom Notification Sound (iOS) #

  1. Add your audio file (e.g. alert.caf, alert.wav, or alert.aiff) to Xcode.
  2. In the file inspector, check both Runner and ImageNotification target memberships.
  3. In NotifySphere dashboard, enter alert.caf in the sound field.

5. Flutter Dart Integration #

5.1 Initialize in main.dart #

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

/// Top-level background message handler
@pragma('vm:entry-point')
Future<void> backgroundMessageHandler(RemoteMessage message) async {
  debugPrint('Background message received: ${message.data}');
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // Initialize NotifySphere
  await FlutterNotifySphere().initialize(
    showForegroundNotification: true,
    onForegroundMessage: (RemoteMessage message) {
      debugPrint('Foreground notification: ${message.data}');
    },
    onNotificationClick: (RemoteMessage? message) {
      debugPrint('Notification clicked: ${message?.data}');
      // Handle navigation or in-app routing here
    },
    backgroundMessageHandler: backgroundMessageHandler,
  );

  runApp(const MyApp());
}

5.2 Register User & Device #

Call registerUser when your user logs in or on your app's home screen:

await FlutterNotifySphere().registerUser(
  appId: "YOUR_NOTIFYSPHERE_APP_ID",   // From notifysphere.net
  apiKey: "YOUR_NOTIFYSPHERE_API_KEY", // From notifysphere.net
  userData: {
    "applicationUserId": "user_12345",
    "name": "Jane Doe",
    "email": "jane@example.com",
    // Any custom metadata you want to associate with this subscriber
  },
  useLocationData: false, // Set to true to include lat/long and reverse-geocoded address
  onFcmToken: (String? fcmToken) {
    debugPrint("Device FCM Token: $fcmToken");
  },
  onRegistrationComplete: (String? subscriptionId) {
    debugPrint("Registered with NotifySphere! Subscription ID: $subscriptionId");
  },
  onError: (Object error) {
    debugPrint("Registration error: $error");
  },
);

6. NotifySphere Payload Reference #

Notifications sent from the NotifySphere panel or REST API deliver the following data structure:

Key Type Description
notification_id String Unique tracking ID generated by NotifySphere for delivery and click tracking.
title String The notification title.
body String The notification body text.
imageUrl String? Optional URL of the image attachment.
sound String? Optional custom sound file name (e.g. notification_sound).
custom_key dynamic Any additional key-value pairs configured in the NotifySphere campaign.

7. Verifying Integration #

  1. Registration: Run your application. Inspect debug console logs for:
    Registration Complete: <subscription_id>
    
  2. Delivery Confirmation: Send a test notification from the NotifySphere panel:
    • Check the NotifySphere campaign dashboard: the Delivered count will increment in real time.
  3. Click Tracking: Tap the notification banner:
    • The Clicked count will increment in the campaign dashboard.
  4. iOS Console Logs: On macOS, open Console.app, select your test device, and filter for NotifySphereExtension or category FlutterNotifySphere.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

0
likes
140
points
227
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter SDK for NotifySphere (notifysphere.net) to monitor push notification delivery confirmations, click tracking, and user subscriptions on Android and iOS.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

connectivity_plus, device_info_plus, dio, firebase_core, firebase_messaging, flutter, flutter_cache_manager, flutter_local_notifications, flutter_timezone, geocoding, geolocator, http, package_info_plus, shared_preference_app_group, shared_preferences

More

Packages that depend on flutter_notify_sphere