doopush-react-native-sdk 0.1.2 → 0.5.2
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/README.md +71 -34
- package/android/build.gradle +9 -7
- package/android/src/main/java/com/doopush/reactnative/DooPushReactNativeSDKModule.kt +188 -28
- package/build/DooPush.d.ts +44 -7
- package/build/DooPush.d.ts.map +1 -1
- package/build/DooPush.js +76 -1
- package/build/DooPush.js.map +1 -1
- package/build/events.d.ts +7 -4
- package/build/events.d.ts.map +1 -1
- package/build/events.js +5 -2
- package/build/events.js.map +1 -1
- package/build/hooks.d.ts +34 -0
- package/build/hooks.d.ts.map +1 -0
- package/build/hooks.js +138 -0
- package/build/hooks.js.map +1 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/types.d.ts +28 -1
- package/build/types.d.ts.map +1 -1
- package/build/types.js.map +1 -1
- package/ios/DooPushReactNativeSDK.podspec +1 -3
- package/ios/DooPushReactNativeSDKModule.swift +169 -4
- package/package.json +13 -8
- package/plugin/build/android/withAndroid.js +6 -0
- package/plugin/build/android/withAppBuildGradle.js +71 -30
- package/plugin/build/android/withGoogleServices.js +74 -12
- package/plugin/build/android/withGradleProperties.d.ts +3 -0
- package/plugin/build/android/withGradleProperties.js +26 -0
- package/plugin/build/android/withOppoManifest.d.ts +3 -0
- package/plugin/build/android/withOppoManifest.js +61 -0
- package/plugin/build/android/withRootBuildGradle.d.ts +2 -2
- package/plugin/build/android/withRootBuildGradle.js +65 -10
- package/plugin/build/android/withSettingsGradle.d.ts +8 -0
- package/plugin/build/android/withSettingsGradle.js +33 -0
- package/plugin/build/ios/withIOS.js +2 -0
- package/plugin/build/ios/withPodfile.d.ts +8 -0
- package/plugin/build/ios/withPodfile.js +48 -0
- package/plugin/build/schema.d.ts +327 -1
- package/plugin/build/schema.js +82 -1
package/README.md
CHANGED
|
@@ -1,48 +1,35 @@
|
|
|
1
1
|
# DooPush React Native SDK
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
> 仅支持 FCM (Android) + APNs (iOS)。OEM 通道、React Hooks 在 v0.5.0 beta。
|
|
3
|
+
> React Native / Expo SDK,支持 APNs、FCM、Android 6 类 OEM 通道、Hooks、通知事件、WebSocket Gateway、角标、统计和第三方共存控制。
|
|
5
4
|
|
|
6
5
|
[DooPush](https://doopush.com) 推送通知服务的 React Native SDK。基于 Expo Modules API 实现,可在 Expo(managed / prebuild)和 bare React Native 项目里使用。
|
|
7
6
|
|
|
8
|
-
##
|
|
7
|
+
## 功能
|
|
9
8
|
|
|
10
9
|
- ✅ `DooPush.configure(config)`
|
|
11
|
-
- ✅ `DooPush.register()` —— iOS APNs / Android FCM 自动流程
|
|
12
|
-
- ✅ `DooPush.registerWithToken(token, vendor)` ——
|
|
13
|
-
-
|
|
14
|
-
- ✅
|
|
15
|
-
- ✅
|
|
16
|
-
- ✅
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
- `getDeviceToken()` / `getDeviceId()` 在 Android 上一直返回 `null`(底层 SDK 还没公开 getter)。
|
|
22
|
-
|
|
23
|
-
## v0.1 不包含(v0.5.0+ 才有)
|
|
24
|
-
|
|
25
|
-
- React Hooks(`useDooPush`、`useDooPushToken`)
|
|
26
|
-
- OEM 通道(HMS / Honor / Xiaomi / OPPO / VIVO / Meizu)
|
|
27
|
-
- WebSocket gateway 的 JS API
|
|
28
|
-
- 统计 / 角标 / 通道相关的 JS API
|
|
29
|
-
- npm 发布(当前用 git tag)
|
|
10
|
+
- ✅ `DooPush.register()` —— iOS APNs / Android FCM 或 OEM 自动流程
|
|
11
|
+
- ✅ `DooPush.registerWithToken(token, vendor)` —— 调用方已有 token 时的 passive 模式
|
|
12
|
+
- ✅ `DooPush.getDeviceToken()` / `getDeviceId()` / `getDeviceInfo()` —— iOS 与 Android 均返回原生 SDK 缓存值
|
|
13
|
+
- ✅ `DooPush.updateDeviceInfo()` / `reportStatistics()` / `checkPermissionStatus()`
|
|
14
|
+
- ✅ 角标 API:`setBadge()` / `clearBadge()` / `getBadge()`
|
|
15
|
+
- ✅ React Hooks:`useDooPush()` / `useDooPushMessage()`
|
|
16
|
+
- ✅ 事件监听:注册、注册错误、消息、通知点击、通知打开、Gateway 状态
|
|
17
|
+
- ✅ 第三方共存控制:`setNotificationManagementMode`、`setExpoNotificationRelayEnabled`、`setNotificationDisplayEnabled`
|
|
18
|
+
- ✅ Config Plugin:iOS entitlement / background mode、Android FCM/HMS/Honor 配置文件、OEM 配置文件生成、Gradle plugin/dependency 注入和 manifest placeholders 合并
|
|
19
|
+
- ✅ Android OEM 通道:HMS / Honor / Xiaomi / OPPO / VIVO / Meizu
|
|
30
20
|
|
|
31
21
|
## 前置条件
|
|
32
22
|
|
|
33
|
-
- iOS 原生 SDK ≥ **1.
|
|
34
|
-
- Android 原生 SDK ≥ **1.
|
|
23
|
+
- iOS 原生 SDK ≥ **1.2.0**(monorepo 本地开发可路径引用未发布版本)
|
|
24
|
+
- Android 原生 SDK ≥ **1.2.0**(monorepo 本地开发可走 mavenLocal 用未发布版本)
|
|
35
25
|
- Expo SDK 50+(或 RN 0.73+ bare)。**新项目推荐 Expo SDK 54+**
|
|
36
26
|
|
|
37
|
-
##
|
|
27
|
+
## 快速安装
|
|
38
28
|
|
|
39
29
|
```bash
|
|
40
30
|
npx expo install doopush-react-native-sdk
|
|
41
31
|
```
|
|
42
32
|
|
|
43
|
-
> v0.1.x alpha **暂未发到 npm**,公开仓走 git tag:
|
|
44
|
-
> `npm install github:doopush/doopush-react-native-sdk#v0.1.1`
|
|
45
|
-
|
|
46
33
|
`app.json` 配 plugin:
|
|
47
34
|
|
|
48
35
|
```json
|
|
@@ -58,7 +45,15 @@ npx expo install doopush-react-native-sdk
|
|
|
58
45
|
"ios": { "mode": "production" },
|
|
59
46
|
"android": {
|
|
60
47
|
"vendors": {
|
|
61
|
-
"fcm": { "googleServicesFile": "./google-services.json" }
|
|
48
|
+
"fcm": { "googleServicesFile": "./google-services.json" },
|
|
49
|
+
"hms": { "agconnectServicesFile": "./agconnect-services.json" },
|
|
50
|
+
"honor": {
|
|
51
|
+
"mcsServicesFile": "./mcs-services.json"
|
|
52
|
+
},
|
|
53
|
+
"xiaomi": { "appId": "mi_app_id", "appKey": "mi_app_key" },
|
|
54
|
+
"oppo": { "appKey": "oppo_app_key", "appSecret": "oppo_app_secret" },
|
|
55
|
+
"vivo": { "appId": "vivo_app_id", "apiKey": "vivo_api_key" },
|
|
56
|
+
"meizu": { "appId": "meizu_app_id", "appKey": "meizu_app_key" }
|
|
62
57
|
}
|
|
63
58
|
}
|
|
64
59
|
}
|
|
@@ -68,6 +63,8 @@ npx expo install doopush-react-native-sdk
|
|
|
68
63
|
}
|
|
69
64
|
```
|
|
70
65
|
|
|
66
|
+
> OEM 配置支持两种方式:传 `servicesFile`/`mcsServicesFile`/`agconnectServicesFile` 复制厂商 JSON;或对 Xiaomi / OPPO / VIVO / Meizu / Honor 传内联凭证,prebuild 时会生成对应 `android/app/src/main/assets/*-services.json`。HMS 仍需 `agconnect-services.json` 文件。
|
|
67
|
+
|
|
71
68
|
```bash
|
|
72
69
|
npx expo prebuild --clean
|
|
73
70
|
npx expo run:android # 或 run:ios
|
|
@@ -76,10 +73,12 @@ npx expo run:android # 或 run:ios
|
|
|
76
73
|
## 用法
|
|
77
74
|
|
|
78
75
|
```tsx
|
|
79
|
-
import { useEffect
|
|
80
|
-
import { DooPush, type DooPushMessage } from 'doopush-react-native-sdk';
|
|
76
|
+
import { useEffect } from 'react';
|
|
77
|
+
import { DooPush, useDooPush, type DooPushMessage } from 'doopush-react-native-sdk';
|
|
81
78
|
|
|
82
79
|
export default function App() {
|
|
80
|
+
const { token, deviceId, register, lastMessage, error } = useDooPush();
|
|
81
|
+
|
|
83
82
|
useEffect(() => {
|
|
84
83
|
DooPush.configure({
|
|
85
84
|
appId: 'your_app_id',
|
|
@@ -88,19 +87,32 @@ export default function App() {
|
|
|
88
87
|
const sub = DooPush.addMessageListener((m: DooPushMessage) => {
|
|
89
88
|
console.log('收到推送', m);
|
|
90
89
|
});
|
|
91
|
-
|
|
90
|
+
const clickSub = DooPush.addNotificationClickListener((m) => {
|
|
91
|
+
console.log('点击推送', m);
|
|
92
|
+
});
|
|
93
|
+
return () => { sub.remove(); clickSub.remove(); };
|
|
92
94
|
}, []);
|
|
93
95
|
|
|
94
96
|
const handleRegister = async () => {
|
|
95
97
|
try {
|
|
96
|
-
const { token, deviceId } = await
|
|
98
|
+
const { token, deviceId } = await register();
|
|
97
99
|
console.log('注册成功', token, deviceId);
|
|
98
100
|
} catch (e) {
|
|
99
101
|
console.error('注册失败', e);
|
|
100
102
|
}
|
|
101
103
|
};
|
|
102
104
|
|
|
103
|
-
//
|
|
105
|
+
// 也可以直接使用 hook 暴露的状态:token / deviceId / lastMessage / error
|
|
106
|
+
console.log({ token, deviceId, lastMessage, error });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 常用补充 API:
|
|
110
|
+
async function maintenance() {
|
|
111
|
+
await DooPush.setBadge(3);
|
|
112
|
+
await DooPush.clearBadge();
|
|
113
|
+
await DooPush.reportStatistics();
|
|
114
|
+
const permission = await DooPush.checkPermissionStatus();
|
|
115
|
+
console.log(permission);
|
|
104
116
|
}
|
|
105
117
|
```
|
|
106
118
|
|
|
@@ -144,9 +156,13 @@ sdk/react-native/
|
|
|
144
156
|
默认兼容。iOS 上 DooPush 接管 `UNUserNotificationCenterDelegate` 但走 delegate-forwarding,`expo-notifications` 的监听依然能收到。Android 上 DooPush 接管 `FirebaseMessagingService`,如果你也想让 `expo-notifications` 收到 FCM 消息,调(v0.5.0+):
|
|
145
157
|
|
|
146
158
|
```ts
|
|
159
|
+
DooPush.setNotificationManagementMode('active');
|
|
160
|
+
// relay 是独立开关;setNotificationManagementMode 不会覆盖该值。
|
|
147
161
|
DooPush.setExpoNotificationRelayEnabled(true);
|
|
148
162
|
```
|
|
149
163
|
|
|
164
|
+
> `setNotificationDisplayEnabled` 仅控制 Android FCM 由 DooPush 自管展示通知的开关;iOS 端是 no-op。`setExpoNotificationRelayEnabled` 是独立开关,不会被 active/passive 模式切换重置。若 iOS 需要让位给其它通知库,请使用 `setNotificationManagementMode('passive')`。
|
|
165
|
+
|
|
150
166
|
### 与 `@react-native-firebase/messaging`
|
|
151
167
|
|
|
152
168
|
**二选一** —— 两个库都声明 `FirebaseMessagingService`,manifest merger 只能留一个。如果你已经在用 `react-native-firebase`,就在 DooPush plugin 里**省略 fcm 厂商**,用 `react-native-firebase` 拿 token 后再交给 DooPush:
|
|
@@ -165,6 +181,27 @@ MIT
|
|
|
165
181
|
|
|
166
182
|
## CHANGELOG
|
|
167
183
|
|
|
184
|
+
### v0.5.2
|
|
185
|
+
- **Fix (config plugin)**:OPPO 注册静默超时(拿不到 RegisterId),因为构建产物缺少 HeyTap MCS 所需的 manifest 声明;新增 `withDooPushOppoManifest`,启用 `oppo` 厂商时注入两条 `RECIEVE_MCS_MESSAGE` 权限与 `CompatibleDataMessageCallbackService` / `DataMessageCallbackService` 回调服务。
|
|
186
|
+
- **Fix (Android)**:注册失败事件(`onRegisterError` / `register` reject)透出厂商返回的真实错误信息,替换此前的通用 "register failed"。
|
|
187
|
+
- **Docs**:更正 OPPO 集成说明,此前错误标注"无需额外配置"。
|
|
188
|
+
|
|
189
|
+
### v0.5.1
|
|
190
|
+
- **Fix (Android)**:`expo prebuild` 流程缺失 `google-services` Gradle 插件 classpath 注入,原生工程 sync 失败;config plugin 现在补齐 `withRootBuildGradle` / `withSettingsGradle` / `withGradleProperties`,prebuild 全流程跑通。
|
|
191
|
+
- **Fix (config plugin)**:`zod` 等 plugin 运行时依赖错误地放在 `devDependencies` 里,用户 `npx expo prebuild` 时 plugin 解析失败;改为生产依赖。
|
|
192
|
+
- **Fix (iOS)**:`normalizePermissionStatus` 在 `AsyncFunction` 闭包里少了 `self.` 前缀,调用 permission 相关 API 时崩溃;同步修复。
|
|
193
|
+
- **Dev**:example app 的 Podfile 在 monorepo 中可自动指向同仓库 `sdk/ios/DooPushSDK`,便于联动调试本地原生 SDK。
|
|
194
|
+
- **Install**:默认 npm dist-tag 改为 `latest`(不再要求 `@beta`),`npm install doopush-react-native-sdk` 直接安装最新版。
|
|
195
|
+
|
|
196
|
+
### v0.5.0
|
|
197
|
+
- **能力补齐**:Android `register()` / `registerWithToken()` 返回真实 `deviceId`,`getDeviceToken()` / `getDeviceId()` / `getDeviceInfo()` 接入原生缓存。
|
|
198
|
+
- **新增 Hooks**:`useDooPush()`、`useDooPushMessage()`。
|
|
199
|
+
- **新增 API**:角标、权限状态、设备信息更新、统计上报。
|
|
200
|
+
- **新增事件**:通知点击、通知打开、Gateway open/closed/error;`connectGateway()` 在缺少 token 时会拒绝。
|
|
201
|
+
- **共存控制**:新增 active/passive 管理模式、Expo relay、通知展示开关。
|
|
202
|
+
- **Config Plugin**:扩展 Android OEM vendor 配置入口;支持内联凭证生成 services JSON,HMS/Honor Gradle plugin 注入,HMS/Honor services 文件同时复制到 app 根目录和 assets。
|
|
203
|
+
- **依赖底座**:iOS / Android 原生 SDK 对齐到 v1.2.0。
|
|
204
|
+
|
|
168
205
|
### v0.1.2
|
|
169
206
|
- **chore**:发版流水线连通性测试(无功能变更)。验证 monorepo `sync-rn-sdk.yml` → `doopush-react-native-sdk` 公仓 → `auto-publish-release.yml` → GitHub Release + npm publish 全链路。dist-tag 应解析为 `alpha`(0.1.x ≤ 0.4.x)。
|
|
170
207
|
|
package/android/build.gradle
CHANGED
|
@@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
|
|
|
2
2
|
apply plugin: 'kotlin-android'
|
|
3
3
|
|
|
4
4
|
group = 'com.doopush.reactnative'
|
|
5
|
-
version = '0.
|
|
5
|
+
version = '0.5.0'
|
|
6
6
|
|
|
7
7
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
8
8
|
apply from: expoModulesCorePlugin
|
|
@@ -18,15 +18,15 @@ android {
|
|
|
18
18
|
minSdkVersion safeExtGet("minSdkVersion", 26)
|
|
19
19
|
targetSdkVersion safeExtGet("targetSdkVersion", 34)
|
|
20
20
|
versionCode 1
|
|
21
|
-
versionName "0.
|
|
21
|
+
versionName "0.5.0"
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
compileOptions {
|
|
25
|
-
sourceCompatibility JavaVersion.
|
|
26
|
-
targetCompatibility JavaVersion.
|
|
25
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
26
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
27
27
|
}
|
|
28
28
|
kotlinOptions {
|
|
29
|
-
jvmTarget = '
|
|
29
|
+
jvmTarget = '17'
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -39,10 +39,12 @@ repositories {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
dependencies {
|
|
42
|
-
//
|
|
42
|
+
// RN bridge directly uses NotificationManagerCompat / ContextCompat for permission checks.
|
|
43
|
+
implementation 'androidx.core:core-ktx:1.12.0'
|
|
44
|
+
// DooPush native Android SDK v1.2.0+
|
|
43
45
|
// During v0.1 alpha dev: rely on mavenLocal (./gradlew :lib:publishToMavenLocal in sdk/android/DooPushSDK).
|
|
44
46
|
// Once published, this resolves from JitPack via the maven{} block above.
|
|
45
|
-
implementation 'com.
|
|
47
|
+
implementation 'com.doopush:android-sdk:1.2.0'
|
|
46
48
|
|
|
47
49
|
// FCM (transitive via DooPush AAR's runtime deps for FCM, but explicit here for clarity).
|
|
48
50
|
implementation platform('com.google.firebase:firebase-bom:32.7.0')
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
package com.doopush.reactnative
|
|
2
2
|
|
|
3
|
+
import android.Manifest
|
|
4
|
+
import android.content.pm.PackageManager
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import androidx.core.app.NotificationManagerCompat
|
|
7
|
+
import androidx.core.content.ContextCompat
|
|
3
8
|
import com.doopush.sdk.DooPushCallback
|
|
4
9
|
import com.doopush.sdk.DooPushManager
|
|
5
10
|
import com.doopush.sdk.DooPushNotificationHandler
|
|
6
11
|
import com.doopush.sdk.DooPushRegisterCallback
|
|
12
|
+
import com.doopush.sdk.DooPushRegisterResult
|
|
7
13
|
import com.doopush.sdk.models.DooPushError
|
|
8
14
|
import com.doopush.sdk.models.PushMessage
|
|
9
15
|
import expo.modules.kotlin.Promise
|
|
@@ -12,18 +18,27 @@ import expo.modules.kotlin.modules.ModuleDefinition
|
|
|
12
18
|
|
|
13
19
|
/**
|
|
14
20
|
* DooPush React Native SDK — Android bridge
|
|
15
|
-
* v0.
|
|
21
|
+
* v0.5.0
|
|
16
22
|
*
|
|
17
23
|
* Mode: ACTIVE (default) — DooPush owns FCM display via DooPushFirebaseMessagingService.
|
|
18
|
-
* Coexistence with expo-notifications/react-native-firebase is
|
|
19
|
-
*
|
|
24
|
+
* Coexistence with expo-notifications/react-native-firebase is exposed through
|
|
25
|
+
* notification-management / relay APIs.
|
|
20
26
|
*/
|
|
21
27
|
class DooPushReactNativeSDKModule : Module(), DooPushCallback {
|
|
22
28
|
|
|
23
29
|
override fun definition() = ModuleDefinition {
|
|
24
30
|
Name("DooPushReactNativeSDK")
|
|
25
31
|
|
|
26
|
-
Events(
|
|
32
|
+
Events(
|
|
33
|
+
"onRegister",
|
|
34
|
+
"onRegisterError",
|
|
35
|
+
"onMessage",
|
|
36
|
+
"onNotificationClick",
|
|
37
|
+
"onNotificationOpen",
|
|
38
|
+
"onGatewayOpen",
|
|
39
|
+
"onGatewayClosed",
|
|
40
|
+
"onGatewayError"
|
|
41
|
+
)
|
|
27
42
|
|
|
28
43
|
OnCreate {
|
|
29
44
|
DooPushManager.getInstance().setCallback(this@DooPushReactNativeSDKModule)
|
|
@@ -50,19 +65,22 @@ class DooPushReactNativeSDKModule : Module(), DooPushCallback {
|
|
|
50
65
|
DooPushManager.getInstance().registerForPushNotifications(
|
|
51
66
|
object : DooPushRegisterCallback {
|
|
52
67
|
override fun onSuccess(token: String) {
|
|
68
|
+
// Compatibility fallback for older native SDK callback dispatch.
|
|
53
69
|
promise.resolve(mapOf(
|
|
54
70
|
"token" to token,
|
|
55
|
-
"deviceId" to (DooPushManager.getInstance().
|
|
56
|
-
// Try to read deviceId via reflection / public getter; v1.1.0 doesn't expose
|
|
57
|
-
// a public getDeviceId(), so we fall back to empty string for v0.1.0.
|
|
58
|
-
// TODO P3: expose getDeviceId() on Android Manager parity with iOS.
|
|
59
|
-
""
|
|
60
|
-
}),
|
|
71
|
+
"deviceId" to (DooPushManager.getInstance().getDeviceId() ?: ""),
|
|
61
72
|
"vendor" to currentVendor()
|
|
62
73
|
))
|
|
63
74
|
}
|
|
75
|
+
override fun onSuccess(result: DooPushRegisterResult) {
|
|
76
|
+
promise.resolve(mapOf(
|
|
77
|
+
"token" to result.token,
|
|
78
|
+
"deviceId" to result.deviceId,
|
|
79
|
+
"vendor" to normalizeVendor(result.vendor)
|
|
80
|
+
))
|
|
81
|
+
}
|
|
64
82
|
override fun onError(error: DooPushError) {
|
|
65
|
-
promise.reject("E_REGISTER", error.
|
|
83
|
+
promise.reject("E_REGISTER", error.getFullDescription(), error)
|
|
66
84
|
}
|
|
67
85
|
}
|
|
68
86
|
)
|
|
@@ -75,10 +93,13 @@ class DooPushReactNativeSDKModule : Module(), DooPushCallback {
|
|
|
75
93
|
vendor = vendor,
|
|
76
94
|
callback = object : DooPushRegisterCallback {
|
|
77
95
|
override fun onSuccess(t: String) {
|
|
78
|
-
promise.resolve(mapOf("deviceId" to ""))
|
|
96
|
+
promise.resolve(mapOf("deviceId" to (DooPushManager.getInstance().getDeviceId() ?: "")))
|
|
97
|
+
}
|
|
98
|
+
override fun onSuccess(result: DooPushRegisterResult) {
|
|
99
|
+
promise.resolve(mapOf("deviceId" to result.deviceId))
|
|
79
100
|
}
|
|
80
101
|
override fun onError(error: DooPushError) {
|
|
81
|
-
promise.reject("E_REGISTER", error.
|
|
102
|
+
promise.reject("E_REGISTER", error.getFullDescription(), error)
|
|
82
103
|
}
|
|
83
104
|
}
|
|
84
105
|
)
|
|
@@ -86,13 +107,97 @@ class DooPushReactNativeSDKModule : Module(), DooPushCallback {
|
|
|
86
107
|
|
|
87
108
|
// ── token getters ───────────────────────────────────────────────
|
|
88
109
|
AsyncFunction("getDeviceToken") { ->
|
|
89
|
-
|
|
90
|
-
// TODO P3: add public getter on Android Manager and wire here.
|
|
91
|
-
null as String?
|
|
110
|
+
DooPushManager.getInstance().getDeviceToken()
|
|
92
111
|
}
|
|
93
112
|
|
|
94
113
|
AsyncFunction("getDeviceId") { ->
|
|
95
|
-
|
|
114
|
+
DooPushManager.getInstance().getDeviceId()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
AsyncFunction("getDeviceInfo") { ->
|
|
118
|
+
DooPushManager.getInstance().getDeviceInfo()?.let { deviceInfo ->
|
|
119
|
+
mapOf(
|
|
120
|
+
"platform" to deviceInfo.platform,
|
|
121
|
+
"channel" to normalizeVendor(deviceInfo.channel),
|
|
122
|
+
"bundleId" to deviceInfo.bundleId,
|
|
123
|
+
"brand" to deviceInfo.brand,
|
|
124
|
+
"model" to deviceInfo.model,
|
|
125
|
+
"systemVersion" to deviceInfo.systemVersion,
|
|
126
|
+
"appVersion" to deviceInfo.appVersion,
|
|
127
|
+
"userAgent" to deviceInfo.userAgent
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
AsyncFunction("updateDeviceInfo") { promise: Promise ->
|
|
133
|
+
DooPushManager.getInstance().updateDeviceInfo { success, error ->
|
|
134
|
+
if (success) {
|
|
135
|
+
promise.resolve(null)
|
|
136
|
+
} else {
|
|
137
|
+
promise.reject("E_UPDATE_DEVICE_INFO", error?.message ?: "updateDeviceInfo failed", null)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
AsyncFunction("reportStatistics") { ->
|
|
143
|
+
DooPushManager.getInstance().reportStatistics()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
AsyncFunction("checkPermissionStatus") { ->
|
|
147
|
+
checkPermissionStatus()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
AsyncFunction("setBadge") { count: Int, promise: Promise ->
|
|
151
|
+
if (count < 0) {
|
|
152
|
+
promise.reject("E_BADGE", "badge count must be >= 0", null)
|
|
153
|
+
} else {
|
|
154
|
+
promise.resolve(DooPushManager.getInstance().setBadgeCount(count))
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
AsyncFunction("clearBadge") { ->
|
|
159
|
+
DooPushManager.getInstance().clearBadge()
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
AsyncFunction("getBadge") { ->
|
|
163
|
+
DooPushManager.getInstance().getBadgeCount()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ── notification management / coexistence ───────────────────────
|
|
167
|
+
Function("setNotificationManagementMode") { mode: String ->
|
|
168
|
+
val manager = DooPushManager.getInstance()
|
|
169
|
+
val resolved = when (mode.lowercase()) {
|
|
170
|
+
"active" -> DooPushManager.NotificationManagementMode.ACTIVE
|
|
171
|
+
"passive" -> DooPushManager.NotificationManagementMode.PASSIVE
|
|
172
|
+
else -> throw IllegalArgumentException("mode must be 'active' or 'passive'")
|
|
173
|
+
}
|
|
174
|
+
manager.setNotificationManagementMode(resolved)
|
|
175
|
+
// Keep relay independent: callers may opt into Expo relay in either mode.
|
|
176
|
+
manager.setFCMNotificationDisplayEnabled(
|
|
177
|
+
resolved == DooPushManager.NotificationManagementMode.ACTIVE
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Function("setExpoNotificationRelayEnabled") { enabled: Boolean ->
|
|
182
|
+
DooPushManager.getInstance().setExpoNotificationRelayEnabled(enabled)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Function("setNotificationDisplayEnabled") { enabled: Boolean ->
|
|
186
|
+
DooPushManager.getInstance().setFCMNotificationDisplayEnabled(enabled)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
AsyncFunction("connectGateway") { promise: Promise ->
|
|
190
|
+
if (DooPushManager.getInstance().getDeviceToken().isNullOrBlank()) {
|
|
191
|
+
promise.reject("E_GATEWAY", "device token is required before connecting gateway", null)
|
|
192
|
+
} else {
|
|
193
|
+
DooPushManager.getInstance().connectWebSocket()
|
|
194
|
+
promise.resolve(null)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
AsyncFunction("disconnectGateway") { promise: Promise ->
|
|
199
|
+
DooPushManager.getInstance().disconnectWebSocket()
|
|
200
|
+
promise.resolve(null)
|
|
96
201
|
}
|
|
97
202
|
}
|
|
98
203
|
|
|
@@ -101,15 +206,23 @@ class DooPushReactNativeSDKModule : Module(), DooPushCallback {
|
|
|
101
206
|
override fun onRegisterSuccess(token: String) {
|
|
102
207
|
sendEvent("onRegister", mapOf(
|
|
103
208
|
"token" to token,
|
|
104
|
-
"deviceId" to "",
|
|
209
|
+
"deviceId" to (DooPushManager.getInstance().getDeviceId() ?: ""),
|
|
105
210
|
"vendor" to currentVendor()
|
|
106
211
|
))
|
|
107
212
|
}
|
|
108
213
|
|
|
214
|
+
override fun onRegisterSuccess(result: DooPushRegisterResult) {
|
|
215
|
+
sendEvent("onRegister", mapOf(
|
|
216
|
+
"token" to result.token,
|
|
217
|
+
"deviceId" to result.deviceId,
|
|
218
|
+
"vendor" to normalizeVendor(result.vendor)
|
|
219
|
+
))
|
|
220
|
+
}
|
|
221
|
+
|
|
109
222
|
override fun onRegisterError(error: DooPushError) {
|
|
110
223
|
sendEvent("onRegisterError", mapOf(
|
|
111
224
|
"code" to "E_REGISTER",
|
|
112
|
-
"message" to
|
|
225
|
+
"message" to error.getFullDescription()
|
|
113
226
|
))
|
|
114
227
|
}
|
|
115
228
|
|
|
@@ -125,22 +238,69 @@ class DooPushReactNativeSDKModule : Module(), DooPushCallback {
|
|
|
125
238
|
))
|
|
126
239
|
}
|
|
127
240
|
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// direct token-fetch results to JS isn't part of the v0.1 surface (the JS layer only
|
|
131
|
-
// consumes onRegister/onRegisterError/onMessage). v0.5.0 may surface these.
|
|
241
|
+
// Direct token-fetch callbacks are not part of the RN v0.5.0 surface; apps consume
|
|
242
|
+
// register/registerWithToken plus onRegister/onRegisterError/onMessage events.
|
|
132
243
|
override fun onTokenReceived(token: String) {
|
|
133
|
-
// No-op
|
|
244
|
+
// No-op.
|
|
134
245
|
}
|
|
135
246
|
|
|
136
247
|
override fun onTokenError(error: DooPushError) {
|
|
137
|
-
// No-op
|
|
248
|
+
// No-op.
|
|
138
249
|
}
|
|
139
250
|
|
|
140
251
|
override fun onNotificationClick(notificationData: DooPushNotificationHandler.NotificationData) {
|
|
141
|
-
|
|
252
|
+
sendEvent("onNotificationClick", normalizeNotification(notificationData))
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
override fun onNotificationOpen(notificationData: DooPushNotificationHandler.NotificationData) {
|
|
256
|
+
sendEvent("onNotificationOpen", normalizeNotification(notificationData))
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
override fun onWebSocketOpen() {
|
|
260
|
+
sendEvent("onGatewayOpen", mapOf("connected" to true))
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
override fun onWebSocketClosed(code: Int, reason: String) {
|
|
264
|
+
sendEvent("onGatewayClosed", mapOf("code" to code, "reason" to reason))
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
override fun onWebSocketFailure(t: Throwable) {
|
|
268
|
+
sendEvent("onGatewayError", mapOf(
|
|
269
|
+
"code" to "E_GATEWAY",
|
|
270
|
+
"message" to (t.message ?: "WebSocket failure")
|
|
271
|
+
))
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private fun normalizeNotification(
|
|
275
|
+
notificationData: DooPushNotificationHandler.NotificationData
|
|
276
|
+
): Map<String, Any?> = mapOf(
|
|
277
|
+
"vendor" to currentVendor(),
|
|
278
|
+
"title" to notificationData.title,
|
|
279
|
+
"body" to notificationData.body,
|
|
280
|
+
"pushLogId" to notificationData.pushLogId,
|
|
281
|
+
"dedupKey" to notificationData.dedupKey,
|
|
282
|
+
"data" to notificationData.payload.mapValues { it.value.toString() }
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
private fun currentVendor(): String =
|
|
286
|
+
normalizeVendor(DooPushManager.getInstance().getCurrentVendor() ?: "fcm")
|
|
287
|
+
|
|
288
|
+
private fun checkPermissionStatus(): String {
|
|
289
|
+
val context = appContext.reactContext ?: return "unknown"
|
|
290
|
+
val notificationsEnabled = NotificationManagerCompat.from(context).areNotificationsEnabled()
|
|
291
|
+
if (!notificationsEnabled) return "denied"
|
|
292
|
+
|
|
293
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
294
|
+
val granted = ContextCompat.checkSelfPermission(
|
|
295
|
+
context,
|
|
296
|
+
Manifest.permission.POST_NOTIFICATIONS
|
|
297
|
+
) == PackageManager.PERMISSION_GRANTED
|
|
298
|
+
return if (granted) "authorized" else "denied"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return "authorized"
|
|
142
302
|
}
|
|
143
303
|
|
|
144
|
-
|
|
145
|
-
|
|
304
|
+
private fun normalizeVendor(vendor: String): String =
|
|
305
|
+
if (vendor == "huawei") "hms" else vendor
|
|
146
306
|
}
|
package/build/DooPush.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Subscription } from 'expo-modules-core';
|
|
2
|
-
import type { DooPushConfig, DooPushVendor, DooPushMessage } from './types';
|
|
2
|
+
import type { DooPushConfig, DooPushVendor, DooPushMessage, DooPushNotificationManagementMode, DooPushGatewayOpenEvent, DooPushGatewayClosedEvent, DooPushGatewayErrorEvent, DooPushRegisterResult, DooPushDeviceInfo, DooPushPermissionStatus } from './types';
|
|
3
3
|
import type { OnRegisterEvent, OnRegisterErrorEvent } from './events';
|
|
4
4
|
/**
|
|
5
5
|
* DooPush React Native SDK — imperative API
|
|
6
6
|
*
|
|
7
|
-
* v0.
|
|
7
|
+
* v0.5.0 — registration, OEM channels, token/device getters, hooks,
|
|
8
|
+
* notification events, WebSocket gateway, badge, statistics, and coexistence controls.
|
|
8
9
|
*/
|
|
9
10
|
/**
|
|
10
11
|
* Configure the SDK. Call once per app launch, ideally in App entry point.
|
|
@@ -18,11 +19,7 @@ export declare function configure(config: DooPushConfig): void;
|
|
|
18
19
|
* Returns the device token + DooPush deviceId on success.
|
|
19
20
|
* Rejects if user denies permission or network fails.
|
|
20
21
|
*/
|
|
21
|
-
export declare function register(): Promise<
|
|
22
|
-
token: string;
|
|
23
|
-
deviceId: string;
|
|
24
|
-
vendor: DooPushVendor;
|
|
25
|
-
}>;
|
|
22
|
+
export declare function register(): Promise<DooPushRegisterResult>;
|
|
26
23
|
/**
|
|
27
24
|
* Register with a token already obtained externally (e.g. via expo-notifications
|
|
28
25
|
* `getDevicePushTokenAsync()`). Skips SDK's internal permission/token flow.
|
|
@@ -34,7 +31,47 @@ export declare function registerWithToken(token: string, vendor?: DooPushVendor)
|
|
|
34
31
|
export declare function getDeviceToken(): Promise<string | null>;
|
|
35
32
|
/** Returns DooPush server-assigned deviceId (after register success), or null. */
|
|
36
33
|
export declare function getDeviceId(): Promise<string | null>;
|
|
34
|
+
/** Returns the current native SDK device information snapshot, or null before configure. */
|
|
35
|
+
export declare function getDeviceInfo(): Promise<DooPushDeviceInfo | null>;
|
|
36
|
+
/** Refresh device information on the DooPush server using the current token. */
|
|
37
|
+
export declare function updateDeviceInfo(): Promise<void>;
|
|
38
|
+
/** Immediately flush locally collected push statistics. */
|
|
39
|
+
export declare function reportStatistics(): Promise<void>;
|
|
40
|
+
/** Check OS-level push notification permission status. */
|
|
41
|
+
export declare function checkPermissionStatus(): Promise<DooPushPermissionStatus>;
|
|
42
|
+
/** Set the application badge count. */
|
|
43
|
+
export declare function setBadge(count: number): Promise<boolean>;
|
|
44
|
+
/** Clear the application badge count. */
|
|
45
|
+
export declare function clearBadge(): Promise<boolean>;
|
|
46
|
+
/** Return the last known application badge count. */
|
|
47
|
+
export declare function getBadge(): Promise<number>;
|
|
48
|
+
/**
|
|
49
|
+
* Set notification management mode.
|
|
50
|
+
*
|
|
51
|
+
* - active: DooPush requests permission / owns notification handling where possible.
|
|
52
|
+
* - passive: host app obtains token and calls registerWithToken().
|
|
53
|
+
*/
|
|
54
|
+
export declare function setNotificationManagementMode(mode: DooPushNotificationManagementMode): void;
|
|
55
|
+
/**
|
|
56
|
+
* Android: relay FCM messages to Expo Notifications coexistence broadcast.
|
|
57
|
+
* iOS: no-op because delegate forwarding is used.
|
|
58
|
+
*/
|
|
59
|
+
export declare function setExpoNotificationRelayEnabled(enabled: boolean): void;
|
|
60
|
+
/**
|
|
61
|
+
* Android: toggle SDK-owned FCM notification display.
|
|
62
|
+
* iOS: no-op; use setNotificationManagementMode('passive') to disable DooPush delegate tracking.
|
|
63
|
+
*/
|
|
64
|
+
export declare function setNotificationDisplayEnabled(enabled: boolean): void;
|
|
65
|
+
/** Manually connect the WebSocket gateway using the registered device token. */
|
|
66
|
+
export declare function connectGateway(): Promise<void>;
|
|
67
|
+
/** Manually disconnect the WebSocket gateway. */
|
|
68
|
+
export declare function disconnectGateway(): Promise<void>;
|
|
37
69
|
export declare function addRegisterListener(listener: (e: OnRegisterEvent) => void): Subscription;
|
|
38
70
|
export declare function addRegisterErrorListener(listener: (e: OnRegisterErrorEvent) => void): Subscription;
|
|
39
71
|
export declare function addMessageListener(listener: (msg: DooPushMessage) => void): Subscription;
|
|
72
|
+
export declare function addNotificationClickListener(listener: (msg: DooPushMessage) => void): Subscription;
|
|
73
|
+
export declare function addNotificationOpenListener(listener: (msg: DooPushMessage) => void): Subscription;
|
|
74
|
+
export declare function addGatewayOpenListener(listener: (e: DooPushGatewayOpenEvent) => void): Subscription;
|
|
75
|
+
export declare function addGatewayClosedListener(listener: (e: DooPushGatewayClosedEvent) => void): Subscription;
|
|
76
|
+
export declare function addGatewayErrorListener(listener: (e: DooPushGatewayErrorEvent) => void): Subscription;
|
|
40
77
|
//# sourceMappingURL=DooPush.d.ts.map
|
package/build/DooPush.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DooPush.d.ts","sourceRoot":"","sources":["../src/DooPush.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,cAAc,
|
|
1
|
+
{"version":3,"file":"DooPush.d.ts","sourceRoot":"","sources":["../src/DooPush.ts"],"names":[],"mappings":"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"}
|