| // Copyright 2017 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | import 'dart:async'; | 
 |  | 
 | import 'package:flutter/services.dart'; | 
 | import 'package:meta/meta.dart'; | 
 | import 'package:platform/platform.dart'; | 
 |  | 
 | typedef Future<dynamic> MessageHandler(Map<String, dynamic> message); | 
 |  | 
 | /// Implementation of the Firebase Cloud Messaging API for Flutter. | 
 | /// | 
 | /// Your app should call [requestNotificationPermissions] first and then | 
 | /// register handlers for incoming messages with [configure]. | 
 | class FirebaseMessaging { | 
 |   factory FirebaseMessaging() => _instance; | 
 |  | 
 |   @visibleForTesting | 
 |   FirebaseMessaging.private(MethodChannel channel, Platform platform) | 
 |       : _channel = channel, | 
 |         _platform = platform; | 
 |  | 
 |   static final FirebaseMessaging _instance = FirebaseMessaging.private( | 
 |       const MethodChannel('plugins.flutter.io/firebase_messaging'), | 
 |       const LocalPlatform()); | 
 |  | 
 |   final MethodChannel _channel; | 
 |   final Platform _platform; | 
 |  | 
 |   MessageHandler _onMessage; | 
 |   MessageHandler _onLaunch; | 
 |   MessageHandler _onResume; | 
 |  | 
 |   /// On iOS, prompts the user for notification permissions the first time | 
 |   /// it is called. | 
 |   /// | 
 |   /// Does nothing on Android. | 
 |   void requestNotificationPermissions( | 
 |       [IosNotificationSettings iosSettings = const IosNotificationSettings()]) { | 
 |     if (!_platform.isIOS) { | 
 |       return; | 
 |     } | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     _channel.invokeMethod( | 
 |         'requestNotificationPermissions', iosSettings.toMap()); | 
 |   } | 
 |  | 
 |   final StreamController<IosNotificationSettings> _iosSettingsStreamController = | 
 |       StreamController<IosNotificationSettings>.broadcast(); | 
 |  | 
 |   /// Stream that fires when the user changes their notification settings. | 
 |   /// | 
 |   /// Only fires on iOS. | 
 |   Stream<IosNotificationSettings> get onIosSettingsRegistered { | 
 |     return _iosSettingsStreamController.stream; | 
 |   } | 
 |  | 
 |   /// Sets up [MessageHandler] for incoming messages. | 
 |   void configure({ | 
 |     MessageHandler onMessage, | 
 |     MessageHandler onLaunch, | 
 |     MessageHandler onResume, | 
 |   }) { | 
 |     _onMessage = onMessage; | 
 |     _onLaunch = onLaunch; | 
 |     _onResume = onResume; | 
 |     _channel.setMethodCallHandler(_handleMethod); | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     _channel.invokeMethod('configure'); | 
 |   } | 
 |  | 
 |   final StreamController<String> _tokenStreamController = | 
 |       StreamController<String>.broadcast(); | 
 |  | 
 |   /// Fires when a new FCM token is generated. | 
 |   Stream<String> get onTokenRefresh { | 
 |     return _tokenStreamController.stream; | 
 |   } | 
 |  | 
 |   /// Returns the FCM token. | 
 |   Future<String> getToken() async { | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     return await _channel.invokeMethod('getToken'); | 
 |   } | 
 |  | 
 |   /// Subscribe to topic in background. | 
 |   /// | 
 |   /// [topic] must match the following regular expression: | 
 |   /// "[a-zA-Z0-9-_.~%]{1,900}". | 
 |   void subscribeToTopic(String topic) { | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     _channel.invokeMethod('subscribeToTopic', topic); | 
 |   } | 
 |  | 
 |   /// Unsubscribe from topic in background. | 
 |   void unsubscribeFromTopic(String topic) { | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     _channel.invokeMethod('unsubscribeFromTopic', topic); | 
 |   } | 
 |  | 
 |   /// Resets Instance ID and revokes all tokens. In iOS, it also unregisters from remote notifications. | 
 |   /// | 
 |   /// A new Instance ID is generated asynchronously if Firebase Cloud Messaging auto-init is enabled. | 
 |   /// | 
 |   /// returns true if the operations executed successfully and false if an error ocurred | 
 |   Future<bool> deleteInstanceID() async { | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     return await _channel.invokeMethod('deleteInstanceID'); | 
 |   } | 
 |  | 
 |   /// Determine whether FCM auto-initialization is enabled or disabled. | 
 |   Future<bool> autoInitEnabled() async { | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     return await _channel.invokeMethod('autoInitEnabled'); | 
 |   } | 
 |  | 
 |   /// Enable or disable auto-initialization of Firebase Cloud Messaging. | 
 |   Future<void> setAutoInitEnabled(bool enabled) async { | 
 |     // TODO(amirh): remove this on when the invokeMethod update makes it to stable Flutter. | 
 |     // https://github.com/flutter/flutter/issues/26431 | 
 |     // ignore: strong_mode_implicit_dynamic_method | 
 |     await _channel.invokeMethod('setAutoInitEnabled', enabled); | 
 |   } | 
 |  | 
 |   Future<dynamic> _handleMethod(MethodCall call) async { | 
 |     switch (call.method) { | 
 |       case "onToken": | 
 |         final String token = call.arguments; | 
 |         _tokenStreamController.add(token); | 
 |         return null; | 
 |       case "onIosSettingsRegistered": | 
 |         _iosSettingsStreamController.add(IosNotificationSettings._fromMap( | 
 |             call.arguments.cast<String, bool>())); | 
 |         return null; | 
 |       case "onMessage": | 
 |         return _onMessage(call.arguments.cast<String, dynamic>()); | 
 |       case "onLaunch": | 
 |         return _onLaunch(call.arguments.cast<String, dynamic>()); | 
 |       case "onResume": | 
 |         return _onResume(call.arguments.cast<String, dynamic>()); | 
 |       default: | 
 |         throw UnsupportedError("Unrecognized JSON message"); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | class IosNotificationSettings { | 
 |   const IosNotificationSettings({ | 
 |     this.sound = true, | 
 |     this.alert = true, | 
 |     this.badge = true, | 
 |   }); | 
 |  | 
 |   IosNotificationSettings._fromMap(Map<String, bool> settings) | 
 |       : sound = settings['sound'], | 
 |         alert = settings['alert'], | 
 |         badge = settings['badge']; | 
 |  | 
 |   final bool sound; | 
 |   final bool alert; | 
 |   final bool badge; | 
 |  | 
 |   @visibleForTesting | 
 |   Map<String, dynamic> toMap() { | 
 |     return <String, bool>{'sound': sound, 'alert': alert, 'badge': badge}; | 
 |   } | 
 |  | 
 |   @override | 
 |   String toString() => 'PushNotificationSettings ${toMap()}'; | 
 | } |