lemnisk_flutter 1.1.9 copy "lemnisk_flutter: ^1.1.9" to clipboard
lemnisk_flutter: ^1.1.9 copied to clipboard

The Lemnisk Flutter Plugin allows you to track user event data from your Android or IOS app. The Plugin can be easily imported into any Android or iOS app. Based on the data it receives from the user [...]

example/lib/main.dart

import 'dart:async';
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:lemnisk_flutter/flutter_wrapper_method_channel.dart';
import 'package:lemnisk_flutter/flutter_wrapper.dart';

// Import the separated pages
import 'notification_details_page.dart';
import 'button_screen.dart';

// Global navigator key to access navigator from anywhere
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

// Global initialization flag to prevent duplicate initialization
bool _firebaseInitialized = false;

// Global stream controller for notification data
final StreamController<Map<String, dynamic>> notificationDataController = 
    StreamController<Map<String, dynamic>>.broadcast();

Stream<Map<String, dynamic>> get notificationDataStream => 
    notificationDataController.stream;

// Cache the last notification data to prevent loss during race conditions
Map<String, dynamic>? _lastNotificationData;

// Getter and setter for notification data cache
Map<String, dynamic>? getLastNotificationData() => _lastNotificationData;
void setLastNotificationData(Map<String, dynamic>? data) => _lastNotificationData = data;
void clearLastNotificationData() => _lastNotificationData = null;

// Background message handler (must be top-level function)
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('\n========== FCM BACKGROUND MESSAGE ==========');
  print('Message ID: ${message.messageId}');
  print('Notification: ${message.notification?.toMap()}');
  print('Data: ${message.data}');
  print('==========================================\n');
}

// Safe Firebase initialization that won't cause duplicate initialization errors
Future<FirebaseApp> _initializeFirebase() async {
  if (_firebaseInitialized) {
    // Return the existing instance if already initialized
    return Firebase.app();
  }
  
  _firebaseInitialized = true;
  return await Firebase.initializeApp();
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  try {
    await _initializeFirebase();
    
    // Set up background message handler
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
    
    print('\n========== FIREBASE INITIALIZED ==========');
    print('Firebase initialized successfully');
    print('==========================================\n');
    
    runApp(MyApp());
  } catch (e) {
    print('\n========== FIREBASE INIT ERROR ==========');
    print('Error initializing Firebase: $e');
    print('==========================================\n');
    runApp(MyApp());
  }
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // Initialize method channel in the app's state
  static const MethodChannel _channel = MethodChannel('com.example.lemnisk/notification_navigation');
  
  @override
  void initState() {
    super.initState();
    
    _setupMethodChannel();
    _setupFirebaseMessaging();
    _setupLemniskNotificationHandler();
    _handleInitialIntent();
  }
  
  Future<void> _handleInitialIntent() async {
    print('\n========== HANDLING INITIAL INTENT ==========');
    
    
    try {
      // Check if app was opened with a deep link (terminated state)
      final intent = await _channel.invokeMethod('getInitialIntent');
      if (intent != null && intent is Map) {
        print('Initial intent data: $intent');
        
        // Check if there's a deep link
        final deepLink = intent['deepLink'];
        if (deepLink != null && deepLink.toString().isNotEmpty) {
          print('Found deep link in initial intent: $deepLink');
          
          // Parse the deep link to determine the route
          final uri = Uri.parse(deepLink.toString());
          if (uri.host == 'notification-details' || uri.path.contains('notification-details')) {
            print('Navigating to notification-details from initial intent');
            
            // Navigate to the page
            navigatorKey.currentState?.pushNamed(
              '/notification-details'
            );
          }
        }
      } else {
        print('No initial intent found');
      }
    } catch (e) {
      print('Error handling initial intent: $e');
    }
    print('==========================================\n');
  }
  
  
  void _setupMethodChannel() {
    print('Setting up notification method channel');
    
    _channel.setMethodCallHandler((call) async {
      print('Received method call: ${call.method}');
      
      // Handle notification navigation
      if (call.method == 'navigateToNotificationPage') {
        if (call.arguments == null) {
          print('ERROR: Null arguments received');
          return false;
        }
        
        try {
          // Convert arguments to the right format
          final arguments = Map<String, dynamic>.from(call.arguments);
          
          // Navigate to notification details page
          if (navigatorKey.currentState != null) {
            navigatorKey.currentState!.pushNamed(
              '/notification-details',
              arguments: arguments,
            );
            return true;
          } else {
            print('ERROR: Navigator not available');
            return false;
          }
        } catch (e) {
          print('ERROR: Failed to handle notification: $e');
          return false;
        }
      } 
      
      return null;
    });
    
    print('Method channel setup complete');
  }
  
  void _setupFirebaseMessaging() {
    print('\n========== SETTING UP FCM LISTENERS ==========');
    
    // 1. Foreground messages (app is open and visible)
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('\n========== FCM FOREGROUND MESSAGE ==========');
      print('Message ID: ${message.messageId}');
      print('Sent Time: ${message.sentTime}');
      print('From: ${message.from}');
      print('Category: ${message.category}');
      print('Collapse Key: ${message.collapseKey}');
      print('Thread ID: ${message.threadId}');
      print('Message Type: ${message.messageType}');
      
      if (message.notification != null) {
        print('\n--- Notification Payload ---');
        print('Title: ${message.notification!.title}');
        print('Body: ${message.notification!.body}');
        print('Android: ${message.notification!.android?.toMap()}');
        print('Apple: ${message.notification!.apple?.toMap()}');
      } else {
        print('\n--- No Notification Payload (Data-only message) ---');
      }
      
      print('\n--- Data Payload ---');
      message.data.forEach((key, value) {
        print('  $key: $value');
      });
      print('==========================================\n');
    });
    
    // 2. Background tap (app was in background, user tapped notification)
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('\n========== FCM NOTIFICATION TAPPED (BACKGROUND) ==========');
      print('Message ID: ${message.messageId}');
      print('Sent Time: ${message.sentTime}');
      
      if (message.notification != null) {
        print('\n--- Notification Payload ---');
        print('Title: ${message.notification!.title}');
        print('Body: ${message.notification!.body}');
      }
      
      print('\n--- Data Payload ---');
      message.data.forEach((key, value) {
        print('  $key: $value');
      });
      print('==========================================\n');
      
      // Navigate to notification details if needed
      if (message.data.isNotEmpty) {
        navigatorKey.currentState?.pushNamed(
          '/notification-details',
          arguments: message.data,
        );
      }
    });
    
    // 3. Terminated tap (app was killed, user tapped notification)
    FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
      if (message != null) {
        print('\n========== FCM NOTIFICATION TAPPED (TERMINATED) ==========');
        print('Message ID: ${message.messageId}');
        print('Sent Time: ${message.sentTime}');
        
        if (message.notification != null) {
          print('\n--- Notification Payload ---');
          print('Title: ${message.notification!.title}');
          print('Body: ${message.notification!.body}');
        }
        
        print('\n--- Data Payload ---');
        message.data.forEach((key, value) {
          print('  $key: $value');
        });
        print('==========================================\n');
        
        // Navigate to notification details if needed
        if (message.data.isNotEmpty) {
          Future.delayed(Duration(seconds: 1), () {
            navigatorKey.currentState?.pushNamed(
              '/notification-details',
              arguments: message.data,
            );
          });
        }
      } else {
        print('\n========== NO INITIAL MESSAGE ==========');
        print('App was not opened from a notification');
        print('==========================================\n');
      }
    });
    
    print('FCM listeners setup complete');
    print('==========================================\n');
  }

  void _setupLemniskNotificationHandler() {
    print('\n========== SETTING UP LEMNISK NOTIFICATION HANDLER ==========');
    
    // Listen to Lemnisk notification taps
    LemniskFlutter.onNotificationTapped.listen((data) {
      print('\n========== LEMNISK NOTIFICATION TAPPED ==========');
      print('Received notification tap with data:');
      
      print('\n--- Notification Data ---');
      data.forEach((key, value) {
        print('  $key: $value');
      });
      print('==========================================\n');
      
      // Cache the data globally
      _lastNotificationData = data;
      
      // Emit data to stream for any listening pages
      notificationDataController.add(data);
      
      // DON'T navigate here - let the deep link handle navigation
      // The deep link from LemActivity will open the correct page
      print('Notification data cached and emitted to stream');
    });
    
    print('Lemnisk notification handler setup complete');
    print('==========================================\n');
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: navigatorKey,
      routes: {
        '/': (context) => MyButtonScreen(),
        '/notification-details': (context) => NotificationDetailsPage(),
      },
    );
  }
}
1
likes
120
points
97
downloads

Publisher

verified publisherlemnisk.co

Weekly Downloads

The Lemnisk Flutter Plugin allows you to track user event data from your Android or IOS app. The Plugin can be easily imported into any Android or iOS app. Based on the data it receives from the user activity, it sends real-time personalized push notifications to the users about the services and products that our clients provide.

Documentation

API reference

License

unknown (license)

Dependencies

flutter, plugin_platform_interface, webview_flutter

More

Packages that depend on lemnisk_flutter

Packages that implement lemnisk_flutter