firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.68k stars 3.97k forks source link

FirebaseMessaging - onMessage, onResume, onLunch call backs are not getting invoked in iOS (real device only) #3165

Closed areeg-ad closed 4 years ago

areeg-ad commented 4 years ago

I am working on version 6.0.16 (Latest), push notification working as expected in both android and iOS simulators, in forground and background, but in real iOS device I just receive the notification in notification tray if app is terminated or in the background, but I can't catch the click action or execute on message logic.

Here's my flutter doctor summary

[✓] Flutter (Channel master, 1.21.0-10.0.pre.55, on Mac OS X 10.15.6 19G73, locale en-EG)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1) [✓] Xcode - develop for iOS and macOS (Xcode 11.5) [✓] Android Studio (version 4.0) [✓] Connected device (2 available)

aabughazaleh commented 4 years ago

Same issue here. [✓] Flutter (Channel stable, 1.20.1, on Mac OS X 10.15.6 19G73, locale en-SA)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3) [✓] Xcode - develop for iOS and macOS (Xcode 11.6) [✓] Android Studio (version 4.0) [✓] VS Code (version 1.47.2) [✓] Connected device (3 available)

• No issues found!

firebase_core: ^0.5.0-dev.2 firebase_auth: ^0.17.0-dev.2 google_sign_in: ^4.5.1 cloud_firestore: ^0.14.0-dev.1

TahaTesser commented 4 years ago

Hi @areeg-ad Can you please provide your pubspec.yaml and a complete reproducible minimal code sample Thank you

aabughazaleh commented 4 years ago

@TahaTesser files for me are:

pubspec.yaml:

`name: ******
description: *****

publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

  cupertino_icons: ^0.1.3
  firebase_core: ^0.5.0-dev.2
  firebase_auth: ^0.17.0-dev.2
  google_sign_in: ^4.5.1
  provider: ^4.3.2
  cloud_firestore: ^0.14.0-dev.1
  firebase_messaging: ^7.0.0-dev.1
  modal_progress_hud: ^0.1.3
  fluttertoast: ^7.0.2
  intl: ^0.16.1
  rxdart: ^0.24.1
  shared_preferences: ^0.5.8
  path_provider: ^1.6.11
  sqflite: ^1.3.1
  easy_localization: ^2.3.3
  flushbar: ^1.10.4
  http: ^0.12.2
  timeago: ^2.0.26
  sqlcool: ^4.3.1
  flutter_icons: ^1.1.0
  image_cropper: ^1.3.0
  photo_view: ^0.10.0
  #camera: ^0.5.8+2
  path: ^1.7.0
  image_picker: ^0.6.7+4
  flutter_image_compress: ^0.7.0
  recase: ^3.0.0
  overlay_support: ^1.0.5
  cached_network_image: ^2.2.0+1
  share: ^0.6.4+3
  font_awesome_flutter: ^8.8.1
  flutter_widget_from_html: ^0.4.3
  easy_listview: ^0.1.3
  url_launcher: ^5.5.0
  theme_provider: ^0.4.0+1
  flutter_staggered_animations: ^0.1.2
  shimmer: ^1.1.1
  flutter_staggered_grid_view: ^0.3.2

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
  assets:
    - assets/images/
    - assets/i18n/

  fonts:
    - family: Tajawal
      fonts:
        - asset: assets/fonts/Tajawal/Tajawal-Medium.ttf
        - asset: assets/fonts/Tajawal/Tajawal-Bold.ttf
          weight: 700`

code:

Future<void> init({@required BuildContext context}) async {
    if (!_initialized) {
      // For iOS: request permission first.
      if (Platform.isIOS) {
        iosSubscription = _firebaseMessaging.onIosSettingsRegistered.listen(
          (data) async {
            print('onIosSettingsRegistered.listen: $data');
            if (!_tokenSaved) {
              _tokenSaved = true;
              await _saveDeviceToken();
            }
          },
        );
        await _firebaseMessaging
            .requestNotificationPermissions(IosNotificationSettings(
          alert: true,
          badge: true,
          sound: true,
        ));
      } else {
        await _saveDeviceToken();
      }

      _firebaseMessaging.configure(
        onMessage: (Map<String, dynamic> message) async {
          print("onMessage");
          ReceivedMessage msg = ReceivedMessage.fromMap(message);
          if (msg != null) {
            print('_currentPage: $_currentPage');
            String generatedPage =
                (msg.serviceType == PushNotificationServiceType.chat.toString())
                    ? '${ChatPage.id}/${msg.sender}'
                    : FriendRequestsPage.id;
            print('generatedPage: $generatedPage');
            if (_currentPage == generatedPage) {
              print('chatting in same page, don\'t show notification');
              return;
            } else {
              print('ready to go to user page');
            }
            if (!msg.enablePushNotificationInsideApp) return;
            //ReceivedMessage.print(msg);
            try {
              _showSnackBar(
                context: context,
                title: msg.title,
                message: msg.body,
                friendId: msg.sender,
                serviceType: msg.serviceType,
              );
            } catch (e) {
              print('onMessage-Exception: ${e.toString()}');
            }
          }
        },
        onLaunch: (Map<String, dynamic> message) async {
          print("onLaunch");
          //print("onLaunch: $message");
          ReceivedMessage msg = ReceivedMessage.fromMap(message);
          if (msg != null) {
            //ReceivedMessage.print(msg);
            try {
              //
              await _goToRoute(
                context: context,
                friendId: msg.sender,
                serviceType: msg.serviceType,
              );
            } catch (e) {
              print('onMessage-Exception: ${e.toString()}');
            }
          }
        },
        onResume: (Map<String, dynamic> message) async {
          print("onResume");
          //print("onResume: $message");
          ReceivedMessage msg = ReceivedMessage.fromMap(message);
          if (msg != null) {
            print('_currentPage: $_currentPage');
            String generatedPage =
                (msg.serviceType == PushNotificationServiceType.chat.toString())
                    ? '${ChatPage.id}/${msg.sender}'
                    : FriendRequestsPage.id;
            print('generatedPage: $generatedPage');
            if (_currentPage == generatedPage) {
              print('Stay in the same room, don\'t go away');
              return;
            } else {
              print('go to user page');
            }
            //ReceivedMessage.print(msg);
            try {
              //
              await _goToRoute(
                context: context,
                friendId: msg.sender,
                serviceType: msg.serviceType,
              );
            } catch (e) {
              print('onMessage-Exception: ${e.toString()}');
            }
          }
        },
      );

      _initialized = true;
    }
  }
areeg-ad commented 4 years ago

@TahaTesser here my pubspec.yaml

name: sabbar
description: A new Flutter project.

version: 2.1.0+57

environment:
  sdk: ">=2.6.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

  flutter_bloc: ^4.0.1
  dio:
  permission_handler:
  provider:
  pedantic:
  hive: ^1.4.0+1
  hive_flutter:
  path_provider:
  url_launcher: ^5.4.1
  location: ^2.4.0
  flutter_markdown: ^0.3.4
  google_maps_flutter: 0.5.24+1
  intl:
  intercom_flutter:
  firebase_messaging: ^6.0.16
  firebase_remote_config: 0.3.0+3
  package_info:
  sentry:
  smooth_page_indicator: ^0.1.4
  firebase_analytics: ^5.0.11
  # pdf viewer
  pdf_viewer_plugin: ^1.0.0+2
  # share files
  esys_flutter_share: ^1.0.2
  #get device unique identifer
  device_info: ^0.4.2+4
  #search google places textfield
  flutter_google_places: ^0.2.5
  #detect keyboard visibility
  keyboard_visibility: ^0.5.6
  #get user exact location details
  geocoder: ^0.2.1
  #get accurate user permission
  geolocator: ^5.3.2+2
  #open device settings
  app_settings: ^4.0.2
  #webview
  flutter_inappwebview: ^4.0.0+4
  #convert html to pdf
  flutter_html_to_pdf: ^0.5.2
  #show in app notification
  flutter_local_notifications: ^1.4.4+2

dev_dependencies:
  flutter_test:
    sdk: flutter
  mockito:
  hive_generator:
  build_runner: ^1.7.4
  device_preview: 0.1.9-beta

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter.
flutter:
  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  assets:
    - assets/images/
    - assets/images/0.75x/
    - assets/images/1.0x/
    - assets/images/1.5x/
    - assets/images/2.0x/
    - assets/images/3.0x/
    - assets/google-maps-style.json

  fonts:
    - family: Nunito
      fonts:
        - asset: assets/fonts/Nunito/Nunito-Regular.ttf
        - asset: assets/fonts/Nunito/Nunito-Bold.ttf
          weight: 700
        - asset: assets/fonts/Nunito/Nunito-SemiBold.ttf
          weight: 600
    - family: NotoSANS
      fonts:
        - asset: assets/fonts/NotoSans/NotoSansUI-Regular.ttf
        - asset: assets/fonts/NotoSans/NotoSansUI-Bold.ttf
          weight: 700
    - family: ArabicFont
      fonts:
        - asset: assets/fonts/ArabicFonts/arabic_font.ttf
    - family: Helvetica
      fonts:
        - asset: assets/fonts/ArabicFonts/HelveticaRegular.ttf
        - asset: assets/fonts/ArabicFonts/HelveticaBold.ttf
          weight: 700

the main firebase messaging file

class NotificationUsecase {
  final HttpClient _httpClient;
  final DeviceInfoUseCase _deviceInfoUseCase;
  final PermissionUsecase _permissionUsecase;
  final FirebaseMessaging _firebaseMessaging;
  final BuildContext _context;
  static bool _isConfigured = false;
  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  NotificationUsecase(
    this._context,
    this._httpClient,
    this._firebaseMessaging,
    this._permissionUsecase,
    this._deviceInfoUseCase,
  );

  Future<PermissionStatus> checkPermissionStatus() async {
    return _permissionUsecase
        .checkPermissionStatus(PermissionEnum.NOTIFICATION);
  }

  Future<bool> init() async {
    var status = await checkPermissionStatus();
    if (status.isUndetermined || status.isGranted) {
      return Permission.notification.request().then((value) async {
        if (value.isGranted) {
          var response = await _httpClient.registerDevice(
              await _deviceInfoUseCase.getId(), await getToken());
          print(response);
          _firebaseMessaging.requestNotificationPermissions(
              const IosNotificationSettings(
                  sound: true, badge: true, alert: true, provisional: true));
          _firebaseMessaging.onIosSettingsRegistered
              .listen((IosNotificationSettings settings) {});
          _configureListeners();
          return true;
        } else {
          return false;
        }
      });
    }
    return false;
  }

  Future<String> getToken() async => await _firebaseMessaging.getToken();

  void _configureListeners() {
    if (!_isConfigured) {
      _firebaseMessaging.configure(
        onBackgroundMessage: Platform.isIOS ? null : _handleBackgroundMessage,
        onLaunch: _onLunch,
        onMessage: _onMessage,
        onResume: _onResume,
      );
      _isConfigured = true;
    }
  }

  Future<void> _onLunch(Map<String, dynamic> payload) async {
    if ((payload['date'] ?? payload['data']['date'])
        .toString()
        .contains('newAssignment')) {
      await Future.delayed(const Duration(seconds: 0), () {
        Navigator.pushNamedAndRemoveUntil(
            _context, AppRouter.home, (Route<dynamic> route) => false,
            arguments: {
              'timeStamp':
                  int.parse((payload['date'] ?? payload['data']['date'])),
            });
      });
    }
  }

  Future<void> _onMessage(Map<String, dynamic> payload) async {
    var type =
        payload['data'] != null ? payload['data']['type'] : payload['type'];
    if (type.toString().contains('newAssignment')) {
      await showNotification(payload);
    }
  }

  Future<void> _onResume(Map<String, dynamic> payload) async {
    if ((payload['date'] ?? payload['data']['date'])
        .toString()
        .contains('newAssignment')) {
      await Future.delayed(const Duration(seconds: 0), () {
        Navigator.pushNamedAndRemoveUntil(
            _context, AppRouter.home, (Route<dynamic> route) => false,
            arguments: {
              'timeStamp':
                  int.parse((payload['date'] ?? payload['data']['date'])),
            });
      });
    }
  }

  Future<void> _onBackgroundNotification(Map<String, dynamic> payload) async {
    print('Incoming notification $payload');

    final data = (payload['data'] as Map).cast<String, dynamic>();
    if (await Intercom.isIntercomPush(data)) {
      await Intercom.handlePush(data);
      return;
    }
  }

  void _initializePlatformSpecifics(Map<String, dynamic> mPayload) async {
    var initializationSettingsAndroid =
        AndroidInitializationSettings('ic_launcher');
    var initializationSettingsIOS = IOSInitializationSettings(
      requestAlertPermission: true,
      requestBadgePermission: true,
      requestSoundPermission: false,
      onDidReceiveLocalNotification: (id, title, body, payload) async {
        onNotificationClicked(mPayload);
      },
    );
    var initializationSettings = InitializationSettings(
        initializationSettingsAndroid, initializationSettingsIOS);
    await flutterLocalNotificationsPlugin.initialize(initializationSettings,
        onSelectNotification: (String payload) async {
      onNotificationClicked(mPayload);
    });
  }

  Future<void> showNotification(Map<String, dynamic> payload) async {
    _initializePlatformSpecifics(payload);
    var androidChannelSpecifics = AndroidNotificationDetails(
      'CHANNEL_ID',
      'CHANNEL_NAME',
      "CHANNEL_DESCRIPTION",
      importance: Importance.Max,
      priority: Priority.High,
      playSound: true,
      timeoutAfter: 5000,
      styleInformation: DefaultStyleInformation(true, true),
    );
    var iosChannelSpecifics = IOSNotificationDetails();
    var platformChannelSpecifics =
        NotificationDetails(androidChannelSpecifics, iosChannelSpecifics);
    await flutterLocalNotificationsPlugin.show(
      0, // Notification ID
      payload['notification']['title'], // Notification Title
      payload['notification']['body'],
      // Notification Body, set as null to remove the body
      platformChannelSpecifics,
      payload: payload.toString(), // Notification Payload
    );
  }

  void onNotificationClicked(Map<String, dynamic> payload) {
    if ((payload['type'] ?? payload['data']['type'])
        .toString()
        .contains('newAssignment')) {
      Navigator.pushNamedAndRemoveUntil(
          _context, AppRouter.home, (Route<dynamic> route) => false,
          arguments: {
            'timeStamp':
                int.parse((payload['date'] ?? payload['data']['date'])),
          });
    }
  }
}

Future<dynamic> _handleBackgroundMessage(Map<String, dynamic> payload) async {
  print("_handleBackgroundMessage ${payload}");
}
TahaTesser commented 4 years ago

Hi @areeg-ad Your code isn't minimal and has related code, Can you please provide a minimal complete reproducible code sample? or reproduce using official example Thank you

kristijandraca commented 4 years ago

Hi @areeg-ad Your code isn't minimal and has related code, Can you please provide a minimal complete reproducible code sample? or reproduce using official example Thank you

Same issue here, I tested it on an official example.

[✓] Flutter (Channel stable, 1.20.2, on Mac OS X 10.15.6 19G2021, locale en-GB)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
[✓] Android Studio (version 4.0)
[✓] VS Code (version 1.48.1)
google-oss-bot commented 4 years ago

Hey @areeg-ad. We need more information to resolve this issue but there hasn't been an update in 7 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

google-oss-bot commented 4 years ago

Since there haven't been any recent updates here, I am going to close this issue.

@areeg-ad if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.