【问题标题】:How to get a full screen notification from FCM?如何从 FCM 获取全屏通知?
【发布时间】:2021-04-09 17:50:09
【问题描述】:

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

我在运行我的应用程序时尝试作为顶级函数没有错误:

  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);
    }
});

我的应用程序.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
}

【问题讨论】:

  • 我不是很喜欢这个,但我认为这个插件可以帮助你pub.dev/packages/android_alarm_manager 但请注意该插件仅适用于android
  • 不幸的是,如果它只适用于android,那么我不能使用它,但我很感谢你的帮助:)
  • 那么也许是这个:pub.dev/packages/background_fetch
  • 感谢您的回复,但我已经用 workmanger 库做了一些事情,但问题是它每 15 分钟运行一次,如果有火警,这不是一件好事!我想我今天会尝试一下通知通道,它可以让我为通知选择自定义声音,我会选择长警报,不知道这是否可能(我的意思是单独的警报,也许 30 秒就足够了),但我这几天会尝试一下。

标签: firebase flutter push-notification google-cloud-functions firebase-cloud-messaging


【解决方案1】:

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

解决方案 1:

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

解决方案 2:

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

解决方案 3:

  1. 在文件夹 java/com/yourdomain 内创建一个新文件 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"
       ...
 >

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

【讨论】:

  • 第一个不是解决方案,是的,这个功能与ios一起工作,第二个可以实现声音效果,我正在努力,所以谢谢你的。对于第三个,我做了你在 kotlin 中尝试做的事情,正如我的问题中所述。
【解决方案2】:

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

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

【讨论】:

  • 感谢您的回答 :),我尝试将有效负载仅作为数据消息,但我无法对其进行测试,当我尝试敬酒时它给了我一个错误,当我尝试运行我的应用程序它给我一个错误,当我尝试播放声音时它给我一个错误,当应用程序在后台并且没有被杀死时,所有这些都完成了,我需要这样的交互,以便我可以尝试应用程序被杀,你认为我应该怎么做才能发出警报?还有如何在颤振中禁用电池优化?
  • 我没有 Flutter 体验,但由于 onBackgroundMessage 未在主 UI 线程/上下文中运行,您无法显示 Toast 或对话框。在标准的 android 应用中,Intent 将用于显示主屏幕
  • 将用于 workmanger 库,它每 15 分钟执行一次后台任务,即使应用程序被杀死我也可以运行 toast,在这种情况下我真的不知道如何实现颤振警报屏幕。跨度>
  • onBackgroundMessage 将使用仅数据 FCM 调用,即使应用程序被杀死,问题是如何从 onBackgroundMessage 启动应用程序,我知道如何在 android 应用程序和 Java 中使用和 Intent ,但我不知道颤振
猜你喜欢
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
相关资源
最近更新 更多