courier_flutter 1.0.70 copy "courier_flutter: ^1.0.70" to clipboard
courier_flutter: ^1.0.70 copied to clipboard

PlatformAndroidiOS
outdated

The best way to add push notifications to your Flutter app!

example/lib/main.dart

import 'package:courier_flutter/courier_provider.dart';
import 'package:courier_flutter/ios_foreground_notification_presentation_options.dart';
import 'package:courier_flutter_sample/env.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:courier_flutter/courier_flutter.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Listen to push notification events
  // You likely want these callbacks to be handled
  // at a similar "global" level
  Courier.shared.onPushNotificationDelivered = (push) {
    print(push);
    pushDelivered.add(push);
  };

  // This is a good point to check your users authentication
  // or do any other logic needed before your users take action
  // on the notification
  Courier.shared.onPushNotificationClicked = (push) {
    print(push);
    pushClicked.add(push);
  };

  // This is needed to handle FCM tokens
  await Firebase.initializeApp();

  runApp(
    const MaterialApp(
      home: MyApp(),
    ),
  );
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

// These streams are used to simply pass the data to the current UI
// Your implementation will likely be different
StreamController<dynamic> pushDelivered = StreamController<dynamic>();
StreamController<dynamic> pushClicked = StreamController<dynamic>();

class _MyAppState extends State<MyApp> {
  bool _isLoading = true;
  String? _currentUserId;
  final List<CourierProvider> _providers = [CourierProvider.apns, CourierProvider.fcm];

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

    if (!mounted) {
      return;
    }

    _registerAlertStreams();
    _start();
  }

  _registerAlertStreams() {
    // These exist to simply show the message
    // Your implementation will be different
    pushDelivered.stream.listen((push) {
      _showAlert(context, 'Push Delivered', push.toString());
    });

    pushClicked.stream.listen((push) {
      _showAlert(context, 'Push Clicked', push.toString());
    });
  }

  Future _start() async {
    try {
      setState(() {
        _isLoading = true;
      });

      Courier.shared.isDebugging = true;
      print(Courier.shared.isDebugging);

      Courier.shared.iOSForegroundNotificationPresentationOptions = [
        iOSNotificationPresentationOption.banner,
        iOSNotificationPresentationOption.sound,
        iOSNotificationPresentationOption.list,
        iOSNotificationPresentationOption.badge,
      ];
      print(Courier.shared.iOSForegroundNotificationPresentationOptions);

      final userId = await Courier.shared.userId;
      print(userId);

      final fetchStatus = await Courier.shared.getNotificationPermissionStatus();
      print(fetchStatus);

      final requestStatus = await Courier.shared.requestNotificationPermission();
      print(requestStatus);

      // Set the current FCM token
      // Android will automatically handle this, but iOS will not
      final fcmToken = await FirebaseMessaging.instance.getToken();
      if (fcmToken != null) {
        await Courier.shared.setFcmToken(token: fcmToken);
      }

      // Handle FCM token changes
      FirebaseMessaging.instance.onTokenRefresh.listen((fcmToken) {
        Courier.shared.setFcmToken(token: fcmToken);
      }).onError((err) {
        throw err;
      });

      setState(() {
        _currentUserId = userId;
      });
    } catch (e) {
      print(e);
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<String> _showUserIdAlert() async {
    final textController = TextEditingController();

    await showDialog(
      barrierDismissible: false,
      context: context,
      builder: (context) => AlertDialog(
        title: const Text("Enter User Id"),
        content: TextField(
          autofocus: true,
          autocorrect: false,
          enableSuggestions: false,
          decoration: const InputDecoration(hintText: "Courier User Id"),
          controller: textController,
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text("Cancel"),
          ),
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text("Sign In"),
          ),
        ],
      ),
    );

    return Future.value(textController.text);
  }

  _signIn() async {
    try {
      setState(() {
        _isLoading = true;
      });

      final courierUserId = await _showUserIdAlert();
      if (courierUserId.isEmpty) return;

      await Courier.shared.signIn(
        accessToken: Env.accessToken,
        userId: courierUserId,
      );

      final userId = await Courier.shared.userId;
      setState(() {
        _currentUserId = userId;
      });
    } catch (e) {
      print(e);
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _signOut() async {
    try {
      setState(() {
        _isLoading = true;
      });

      await Courier.shared.signOut();
      final userId = await Courier.shared.userId;
      setState(() {
        _currentUserId = userId;
      });
    } catch (e) {
      print(e);
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _showAlert(BuildContext context, String title, String body) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(body),
        actions: [
          TextButton(
            child: const Text('Ok'),
            onPressed: () => Navigator.pop(context),
          )
        ],
      ),
    );
  }

  _getFcmToken(BuildContext context) async {
    final token = await Courier.shared.fcmToken;
    print(token);
    _showAlert(context, 'FCM Token', token ?? 'No token set');
  }

  _getApnsToken(BuildContext context) async {
    final token = await Courier.shared.apnsToken;
    print(token);
    _showAlert(context, 'APNS Token', token ?? 'No token set');
  }

  _handleProviderSwitch(CourierProvider selectedProvider) {
    if (_providers.contains(selectedProvider)) {
      setState(() {
        _providers.removeWhere((provider) => provider == selectedProvider);
      });
    } else {
      setState(() {
        _providers.add(selectedProvider);
      });
    }
  }

  Future _sendPush() async {
    if (_providers.isEmpty) {
      return;
    }

    try {
      setState(() {
        _isLoading = true;
      });

      final userId = await Courier.shared.userId ?? '';

      final requestId = await Courier.shared.sendPush(
        authKey: Env.authKey,
        userId: userId,
        title: 'Hey $userId',
        body: 'Push sent from: ${_providers.map((e) => e.name).join(' & ')}',
        providers: _providers,
      );

      print(requestId);
    } catch (e) {
      print(e);
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Widget _buildContent() {
    if (_isLoading) {
      return const Center(
        child: CircularProgressIndicator(),
      );
    }

    if (_currentUserId != null) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text('Current user id: ${_currentUserId!}'),
          TextButton(
            child: const Text('Sign Out'),
            onPressed: () => _signOut(),
          ),
          const Divider(),
          SwitchListTile(
            value: _providers.contains(CourierProvider.apns),
            onChanged: (bool value) {
              _handleProviderSwitch(CourierProvider.apns);
            },
            title: Text(
              CourierProvider.apns.name.toUpperCase(),
            ),
          ),
          SwitchListTile(
            value: _providers.contains(CourierProvider.fcm),
            onChanged: (bool value) {
              _handleProviderSwitch(CourierProvider.fcm);
            },
            title: Text(
              CourierProvider.fcm.name.toUpperCase(),
            ),
          ),
          TextButton(
            onPressed: () => _sendPush(),
            child: const Text('Send Push'),
          ),
          const Divider(),
          TextButton(
            child: const Text('See FCM Token'),
            onPressed: () => _getFcmToken(context),
          ),
          TextButton(
            child: const Text('See APNS Token'),
            onPressed: () => _getApnsToken(context),
          ),
        ],
      );
    }

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Text('No user signed into Courier'),
        TextButton(
          child: const Text('Sign In'),
          onPressed: () => _signIn(),
        ),
        const Divider(),
        TextButton(
          child: const Text('See FCM Token'),
          onPressed: () => _getFcmToken(context),
        ),
        TextButton(
          child: const Text('See APNS Token'),
          onPressed: () => _getApnsToken(context),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Courier example app'),
      ),
      body: _buildContent(),
    );
  }

  @override
  void dispose() {
    super.dispose();
    pushDelivered.close();
    pushClicked.close();
  }
}
4
likes
135
points
1.35k
downloads

Publisher

unverified uploader

Weekly Downloads

The best way to add push notifications to your Flutter app!

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on courier_flutter

Packages that implement courier_flutter