【发布时间】: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,那么我不能使用它,但我很感谢你的帮助:)
-
感谢您的回复,但我已经用 workmanger 库做了一些事情,但问题是它每 15 分钟运行一次,如果有火警,这不是一件好事!我想我今天会尝试一下通知通道,它可以让我为通知选择自定义声音,我会选择长警报,不知道这是否可能(我的意思是单独的警报,也许 30 秒就足够了),但我这几天会尝试一下。
标签: firebase flutter push-notification google-cloud-functions firebase-cloud-messaging