Previously, nearby_connection v2.0.2
is working fine, but after adding firebase_messaging v8.0.0-dev.15
to the app, onEndpointFound
and onConnectionInitiated
never get called.
I have a git commit of a working app (onEndpointFound
and onConnectionInitiated
get called correctly, before adding firebase_messaging
) and the latest git commit that integrated firebase_messaging
where nearby_connection
started to break.
I ran this command git diff <hash before nearby_connection breaks> <hash of firebase_messaging integration>
, the result is pretty clear that all code related to nearby_connections
is intanct. There is no new code related to nearby_connections
.
When I do git checkout
to the commit before integrating firebase_messaging
, nearby_connections
works great. But as soon as git checkout
to the firebase_messaging
integration commit, it breaks.
The environment is the same as before and after nearby_connections
breaks.
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 33df214..ab3dd80 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -23,6 +23,7 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
+apply plugin: 'com.google.gms.google-services'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
@@ -59,5 +60,8 @@ flutter {
}
dependencies {
+ implementation platform('com.google.firebase:firebase-bom:25.3.1')
+ implementation 'com.google.firebase:firebase-analytics-ktx'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
diff --git a/android/app/google-services.json b/android/app/google-services.json
new file mode 100644
index 0000000..1dd6783
--- /dev/null
+++ b/android/app/google-services.json
@@ -0,0 +1,40 @@
+{
+ "project_info": { ... }
+}
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2878b8a..73e8407 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -66,6 +66,8 @@
<meta-data android:name="flutterEmbedding" android:value="2" />
<!-- Google map -->
<meta-data android:name="com.google.android.geo.API_KEY" android:value="XXXX"/>
+ <!-- A custom Android Notification Channel to deliver FCM notifications on a non-default channel -->
+ <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="high_importance_channel" />
</application>
<!-- Required for Nearby Connections -->
@@ -90,4 +92,4 @@
<!-- Internet -->
<uses-permission android:name="android.permission.INTERNET" />
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/android/build.gradle b/android/build.gradle
index 3100ad2..bb6f91b 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -8,6 +8,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.google.gms:google-services:4.3.8'
}
}
diff --git a/lib/main.dart b/lib/main.dart
index 8fbf391..b2db7e1 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -2,13 +2,17 @@ import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'dart:math';
+import 'package:http/http.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';
import 'package:nearby_connections/nearby_connections.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:mime/mime.dart';
import 'package:geolocator/geolocator.dart';
+import 'package:firebase_core/firebase_core.dart';
+import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:rpd_prototype/helpers/database.dart';
import 'package:rpd_prototype/helpers/BleCharRef.dart';
@@ -27,12 +31,50 @@ import 'package:rpd_prototype/pages/qzqsmMessages.dart';
import 'package:rpd_prototype/pages/user.dart';
import 'package:rpd_prototype/pages/warning.dart';
+FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
+
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SqLiteDatabase.initializeDb();
+ await firebaseMessagingSetup();
runApp(MyApp());
}
+Future<void> firebaseMessagingSetup() async {
+ await Firebase.initializeApp();
+ FirebaseMessaging.onBackgroundMessage(firebaseBackgroundMessageHandler);
+ /// Create a [AndroidNotificationChannel] for heads up notifications
+ const AndroidNotificationChannel channel = AndroidNotificationChannel(
+ 'high_importance_channel', // id
+ 'High Importance Notifications', // title
+ 'This channel is used for important notifications.', // description
+ importance: Importance.high,
+ enableVibration: true,
+ playSound: true,
+ );
+ if (defaultTargetPlatform == TargetPlatform.android) {
+ /// Create an Android Notification Channel.
+ ///
+ /// We use this channel in the `AndroidManifest.xml` file to override the
+ /// default FCM channel to enable heads up notifications.
+ await flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()?.createNotificationChannel(channel);
+ }
+ /// Update the iOS foreground notification presentation options to allow
+ /// heads up notifications.
+ await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
+ alert: true,
+ badge: true,
+ sound: true,
+ );
+}
+
+Future<void> firebaseBackgroundMessageHandler(RemoteMessage message) async {
+ print(">>> firebaseBackgroundMessageHandler: ${message.data}");
+ if(message.notification != null) {
+ print(">>> message also contained notification: ${message.notification}");
+ }
+}
+
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
@@ -89,12 +131,15 @@ class MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
Timer flutterBlueReadDataTimeout;
Timer flutterBlueScanTimer;
StreamSubscription<BluetoothState> streamBluetoothSubscription;
- FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Map<int, File> tempFiles = {}; // { payloadId: file }
Map<int, Map<String, dynamic>> tempFileData = {}; // { payloadId: { String fileName, String senderDisplayName, DateTime timestamp } }
StreamSubscription<Position> userPositionStream;
+ // Firebase messaging
+ StreamSubscription<RemoteMessage> firebaseMessagingForegroundSubscription;
+ StreamSubscription<RemoteMessage> firebaseMessagingAppOpenedSubscription;
+
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
@@ -108,6 +153,9 @@ class MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
var initSetttings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOs);
flutterLocalNotificationsPlugin.initialize(initSetttings, onSelectNotification: onSelectNotification);
+ // Firebase Messaging
+ firebaseMessagingListenForeground();
+
MessageQueue.watchQueue(connectedDeviceModel);
nearbyCheckPermission();
timerToggleNearbyAdvertiseDiscovery();
@@ -116,6 +164,44 @@ class MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
subscribeUserPosition();
}
+ void firebaseMessagingListenForeground() async {
+ FirebaseMessaging.instance.getToken().then((value) {
+ print(">>> got firebase token: $value");
+ post("http://192.168.1.38:8000/api/add-firebase-messaging-token", headers: { 'content-type': 'application/json; charset=UTF-8' }, body: jsonEncode({ "token": value })).then((res) {
+ print(">>> sent firebase token to 192.168.1.38:8000");
+ }).catchError((error) {
+ print(">>> Error while sending token to 192.168.1.38:8000");
+ print(error);
+ });
+ });
+ // Firebase messaging
+ firebaseMessagingForegroundSubscription = FirebaseMessaging.onMessage.listen((RemoteMessage message) {
+ print(">>> received firebase foreground message: ${message.data.toString()}");
+ handleFirebaseMessaging(message);
+ });
+ firebaseMessagingAppOpenedSubscription = FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
+ print(">>> onMessageOpenedApp: ${message.data.toString()}");
+ handleFirebaseMessaging(message);
+ });
+ }
+
+ Future<void> handleFirebaseMessaging(RemoteMessage message) async {
+ String qzqsm = message.data["qzqsm"];
+ List<ConnectedDevice> devices = connectedDeviceModel.devices.where((device) => device.type == ConnectedDeviceType.nearbyDevice).toList();
+ // if message is QZQSM
+ if(QzqsmMessageListModel.isQzqsmString(qzqsm)) {
+ QzqsmMessage qzqsmMessage = await handleQzqsmInput(qzqsm);
+ // if message is already received, do nothing
+ if(qzqsmMessage == null) { return; }
+ // send EWS to others
+ for(int i=0; i<devices.length; i++) {
+ print(">>> RECEIVED PUSHED QZQSM TO MOBILE >>> mobile: ${devices[i].id}, qzqsm: ${qzqsmMessage.qzqsmString}");
+ MessageQueue.add(MessageType.TEXT, devices[i].id, "QZQSM>${qzqsmMessage.qzqsmString}");
+ await SqLiteDatabase.associateDeviceWithEWS(deviceId: devices[i].name, ewsBinPayload: qzqsmMessage.binPayload);
+ }
+ }
+ }
+
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() { appLifecycleState = state; });
print(">>> app state changes: ${state.toString()}");
@@ -813,5 +899,8 @@ class MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
super.dispose();
SqLiteDatabase.instance.close();
ChatMessageDBStream.dispose();
+ // Firebase Messaging dispose
+ firebaseMessagingForegroundSubscription?.cancel();
+ firebaseMessagingAppOpenedSubscription?.cancel();
}
}
diff --git a/pubspec.lock b/pubspec.lock
index 1eb7696..ecfdb5b 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -8,13 +8,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0"
boolean_selector:
dependency: transitive
description:
@@ -91,7 +84,7 @@ packages:
name: device_info
url: "https://pub.dartlang.org"
source: hosted
- version: "2.0.0"
+ version: "2.0.2"
device_info_platform_interface:
dependency: transitive
description:
@@ -120,6 +113,48 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.1"
+ firebase_core:
+ dependency: "direct main"
+ description:
+ name: firebase_core
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.7.0"
+ firebase_core_platform_interface:
+ dependency: transitive
+ description:
+ name: firebase_core_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.0.1"
+ firebase_core_web:
+ dependency: transitive
+ description:
+ name: firebase_core_web
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.2.1+3"
+ firebase_messaging:
+ dependency: "direct main"
+ description:
+ name: firebase_messaging
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "8.0.0-dev.15"
+ firebase_messaging_platform_interface:
+ dependency: transitive
+ description:
+ name: firebase_messaging_platform_interface
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.0-dev.10"
+ firebase_messaging_web:
+ dependency: transitive
+ description:
+ name: firebase_messaging_web
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.0-dev.6"
fixnum:
dependency: transitive
description:
@@ -436,6 +471,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.2+2"
+ quiver:
+ dependency: transitive
+ description:
+ name: quiver
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.1.5"
recase:
dependency: transitive
description:
@@ -450,6 +492,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.24.1"
+ service_worker:
+ dependency: transitive
+ description:
+ name: service_worker
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.2.4"
sky_engine:
dependency: transitive
description: flutter
@@ -610,5 +659,5 @@ packages:
source: hosted
version: "0.1.2"
sdks:
- dart: ">=2.12.0-259.9.beta <3.0.0"
+ dart: ">=2.12.0 <3.0.0"
flutter: ">=1.22.2"
diff --git a/pubspec.yaml b/pubspec.yaml
index 6ddcf2c..b6f474c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -29,7 +29,7 @@ dependencies:
nearby_connections: ^2.0.2
flutter_blue: ^0.7.2
flutter_local_notifications: ^3.0.1+5
image_picker: ^0.6.7+22
mime: ^0.9.7
video_player: ^1.0.1
@@ -51,6 +51,10 @@ dependencies:
# SQLite database
sqflite:
+ # Firebase Push Notification
+ firebase_core: "^0.7.0"
+ firebase_messaging: "^8.0.0-dev.15"
+
dev_dependencies:
flutter_test:
sdk: flutter
However, it looks like nearby_connections
knows when it find new endpoint, as I see this in the terminal.
D/nearby_connections(26285): startDiscovery
D/nearby_connections(26285): onEndpointFound
But for some reason, onEndpointFound
and onConnectionInitiated
never get called.
This my flutter doctor -v
[✓] Flutter (Channel dev, 1.27.0-8.0.pre, on Linux, locale en_US.UTF-8)
• Flutter version 1.27.0-8.0.pre at /home/apt/snap/flutter/common/flutter
• Framework revision b7d4806243 (4 months ago), 2021-02-19 09:22:45 -0800
• Engine revision 6993cb229b
• Dart version 2.13.0 (build 2.13.0-30.0.dev)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at /home/apt/Android/Sdk
• Platform android-30, build-tools 30.0.3
• Java binary at: /usr/local/android-studio/jre/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.8+0-b944-P17168821)
• All Android licenses accepted.
[✓] Chrome - develop for the web
• Chrome at google-chrome
[✓] Android Studio
• Android Studio at /usr/local/android-studio
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• android-studio-dir = /usr/local/android-studio
• Java version OpenJDK Runtime Environment (build 11.0.8+0-b944-P17168821)
[✓] Connected device (2 available)
• SM A015F (mobile) • R9JN20BEXCJ • android-arm • Android 10 (API 29)
• Chrome (web) • chrome • web-javascript • Google Chrome 91.0.4472.101
• No issues found!
I have no idea why nearby_connections
break as I didn't touch any code related to nearby_connections
, so it is possibly a bug in nearby_connections
. Thank you in advance for your response.