From 9a39917a2c208572c39f3fb1cf894d0ebad6a305 Mon Sep 17 00:00:00 2001 From: toki Date: Sat, 21 Mar 2026 15:06:19 +0900 Subject: [PATCH] Add Firebase push notification support and Android Mattermost integration - Android: MainActivity, AppLifecycleTracker, Firebase Messaging Service - Android: Notification handlers (dismiss, reply, receipt delivery) - Android: Custom push notification helper and database support - Android: Drawable resources for notification actions - Android: Mipmap resources with foreground/background/round icons - iOS: Push notification service support - Flutter: Push notification background and foreground services - Web/Windows: Generated plugin registrant updates - Config: Added google-services.json for Firebase --- android/app/build.gradle.kts | 30 +- android/app/google-services.json | 29 + android/app/src/main/AndroidManifest.xml | 31 +- .../mattermost/AppLifecycleTracker.kt | 35 ++ .../com/tokilabs/mattermost/MainActivity.kt | 102 ++++ .../tokilabs/mattermost/MainApplication.kt | 27 + .../MattermostFirebaseMessagingService.kt | 231 ++++++++ .../NotificationDismissService.java | 40 ++ .../NotificationReplyBroadcastReceiver.java | 152 +++++ .../tokilabs/mattermost/ReceiptDelivery.java | 65 +++ .../mattermost/helpers/BitmapCache.kt | 28 + .../helpers/CustomPushNotificationHelper.java | 525 ++++++++++++++++++ .../mattermost/helpers/DatabaseHelper.kt | 102 ++++ .../tokilabs/mattermost/helpers/Network.kt | 116 ++++ .../mattermost/helpers/NotificationHelper.kt | 93 ++++ .../helpers/PushNotificationDataHelper.kt | 145 +++++ .../mattermost/helpers/db/GlobalDatabase.kt | 38 ++ .../mattermost/helpers/db/GlobalEntities.kt | 53 ++ .../helpers/db/MattermostDatabase.kt | 50 ++ .../mattermost/helpers/db/ServerEntities.kt | 71 +++ .../com/nomadcode/nomadcode/MainActivity.kt | 5 - .../drawable-hdpi/ic_notif_action_reply.png | Bin 0 -> 413 bytes .../drawable-mdpi/ic_notif_action_reply.png | Bin 0 -> 348 bytes .../ic_notif_action_reply.png | Bin 0 -> 413 bytes .../ic_notif_action_reply.png | Bin 0 -> 348 bytes .../ic_notif_action_reply.png | Bin 0 -> 610 bytes .../ic_notif_action_reply.png | Bin 0 -> 833 bytes .../ic_notif_action_reply.png | Bin 0 -> 1261 bytes .../drawable-xhdpi/ic_notif_action_reply.png | Bin 0 -> 610 bytes .../drawable-xxhdpi/ic_notif_action_reply.png | Bin 0 -> 833 bytes .../ic_notif_action_reply.png | Bin 0 -> 1261 bytes .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 544 -> 2805 bytes .../mipmap-hdpi/ic_launcher_background.png | Bin 0 -> 2805 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 2805 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 2805 bytes .../main/res/mipmap-hdpi/ic_notification.png | Bin 0 -> 638 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 442 -> 1759 bytes .../mipmap-mdpi/ic_launcher_background.png | Bin 0 -> 1759 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 1759 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1759 bytes .../main/res/mipmap-mdpi/ic_notification.png | Bin 0 -> 481 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 721 -> 3784 bytes .../mipmap-xhdpi/ic_launcher_background.png | Bin 0 -> 3784 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 3784 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 3784 bytes .../main/res/mipmap-xhdpi/ic_notification.png | Bin 0 -> 847 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 1031 -> 5914 bytes .../mipmap-xxhdpi/ic_launcher_background.png | Bin 0 -> 5914 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 5914 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 5914 bytes .../res/mipmap-xxhdpi/ic_notification.png | Bin 0 -> 1313 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 1443 -> 7878 bytes .../mipmap-xxxhdpi/ic_launcher_background.png | Bin 0 -> 7878 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 7878 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 7878 bytes .../res/mipmap-xxxhdpi/ic_notification.png | Bin 0 -> 1791 bytes android/build.gradle.kts | 6 + lib/main.dart | 133 ++--- .../push_notification_background.dart | 12 + lib/services/push_notification_service.dart | 233 ++++++++ macos/Flutter/GeneratedPluginRegistrant.swift | 6 + pubspec.lock | 191 ++++++- pubspec.yaml | 7 + .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 67 files changed, 2469 insertions(+), 101 deletions(-) create mode 100644 android/app/google-services.json create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/AppLifecycleTracker.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/MainActivity.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/MainApplication.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/MattermostFirebaseMessagingService.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/NotificationDismissService.java create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/NotificationReplyBroadcastReceiver.java create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/ReceiptDelivery.java create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/BitmapCache.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/CustomPushNotificationHelper.java create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/DatabaseHelper.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/Network.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/NotificationHelper.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/PushNotificationDataHelper.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/db/GlobalDatabase.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/db/GlobalEntities.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/db/MattermostDatabase.kt create mode 100644 android/app/src/main/java/com/tokilabs/mattermost/helpers/db/ServerEntities.kt delete mode 100644 android/app/src/main/kotlin/com/nomadcode/nomadcode/MainActivity.kt create mode 100644 android/app/src/main/res/drawable-hdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-mdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-night-hdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-night-mdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-night-xhdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-night-xxhdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-night-xxxhdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-xhdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_notif_action_reply.png create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-hdpi/ic_notification.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-mdpi/ic_notification.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xhdpi/ic_notification.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xxhdpi/ic_notification.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 android/app/src/main/res/mipmap-xxxhdpi/ic_notification.png create mode 100644 lib/services/push_notification_background.dart create mode 100644 lib/services/push_notification_service.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 1ab7a8a..b9a85ca 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,12 +1,14 @@ plugins { id("com.android.application") id("kotlin-android") + id("kotlin-kapt") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") + id("com.google.gms.google-services") } android { - namespace = "com.nomadcode.nomadcode" + namespace = "com.tokilabs.mattermost" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +23,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.nomadcode.nomadcode" + applicationId = "com.tokilabs.mattermost" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion @@ -42,3 +44,27 @@ android { flutter { source = "../.." } + +dependencies { + // Firebase BOM (버전 통합 관리) + implementation(platform("com.google.firebase:firebase-bom:33.7.0")) + implementation("com.google.firebase:firebase-messaging") + + // JWT 서명 검증 (mattermost와 동일 버전) + implementation("io.jsonwebtoken:jjwt-api:0.12.5") + runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.5") + runtimeOnly("io.jsonwebtoken:jjwt-orgjson:0.12.5") { + exclude(group = "org.json", module = "json") + } + + // HTTP 클라이언트 + implementation("com.squareup.okhttp3:okhttp:4.12.0") + + // Kotlin Coroutines + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") + + // Room DB (로컬 캐시용) + implementation("androidx.room:room-runtime:2.6.1") + implementation("androidx.room:room-ktx:2.6.1") + kapt("androidx.room:room-compiler:2.6.1") +} diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..24bda37 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "1047648748539", + "project_id": "mattermost-6ac08", + "storage_bucket": "mattermost-6ac08.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:1047648748539:android:818bf70bfbb3f9d070415e", + "android_client_info": { + "package_name": "com.tokilabs.mattermost" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyAW6j_oPl9MVcm93qS3JgaEPD5ywp-TzZ0" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 99c2c49..4350882 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,14 @@ + + + + + + android:name=".MainApplication" + android:icon="@mipmap/ic_launcher" + android:roundIcon="@mipmap/ic_launcher_round"> + + + + + + + + + + + + +