Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '1.21'
cache-dependency-path: notification-backend/go.sum

- name: Build app-backend
run: |
Expand Down Expand Up @@ -76,6 +77,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '1.21'
cache-dependency-path: notification-backend/go.sum

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
Expand Down
12 changes: 6 additions & 6 deletions demo-app/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# FCM Android Demo App
# Remote Notify Demo App

Android client that registers FCM tokens using hybrid encryption and receives push notifications.
Android client that registers notification tokens using hybrid encryption and receives push notifications.

## Setup

### 1. Firebase Configuration

1. Go to [Firebase Console](https://console.firebase.google.com/)
2. Create or select a project
3. Add Android app with package name: `org.nella.fcmapp` (demo app)
3. Add Android app with package name: `org.nella.rn.demo` (demo app)
4. Download `google-services.json` and replace the placeholder in `app/` directory

### 2. Public Key
Expand All @@ -20,11 +20,11 @@ Ensure `app/src/main/assets/public_key.pem` contains the RSA public key (see mai
1. Open project in Android Studio
2. Sync project to download dependencies
3. Run on device or emulator
4. Tap "Register Device Token" to encrypt and send FCM token
4. Tap "Register Device Token" to encrypt and send notification token

## Features

- Single-button FCM token registration
- Single-button notification token registration
- Client-side hybrid encryption (AES-256-GCM + RSA-4096)
- Automatic certificate bypass for development servers
- Push notification handling
Expand All @@ -45,7 +45,7 @@ Sends encrypted token to `https://10.0.2.2:8443/register` (emulator) with payloa

## Dependencies

- Firebase Cloud Messaging: `com.google.firebase:firebase-messaging-ktx:23.3.1`
- Firebase Cloud Messaging: `com.google.firebase:firebase-messaging-ktx:24.1.2`
- OkHttp: `com.squareup.okhttp3:okhttp:4.12.0`
- AndroidX UI components

Expand Down
4 changes: 2 additions & 2 deletions demo-app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ plugins {
}

android {
namespace 'org.nella.fcmapp'
namespace 'org.nella.rn.demo'
compileSdk 36

defaultConfig {
applicationId "org.nella.fcmapp"
applicationId "org.nella.rn.demo"
minSdk 21
targetSdk 34
versionCode 1
Expand Down
8 changes: 4 additions & 4 deletions demo-app/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FCMApp"
android:theme="@style/Theme.RemoteNotifyDemoApp"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.FCMApp">
android:theme="@style/Theme.RemoteNotifyDemoApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand All @@ -30,11 +30,11 @@
android:name=".SettingsActivity"
android:exported="false"
android:parentActivityName=".MainActivity"
android:theme="@style/Theme.FCMApp" />
android:theme="@style/Theme.RemoteNotifyDemoApp" />

<!-- Firebase Messaging Service -->
<service
android:name=".FCMService"
android:name=".RnDemoService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.nella.fcmapp
package org.nella.rn.demo

import android.content.Intent
import android.os.Bundle
Expand Down Expand Up @@ -80,20 +80,20 @@ class MainActivity : AppCompatActivity() {
}

private fun registerDeviceToken() {
updateStatus("Getting FCM token...")
updateStatus("Getting notification token...")
registerButton.isEnabled = false

FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w(TAG, "Fetching FCM registration token failed", task.exception)
updateStatus("Failed to get FCM token: ${task.exception?.message}")
Log.w(TAG, "Fetching Firebase registration token failed", task.exception)
updateStatus("Failed to get notification token: ${task.exception?.message}")
registerButton.isEnabled = true
return@addOnCompleteListener
}

// Get new FCM registration token
// Get new Firebase registration token
val token = task.result
Log.d(TAG, "FCM Registration Token: $token")
Log.d(TAG, "Firebase Registration Token: $token")

// Send token to server
sendTokenToServer(token)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.nella.fcmapp
package org.nella.rn.demo

import android.app.NotificationChannel
import android.app.NotificationManager
Expand All @@ -11,11 +11,11 @@ import androidx.core.app.NotificationCompat
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class FCMService : FirebaseMessagingService() {
class RnDemoService : FirebaseMessagingService() {

companion object {
private const val TAG = "FCMService"
private const val CHANNEL_ID = "fcm_default_channel"
private const val TAG = "RnDemoService"
private const val CHANNEL_ID = "rn_demo_channel"
}

override fun onMessageReceived(remoteMessage: RemoteMessage) {
Expand All @@ -26,7 +26,7 @@ class FCMService : FirebaseMessagingService() {
// Check if message contains a notification payload
remoteMessage.notification?.let {
Log.d(TAG, "Message Notification Body: ${it.body}")
sendNotification(it.title ?: "FCM Message", it.body ?: "")
sendNotification(it.title ?: "Notification", it.body ?: "")
}

// Check if message contains a data payload
Expand All @@ -40,7 +40,7 @@ class FCMService : FirebaseMessagingService() {

// If you want to send messages to this application instance or
// manage this app's subscriptions on the server side, send the
// FCM registration token to your app server.
// Firebase registration token to your app server.
sendRegistrationToServer(token)
}

Expand Down Expand Up @@ -68,7 +68,7 @@ class FCMService : FirebaseMessagingService() {
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId,
"FCM Channel",
"RN Demo Channel",
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.nella.fcmapp
package org.nella.rn.demo

import android.content.Context
import android.content.SharedPreferences
Expand All @@ -17,9 +17,9 @@ class SettingsActivity : AppCompatActivity() {
private lateinit var prefs: SharedPreferences

companion object {
const val PREFS_NAME = "FCMAppSettings"
const val PREFS_NAME = "RnDemoSettings"
const val PREF_BACKEND_URL = "backend_url"
const val DEFAULT_BACKEND_URL = "https://r-notify.nella.org"
const val DEFAULT_BACKEND_URL = "https://demo.rn.nella.org"

fun getBackendUrl(context: Context): String {
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
Expand Down
6 changes: 3 additions & 3 deletions demo-app/app/src/main/res/layout/activity_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
android:id="@+id/urlEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="https://r-notify.nella.org"
android:hint="https://demo.rn.nella.org"
android:inputType="textUri"
android:layout_marginBottom="16dp"
android:padding="12dp"
Expand All @@ -33,7 +33,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Examples:\n• https://r-notify.nella.org\n• https://your-domain.com\n• https://10.0.2.2:8443 (Android emulator)"
android:text="Examples:\n• https://demo.rn.nella.org\n• https://your-domain.com\n• https://10.0.2.2:8443 (Android emulator)"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"
android:layout_marginBottom="24dp" />
Expand Down Expand Up @@ -66,7 +66,7 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="\n🔒 Security Note:\nAll communication uses encrypted FCM tokens. The backend URL should use HTTPS for security."
android:text="\n🔒 Security Note:\nAll communication uses encrypted notification tokens. The backend URL should use HTTPS for security."
android:textSize="12sp"
android:textColor="@android:color/darker_gray"
android:layout_marginTop="24dp"
Expand Down
2 changes: 1 addition & 1 deletion demo-app/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">FCM App</string>
<string name="app_name">Remote Notify Demo App</string>
</resources>
2 changes: 1 addition & 1 deletion demo-app/app/src/main/res/values/themes.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.FCMApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.RemoteNotifyDemoApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
Expand Down
Loading