Flutterfire: [Firebase Messaging Flutter] onResume and onLaunch callbacks are not called on Android

Created on 22 Feb 2020  Â·  3Comments  Â·  Source: FirebaseExtended/flutterfire

Issue Description
I'm trying to implement FCM in a flutter App. The issue I'm facing is that "onResume and onLaunch call backs are not called" when a user taps on the notification in the system tray. While onMessage callback works fine when the app is in the foreground.

Have also posted the issue on stack overflow here
Here are all the files I changed for the implementation:

Plugin Version: firebase_messaging 6.0.9

Project Level build.gradle:

buildscript {
    ext.kotlin_version = '1.3.50'
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.3'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.3'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

rootProject.buildDir = '../build'
subprojects {
    project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
    project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

App Level build.gradle

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
    throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}

def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
    flutterVersionCode = '1'
}


def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
    flutterVersionName = '1.0'
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
    compileSdkVersion 28

    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }

    lintOptions {
        disable 'InvalidPackage'
    }

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.tripmate.travelguidePakistan.tripmate2_0"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }

    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.debug
        }
    }
}

flutter {
    source '../..'
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:multidex:1.0.3' // use latest version
    implementation 'com.google.firebase:firebase-messaging:20.1.0'
}

apply plugin: 'com.google.gms.google-services'

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tripmate.travelguidePakistan.tripmate2_0">

    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
         calls FlutterMain.startInitialization(this); in its onCreate method.
         In most cases you can leave this as-is, but you if you want to provide
         additional functionality it is fine to subclass or reimplement
         FlutterApplication and put your custom class here. -->

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <application
        android:name=".Application"
        android:label="tripmate2_0"
        android:icon="@mipmap/ic_launcher">
        <meta-data android:name="com.google.android.geo.API_KEY"
            android:value="AIzaSyB7ysetHlNe*********_HXL879M"/>
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- This keeps the window background of the activity showing
                 until Flutter renders its first frame. It can be removed if
                 there is no splash screen (such as the default splash screen
                 defined in @style/LaunchTheme). -->
            <meta-data
                android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
                android:value="true" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <intent-filter>
                <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Application.java

package com.tripmate.travelguidePakistan.tripmate2_0;

import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;

public class Application extends FlutterApplication implements PluginRegistrantCallback {
    @Override
    public void onCreate() {
        super.onCreate();
        FlutterFirebaseMessagingService.setPluginRegistrant(this);
    }

    @Override
    public void registerWith(PluginRegistry registry) {
        GeneratedPluginRegistrant.registerWith(registry);
    }
}

MainActivity.kt

package com.tripmate.travelguidePakistan.tripmate2_0

import android.os.Bundle

import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity: FlutterActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    GeneratedPluginRegistrant.registerWith(this)
  }
}

main.dart


//Other packages here
import 'package:firebase_messaging/firebase_messaging.dart';

Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
  if (message.containsKey('data')) {
    print('Data Message');
//      // Handle data message
//      final dynamic data = message['data'];
  }

  if (message.containsKey('notification')) {
    print('Notification message');
    // Handle notification message
//      final dynamic notification = message['notification'];
  }

  // Or do other work.
}

int count; // This is used to track the onboarding pages user has visited
SharedPreferences prefs;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Shared Prefs are used to check if users is done with
  // onboarding screens. It tracks how many onboarding
  // screens the user has iterated.
  prefs = await SharedPreferences.getInstance();
  count = prefs.getInt('onBoardingCount') ?? 0;

  print('Onboarding Screen count: $count');
  try {
    prefs.setInt('onBoardingCount', count);
  } catch (e) {
    print('Exception @main: $e');
  }
  return runApp(MyApp());
}

class MyApp extends StatefulWidget {
  static SharedPreferences sharedPrefs = prefs;

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _fcm = FirebaseMessaging();

  @override
  void initState() {
    super.initState();
    _fcm.configure(
        onBackgroundMessage: myBackgroundMessageHandler,
        onMessage: (Map<String, dynamic> message) async {
          print('@onMessage');
          SharePrefHelper().incrementNotificationsCount();
          setState(() {
            HomeScreen.notificationsCount++;
          });
          print('OnMessage: $message');
        },
        onResume: (Map<String, dynamic> message) async {
          print('@onResume');
          SharePrefHelper().incrementNotificationsCount();
          setState(() {
            HomeScreen.notificationsCount++;
          });
          print('onResume: $message');
          Navigator.push(context,
              MaterialPageRoute(builder: (context) => NotificationsScreen()));
        },
        onLaunch: (Map<String, dynamic> message) async {
          print('@onLaunch');
          SharePrefHelper().incrementNotificationsCount();
          setState(() {
            HomeScreen.notificationsCount++;
          });
          print('onLaunch: $message');
          Navigator.push(context,
              MaterialPageRoute(builder: (context) => NotificationsScreen()));
        });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(fontFamily: 'OpenSans', backgroundColor: Colors.white),
      initialRoute: (count >= 4) ? rootScreen : onBoardingScreen,
      routes: {
        //All routes here
      },
    );
  }
}

**Flutter Doctor output

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.7, on Mac OS X 10.15.1 19B88, locale en-PK)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[!] Xcode - develop for iOS and macOS (Xcode 11.2.1)
    ✗ CocoaPods installed but not working.
        You appear to have CocoaPods installed but it is not working.
        This can happen if the version of Ruby that CocoaPods was installed with is different from the one being used to invoke it.
        This can usually be fixed by re-installing CocoaPods. For more info, see https://github.com/flutter/flutter/issues/14293.
      To re-install CocoaPods, run:
        sudo gem install cocoapods
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.41.1)
[✓] VS Code (version 1.41.1)
[✓] Connected device (1 available)

! Doctor found issues in 1 category.

To Reproduce
Steps to reproduce the behavior:

  1. Just follow the steps mentioned in the official docs.

Expected behavior
The expected behaviour is that the onResume and onLaunch callbacks should be called when the user taps on notifications received while the app is in background or closed.

Actual behaviour
onLaunch and onResume callbacks are not called and there is no exception message as well.
Additional context
Add any other context about the problem here.

bug

Most helpful comment

The issue got resolved as I didn't add 'click_action' key while generating notification.

All 3 comments

The issue got resolved as I didn't add 'click_action' key while generating notification.

@haroonkhan9426 where your put Application.java at? is your project base on kotlin?
Screenshot 2020-03-04 at 3 52 04 PM

Hi @haroonkhan9426
I see there's an open issue addressing the case you described.
Please follow up on that issue,
I'm closing the current one as duplicate.
If you disagree please write in the comments
and I will reopen it.
Thank you

Was this page helpful?
0 / 5 - 0 ratings