如何从 FCM 获取全屏通知?

How to get a full screen notification from FCM?

我正在构建一个家庭自动化项目,它有一个火灾传感器,如果检测到火灾,它将写入 Firebase 数据库,然后我需要为用户发出警报。 我设法触发了来自 Firebase 云功能的通知,但这并不是我想要的。 我想要的是使用自定义声音向用户发出全屏通知,例如 phone 警报或发生火警时的应用程序调用 - 数据库中发生变化 -

我在 运行 我的应用程序:

时尝试作为顶级函数没有错误
  firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print('onMessage: $message');
        toast3('asdasdsawwwww $message');
        setMessage(message);
      },
      onLaunch: (Map<String, dynamic> message) async {
        print('onLaunch: $message');
        setMessage(message);
      },
      onResume: (Map<String, dynamic> message) async {
        print('onResume: $message');
        setMessage(message);
      },
      onBackgroundMessage: myBackgroundMessageHandler);
  print('onMessage:12qew11');

  firebaseMessaging.requestNotificationPermissions(
    const IosNotificationSettings(sound: true, badge: true, alert: true),
  );
}


Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
  print('HEREE');
 final assetsAudioPlayer = AssetsAudioPlayer();

    assetsAudioPlayer.open(
        Audio("assets/audio/alarm.mp3"),
    );
  return Fluttertoast.showToast(
      msg: 'done background:))))$message',
      toastLength: Toast.LENGTH_LONG,
      gravity: ToastGravity.BOTTOM,
      timeInSecForIos: 4,
      backgroundColor: Colors.redAccent,
      textColor: Colors.white,
      fontSize: 15.0);
}

我的 Firebase 函数:

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().functions);

var fireDatabase;
exports.myFirstCloudFun = functions.database.ref('/usersData/{userID}/Fire').onUpdate(async (event, context) => {

    const uidGotten = context.params.userID;

    const fireData = event.after.val()
    console.log('data changed in fire is' + fireData + 'userID is ' + uidGotten);
    const usereIdTokens = await admin
        .firestore()
        .collection(uidGotten)
        .doc('userTokens')
        .get();
    console.log('Tokens to try are' + usereIdTokens.data);

    var tokens = usereIdTokens.data().user_all_tokens;
    var payload = {
        notification: {
            title: 'Push Title',
            body: 'Push Body' + fireData,
            sound: 'default',
        },
        data: {
            push_key: 'Fire Value Is',
            key1: "fireData is " + fireData,
        },
    };
    tokens.forEach.toString().trim;

    console.log('Tokens to send are ' + tokens[1] + '   //////   ' + tokens);

    try {
        const response = await admin.messaging().sendToDevice(tokens, payload);
        console.log('Notification sent successfully');
    } catch (err) {
        console.log(err);
    }
});

我的Application.kt

package com.eghubs.eg_home_hubs

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

public class Application: FlutterApplication(), PluginRegistrantCallback {
    override fun onCreate() {
        super.onCreate()
        FlutterFirebaseMessagingService.setPluginRegistrant(this)
    }

    override fun registerWith(registry: PluginRegistry) {
        FirebaseCloudMessagingPluginRegistrant.registerWith(registry)
    }
}

我的FirebaseCloudMessagingPluginRegistrant.kt

package com.eghubs.eg_home_hubs


import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin

class FirebaseCloudMessagingPluginRegistrant {
    companion object {
        fun registerWith(registry: PluginRegistry) {
            if (alreadyRegisteredWith(registry)) {
                return;
            }
            FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"))
        }

        fun alreadyRegisteredWith(registry: PluginRegistry): Boolean {
            val key = FirebaseCloudMessagingPluginRegistrant::class.java.name
            if (registry.hasPlugin(key)) {
                return true
            }
            registry.registrarFor(key)
            return false
        }
    }
}

我的 AndroidManifest 是:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.eghubs.eg_home_hubs">
    <uses-permission android:name="android.permission.ACCESS_CORSE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET"/>



    <!-- 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.
                  android:name="io.flutter.app.FlutterApplication"
                  android:name="androidx.multidex.MultiDexApplication"

-->
    <application
        android:name=".Application" <!-- here is the change-->
        android:label="EG HomeHubs"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher">
        tools:replace="android:allowBackup">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            android:showWhenLocked="true"
            android:turnScreenOn="true">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <!-- Displays an Android View that continues showing the launch screen
                 Drawable until Flutter paints its first frame, then this splash
                 screen fades out. A splash screen is useful to avoid any visual
                 gap between the end of Android's launch screen and the painting of
                 Flutter's first frame. -->
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/launch_background"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <intent-filter>   <!-- Noti:this is for cloud messiging -->
                <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>

</manifest>

但是后台没有打开应用我什么也没有,为什么没有调用onBackgroundMessage函数?

我的问题是我怎样才能实现什么是应用程序调用或类似的东西?

是否有更好的方法来执行此操作,是否有其他方法可以通过更改 firebase 数据库在我的项目中实现该火警功能?

编辑:我的 app/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 FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
//GradleException

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"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
    packagingOptions {
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
    compileSdkVersion 30

    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.eghubs.eg_home_hubs"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
      //  multiDexEnabled true

    }
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
            storePassword keystoreProperties['storePassword']
        }
    }
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            // 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
        }
        debug {
            minifyEnabled true
            shrinkResources true
      }

    }
}

flutter {
    source '../..'
}

dependencies {
    implementation 'com.google.firebase:firebase-analytics'
    implementation platform('com.google.firebase:firebase-bom:26.0.0')
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
  //  implementation 'androidx.multidex:multidex:2.0.1'  //with androidx libraries
    implementation'com.google.firebase:firebase-messaging:21.0.1'


}
apply plugin: 'com.android.application'
// Add this line
apply plugin: 'com.google.gms.google-services'

我的android/build.gradle:

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

    dependencies {
        classpath 'com.google.gms:google-services:4.3.4'
        //classpath 'com.android.tools.build:gradle:3.5.3' //todo rollback this
        classpath 'com.android.tools.build:gradle:4.1.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

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
}

我有一些方法可以解决这个问题。

解决方案 1:

您要做的第一件事是检查 iOS 是否支持 onBackgroundMessage
而在Android中,你必须开启Allow running in background选项。

解决方案 2:

通过 flutter_local_notifications 包创建一个高重要性频道。
flutter_local_notifications 包裹 link: https://pub.dev/packages/flutter_local_notifications

解决方案 3:

  1. 在文件夹 java/com/yourdomain
  2. 中创建一个新文件 App.java
package com.yourdomain;
import io.flutter.app.FlutterApplication;

public class App extends FlutterApplication {
  @Override
  public void onCreate() {
    super.onCreate();
  }
}
  1. 然后,在 AndroidManifest.xml 文件中,添加 android:name=".App"
<application
        android:name=".App"
       ...
 >

之后重建应用程序,即使应用程序被终止或终止,通知也会正常工作。

在 Android,要在应用程序处于后台时调用您的 onBackgroundMessage,FCM 消息必须是没有通知的数据消息,请查看此处:https://firebase.google.com/docs/cloud-messaging/android/receive

此外,当设备处于休眠状态时,要立即接收消息,您应该禁用电池优化,看这个:https://developer.android.com/training/monitoring-device-state/doze-standby

好的。

自更新后8.0.0-dev.1 我们可以默认获取onBackgroundMessage,不需要这些安装过程

NEW: FirebaseMessaging.onBackgroundMessage() Sets a background message handler to trigger when the app is in the background or terminated.