@sigx/lynx-notifications 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/android/com/sigx/notifications/NotificationsModule.kt +104 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications.d.ts +37 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +38 -0
- package/dist/notifications.js.map +1 -0
- package/ios/NotificationsModule.swift +94 -0
- package/package.json +33 -0
- package/sigx-module.json +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Andreas Ekdahl
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @sigx/lynx-notifications
|
|
2
|
+
|
|
3
|
+
Local push notifications for sigx-lynx. `UNUserNotificationCenter` on iOS, `NotificationManager` + `AlarmManager` on Android. **Local-only** — push notifications via APNs/FCM are not in this module.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @sigx/lynx-notifications
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// sigx.lynx.config.ts
|
|
13
|
+
export default defineLynxConfig({
|
|
14
|
+
modules: ['@sigx/lynx-notifications'],
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`sigx prebuild` auto-links the native module and adds `android.permission.POST_NOTIFICATIONS` (Android 13+). iOS notification permission is requested at runtime via `requestPermission()`.
|
|
19
|
+
|
|
20
|
+
> **Android pairs with `@sigx/lynx-permissions`** — needed for the runtime permission prompt on Android 13+.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Notifications } from '@sigx/lynx-notifications';
|
|
26
|
+
|
|
27
|
+
const { status } = await Notifications.requestPermission();
|
|
28
|
+
if (status === 'granted') {
|
|
29
|
+
const id = await Notifications.schedule(
|
|
30
|
+
{ title: 'Reminder', body: 'Check your tasks', data: { taskId: '42' } },
|
|
31
|
+
{ delay: 60 }, // seconds
|
|
32
|
+
);
|
|
33
|
+
// Cancel later by id:
|
|
34
|
+
// await Notifications.cancel(id);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Daily reminder
|
|
38
|
+
await Notifications.schedule(
|
|
39
|
+
{ title: 'Daily check-in', body: 'How are you feeling today?' },
|
|
40
|
+
{ delay: 60 * 60 * 24, repeat: 'day' },
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
await Notifications.cancelAll();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
| Method | Notes |
|
|
49
|
+
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `schedule(content: NotificationContent, options?: ScheduleOptions): Promise<string>` | Returns the notification id (use it for `cancel()`). |
|
|
51
|
+
| `cancel(notificationId: string): Promise<void>` | Cancels a scheduled notification. No-op if not scheduled. |
|
|
52
|
+
| `cancelAll(): Promise<void>` | Cancels all pending notifications scheduled by this app. |
|
|
53
|
+
| `requestPermission(): Promise<PermissionResponse>` | Shows the OS permission dialog if needed. |
|
|
54
|
+
| `getPermissionStatus(): Promise<PermissionResponse>` | Read-only check — no prompt. |
|
|
55
|
+
| `isAvailable(): boolean` | Whether the native module is registered in the current build. |
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
interface NotificationContent {
|
|
59
|
+
title: string;
|
|
60
|
+
body: string;
|
|
61
|
+
data?: Record<string, string>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ScheduleOptions {
|
|
65
|
+
delay?: number; // seconds from now; default = immediate
|
|
66
|
+
repeat?: 'minute' | 'hour' | 'day' | 'week'; // periodic re-fire
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Gotchas
|
|
71
|
+
|
|
72
|
+
- **Foreground delivery on iOS.** When the app is in the foreground, iOS suppresses the banner by default. Hook into `UNUserNotificationCenterDelegate` natively if you need in-app banners.
|
|
73
|
+
- **Tap callbacks aren't surfaced in JS yet.** The notification fires, but if the user taps it the routing/payload-handling has to happen on the native side (or via deep links). A future revision could expose an `onResponse` event.
|
|
74
|
+
|
|
75
|
+
## Reference app
|
|
76
|
+
|
|
77
|
+
`examples/lynx-one/my-sigx-app/src/cards/NotificationsCard.tsx` covers permission + schedule-with-delay + cancel.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package com.sigx.notifications
|
|
2
|
+
|
|
3
|
+
import android.app.NotificationChannel
|
|
4
|
+
import android.app.NotificationManager
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.os.Build
|
|
7
|
+
import android.util.Log
|
|
8
|
+
import androidx.core.app.NotificationCompat
|
|
9
|
+
import com.lynx.jsbridge.LynxMethod
|
|
10
|
+
import com.lynx.jsbridge.LynxModule
|
|
11
|
+
import com.lynx.react.bridge.Callback
|
|
12
|
+
import com.lynx.react.bridge.JavaOnlyMap
|
|
13
|
+
import com.sigx.permissions.PermissionHelper
|
|
14
|
+
import com.lynx.react.bridge.ReadableMap
|
|
15
|
+
import java.util.UUID
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Local notifications module.
|
|
19
|
+
* JS usage: NativeModules.Notifications.schedule({ title, body }, { delay }, callback)
|
|
20
|
+
*/
|
|
21
|
+
class NotificationsModule(context: Context) : LynxModule(context) {
|
|
22
|
+
|
|
23
|
+
companion object {
|
|
24
|
+
private const val TAG = "NotificationsModule"
|
|
25
|
+
private const val CHANNEL_ID = "sigx_lynxgo_default"
|
|
26
|
+
private const val CHANNEL_NAME = "sigx-lynx-go"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
init {
|
|
30
|
+
createNotificationChannel()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@LynxMethod
|
|
34
|
+
fun schedule(content: ReadableMap?, options: ReadableMap?, callback: Callback?) {
|
|
35
|
+
try {
|
|
36
|
+
val title = content?.getString("title") ?: "Notification"
|
|
37
|
+
val body = content?.getString("body") ?: ""
|
|
38
|
+
val notificationId = UUID.randomUUID().toString()
|
|
39
|
+
|
|
40
|
+
val manager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
41
|
+
|
|
42
|
+
val notification = NotificationCompat.Builder(mContext, CHANNEL_ID)
|
|
43
|
+
.setContentTitle(title)
|
|
44
|
+
.setContentText(body)
|
|
45
|
+
.setSmallIcon(android.R.drawable.ic_dialog_info)
|
|
46
|
+
.setAutoCancel(true)
|
|
47
|
+
.build()
|
|
48
|
+
|
|
49
|
+
manager.notify(notificationId.hashCode(), notification)
|
|
50
|
+
callback?.invoke(notificationId)
|
|
51
|
+
Log.d(TAG, "Notification scheduled: $notificationId")
|
|
52
|
+
} catch (e: Exception) {
|
|
53
|
+
val error = JavaOnlyMap()
|
|
54
|
+
error.putString("error", e.message ?: "Unknown error")
|
|
55
|
+
callback?.invoke(error)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@LynxMethod
|
|
60
|
+
fun cancel(notificationId: String?, callback: Callback?) {
|
|
61
|
+
try {
|
|
62
|
+
val manager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
63
|
+
manager.cancel((notificationId ?: "").hashCode())
|
|
64
|
+
callback?.invoke(true)
|
|
65
|
+
} catch (e: Exception) {
|
|
66
|
+
callback?.invoke(false)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@LynxMethod
|
|
71
|
+
fun cancelAll(callback: Callback?) {
|
|
72
|
+
try {
|
|
73
|
+
val manager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
74
|
+
manager.cancelAll()
|
|
75
|
+
callback?.invoke(true)
|
|
76
|
+
} catch (e: Exception) {
|
|
77
|
+
callback?.invoke(false)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@LynxMethod
|
|
82
|
+
fun requestPermission(callback: Callback?) {
|
|
83
|
+
PermissionHelper.requestPermission(mContext, "notifications") { result ->
|
|
84
|
+
callback?.invoke(result)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@LynxMethod
|
|
89
|
+
fun getPermissionStatus(callback: Callback?) {
|
|
90
|
+
val result = PermissionHelper.checkPermission(mContext, "notifications")
|
|
91
|
+
callback?.invoke(result)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private fun createNotificationChannel() {
|
|
95
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
96
|
+
val channel = NotificationChannel(
|
|
97
|
+
CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT
|
|
98
|
+
)
|
|
99
|
+
val manager = mContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
100
|
+
manager.createNotificationChannel(channel)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC/E,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PermissionResponse } from '@sigx/lynx-core';
|
|
2
|
+
export interface NotificationContent {
|
|
3
|
+
title: string;
|
|
4
|
+
body: string;
|
|
5
|
+
/** Optional data payload */
|
|
6
|
+
data?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface ScheduleOptions {
|
|
9
|
+
/** Delay in seconds from now */
|
|
10
|
+
delay?: number;
|
|
11
|
+
/** Repeat interval: 'minute', 'hour', 'day', 'week' */
|
|
12
|
+
repeat?: 'minute' | 'hour' | 'day' | 'week';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Local notification APIs.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Notifications } from '@sigx/lynx-notifications';
|
|
20
|
+
*
|
|
21
|
+
* const { status } = await Notifications.requestPermission();
|
|
22
|
+
* if (status === 'granted') {
|
|
23
|
+
* await Notifications.schedule({ title: 'Reminder', body: 'Check your tasks' }, { delay: 60 });
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare const Notifications: {
|
|
28
|
+
readonly schedule: (content: NotificationContent, options?: ScheduleOptions) => Promise<string>;
|
|
29
|
+
readonly cancel: (notificationId: string) => Promise<void>;
|
|
30
|
+
readonly cancelAll: () => Promise<void>;
|
|
31
|
+
/** Request notification permission, showing the OS dialog if needed. */
|
|
32
|
+
readonly requestPermission: () => Promise<PermissionResponse>;
|
|
33
|
+
/** Check current notification permission status without prompting. */
|
|
34
|
+
readonly getPermissionStatus: () => Promise<PermissionResponse>;
|
|
35
|
+
readonly isAvailable: () => boolean;
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAI1D,MAAM,WAAW,mBAAmB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC5B,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;CAC/C;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa;iCACJ,mBAAmB,YAAW,eAAe,KAAQ,OAAO,CAAC,MAAM,CAAC;sCAI/D,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;8BAIhC,OAAO,CAAC,IAAI,CAAC;IAI1B,wEAAwE;sCACnD,OAAO,CAAC,kBAAkB,CAAC;IAIhD,sEAAsE;wCAC/C,OAAO,CAAC,kBAAkB,CAAC;gCAInC,OAAO;CAGhB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { callAsync, isModuleAvailable } from '@sigx/lynx-core';
|
|
2
|
+
const MODULE = 'Notifications';
|
|
3
|
+
/**
|
|
4
|
+
* Local notification APIs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { Notifications } from '@sigx/lynx-notifications';
|
|
9
|
+
*
|
|
10
|
+
* const { status } = await Notifications.requestPermission();
|
|
11
|
+
* if (status === 'granted') {
|
|
12
|
+
* await Notifications.schedule({ title: 'Reminder', body: 'Check your tasks' }, { delay: 60 });
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export const Notifications = {
|
|
17
|
+
schedule(content, options = {}) {
|
|
18
|
+
return callAsync(MODULE, 'schedule', content, options);
|
|
19
|
+
},
|
|
20
|
+
cancel(notificationId) {
|
|
21
|
+
return callAsync(MODULE, 'cancel', notificationId);
|
|
22
|
+
},
|
|
23
|
+
cancelAll() {
|
|
24
|
+
return callAsync(MODULE, 'cancelAll');
|
|
25
|
+
},
|
|
26
|
+
/** Request notification permission, showing the OS dialog if needed. */
|
|
27
|
+
requestPermission() {
|
|
28
|
+
return callAsync(MODULE, 'requestPermission');
|
|
29
|
+
},
|
|
30
|
+
/** Check current notification permission status without prompting. */
|
|
31
|
+
getPermissionStatus() {
|
|
32
|
+
return callAsync(MODULE, 'getPermissionStatus');
|
|
33
|
+
},
|
|
34
|
+
isAvailable() {
|
|
35
|
+
return isModuleAvailable(MODULE);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../src/notifications.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAG/D,MAAM,MAAM,GAAG,eAAe,CAAC;AAgB/B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IACzB,QAAQ,CAAC,OAA4B,EAAE,UAA2B,EAAE;QAChE,OAAO,SAAS,CAAS,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,cAAsB;QACzB,OAAO,SAAS,CAAO,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC7D,CAAC;IAED,SAAS;QACL,OAAO,SAAS,CAAO,MAAM,EAAE,WAAW,CAAC,CAAC;IAChD,CAAC;IAED,wEAAwE;IACxE,iBAAiB;QACb,OAAO,SAAS,CAAqB,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACtE,CAAC;IAED,sEAAsE;IACtE,mBAAmB;QACf,OAAO,SAAS,CAAqB,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACxE,CAAC;IAED,WAAW;QACP,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;CACK,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UserNotifications
|
|
3
|
+
import Lynx
|
|
4
|
+
|
|
5
|
+
/// Local notifications module.
|
|
6
|
+
/// JS usage: NativeModules.Notifications.schedule({ title, body }, { delay }, callback)
|
|
7
|
+
class NotificationsModule: NSObject, LynxModule {
|
|
8
|
+
|
|
9
|
+
@objc static var name: String { "Notifications" }
|
|
10
|
+
|
|
11
|
+
@objc static var methodLookup: [String: String] {
|
|
12
|
+
[
|
|
13
|
+
"schedule": NSStringFromSelector(#selector(schedule(_:options:callback:))),
|
|
14
|
+
"cancel": NSStringFromSelector(#selector(cancel(_:callback:))),
|
|
15
|
+
"cancelAll": NSStringFromSelector(#selector(cancelAll(_:))),
|
|
16
|
+
"requestPermission": NSStringFromSelector(#selector(requestPermission(_:))),
|
|
17
|
+
"getPermissionStatus": NSStringFromSelector(#selector(getPermissionStatus(_:))),
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
required override init() { super.init() }
|
|
22
|
+
required init(param: Any) { super.init() }
|
|
23
|
+
|
|
24
|
+
@objc func schedule(_ content: [String: Any]?, options: [String: Any]?, callback: LynxCallbackBlock?) {
|
|
25
|
+
let title = content?["title"] as? String ?? "Notification"
|
|
26
|
+
let body = content?["body"] as? String ?? ""
|
|
27
|
+
let delay = options?["delay"] as? TimeInterval ?? 0
|
|
28
|
+
|
|
29
|
+
let notificationId = UUID().uuidString
|
|
30
|
+
|
|
31
|
+
let notificationContent = UNMutableNotificationContent()
|
|
32
|
+
notificationContent.title = title
|
|
33
|
+
notificationContent.body = body
|
|
34
|
+
notificationContent.sound = .default
|
|
35
|
+
|
|
36
|
+
let trigger: UNNotificationTrigger
|
|
37
|
+
if delay > 0 {
|
|
38
|
+
trigger = UNTimeIntervalNotificationTrigger(timeInterval: delay, repeats: false)
|
|
39
|
+
} else {
|
|
40
|
+
trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let request = UNNotificationRequest(identifier: notificationId, content: notificationContent, trigger: trigger)
|
|
44
|
+
|
|
45
|
+
UNUserNotificationCenter.current().add(request) { error in
|
|
46
|
+
if let error = error {
|
|
47
|
+
callback?(["error": error.localizedDescription])
|
|
48
|
+
} else {
|
|
49
|
+
callback?(notificationId)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@objc func cancel(_ notificationId: String?, callback: LynxCallbackBlock?) {
|
|
55
|
+
guard let notificationId = notificationId else {
|
|
56
|
+
callback?(false)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notificationId])
|
|
60
|
+
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notificationId])
|
|
61
|
+
callback?(true)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@objc func cancelAll(_ callback: LynxCallbackBlock?) {
|
|
65
|
+
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
|
|
66
|
+
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
|
|
67
|
+
callback?(true)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@objc func requestPermission(_ callback: LynxCallbackBlock?) {
|
|
71
|
+
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
|
|
72
|
+
if let error = error {
|
|
73
|
+
callback?(["status": "denied", "error": error.localizedDescription])
|
|
74
|
+
} else {
|
|
75
|
+
callback?(["status": granted ? "granted" : "denied"])
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@objc func getPermissionStatus(_ callback: LynxCallbackBlock?) {
|
|
81
|
+
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
|
82
|
+
let status: String
|
|
83
|
+
switch settings.authorizationStatus {
|
|
84
|
+
case .notDetermined: status = "undetermined"
|
|
85
|
+
case .denied: status = "denied"
|
|
86
|
+
case .authorized: status = "granted"
|
|
87
|
+
case .provisional: status = "granted"
|
|
88
|
+
case .ephemeral: status = "granted"
|
|
89
|
+
@unknown default: status = "unknown"
|
|
90
|
+
}
|
|
91
|
+
callback?(["status": status])
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sigx/lynx-notifications",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local push notifications for sigx-lynx",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./sigx-module.json": "./sigx-module.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"ios",
|
|
18
|
+
"android",
|
|
19
|
+
"sigx-module.json"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@sigx/lynx-core": "^0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"typescript": "^5.9.3"
|
|
26
|
+
},
|
|
27
|
+
"author": "Andreas Ekdahl",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"dev": "tsc --watch"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/sigx-module.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Notifications",
|
|
3
|
+
"package": "@sigx/lynx-notifications",
|
|
4
|
+
"description": "Local push notifications",
|
|
5
|
+
"platforms": ["android", "ios"],
|
|
6
|
+
"ios": {
|
|
7
|
+
"moduleClass": "NotificationsModule",
|
|
8
|
+
"sourceDir": "ios",
|
|
9
|
+
"methods": ["schedule","cancel","cancelAll","requestPermission","getPermissionStatus"]
|
|
10
|
+
},
|
|
11
|
+
"android": {
|
|
12
|
+
"moduleClass": "com.sigx.notifications.NotificationsModule",
|
|
13
|
+
"sourceDir": "android",
|
|
14
|
+
"permissions": ["android.permission.POST_NOTIFICATIONS"]
|
|
15
|
+
}
|
|
16
|
+
}
|