From b52d3e4281a9da7e0ae9f0d41d5f14c4f18b5a36 Mon Sep 17 00:00:00 2001 From: "aria.ark" Date: Fri, 17 Apr 2026 16:35:07 +0900 Subject: [PATCH] add notification permission status --- README.md | 26 +++++++++++ src/android/BluememeUtils.java | 48 ++++++++++++++++++++ src/ios/CDVBluememeUtils.m | 80 ++++++++++++++++++++++++++++++++++ www/BluememeUtils.js | 4 ++ 4 files changed, 158 insertions(+) diff --git a/README.md b/README.md index 5e52fee..93d9783 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ WiFi options: ```js BluememeUtils.requestPushPermission(success, error); +BluememeUtils.getPushPermissionStatus(success, error); BluememeUtils.getFirebaseToken(function (result) { console.log(result.token); }, error); @@ -134,6 +135,31 @@ BluememeUtils.getInitialNotification(success, error); BluememeUtils.stopNotificationListener(success, error); ``` +`getPushPermissionStatus` 只读取当前系统通知状态,不弹授权框。可用于填充后端 `NotificationsEnabled`。 + +返回示例: + +```json +{ + "type": "notification", + "platform": "Android", + "enabled": true, + "granted": true, + "runtimePermissionGranted": true, + "appNotificationsEnabled": true, + "authorizationStatus": "authorized", + "missing": [] +} +``` + +推荐注册 token 前调用: + +```js +BluememeUtils.getPushPermissionStatus(function (status) { + var notificationsEnabled = status.enabled === true; +}, error); +``` + 事件也会派发到 `window`: - `bluememeutils.token` diff --git a/src/android/BluememeUtils.java b/src/android/BluememeUtils.java index aeb917d..11be177 100644 --- a/src/android/BluememeUtils.java +++ b/src/android/BluememeUtils.java @@ -4,6 +4,7 @@ import android.Manifest; import android.annotation.TargetApi; import android.app.Activity; import android.app.KeyguardManager; +import android.app.NotificationManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -115,6 +116,10 @@ public class BluememeUtils extends CordovaPlugin { requestPushPermission(callbackContext); return true; } + if ("getPushPermissionStatus".equals(action)) { + getPushPermissionStatus(callbackContext); + return true; + } if ("getFirebaseToken".equals(action)) { getFirebaseToken(callbackContext); return true; @@ -387,6 +392,14 @@ public class BluememeUtils extends CordovaPlugin { PermissionHelper.requestPermission(this, REQ_NOTIFICATION_PERMISSION, Manifest.permission.POST_NOTIFICATIONS); } + private void getPushPermissionStatus(CallbackContext callbackContext) { + try { + callbackContext.success(pushPermissionStatus()); + } catch (JSONException ex) { + sendError(callbackContext, "JSON_ERROR", ex.getMessage()); + } + } + private void getFirebaseToken(final CallbackContext callbackContext) { if (!ensureFirebaseInitialized(true)) { sendError(callbackContext, "FIREBASE_NOT_CONFIGURED", "Firebase is not configured. Add Google services files or pass Firebase plugin preferences."); @@ -1109,6 +1122,41 @@ public class BluememeUtils extends CordovaPlugin { return (ConnectivityManager) cordova.getActivity().getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); } + private JSONObject pushPermissionStatus() throws JSONException { + Context context = cordova.getActivity().getApplicationContext(); + boolean runtimeGranted = Build.VERSION.SDK_INT < 33 + || PermissionHelper.hasPermission(this, Manifest.permission.POST_NOTIFICATIONS); + boolean appNotificationsEnabled = areAppNotificationsEnabled(context); + boolean enabled = runtimeGranted && appNotificationsEnabled; + + JSONArray missing = new JSONArray(); + if (!runtimeGranted && Build.VERSION.SDK_INT >= 33) { + missing.put(Manifest.permission.POST_NOTIFICATIONS); + } + if (!appNotificationsEnabled) { + missing.put("app_notifications_disabled"); + } + + JSONObject result = new JSONObject(); + result.put("type", "notification"); + result.put("platform", "Android"); + result.put("enabled", enabled); + result.put("granted", enabled); + result.put("runtimePermissionGranted", runtimeGranted); + result.put("appNotificationsEnabled", appNotificationsEnabled); + result.put("authorizationStatus", enabled ? "authorized" : "denied"); + result.put("missing", missing); + return result; + } + + private boolean areAppNotificationsEnabled(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + return notificationManager == null || notificationManager.areNotificationsEnabled(); + } + return true; + } + private static JSONObject permissionResult(String type, boolean granted, JSONArray missing) throws JSONException { JSONObject result = new JSONObject(); result.put("type", type); diff --git a/src/ios/CDVBluememeUtils.m b/src/ios/CDVBluememeUtils.m index 1915845..8156d9c 100644 --- a/src/ios/CDVBluememeUtils.m +++ b/src/ios/CDVBluememeUtils.m @@ -167,6 +167,31 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k } } +- (void)getPushPermissionStatus:(CDVInvokedUrlCommand *)command +{ + if (@available(iOS 10.0, *)) { + [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings *settings) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self sendSuccessForCommand:command dictionary:[self dictionaryFromNotificationSettings:settings]]; + }); + }]; + } else { + UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings]; + BOOL enabled = settings.types != UIUserNotificationTypeNone; + [self sendSuccessForCommand:command dictionary:@{ + @"type": @"notification", + @"platform": @"iOS", + @"enabled": @(enabled), + @"granted": @(enabled), + @"authorizationStatus": enabled ? @"authorized" : @"denied", + @"alertEnabled": @((settings.types & UIUserNotificationTypeAlert) != 0), + @"soundEnabled": @((settings.types & UIUserNotificationTypeSound) != 0), + @"badgeEnabled": @((settings.types & UIUserNotificationTypeBadge) != 0), + @"missing": enabled ? @[] : @[@"notification"] + }]; + } +} + - (void)getFirebaseToken:(CDVInvokedUrlCommand *)command { NSError *firebaseError = nil; @@ -337,6 +362,61 @@ static NSString * const BluememeDeviceKeyDefaultsKey = @"bluememe_utils_device_k return @"touch"; } +- (NSDictionary *)dictionaryFromNotificationSettings:(UNNotificationSettings *)settings API_AVAILABLE(ios(10.0)) +{ + NSString *status = [self authorizationStatusName:settings.authorizationStatus]; + BOOL enabled = settings.authorizationStatus == UNAuthorizationStatusAuthorized; + if (@available(iOS 12.0, *)) { + enabled = enabled || settings.authorizationStatus == UNAuthorizationStatusProvisional; + } + if (@available(iOS 14.0, *)) { + enabled = enabled || settings.authorizationStatus == UNAuthorizationStatusEphemeral; + } + + BOOL alertEnabled = settings.alertSetting == UNNotificationSettingEnabled; + BOOL soundEnabled = settings.soundSetting == UNNotificationSettingEnabled; + BOOL badgeEnabled = settings.badgeSetting == UNNotificationSettingEnabled; + NSArray *missing = enabled ? @[] : @[@"notification"]; + + return @{ + @"type": @"notification", + @"platform": @"iOS", + @"enabled": @(enabled), + @"granted": @(enabled), + @"authorizationStatus": status, + @"alertEnabled": @(alertEnabled), + @"soundEnabled": @(soundEnabled), + @"badgeEnabled": @(badgeEnabled), + @"missing": missing + }; +} + +- (NSString *)authorizationStatusName:(UNAuthorizationStatus)status API_AVAILABLE(ios(10.0)) +{ + switch (status) { + case UNAuthorizationStatusNotDetermined: + return @"notDetermined"; + case UNAuthorizationStatusDenied: + return @"denied"; + case UNAuthorizationStatusAuthorized: + return @"authorized"; + default: + break; + } + + if (@available(iOS 12.0, *)) { + if (status == UNAuthorizationStatusProvisional) { + return @"provisional"; + } + } + if (@available(iOS 14.0, *)) { + if (status == UNAuthorizationStatusEphemeral) { + return @"ephemeral"; + } + } + return @"unknown"; +} + - (BOOL)ensureFirebaseConfigured:(NSError **)error { if ([FIRApp defaultApp] != nil) { diff --git a/www/BluememeUtils.js b/www/BluememeUtils.js index 5472296..e33a59c 100644 --- a/www/BluememeUtils.js +++ b/www/BluememeUtils.js @@ -81,6 +81,10 @@ var api = { call('requestPushPermission', [], success, error); }, + getPushPermissionStatus: function (success, error) { + call('getPushPermissionStatus', [], success, error); + }, + getFirebaseToken: function (success, error) { call('getFirebaseToken', [], success, error); },