我想构建一个应用程序,比如当我将带有纬度和经度信息的新数据保存到firebase时,然后在我的应用程序中计算这些纬度和经度之间的距离;经度和用户的当前位置。如果距离小于60公里,则发送onBackgroundMessage
通知。我不将用户的当前位置存储在firebase上。我使用函数_getCurrentLocation
获取用户的当前位置。问题是,我不知道isValidDistance
在哪里以及如何放置,以检查距离是否低于60千米。目前我的应用程序发送通知,但不是通过距离。
index.js
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.myFunction = functions.firestore
.document("animal/{message}")
.onCreate((snapshot, context) => {
return admin.messaging().sendToTopic("animal", {
data: {
latitude: snapshot.data()["latitude"].toString(),
longitude: snapshot.data()["longitude"].toString(),
},
notification: {
title: snapshot.data().username,
body: snapshot.data().description,
clickAction: "FLUTTER_NOTIFICATION_CLICK",
},
});
});
main.dart
Future<void> _messageHandler(RemoteMessage message) async {
print('background message ${message.data}');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
double? currentLatitude;
double? currentLongitude;
Future<void> _getCurrentLocation() async {
final locData = await Location().getLocation();
setState(() {
currentLatitude = locData.latitude;
currentLongitude = locData.longitude;
});
}
int getDistanceInMeters(currLat, currLng, lat, lng) {
return Geolocator.distanceBetween(
currLat,
currLng,
lat,
lng,
).round();
}
bool isValidDistance(RemoteMessage messaging) {
Map<String, dynamic> data = messaging.data;
var _list = data.values.toList();
var lat = double.parse(_list[0]);
var lng = double.parse(_list[1]);
print(_list);
int distance =
getDistanceInMeters(currentLatitude, currentLongitude, lat, lng);
var distanceInKm = (distance / 1000).round();
print('Distance is: ${distanceInKm.toString()}');
if (distance < 60000) {
return true;
}
return false;
}
@override
void initState() {
super.initState();
_getCurrentLocation();
final messaging = FirebaseMessaging.instance;
messaging.subscribeToTopic('animal');
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (isValidDistance(message)) {
print('onMessageListen');
}
});
FirebaseMessaging.onMessageOpenedApp.listen((message) {
if (isValidDistance(message)) {
print('onMessageOpened');
}
});
FirebaseMessaging.onBackgroundMessage(_messageHandler);
}
...
首先,您需要将fcm从通知消息更改为数据消息,以允许应用程序在后台处理消息。请在此处查看。
exports.myFunction = functions.firestore
.document("animal/{message}")
.onCreate((snapshot, context) => {
return admin.messaging().sendToTopic("animal", {
data: {
latitude: snapshot.data()["latitude"].toString(),
longitude: snapshot.data()["longitude"].toString(),
title: snapshot.data().username,
body: snapshot.data().description,
},
});
});
选中此处可在应用程序打开时显示推送通知。您的代码应该是这样的。
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (isValidDistance(message)) {
print('onMessageListen');
showNotification(message);
}
});
Yo可以访问通过以下发送的数据
Map<String, dynamic> data = message.data;
然后后台处理程序将如下所示。
_messageHandler(RemoteMessaging message){
if (isValidDistance(message)) {
print('onMessageListen');
showNotification(message);
}
}
或者创建一个Notification类,如下所示并使用。
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:geolocator/geolocator.dart';
import 'package:location/location.dart';
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description: 'This channel is used for important notifications.',
importance: Importance.max,
);
Future<LocationData> _getCurrentLocation() => Location().getLocation();
int getDistanceInMeters(currLat, currLng, lat, lng) {
return Geolocator.distanceBetween(
currLat,
currLng,
lat,
lng,
).round();
}
Future<bool> isValidDistance(RemoteMessage messaging) async {
Map<String, dynamic> data = messaging.data;
var _list = data.values.toList();
var lat = double.parse(_list[0]);
var lng = double.parse(_list[1]);
print(_list);
var location = await _getCurrentLocation();
int distance =
getDistanceInMeters(location.latitude, location.longitude, lat, lng);
var distanceInKm = (distance / 1000).round();
print('Distance is: ${distanceInKm.toString()}');
if (distance < 60000) {
return true;
}
return false;
}
class NotificationServices {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
bool isValid = await isValidDistance(message);
if (isValid) {
print('onMessageListen');
showNotification(message);
}
}
backgroundNotification() {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidInitializationSettings _initialzationSettingsAndriod =
AndroidInitializationSettings('@mipmap/ic_launcher');
final IOSInitializationSettings _initialzationSettingsIOS =
IOSInitializationSettings();
final InitializationSettings _initializationSettings =
InitializationSettings(
android: _initialzationSettingsAndriod,
iOS: _initialzationSettingsIOS);
_flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
_flutterLocalNotificationsPlugin.initialize(_initializationSettings);
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) async {
if (message != null) await onClickNotificationHandler(message);
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
bool isValid = await isValidDistance(message);
if (isValid) {
print('onMessageListen');
showNotification(message);
}
});
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
await onClickNotificationHandler(message);
});
}
onClickNotificationHandler(RemoteMessage message) async {
Map<String, dynamic> data = message.data;
print(data);
//you can handle notificationand navigate to necessary screen here.
}
showNotification(RemoteMessage message) {
Map<String, dynamic> data = message.data;
if (data["body"] != null) {
flutterLocalNotificationsPlugin.show(
data.hashCode,
data["title"],
data["body"],
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
icon: '@mipmap/ic_launcher',
),
iOS: IOSNotificationDetails(
presentAlert: true, presentBadge: true, presentSound: true),
),
);
}
}
}