Android: Fix push notifications and permission handling
parent
8f6ed7c8a0
commit
48bed7bf3e
|
|
@ -26,6 +26,8 @@ import java.util.Random;
|
|||
public class NymeaAppNotificationService extends FirebaseMessagingService {
|
||||
|
||||
private static final String TAG = "nymea-app: NymeaAppNotificationService";
|
||||
private static final String DEFAULT_CHANNEL_ID = "default-channel";
|
||||
private static final String DEFAULT_CHANNEL_NAME = "nymea notifications";
|
||||
|
||||
private int hashId(String id) {
|
||||
int hash = 7;
|
||||
|
|
@ -59,13 +61,28 @@ public class NymeaAppNotificationService extends FirebaseMessagingService {
|
|||
|
||||
super.onMessageReceived(remoteMessage);
|
||||
|
||||
RemoteMessage.Notification notification = remoteMessage.getNotification();
|
||||
String title = notification != null ? notification.getTitle() : null;
|
||||
String body = notification != null ? notification.getBody() : null;
|
||||
if (title == null) {
|
||||
title = remoteMessage.getData().get("title");
|
||||
}
|
||||
if (body == null) {
|
||||
body = remoteMessage.getData().get("body");
|
||||
}
|
||||
|
||||
Log.d(TAG, "Notification from: " + remoteMessage.getFrom());
|
||||
Log.d(TAG, "Notification title: " + remoteMessage.getNotification().getTitle());
|
||||
Log.d(TAG, "Notification body: " + remoteMessage.getNotification().getBody());
|
||||
Log.d(TAG, "Notification title: " + title);
|
||||
Log.d(TAG, "Notification body: " + body);
|
||||
Log.d(TAG, "Notification priority: " + remoteMessage.getPriority());
|
||||
Log.d(TAG, "Notification data: " + remoteMessage.getData());
|
||||
Log.d(TAG, "Notification message ID: " + remoteMessage.getMessageId());
|
||||
|
||||
if (title == null && body == null && remoteMessage.getData().isEmpty()) {
|
||||
Log.w(TAG, "No notification payload received, skipping notification creation.");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, NymeaAppActivity.class);
|
||||
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent.setAction(Intent.ACTION_SEND);
|
||||
|
|
@ -79,21 +96,36 @@ public class NymeaAppNotificationService extends FirebaseMessagingService {
|
|||
// Because of this, we need to dynamically fetch the resource from the package resources
|
||||
int resId = getResources().getIdentifier("notificationicon", "drawable", getPackageName());
|
||||
Log.d(TAG, "Notification icon resource: " + resId + " Package:" + getPackageName());
|
||||
if (resId == 0) {
|
||||
resId = getApplicationInfo().icon;
|
||||
Log.w(TAG, "Notification icon resource missing, using application icon: " + resId);
|
||||
}
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (notificationManager == null) {
|
||||
Log.w(TAG, "NotificationManager not available, cannot display notification.");
|
||||
return;
|
||||
}
|
||||
|
||||
String channelId = resolveStringResource("notification_channel_id", DEFAULT_CHANNEL_ID);
|
||||
String channelName = resolveStringResource("notification_channel_name", DEFAULT_CHANNEL_NAME);
|
||||
|
||||
// Since android Oreo notification channel is needed.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel("default-channel", "Default notification channel for nymea-app", NotificationManager.IMPORTANCE_HIGH);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
NotificationChannel existingChannel = notificationManager.getNotificationChannel(channelId);
|
||||
if (existingChannel == null) {
|
||||
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
|
||||
.setContentTitle(remoteMessage.getNotification().getTitle())
|
||||
.setContentText(remoteMessage.getNotification().getBody())
|
||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
|
||||
.setContentTitle(title)
|
||||
.setContentText(body)
|
||||
.setSmallIcon(resId)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
.setContentIntent(pendingIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||
|
||||
boolean sound = remoteMessage.getData().get("sound") == null || remoteMessage.getData().get("sound").equals("true");
|
||||
Log.d(TAG, "Notification sound enabled: " + (sound ? "true" : "false"));
|
||||
|
|
@ -114,4 +146,19 @@ public class NymeaAppNotificationService extends FirebaseMessagingService {
|
|||
Log.d(TAG, "Posting Notification: " + remoteMessage.getMessageId());
|
||||
notificationManager.notify(0, notificationBuilder.build());
|
||||
}
|
||||
|
||||
private String resolveStringResource(String resourceName, String fallback) {
|
||||
int resId = getResources().getIdentifier(resourceName, "string", getPackageName());
|
||||
if (resId != 0) {
|
||||
try {
|
||||
String resolved = getString(resId);
|
||||
if (resolved != null && !resolved.isEmpty()) {
|
||||
return resolved;
|
||||
}
|
||||
} catch (Resources.NotFoundException e) {
|
||||
Log.w(TAG, "String resource not found for " + resourceName + ", using fallback");
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include <QApplication>
|
||||
#include <QPermission>
|
||||
#include <QOperatingSystemVersion>
|
||||
#include <QFuture>
|
||||
#include <QtCore/private/qandroidextras_p.h>
|
||||
|
||||
#include "logging.h"
|
||||
NYMEA_LOGGING_CATEGORY(dcPlatformPermissions, "PlatformPermissions")
|
||||
|
|
@ -108,8 +110,30 @@ PlatformPermissions::PermissionStatus PlatformPermissionsAndroid::checkPermissio
|
|||
});
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PlatformPermissions::PermissionNotifications: {
|
||||
if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::Android, 13)) {
|
||||
status = PermissionStatusGranted;
|
||||
break;
|
||||
}
|
||||
|
||||
auto futureResult = QtAndroidPrivate::checkPermission("android.permission.POST_NOTIFICATIONS");
|
||||
QtAndroidPrivate::PermissionResult result = futureResult.result();
|
||||
switch (result) {
|
||||
case QtAndroidPrivate::Authorized:
|
||||
qCDebug(dcPlatformPermissions()) << "Notifications permission already granted.";
|
||||
status = PermissionStatusGranted;
|
||||
break;
|
||||
case QtAndroidPrivate::Denied:
|
||||
qCDebug(dcPlatformPermissions()) << "Notifications permission denied.";
|
||||
status = PermissionStatusDenied;
|
||||
break;
|
||||
case QtAndroidPrivate::Undetermined:
|
||||
qCDebug(dcPlatformPermissions()) << "Notifications permission not yet requested. Requesting...";
|
||||
status = PermissionStatusNotDetermined;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -154,8 +178,7 @@ void PlatformPermissionsAndroid::requestPermission(PlatformPermissions::Permissi
|
|||
}
|
||||
case PlatformPermissions::PermissionLocalNetwork: {
|
||||
QFuture permission_request = QtAndroidPrivate::requestPermission("android.permission.POST_NOTIFICATIONS");
|
||||
switch(permission_request.result())
|
||||
{
|
||||
switch(permission_request.result()) {
|
||||
case QtAndroidPrivate::Undetermined:
|
||||
qWarning() << "Permission for posting notifications undetermined!";
|
||||
break;
|
||||
|
|
@ -169,6 +192,31 @@ void PlatformPermissionsAndroid::requestPermission(PlatformPermissions::Permissi
|
|||
|
||||
break;
|
||||
}
|
||||
case PlatformPermissions::PermissionNotifications: {
|
||||
if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::Android, 13)) {
|
||||
qCDebug(dcPlatformPermissions()) << "Notifications permission implicitly granted on Android < 13.";
|
||||
emit s_instance->notificationsPermissionChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
QFuture permission_request = QtAndroidPrivate::requestPermission("android.permission.POST_NOTIFICATIONS");
|
||||
auto result = permission_request.result();
|
||||
switch(result) {
|
||||
case QtAndroidPrivate::Undetermined:
|
||||
qWarning() << "Permission for posting notifications undetermined!";
|
||||
s_instance->m_requestedButDeniedPermissions.append(platformPermission);
|
||||
break;
|
||||
case QtAndroidPrivate::Authorized:
|
||||
qDebug() << "Permission for posting notifications authorized";
|
||||
break;
|
||||
case QtAndroidPrivate::Denied:
|
||||
qWarning() << "Permission for posting notifications denied!";
|
||||
s_instance->m_requestedButDeniedPermissions.append(platformPermission);
|
||||
break;
|
||||
}
|
||||
emit s_instance->notificationsPermissionChanged();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCWarning(dcPlatformPermissions()) << "Requested platform permission" << platformPermission << "but is not implemented yet.";
|
||||
break;
|
||||
|
|
@ -276,4 +324,3 @@ void PlatformPermissionsAndroid::requestPermission(PlatformPermissions::Permissi
|
|||
// emit s_instance->backgroundLocationPermissionChanged();
|
||||
// emit s_instance->notificationsPermissionChanged();
|
||||
// }
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,14 @@
|
|||
PlatformPermissions *PlatformPermissions::instance()
|
||||
{
|
||||
#ifdef Q_OS_ANDROID
|
||||
return new PlatformPermissionsAndroid();
|
||||
static PlatformPermissionsAndroid instance;
|
||||
return &instance;
|
||||
#elif defined Q_OS_IOS
|
||||
return new PlatformPermissionsIOS();
|
||||
static PlatformPermissionsIOS instance;
|
||||
return &instance;
|
||||
#else
|
||||
return new PlatformPermissions();
|
||||
static PlatformPermissions instance;
|
||||
return &instance;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -85,4 +88,3 @@ PlatformPermissions::PermissionStatus PlatformPermissions::checkPermission(Permi
|
|||
Q_UNUSED(permission)
|
||||
return PermissionStatusGranted;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "pushnotifications.h"
|
||||
#include "platformhelper.h"
|
||||
#include "platformintegration/platformpermissions.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
|
@ -86,6 +87,9 @@ void PushNotifications::setEnabled(bool enabled)
|
|||
void PushNotifications::registerForPush()
|
||||
{
|
||||
#if defined Q_OS_ANDROID && defined WITH_FIREBASE
|
||||
// Ensure we have runtime permission to post notifications (Android 13+).
|
||||
PlatformPermissions::instance()->requestPermission(PlatformPermissions::PermissionNotifications);
|
||||
|
||||
qDebug() << "Checking for play services";
|
||||
jboolean playServicesAvailable = QJniObject::callStaticMethod<jboolean>("io.guh.nymeaapp.NymeaAppNotificationService", "checkPlayServices", "()Z");
|
||||
if (playServicesAvailable) {
|
||||
|
|
@ -102,8 +106,9 @@ void PushNotifications::registerForPush()
|
|||
firebase::messaging::Initialize(*m_firebaseApp, this);
|
||||
firebase::messaging::SetListener(this);
|
||||
|
||||
// (Optional, Android 13+): Benachrichtigungs-Erlaubnis anfragen
|
||||
// firebase::messaging::RequestPermission();
|
||||
// Android 13+ requires the POST_NOTIFICATIONS runtime permission. Request it here so
|
||||
// Firebase is allowed to show notifications when the app is backgrounded or closed.
|
||||
firebase::messaging::RequestPermission();
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
|
||||
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notificationicon"/>
|
||||
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
|
||||
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/notification_channel_id"/>
|
||||
|
||||
<service android:name="com.google.firebase.messaging.MessageForwardingService" android:exported="false">
|
||||
</service>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">nymea:app</string>
|
||||
<string name="notification_channel_id">default-channel</string>
|
||||
<string name="notification_channel_name">nymea notifications</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue