react-native-push-signal 0.1.8 → 0.1.10
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/PushSignal.podspec +1 -1
- package/README.md +64 -0
- package/README.ru.md +64 -0
- package/android/build.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +7 -0
- package/android/src/main/java/com/pushsignal/PushModels.kt +23 -0
- package/android/src/main/java/com/pushsignal/PushSignalCenter.kt +236 -12
- package/android/src/main/java/com/pushsignal/PushSignalModule.kt +30 -2
- package/ios/PushSignal.mm +18 -0
- package/lib/module/NativePushSignal.js.map +1 -1
- package/lib/module/PushSignalError.js +29 -0
- package/lib/module/PushSignalError.js.map +1 -0
- package/lib/module/index.js +2 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/pushSignal.js +3 -0
- package/lib/module/pushSignal.js.map +1 -1
- package/lib/module/pushSignal.native.js +51 -4
- package/lib/module/pushSignal.native.js.map +1 -1
- package/lib/typescript/src/NativePushSignal.d.ts +19 -0
- package/lib/typescript/src/NativePushSignal.d.ts.map +1 -1
- package/lib/typescript/src/PushSignalError.d.ts +22 -0
- package/lib/typescript/src/PushSignalError.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/pushSignal.d.ts +2 -1
- package/lib/typescript/src/pushSignal.d.ts.map +1 -1
- package/lib/typescript/src/pushSignal.native.d.ts +2 -1
- package/lib/typescript/src/pushSignal.native.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +18 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +16 -6
- package/src/NativePushSignal.ts +20 -0
- package/src/PushSignalError.ts +29 -0
- package/src/index.tsx +4 -0
- package/src/pushSignal.native.tsx +68 -4
- package/src/pushSignal.tsx +5 -0
- package/src/types.ts +28 -0
package/PushSignal.podspec
CHANGED
|
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
13
|
s.platforms = { :ios => min_ios_version_supported }
|
|
14
|
-
s.source = { :git => "https://
|
|
14
|
+
s.source = { :git => "https://github.com/AntonSeagull/react-native-push-signal.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
16
|
s.source_files = "ios/**/*.{h,m,mm,cpp}"
|
|
17
17
|
s.private_header_files = "ios/**/*.h"
|
package/README.md
CHANGED
|
@@ -108,6 +108,70 @@ Without `initialize(...)` or that file, `getCredentials()` throws.
|
|
|
108
108
|
|
|
109
109
|
If the host app already declares its own `FirebaseMessagingService`, only one service can handle `com.google.firebase.MESSAGING_EVENT`. Prefer this library’s service or forward events into it.
|
|
110
110
|
|
|
111
|
+
### When it fails on Xiaomi: `SERVICE_NOT_AVAILABLE`
|
|
112
|
+
|
|
113
|
+
If `getCredentials()` throws `Failed to get an FCM token: SERVICE_NOT_AVAILABLE`, the FCM token could not be obtained. Your server never receives a token, so there is nowhere to send pushes — delivery itself is not the problem.
|
|
114
|
+
|
|
115
|
+
Before requesting the token the library checks Google Play services and retries a few times with backoff, but some causes can only be fixed on the device:
|
|
116
|
+
|
|
117
|
+
- **Google account.** The device must be signed into a Google account. FCM does not issue a token without one.
|
|
118
|
+
- **Google Play services.** They must be installed, enabled and up to date. On a China-only ROM without GMS, FCM cannot work at all — you need another push provider; see [Detecting a non-Google device](#detecting-a-non-google-device-getdiagnostics-and-pushsignalerror).
|
|
119
|
+
- **Network.** Check connectivity and disable VPN and private DNS.
|
|
120
|
+
- **MIUI / HyperOS.** Enable autostart and remove battery restrictions: Settings → Apps → your app → Autostart; Battery → No restrictions. Allow background data for the app.
|
|
121
|
+
|
|
122
|
+
What to look for in the logs:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
adb logcat | grep -iE "SERVICE_NOT_AVAILABLE|FirebaseMessaging|PushSignal"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Detecting a non-Google device: `getDiagnostics()` and `PushSignalError`
|
|
129
|
+
|
|
130
|
+
When Google Play services cannot serve FCM, the library detects it and tells you which service to use instead — both in the error message and as structured data, so the cause is visible in React Native logs.
|
|
131
|
+
|
|
132
|
+
`initialize()` and `getCredentials()` reject with `PushSignalError`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { getCredentials, PushSignalError } from 'react-native-push-signal';
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const credentials = await getCredentials();
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error instanceof PushSignalError) {
|
|
141
|
+
console.warn(error.code); // E_GMS_MISSING, E_FCM_TOKEN, ...
|
|
142
|
+
console.warn(error.message); // "... Use HMS Push Kit (Huawei Push) instead of the standard Google service."
|
|
143
|
+
console.warn(error.provider); // 'hms'
|
|
144
|
+
console.warn(error.hint); // actionable sentence
|
|
145
|
+
console.warn(error.diagnostics); // full device/provider snapshot
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
You can also inspect diagnostics without requesting a token:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { getDiagnostics } from 'react-native-push-signal';
|
|
154
|
+
|
|
155
|
+
const diagnostics = await getDiagnostics();
|
|
156
|
+
// { platform, gmsAvailable, gmsStatus, manufacturer, brand, model,
|
|
157
|
+
// provider, providerName, providerInstalled?, hint? }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Provider suggested when GMS is unavailable:
|
|
161
|
+
|
|
162
|
+
| Manufacturer | `provider` | Service |
|
|
163
|
+
| --------------------------- | ------------ | --------------------------------------- |
|
|
164
|
+
| HUAWEI / HONOR | `hms` | HMS Push Kit (Huawei Push) |
|
|
165
|
+
| Xiaomi / Redmi / POCO | `mi_push` | Mi Push (Xiaomi Push) |
|
|
166
|
+
| OPPO / OnePlus / realme | `oppo_push` | OPPO Push (HeyTap) |
|
|
167
|
+
| vivo / iQOO | `vivo_push` | vivo Push |
|
|
168
|
+
| Meizu | `meizu_push` | Meizu Push |
|
|
169
|
+
| anything else | `unknown` | generic “use another provider” |
|
|
170
|
+
|
|
171
|
+
`providerInstalled` is `true` only when the provider service app was positively found on the device (`com.huawei.hwid`, `com.xiaomi.xmsf`); otherwise it is omitted. iOS always reports `provider: 'apns'`. The library never logs for you — pass the data wherever you need.
|
|
172
|
+
|
|
173
|
+
Error codes: `E_GMS_MISSING`, `E_GMS_DISABLED`, `E_GMS_UPDATE_REQUIRED`, `E_GMS_INVALID`, `E_GMS_UNAVAILABLE`, `E_FCM_TOKEN`, `E_FIREBASE_CONFIG`, `E_NOT_INITIALIZED`.
|
|
174
|
+
|
|
111
175
|
## Incoming messages vs taps
|
|
112
176
|
|
|
113
177
|
| App state | iOS | Android (notification payload) | Android (data-only) |
|
package/README.ru.md
CHANGED
|
@@ -108,6 +108,70 @@ apply plugin: "com.google.gms.google-services"
|
|
|
108
108
|
|
|
109
109
|
Если в хост-приложении уже есть свой `FirebaseMessagingService`, обработать `com.google.firebase.MESSAGING_EVENT` может только один сервис. Оставьте сервис этой библиотеки или пробрасывайте события в него.
|
|
110
110
|
|
|
111
|
+
### Если не работает на Xiaomi: `SERVICE_NOT_AVAILABLE`
|
|
112
|
+
|
|
113
|
+
Если `getCredentials()` бросает `Failed to get an FCM token: SERVICE_NOT_AVAILABLE`, значит не удалось получить FCM-токен. Сервер не получает токен и слать пуши некуда — сама доставка здесь ни при чём.
|
|
114
|
+
|
|
115
|
+
Перед запросом токена библиотека проверяет Google Play services и делает несколько попыток с паузами, но часть причин лечится только на устройстве:
|
|
116
|
+
|
|
117
|
+
- **Google-аккаунт.** На устройстве должен быть выполнен вход в Google-аккаунт. Без него FCM токен не выдаёт.
|
|
118
|
+
- **Google Play services.** Должны быть установлены, включены и обновлены. На китайской прошивке без GMS FCM не заработает в принципе — нужен другой провайдер пушей; см. [Определение не‑Google устройства](#определение-неgoogle-устройства-getdiagnostics-и-pushsignalerror).
|
|
119
|
+
- **Сеть.** Проверьте интернет, отключите VPN и приватный DNS.
|
|
120
|
+
- **MIUI / HyperOS.** Включите автозапуск и снимите ограничения батареи: Настройки → Приложения → «ваше приложение» → Автозапуск; Батарея → Без ограничений. Разрешите приложению фоновые данные.
|
|
121
|
+
|
|
122
|
+
Что смотреть в логах:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
adb logcat | grep -iE "SERVICE_NOT_AVAILABLE|FirebaseMessaging|PushSignal"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Определение не‑Google устройства: `getDiagnostics()` и `PushSignalError`
|
|
129
|
+
|
|
130
|
+
Когда Google Play services не могут обслуживать FCM, библиотека это определяет и подсказывает, какой сервис использовать вместо стандартного — в тексте ошибки и в структурированном виде, чтобы причина была видна в логах React Native.
|
|
131
|
+
|
|
132
|
+
`initialize()` и `getCredentials()` отклоняются с `PushSignalError`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { getCredentials, PushSignalError } from 'react-native-push-signal';
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const credentials = await getCredentials();
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (error instanceof PushSignalError) {
|
|
141
|
+
console.warn(error.code); // E_GMS_MISSING, E_FCM_TOKEN, ...
|
|
142
|
+
console.warn(error.message); // "... Use HMS Push Kit (Huawei Push) instead of the standard Google service."
|
|
143
|
+
console.warn(error.provider); // 'hms'
|
|
144
|
+
console.warn(error.hint); // готовая подсказка
|
|
145
|
+
console.warn(error.diagnostics); // полный снимок устройства и провайдера
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Диагностику можно получить и без запроса токена:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { getDiagnostics } from 'react-native-push-signal';
|
|
154
|
+
|
|
155
|
+
const diagnostics = await getDiagnostics();
|
|
156
|
+
// { platform, gmsAvailable, gmsStatus, manufacturer, brand, model,
|
|
157
|
+
// provider, providerName, providerInstalled?, hint? }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Провайдер, который предлагается при недоступных GMS:
|
|
161
|
+
|
|
162
|
+
| Производитель | `provider` | Сервис |
|
|
163
|
+
| ------------------------ | ------------ | ---------------------------------- |
|
|
164
|
+
| HUAWEI / HONOR | `hms` | HMS Push Kit (Huawei Push) |
|
|
165
|
+
| Xiaomi / Redmi / POCO | `mi_push` | Mi Push (Xiaomi Push) |
|
|
166
|
+
| OPPO / OnePlus / realme | `oppo_push` | OPPO Push (HeyTap) |
|
|
167
|
+
| vivo / iQOO | `vivo_push` | vivo Push |
|
|
168
|
+
| Meizu | `meizu_push` | Meizu Push |
|
|
169
|
+
| остальные | `unknown` | общая подсказка «нужен другой» |
|
|
170
|
+
|
|
171
|
+
`providerInstalled` равно `true` только если сервис-приложение провайдера действительно найдено на устройстве (`com.huawei.hwid`, `com.xiaomi.xmsf`), иначе поле отсутствует. iOS всегда сообщает `provider: 'apns'`. Библиотека сама ничего не логирует — передавайте данные туда, куда нужно.
|
|
172
|
+
|
|
173
|
+
Коды ошибок: `E_GMS_MISSING`, `E_GMS_DISABLED`, `E_GMS_UPDATE_REQUIRED`, `E_GMS_INVALID`, `E_GMS_UNAVAILABLE`, `E_FCM_TOKEN`, `E_FIREBASE_CONFIG`, `E_NOT_INITIALIZED`.
|
|
174
|
+
|
|
111
175
|
## Входящее сообщение и тап
|
|
112
176
|
|
|
113
177
|
| Состояние | iOS | Android (notification payload) | Android (data-only) |
|
package/android/build.gradle
CHANGED
|
@@ -51,5 +51,6 @@ dependencies {
|
|
|
51
51
|
implementation "com.facebook.react:react-android"
|
|
52
52
|
implementation "androidx.activity:activity-ktx:1.10.1"
|
|
53
53
|
implementation "androidx.core:core-ktx:1.16.0"
|
|
54
|
+
implementation "com.google.android.gms:play-services-base:18.5.0"
|
|
54
55
|
implementation "com.google.firebase:firebase-messaging:24.1.2"
|
|
55
56
|
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
2
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
3
3
|
|
|
4
|
+
<!-- Android 11+ package visibility: lets isPackageInstalled() confirm an
|
|
5
|
+
alternative push provider on the device. -->
|
|
6
|
+
<queries>
|
|
7
|
+
<package android:name="com.huawei.hwid" />
|
|
8
|
+
<package android:name="com.xiaomi.xmsf" />
|
|
9
|
+
</queries>
|
|
10
|
+
|
|
4
11
|
<application>
|
|
5
12
|
<provider
|
|
6
13
|
android:name="com.pushsignal.PushSignalInitProvider"
|
|
@@ -13,3 +13,26 @@ data class AndroidFirebaseConfig(
|
|
|
13
13
|
val current_key: String?,
|
|
14
14
|
val project_number: String?,
|
|
15
15
|
)
|
|
16
|
+
|
|
17
|
+
data class PushDiagnostics(
|
|
18
|
+
val platform: String,
|
|
19
|
+
val gmsAvailable: Boolean,
|
|
20
|
+
val gmsStatus: Int,
|
|
21
|
+
val manufacturer: String,
|
|
22
|
+
val brand: String,
|
|
23
|
+
val model: String,
|
|
24
|
+
val provider: String,
|
|
25
|
+
val providerName: String,
|
|
26
|
+
val providerInstalled: Boolean?,
|
|
27
|
+
val hint: String?,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Carries a machine-readable [code] to JavaScript, so the host app can branch on
|
|
32
|
+
* the exact reason (missing GMS, disabled GMS, FCM token failure, ...).
|
|
33
|
+
*/
|
|
34
|
+
class PushSignalException(
|
|
35
|
+
val code: String,
|
|
36
|
+
message: String,
|
|
37
|
+
cause: Throwable? = null,
|
|
38
|
+
) : IllegalStateException(message, cause)
|
|
@@ -7,12 +7,16 @@ import android.app.NotificationManager
|
|
|
7
7
|
import android.app.PendingIntent
|
|
8
8
|
import android.content.Context
|
|
9
9
|
import android.content.Intent
|
|
10
|
+
import android.content.pm.PackageManager
|
|
10
11
|
import android.os.Build
|
|
11
12
|
import android.os.Bundle
|
|
12
13
|
import android.os.Handler
|
|
13
14
|
import android.os.Looper
|
|
15
|
+
import android.util.Log
|
|
14
16
|
import androidx.activity.ComponentActivity
|
|
15
17
|
import androidx.core.app.NotificationCompat
|
|
18
|
+
import com.google.android.gms.common.ConnectionResult
|
|
19
|
+
import com.google.android.gms.common.GoogleApiAvailability
|
|
16
20
|
import com.google.android.gms.tasks.Tasks
|
|
17
21
|
import com.google.firebase.FirebaseApp
|
|
18
22
|
import com.google.firebase.FirebaseOptions
|
|
@@ -22,10 +26,28 @@ import java.util.Collections
|
|
|
22
26
|
import java.util.UUID
|
|
23
27
|
import java.util.WeakHashMap
|
|
24
28
|
import java.util.concurrent.CopyOnWriteArrayList
|
|
29
|
+
import java.util.concurrent.TimeUnit
|
|
25
30
|
|
|
26
31
|
internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
32
|
+
private const val TAG = "PushSignal"
|
|
27
33
|
private const val EXTRA_HANDLED = "pushsignal.handled"
|
|
28
34
|
private const val CHANNEL_ID = "push_signal_default"
|
|
35
|
+
private const val TOKEN_TIMEOUT_SECONDS = 10L
|
|
36
|
+
private const val TOKEN_MAX_ATTEMPTS = 5
|
|
37
|
+
private const val TOKEN_INITIAL_RETRY_DELAY_MS = 1_000L
|
|
38
|
+
private const val TOKEN_MAX_RETRY_DELAY_MS = 8_000L
|
|
39
|
+
|
|
40
|
+
private const val PROVIDER_FCM = "fcm"
|
|
41
|
+
private const val PROVIDER_HMS = "hms"
|
|
42
|
+
private const val PROVIDER_MI_PUSH = "mi_push"
|
|
43
|
+
private const val PROVIDER_OPPO_PUSH = "oppo_push"
|
|
44
|
+
private const val PROVIDER_VIVO_PUSH = "vivo_push"
|
|
45
|
+
private const val PROVIDER_MEIZU_PUSH = "meizu_push"
|
|
46
|
+
private const val PROVIDER_UNKNOWN = "unknown"
|
|
47
|
+
|
|
48
|
+
/** Service apps used to positively confirm an alternative provider on the device. */
|
|
49
|
+
private const val PACKAGE_HMS = "com.huawei.hwid"
|
|
50
|
+
private const val PACKAGE_MI_PUSH = "com.xiaomi.xmsf"
|
|
29
51
|
|
|
30
52
|
private val lock = Any()
|
|
31
53
|
private val mainHandler = Handler(Looper.getMainLooper())
|
|
@@ -98,7 +120,9 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
98
120
|
|
|
99
121
|
fun fetchToken(): String {
|
|
100
122
|
val context = application
|
|
101
|
-
?: throw
|
|
123
|
+
?: throw PushSignalException("E_NOT_INITIALIZED", "PushSignal is not initialized")
|
|
124
|
+
|
|
125
|
+
ensurePlayServices(context)
|
|
102
126
|
|
|
103
127
|
try {
|
|
104
128
|
if (FirebaseApp.getApps(context).isEmpty()) {
|
|
@@ -106,29 +130,229 @@ internal object PushSignalCenter : Application.ActivityLifecycleCallbacks {
|
|
|
106
130
|
}
|
|
107
131
|
FirebaseApp.getInstance()
|
|
108
132
|
} catch (error: IllegalStateException) {
|
|
109
|
-
throw
|
|
133
|
+
throw PushSignalException(
|
|
134
|
+
"E_FIREBASE_CONFIG",
|
|
110
135
|
"Firebase is not configured. Call initialize({ project_id, mobilesdk_app_id, current_key, project_number }) or add google-services.json.",
|
|
111
136
|
error
|
|
112
137
|
)
|
|
113
138
|
}
|
|
114
139
|
|
|
115
|
-
val
|
|
116
|
-
val token = try {
|
|
117
|
-
Tasks.await(task)
|
|
118
|
-
} catch (error: Exception) {
|
|
119
|
-
throw IllegalStateException(
|
|
120
|
-
"Failed to get an FCM token. Call initialize({ project_id, mobilesdk_app_id, current_key, project_number }) or add google-services.json.",
|
|
121
|
-
error
|
|
122
|
-
)
|
|
123
|
-
}
|
|
140
|
+
val token = awaitTokenWithRetry(context)
|
|
124
141
|
|
|
125
142
|
if (token.isNullOrEmpty()) {
|
|
126
|
-
throw
|
|
143
|
+
throw PushSignalException("E_FCM_TOKEN", "Firebase returned an empty FCM token")
|
|
127
144
|
}
|
|
128
145
|
|
|
129
146
|
return token
|
|
130
147
|
}
|
|
131
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Fails fast with an actionable message when Google Play services cannot serve FCM
|
|
151
|
+
* (for example a China-only ROM without GMS). The message names the provider the
|
|
152
|
+
* device should use instead, so the cause is obvious in React Native logs.
|
|
153
|
+
*/
|
|
154
|
+
private fun ensurePlayServices(context: Context) {
|
|
155
|
+
val status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
|
|
156
|
+
if (status == ConnectionResult.SUCCESS) {
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
val code = when (status) {
|
|
161
|
+
ConnectionResult.SERVICE_MISSING -> "E_GMS_MISSING"
|
|
162
|
+
ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED -> "E_GMS_UPDATE_REQUIRED"
|
|
163
|
+
ConnectionResult.SERVICE_DISABLED -> "E_GMS_DISABLED"
|
|
164
|
+
ConnectionResult.SERVICE_INVALID -> "E_GMS_INVALID"
|
|
165
|
+
else -> "E_GMS_UNAVAILABLE"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
val reason = when (status) {
|
|
169
|
+
ConnectionResult.SERVICE_MISSING ->
|
|
170
|
+
"Google Play services are missing on this device, so the standard Google push service (FCM) cannot be used."
|
|
171
|
+
ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED ->
|
|
172
|
+
"Google Play services are outdated. Update them in the Play Store and try again."
|
|
173
|
+
ConnectionResult.SERVICE_DISABLED ->
|
|
174
|
+
"Google Play services are disabled. Enable them in the device settings and try again."
|
|
175
|
+
ConnectionResult.SERVICE_INVALID ->
|
|
176
|
+
"Google Play services are invalid or corrupted on this device. Reinstalling them usually helps."
|
|
177
|
+
else ->
|
|
178
|
+
"Google Play services are unavailable (code $status), so the standard Google push service (FCM) cannot be used."
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
val diagnostics = diagnose(context)
|
|
182
|
+
val message = listOfNotNull(reason, diagnostics.hint).joinToString(" ")
|
|
183
|
+
Log.w(TAG, "Play services check failed ($code): $message")
|
|
184
|
+
throw PushSignalException(code, message)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Collects device and provider diagnostics without throwing. Used both by the
|
|
189
|
+
* `getDiagnostics` API and to enrich errors with a concrete replacement service.
|
|
190
|
+
*/
|
|
191
|
+
fun diagnose(context: Context): PushDiagnostics {
|
|
192
|
+
val status = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context)
|
|
193
|
+
val gmsAvailable = status == ConnectionResult.SUCCESS
|
|
194
|
+
val provider = resolveProvider(context, gmsAvailable)
|
|
195
|
+
val hint = providerHint(provider, gmsAvailable)
|
|
196
|
+
|
|
197
|
+
return PushDiagnostics(
|
|
198
|
+
platform = "android_os",
|
|
199
|
+
gmsAvailable = gmsAvailable,
|
|
200
|
+
gmsStatus = status,
|
|
201
|
+
manufacturer = Build.MANUFACTURER ?: "",
|
|
202
|
+
brand = Build.BRAND ?: "",
|
|
203
|
+
model = Build.MODEL ?: "",
|
|
204
|
+
provider = provider.id,
|
|
205
|
+
providerName = provider.name,
|
|
206
|
+
providerInstalled = provider.installed,
|
|
207
|
+
hint = hint,
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private data class ProviderInfo(
|
|
212
|
+
val id: String,
|
|
213
|
+
val name: String,
|
|
214
|
+
val installed: Boolean?,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Picks the push provider this device should use. Checks the standard Google
|
|
219
|
+
* service first, then positively confirms an installed alternative, then falls
|
|
220
|
+
* back to the manufacturer mapping. Class reflection cannot see another
|
|
221
|
+
* provider's SDK unless the host bundles it, so package checks and the
|
|
222
|
+
* manufacturer are the reliable signals.
|
|
223
|
+
*/
|
|
224
|
+
private fun resolveProvider(context: Context, gmsAvailable: Boolean): ProviderInfo {
|
|
225
|
+
if (gmsAvailable) {
|
|
226
|
+
return ProviderInfo(PROVIDER_FCM, "Firebase Cloud Messaging (FCM)", true)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (isPackageInstalled(context, PACKAGE_HMS)) {
|
|
230
|
+
return ProviderInfo(PROVIDER_HMS, "HMS Push Kit (Huawei Push)", true)
|
|
231
|
+
}
|
|
232
|
+
if (isPackageInstalled(context, PACKAGE_MI_PUSH)) {
|
|
233
|
+
return ProviderInfo(PROVIDER_MI_PUSH, "Mi Push (Xiaomi Push)", true)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
val keys = setOf(Build.MANUFACTURER, Build.BRAND)
|
|
237
|
+
.filterNotNull()
|
|
238
|
+
.map { it.uppercase() }
|
|
239
|
+
|
|
240
|
+
return when {
|
|
241
|
+
keys.any { it.contains("HUAWEI") || it.contains("HONOR") } ->
|
|
242
|
+
ProviderInfo(PROVIDER_HMS, "HMS Push Kit (Huawei Push)", false)
|
|
243
|
+
keys.any { it.contains("XIAOMI") || it.contains("REDMI") || it.contains("POCO") } ->
|
|
244
|
+
ProviderInfo(PROVIDER_MI_PUSH, "Mi Push (Xiaomi Push)", false)
|
|
245
|
+
keys.any { it.contains("OPPO") || it.contains("ONEPLUS") || it.contains("REALME") } ->
|
|
246
|
+
ProviderInfo(PROVIDER_OPPO_PUSH, "OPPO Push (HeyTap)", false)
|
|
247
|
+
keys.any { it.contains("VIVO") || it.contains("IQOO") } ->
|
|
248
|
+
ProviderInfo(PROVIDER_VIVO_PUSH, "vivo Push", false)
|
|
249
|
+
keys.any { it.contains("MEIZU") } ->
|
|
250
|
+
ProviderInfo(PROVIDER_MEIZU_PUSH, "Meizu Push", false)
|
|
251
|
+
else ->
|
|
252
|
+
ProviderInfo(PROVIDER_UNKNOWN, "unknown", null)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private fun providerHint(provider: ProviderInfo, gmsAvailable: Boolean): String? {
|
|
257
|
+
if (gmsAvailable) {
|
|
258
|
+
return null
|
|
259
|
+
}
|
|
260
|
+
val device = listOfNotNull(Build.MANUFACTURER, Build.BRAND)
|
|
261
|
+
.filter { it.isNotBlank() }
|
|
262
|
+
.distinct()
|
|
263
|
+
.joinToString("/")
|
|
264
|
+
|
|
265
|
+
return when (provider.id) {
|
|
266
|
+
PROVIDER_HMS ->
|
|
267
|
+
"This device ($device) has no usable Google Play services, so FCM will not issue a token. Use HMS Push Kit (Huawei Push) instead of the standard Google service."
|
|
268
|
+
PROVIDER_MI_PUSH ->
|
|
269
|
+
"This device ($device) has no usable Google Play services, so FCM will not issue a token. Use Mi Push (Xiaomi Push) instead of the standard Google service."
|
|
270
|
+
PROVIDER_OPPO_PUSH ->
|
|
271
|
+
"This device ($device) has no usable Google Play services, so FCM will not issue a token. Use OPPO Push (HeyTap) instead of the standard Google service."
|
|
272
|
+
PROVIDER_VIVO_PUSH ->
|
|
273
|
+
"This device ($device) has no usable Google Play services, so FCM will not issue a token. Use vivo Push instead of the standard Google service."
|
|
274
|
+
PROVIDER_MEIZU_PUSH ->
|
|
275
|
+
"This device ($device) has no usable Google Play services, so FCM will not issue a token. Use Meizu Push instead of the standard Google service."
|
|
276
|
+
else ->
|
|
277
|
+
"No usable Google Play services were found and no known push provider was detected on this ROM, so FCM cannot be used. Integrate another push provider (HMS, Mi Push, OPPO/vivo/Meizu Push)."
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private fun isPackageInstalled(context: Context, packageName: String): Boolean {
|
|
282
|
+
return try {
|
|
283
|
+
context.packageManager.getPackageInfo(packageName, 0)
|
|
284
|
+
true
|
|
285
|
+
} catch (_: PackageManager.NameNotFoundException) {
|
|
286
|
+
false
|
|
287
|
+
} catch (_: Exception) {
|
|
288
|
+
false
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* FCM returns SERVICE_NOT_AVAILABLE for transient conditions (no Google account yet,
|
|
294
|
+
* Play services still starting, flaky network). Xiaomi/MIUI devices hit this often,
|
|
295
|
+
* so retry with backoff before surfacing the failure.
|
|
296
|
+
*/
|
|
297
|
+
private fun awaitTokenWithRetry(context: Context): String? {
|
|
298
|
+
var delayMs = TOKEN_INITIAL_RETRY_DELAY_MS
|
|
299
|
+
var lastError: Exception? = null
|
|
300
|
+
|
|
301
|
+
for (attempt in 1..TOKEN_MAX_ATTEMPTS) {
|
|
302
|
+
try {
|
|
303
|
+
return Tasks.await(
|
|
304
|
+
FirebaseMessaging.getInstance().token,
|
|
305
|
+
TOKEN_TIMEOUT_SECONDS,
|
|
306
|
+
TimeUnit.SECONDS
|
|
307
|
+
)
|
|
308
|
+
} catch (error: Exception) {
|
|
309
|
+
lastError = error
|
|
310
|
+
if (attempt == TOKEN_MAX_ATTEMPTS || !isRetryableTokenError(error)) {
|
|
311
|
+
break
|
|
312
|
+
}
|
|
313
|
+
Log.w(TAG, "FCM token attempt $attempt/$TOKEN_MAX_ATTEMPTS failed: ${error.message}. Retrying in ${delayMs}ms")
|
|
314
|
+
try {
|
|
315
|
+
Thread.sleep(delayMs)
|
|
316
|
+
} catch (_: InterruptedException) {
|
|
317
|
+
Thread.currentThread().interrupt()
|
|
318
|
+
break
|
|
319
|
+
}
|
|
320
|
+
delayMs = (delayMs * 2).coerceAtMost(TOKEN_MAX_RETRY_DELAY_MS)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
val cause = lastError
|
|
325
|
+
val diagnostics = diagnose(context)
|
|
326
|
+
val message = listOfNotNull(
|
|
327
|
+
"Failed to get an FCM token: ${cause?.message ?: "unknown error"}.",
|
|
328
|
+
"Make sure the device is signed into a Google account, Google Play services are up to date, " +
|
|
329
|
+
"and the app is allowed to use background data.",
|
|
330
|
+
"Call initialize({ project_id, mobilesdk_app_id, current_key, project_number }) or add google-services.json.",
|
|
331
|
+
diagnostics.hint,
|
|
332
|
+
).joinToString(" ")
|
|
333
|
+
Log.w(TAG, "Failed to get an FCM token: $message")
|
|
334
|
+
throw PushSignalException("E_FCM_TOKEN", message, cause)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private fun isRetryableTokenError(error: Throwable): Boolean {
|
|
338
|
+
var current: Throwable? = error
|
|
339
|
+
while (current != null) {
|
|
340
|
+
if (current is java.io.IOException || current is java.util.concurrent.TimeoutException) {
|
|
341
|
+
return true
|
|
342
|
+
}
|
|
343
|
+
val message = current.message?.uppercase() ?: ""
|
|
344
|
+
if (
|
|
345
|
+
message.contains("SERVICE_NOT_AVAILABLE") ||
|
|
346
|
+
message.contains("TIMEOUT") ||
|
|
347
|
+
message.contains("INTERNAL_SERVER_ERROR")
|
|
348
|
+
) {
|
|
349
|
+
return true
|
|
350
|
+
}
|
|
351
|
+
current = current.cause
|
|
352
|
+
}
|
|
353
|
+
return false
|
|
354
|
+
}
|
|
355
|
+
|
|
132
356
|
fun emitMessage(remoteMessage: RemoteMessage) {
|
|
133
357
|
val message = remoteMessage.toPushMessage()
|
|
134
358
|
runOnMain { deliverMessage(message) }
|
|
@@ -26,7 +26,8 @@ class PushSignalModule(reactContext: ReactApplicationContext) :
|
|
|
26
26
|
if (error == null) {
|
|
27
27
|
promise.resolve(null)
|
|
28
28
|
} else {
|
|
29
|
-
|
|
29
|
+
val code = (error as? PushSignalException)?.code ?: "E_INIT"
|
|
30
|
+
promise.reject(code, error.message, error)
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -42,7 +43,19 @@ class PushSignalModule(reactContext: ReactApplicationContext) :
|
|
|
42
43
|
}
|
|
43
44
|
promise.resolve(result)
|
|
44
45
|
} catch (error: Exception) {
|
|
45
|
-
|
|
46
|
+
val code = (error as? PushSignalException)?.code ?: "E_CREDENTIALS"
|
|
47
|
+
promise.reject(code, error.message, error)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
override fun getDiagnostics(promise: Promise) {
|
|
53
|
+
executor.execute {
|
|
54
|
+
try {
|
|
55
|
+
PushSignalCenter.attach(reactApplicationContext)
|
|
56
|
+
promise.resolve(PushSignalCenter.diagnose(reactApplicationContext).toWritableMap())
|
|
57
|
+
} catch (error: Exception) {
|
|
58
|
+
promise.reject("E_DIAGNOSTICS", error.message, error)
|
|
46
59
|
}
|
|
47
60
|
}
|
|
48
61
|
}
|
|
@@ -86,3 +99,18 @@ private fun PushMessage.toWritableMap(): WritableMap {
|
|
|
86
99
|
map.putMap("data", dataMap)
|
|
87
100
|
return map
|
|
88
101
|
}
|
|
102
|
+
|
|
103
|
+
private fun PushDiagnostics.toWritableMap(): WritableMap {
|
|
104
|
+
val map = Arguments.createMap()
|
|
105
|
+
map.putString("platform", platform)
|
|
106
|
+
map.putBoolean("gmsAvailable", gmsAvailable)
|
|
107
|
+
map.putInt("gmsStatus", gmsStatus)
|
|
108
|
+
map.putString("manufacturer", manufacturer)
|
|
109
|
+
map.putString("brand", brand)
|
|
110
|
+
map.putString("model", model)
|
|
111
|
+
map.putString("provider", provider)
|
|
112
|
+
map.putString("providerName", providerName)
|
|
113
|
+
providerInstalled?.let { map.putBoolean("providerInstalled", it) }
|
|
114
|
+
hint?.let { map.putString("hint", it) }
|
|
115
|
+
return map
|
|
116
|
+
}
|
package/ios/PushSignal.mm
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#import "PushSignal.h"
|
|
2
2
|
#import "PushSignalCenter.h"
|
|
3
|
+
#import <UIKit/UIKit.h>
|
|
3
4
|
|
|
4
5
|
@implementation PushSignal {
|
|
5
6
|
BOOL _listening;
|
|
@@ -22,6 +23,23 @@
|
|
|
22
23
|
}];
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
- (void)getDiagnostics:(RCTPromiseResolveBlock)resolve
|
|
27
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
28
|
+
(void)reject;
|
|
29
|
+
UIDevice *device = [UIDevice currentDevice];
|
|
30
|
+
resolve(@{
|
|
31
|
+
@"platform": @"ios",
|
|
32
|
+
@"gmsAvailable": @YES,
|
|
33
|
+
@"gmsStatus": @0,
|
|
34
|
+
@"manufacturer": @"Apple",
|
|
35
|
+
@"brand": @"Apple",
|
|
36
|
+
@"model": device.model ?: @"iOS device",
|
|
37
|
+
@"provider": @"apns",
|
|
38
|
+
@"providerName": @"Apple Push Notification service (APNs)",
|
|
39
|
+
@"providerInstalled": @YES,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
25
43
|
- (void)startListening {
|
|
26
44
|
if (_listening) {
|
|
27
45
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativePushSignal.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativePushSignal.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AA2ClD,eAAeA,mBAAmB,CAACC,YAAY,CAAO,YAAY,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown by `initialize` and `getCredentials`.
|
|
5
|
+
*
|
|
6
|
+
* The message already contains a human-readable, actionable hint when the
|
|
7
|
+
* standard Google service (FCM/GMS) cannot be used. Structured details are
|
|
8
|
+
* available on the instance so the host app can decide how to log or report them.
|
|
9
|
+
*/
|
|
10
|
+
export class PushSignalError extends Error {
|
|
11
|
+
/** Machine-readable code, e.g. `E_GMS_MISSING` or `E_FCM_TOKEN`. */
|
|
12
|
+
|
|
13
|
+
/** Suggested alternative push provider, when the standard service is unusable. */
|
|
14
|
+
|
|
15
|
+
/** Actionable sentence: which service to use instead of the standard one. */
|
|
16
|
+
|
|
17
|
+
/** Full device/provider diagnostics if they could be collected. */
|
|
18
|
+
|
|
19
|
+
/** Original error from the native layer. */
|
|
20
|
+
|
|
21
|
+
constructor(code, message, cause) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = 'PushSignalError';
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.cause = cause;
|
|
26
|
+
Object.setPrototypeOf(this, PushSignalError.prototype);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=PushSignalError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["PushSignalError","Error","constructor","code","message","cause","name","Object","setPrototypeOf","prototype"],"sourceRoot":"../../src","sources":["PushSignalError.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMA,eAAe,SAASC,KAAK,CAAC;EACzC;;EAEA;;EAEA;;EAEA;;EAEA;;EAGAC,WAAWA,CAACC,IAAY,EAAEC,OAAe,EAAEC,KAAe,EAAE;IAC1D,KAAK,CAACD,OAAO,CAAC;IACd,IAAI,CAACE,IAAI,GAAG,iBAAiB;IAC7B,IAAI,CAACH,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACE,KAAK,GAAGA,KAAK;IAClBE,MAAM,CAACC,cAAc,CAAC,IAAI,EAAER,eAAe,CAACS,SAAS,CAAC;EACxD;AACF","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { PushSignalError } from "./PushSignalError.js";
|
|
4
|
+
export { getCredentials, getDiagnostics, initialize, onMessage, onNotificationPress } from './pushSignal';
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["getCredentials","initialize","onMessage","onNotificationPress"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"names":["PushSignalError","getCredentials","getDiagnostics","initialize","onMessage","onNotificationPress"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAUA,SAASA,eAAe,QAAQ,sBAAmB;AACnD,SACEC,cAAc,EACdC,cAAc,EACdC,UAAU,EACVC,SAAS,EACTC,mBAAmB,QACd,cAAc","ignoreList":[]}
|
package/lib/module/pushSignal.js
CHANGED
|
@@ -4,6 +4,9 @@ export async function initialize(_config = {}) {}
|
|
|
4
4
|
export async function getCredentials() {
|
|
5
5
|
throw new Error('Push credentials are not supported on web');
|
|
6
6
|
}
|
|
7
|
+
export async function getDiagnostics() {
|
|
8
|
+
throw new Error('Push diagnostics are not supported on web');
|
|
9
|
+
}
|
|
7
10
|
export function onMessage(_listener) {
|
|
8
11
|
return () => {};
|
|
9
12
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["initialize","_config","getCredentials","Error","onMessage","_listener","onNotificationPress"],"sourceRoot":"../../src","sources":["pushSignal.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"names":["initialize","_config","getCredentials","Error","getDiagnostics","onMessage","_listener","onNotificationPress"],"sourceRoot":"../../src","sources":["pushSignal.tsx"],"mappings":";;AAQA,OAAO,eAAeA,UAAUA,CAC9BC,OAA8B,GAAG,CAAC,CAAC,EACpB,CAAC;AAElB,OAAO,eAAeC,cAAcA,CAAA,EAA6B;EAC/D,MAAM,IAAIC,KAAK,CAAC,2CAA2C,CAAC;AAC9D;AAEA,OAAO,eAAeC,cAAcA,CAAA,EAA6B;EAC/D,MAAM,IAAID,KAAK,CAAC,2CAA2C,CAAC;AAC9D;AAEA,OAAO,SAASE,SAASA,CAACC,SAA4B,EAAc;EAClE,OAAO,MAAM,CAAC,CAAC;AACjB;AAEA,OAAO,SAASC,mBAAmBA,CACjCD,SAAyC,EAC7B;EACZ,OAAO,MAAM,CAAC,CAAC;AACjB","ignoreList":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import NativePushSignal from "./NativePushSignal.js";
|
|
4
|
+
import { PushSignalError } from "./PushSignalError.js";
|
|
4
5
|
const messageListeners = new Set();
|
|
5
6
|
const pressListeners = new Set();
|
|
6
7
|
let nativeCallbacksBound = false;
|
|
@@ -28,6 +29,40 @@ function normalizeCredentials(raw) {
|
|
|
28
29
|
environment: raw.environment
|
|
29
30
|
};
|
|
30
31
|
}
|
|
32
|
+
function normalizeDiagnostics(raw) {
|
|
33
|
+
return {
|
|
34
|
+
platform: raw.platform,
|
|
35
|
+
gmsAvailable: raw.gmsAvailable,
|
|
36
|
+
gmsStatus: raw.gmsStatus,
|
|
37
|
+
manufacturer: raw.manufacturer,
|
|
38
|
+
brand: raw.brand,
|
|
39
|
+
model: raw.model,
|
|
40
|
+
provider: raw.provider,
|
|
41
|
+
providerName: raw.providerName,
|
|
42
|
+
providerInstalled: raw.providerInstalled ?? undefined,
|
|
43
|
+
hint: raw.hint ?? undefined
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function toPushSignalError(error, fallbackCode) {
|
|
47
|
+
const candidate = error;
|
|
48
|
+
return new PushSignalError(candidate?.code ?? fallbackCode, candidate?.message ?? 'PushSignal request failed', error);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Attaches structured diagnostics to an error on a best-effort basis. Failing to
|
|
53
|
+
* collect them must never hide the original, already actionable error.
|
|
54
|
+
*/
|
|
55
|
+
async function enrichError(error) {
|
|
56
|
+
try {
|
|
57
|
+
const diagnostics = normalizeDiagnostics(await NativePushSignal.getDiagnostics());
|
|
58
|
+
error.diagnostics = diagnostics;
|
|
59
|
+
error.provider = diagnostics.provider;
|
|
60
|
+
error.hint = diagnostics.hint;
|
|
61
|
+
} catch {
|
|
62
|
+
// Diagnostics are optional; keep the original error.
|
|
63
|
+
}
|
|
64
|
+
return error;
|
|
65
|
+
}
|
|
31
66
|
function bindNativeCallbacks() {
|
|
32
67
|
if (nativeCallbacksBound) {
|
|
33
68
|
return;
|
|
@@ -49,11 +84,23 @@ function bindNativeCallbacks() {
|
|
|
49
84
|
});
|
|
50
85
|
NativePushSignal.startListening();
|
|
51
86
|
}
|
|
52
|
-
export function initialize(config = {}) {
|
|
53
|
-
|
|
87
|
+
export async function initialize(config = {}) {
|
|
88
|
+
try {
|
|
89
|
+
await NativePushSignal.initialize(config);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw await enrichError(toPushSignalError(error, 'E_INIT'));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export async function getCredentials() {
|
|
95
|
+
try {
|
|
96
|
+
const raw = await NativePushSignal.getCredentials();
|
|
97
|
+
return normalizeCredentials(raw);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
throw await enrichError(toPushSignalError(error, 'E_CREDENTIALS'));
|
|
100
|
+
}
|
|
54
101
|
}
|
|
55
|
-
export function
|
|
56
|
-
return NativePushSignal.
|
|
102
|
+
export async function getDiagnostics() {
|
|
103
|
+
return normalizeDiagnostics(await NativePushSignal.getDiagnostics());
|
|
57
104
|
}
|
|
58
105
|
export function onMessage(listener) {
|
|
59
106
|
bindNativeCallbacks();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativePushSignal","messageListeners","Set","pressListeners","nativeCallbacksBound","normalizeMessage","raw","data","key","value","Object","entries","String","id","title","body","normalizeCredentials","platform","token","environment","
|
|
1
|
+
{"version":3,"names":["NativePushSignal","PushSignalError","messageListeners","Set","pressListeners","nativeCallbacksBound","normalizeMessage","raw","data","key","value","Object","entries","String","id","title","body","normalizeCredentials","platform","token","environment","normalizeDiagnostics","gmsAvailable","gmsStatus","manufacturer","brand","model","provider","providerName","providerInstalled","undefined","hint","toPushSignalError","error","fallbackCode","candidate","code","message","enrichError","diagnostics","getDiagnostics","bindNativeCallbacks","onMessage","listener","Promise","resolve","then","onNotificationPress","forEach","startListening","initialize","config","getCredentials","add","delete"],"sourceRoot":"../../src","sources":["pushSignal.native.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -10,9 +10,28 @@ export type NativePushCredentials = {
|
|
|
10
10
|
token: string;
|
|
11
11
|
environment?: string;
|
|
12
12
|
};
|
|
13
|
+
export type NativePushDiagnostics = {
|
|
14
|
+
platform: string;
|
|
15
|
+
/** True when Google Play services can serve FCM; false on a ROM without GMS. */
|
|
16
|
+
gmsAvailable: boolean;
|
|
17
|
+
/** Raw GoogleApiAvailability status code. 0 means SUCCESS. */
|
|
18
|
+
gmsStatus: number;
|
|
19
|
+
manufacturer: string;
|
|
20
|
+
brand: string;
|
|
21
|
+
model: string;
|
|
22
|
+
/** Machine-readable provider id: fcm, hms, mi_push, oppo_push, vivo_push, meizu_push, apns, unknown. */
|
|
23
|
+
provider: string;
|
|
24
|
+
/** Human-readable provider name, e.g. "HMS Push Kit". */
|
|
25
|
+
providerName: string;
|
|
26
|
+
/** True when the provider service app was found on the device. */
|
|
27
|
+
providerInstalled: boolean;
|
|
28
|
+
/** Actionable sentence explaining which service to use instead of the standard one. */
|
|
29
|
+
hint?: string;
|
|
30
|
+
};
|
|
13
31
|
export interface Spec extends TurboModule {
|
|
14
32
|
initialize(config: Object): Promise<void>;
|
|
15
33
|
getCredentials(): Promise<NativePushCredentials>;
|
|
34
|
+
getDiagnostics(): Promise<NativePushDiagnostics>;
|
|
16
35
|
startListening(): void;
|
|
17
36
|
readonly onMessage: CodegenTypes.EventEmitter<NativePushMessage>;
|
|
18
37
|
readonly onNotificationPress: CodegenTypes.EventEmitter<NativePushMessage>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativePushSignal.d.ts","sourceRoot":"","sources":["../../../src/NativePushSignal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjD,cAAc,IAAI,IAAI,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IACjE,QAAQ,CAAC,mBAAmB,EAAE,YAAY,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;CAC5E;;AAED,wBAAoE"}
|
|
1
|
+
{"version":3,"file":"NativePushSignal.d.ts","sourceRoot":"","sources":["../../../src/NativePushSignal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,gFAAgF;IAChF,YAAY,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,wGAAwG;IACxG,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,kEAAkE;IAClE,iBAAiB,EAAE,OAAO,CAAC;IAC3B,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,cAAc,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjD,cAAc,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACjD,cAAc,IAAI,IAAI,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;IACjE,QAAQ,CAAC,mBAAmB,EAAE,YAAY,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;CAC5E;;AAED,wBAAoE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PushDiagnostics, PushProvider } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown by `initialize` and `getCredentials`.
|
|
4
|
+
*
|
|
5
|
+
* The message already contains a human-readable, actionable hint when the
|
|
6
|
+
* standard Google service (FCM/GMS) cannot be used. Structured details are
|
|
7
|
+
* available on the instance so the host app can decide how to log or report them.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PushSignalError extends Error {
|
|
10
|
+
/** Machine-readable code, e.g. `E_GMS_MISSING` or `E_FCM_TOKEN`. */
|
|
11
|
+
readonly code: string;
|
|
12
|
+
/** Suggested alternative push provider, when the standard service is unusable. */
|
|
13
|
+
provider?: PushProvider;
|
|
14
|
+
/** Actionable sentence: which service to use instead of the standard one. */
|
|
15
|
+
hint?: string;
|
|
16
|
+
/** Full device/provider diagnostics if they could be collected. */
|
|
17
|
+
diagnostics?: PushDiagnostics;
|
|
18
|
+
/** Original error from the native layer. */
|
|
19
|
+
readonly cause?: unknown;
|
|
20
|
+
constructor(code: string, message: string, cause?: unknown);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=PushSignalError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PushSignalError.d.ts","sourceRoot":"","sources":["../../../src/PushSignalError.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAS,CAAC;AAE7D;;;;;;GAMG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,4CAA4C;IAC5C,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEtB,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAO3D"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export type { AndroidFirebaseConfig, OnMessageListener, PushCredentials, PushEnvironment, PushMessage, PushPlatform, } from './types.js';
|
|
2
|
-
export {
|
|
1
|
+
export type { AndroidFirebaseConfig, OnMessageListener, PushCredentials, PushDiagnostics, PushEnvironment, PushMessage, PushPlatform, PushProvider, } from './types.js';
|
|
2
|
+
export { PushSignalError } from './PushSignalError.js';
|
|
3
|
+
export { getCredentials, getDiagnostics, initialize, onMessage, onNotificationPress, } from './pushSignal';
|
|
3
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,YAAS,CAAC;AACjB,OAAO,EACL,cAAc,EACd,UAAU,EACV,SAAS,EACT,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,YAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAmB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,cAAc,EACd,UAAU,EACV,SAAS,EACT,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { AndroidFirebaseConfig, OnMessageListener, PushCredentials, PushMessage } from './types.js';
|
|
1
|
+
import type { AndroidFirebaseConfig, OnMessageListener, PushCredentials, PushDiagnostics, PushMessage } from './types.js';
|
|
2
2
|
export declare function initialize(_config?: AndroidFirebaseConfig): Promise<void>;
|
|
3
3
|
export declare function getCredentials(): Promise<PushCredentials>;
|
|
4
|
+
export declare function getDiagnostics(): Promise<PushDiagnostics>;
|
|
4
5
|
export declare function onMessage(_listener: OnMessageListener): () => void;
|
|
5
6
|
export declare function onNotificationPress(_listener: (message: PushMessage) => void): () => void;
|
|
6
7
|
//# sourceMappingURL=pushSignal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pushSignal.d.ts","sourceRoot":"","sources":["../../../src/pushSignal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACZ,MAAM,YAAS,CAAC;AAEjB,wBAAsB,UAAU,CAC9B,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAAG;AAEnB,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CAE/D;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAElE;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GACxC,MAAM,IAAI,CAEZ"}
|
|
1
|
+
{"version":3,"file":"pushSignal.d.ts","sourceRoot":"","sources":["../../../src/pushSignal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,WAAW,EACZ,MAAM,YAAS,CAAC;AAEjB,wBAAsB,UAAU,CAC9B,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAAG;AAEnB,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CAE/D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CAE/D;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAElE;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GACxC,MAAM,IAAI,CAEZ"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { AndroidFirebaseConfig, OnMessageListener, PushCredentials, PushMessage } from './types.js';
|
|
1
|
+
import type { AndroidFirebaseConfig, OnMessageListener, PushCredentials, PushDiagnostics, PushMessage } from './types.js';
|
|
2
2
|
export declare function initialize(config?: AndroidFirebaseConfig): Promise<void>;
|
|
3
3
|
export declare function getCredentials(): Promise<PushCredentials>;
|
|
4
|
+
export declare function getDiagnostics(): Promise<PushDiagnostics>;
|
|
4
5
|
export declare function onMessage(listener: OnMessageListener): () => void;
|
|
5
6
|
export declare function onNotificationPress(listener: (message: PushMessage) => void): () => void;
|
|
6
7
|
//# sourceMappingURL=pushSignal.native.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pushSignal.native.d.ts","sourceRoot":"","sources":["../../../src/pushSignal.native.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pushSignal.native.d.ts","sourceRoot":"","sources":["../../../src/pushSignal.native.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,eAAe,EAEf,WAAW,EAGZ,MAAM,YAAS,CAAC;AAsHjB,wBAAsB,UAAU,CAC9B,MAAM,GAAE,qBAA0B,GACjC,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CAO/D;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC,CAE/D;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAMjE;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GACvC,MAAM,IAAI,CAMZ"}
|
|
@@ -13,6 +13,24 @@ export interface PushMessage {
|
|
|
13
13
|
data: Record<string, string>;
|
|
14
14
|
}
|
|
15
15
|
export type OnMessageListener = (message: PushMessage) => void | Promise<void>;
|
|
16
|
+
export type PushProvider = 'fcm' | 'hms' | 'mi_push' | 'oppo_push' | 'vivo_push' | 'meizu_push' | 'apns' | 'unknown';
|
|
17
|
+
export interface PushDiagnostics {
|
|
18
|
+
platform: PushPlatform;
|
|
19
|
+
/** True when Google Play services can serve FCM; false on a ROM without GMS. */
|
|
20
|
+
gmsAvailable: boolean;
|
|
21
|
+
/** Raw GoogleApiAvailability status code. 0 means SUCCESS. */
|
|
22
|
+
gmsStatus: number;
|
|
23
|
+
manufacturer: string;
|
|
24
|
+
brand: string;
|
|
25
|
+
model: string;
|
|
26
|
+
provider: PushProvider;
|
|
27
|
+
/** Human-readable provider name, e.g. "HMS Push Kit". */
|
|
28
|
+
providerName: string;
|
|
29
|
+
/** True only when the provider service app was positively found on the device. */
|
|
30
|
+
providerInstalled?: boolean;
|
|
31
|
+
/** Actionable sentence explaining which service to use instead of the standard one. */
|
|
32
|
+
hint?: string;
|
|
33
|
+
}
|
|
16
34
|
export interface AndroidFirebaseConfig {
|
|
17
35
|
project_id?: string;
|
|
18
36
|
mobilesdk_app_id?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,YAAY,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,YAAY,CAAC;AAEvD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE/E,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,YAAY,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,YAAY,CAAC;AAEvD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE/E,MAAM,MAAM,YAAY,GACpB,KAAK,GACL,KAAK,GACL,SAAS,GACT,WAAW,GACX,WAAW,GACX,YAAY,GACZ,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,gFAAgF;IAChF,YAAY,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,yDAAyD;IACzD,YAAY,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-push-signal",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.10",
|
|
4
|
+
"description": "React Native push notifications with direct APNs and FCM integration — get device tokens for your server and listen for incoming messages and taps",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -45,18 +45,28 @@
|
|
|
45
45
|
"keywords": [
|
|
46
46
|
"react-native",
|
|
47
47
|
"ios",
|
|
48
|
-
"android"
|
|
48
|
+
"android",
|
|
49
|
+
"push",
|
|
50
|
+
"push-notifications",
|
|
51
|
+
"notifications",
|
|
52
|
+
"apns",
|
|
53
|
+
"fcm",
|
|
54
|
+
"firebase",
|
|
55
|
+
"firebase-cloud-messaging",
|
|
56
|
+
"device-token",
|
|
57
|
+
"push-token",
|
|
58
|
+
"remote-notifications"
|
|
49
59
|
],
|
|
50
60
|
"repository": {
|
|
51
61
|
"type": "git",
|
|
52
|
-
"url": "git+https://
|
|
62
|
+
"url": "git+https://github.com/AntonSeagull/react-native-push-signal.git"
|
|
53
63
|
},
|
|
54
64
|
"author": "AntonSeagull <hi@antonseagull.com> (https://antonseagull.com)",
|
|
55
65
|
"license": "MIT",
|
|
56
66
|
"bugs": {
|
|
57
|
-
"url": "https://
|
|
67
|
+
"url": "https://github.com/AntonSeagull/react-native-push-signal/issues"
|
|
58
68
|
},
|
|
59
|
-
"homepage": "https://
|
|
69
|
+
"homepage": "https://github.com/AntonSeagull/react-native-push-signal#readme",
|
|
60
70
|
"publishConfig": {
|
|
61
71
|
"registry": "https://registry.npmjs.org/"
|
|
62
72
|
},
|
package/src/NativePushSignal.ts
CHANGED
|
@@ -14,9 +14,29 @@ export type NativePushCredentials = {
|
|
|
14
14
|
environment?: string;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
export type NativePushDiagnostics = {
|
|
18
|
+
platform: string;
|
|
19
|
+
/** True when Google Play services can serve FCM; false on a ROM without GMS. */
|
|
20
|
+
gmsAvailable: boolean;
|
|
21
|
+
/** Raw GoogleApiAvailability status code. 0 means SUCCESS. */
|
|
22
|
+
gmsStatus: number;
|
|
23
|
+
manufacturer: string;
|
|
24
|
+
brand: string;
|
|
25
|
+
model: string;
|
|
26
|
+
/** Machine-readable provider id: fcm, hms, mi_push, oppo_push, vivo_push, meizu_push, apns, unknown. */
|
|
27
|
+
provider: string;
|
|
28
|
+
/** Human-readable provider name, e.g. "HMS Push Kit". */
|
|
29
|
+
providerName: string;
|
|
30
|
+
/** True when the provider service app was found on the device. */
|
|
31
|
+
providerInstalled: boolean;
|
|
32
|
+
/** Actionable sentence explaining which service to use instead of the standard one. */
|
|
33
|
+
hint?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
17
36
|
export interface Spec extends TurboModule {
|
|
18
37
|
initialize(config: Object): Promise<void>;
|
|
19
38
|
getCredentials(): Promise<NativePushCredentials>;
|
|
39
|
+
getDiagnostics(): Promise<NativePushDiagnostics>;
|
|
20
40
|
startListening(): void;
|
|
21
41
|
readonly onMessage: CodegenTypes.EventEmitter<NativePushMessage>;
|
|
22
42
|
readonly onNotificationPress: CodegenTypes.EventEmitter<NativePushMessage>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PushDiagnostics, PushProvider } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error thrown by `initialize` and `getCredentials`.
|
|
5
|
+
*
|
|
6
|
+
* The message already contains a human-readable, actionable hint when the
|
|
7
|
+
* standard Google service (FCM/GMS) cannot be used. Structured details are
|
|
8
|
+
* available on the instance so the host app can decide how to log or report them.
|
|
9
|
+
*/
|
|
10
|
+
export class PushSignalError extends Error {
|
|
11
|
+
/** Machine-readable code, e.g. `E_GMS_MISSING` or `E_FCM_TOKEN`. */
|
|
12
|
+
readonly code: string;
|
|
13
|
+
/** Suggested alternative push provider, when the standard service is unusable. */
|
|
14
|
+
provider?: PushProvider;
|
|
15
|
+
/** Actionable sentence: which service to use instead of the standard one. */
|
|
16
|
+
hint?: string;
|
|
17
|
+
/** Full device/provider diagnostics if they could be collected. */
|
|
18
|
+
diagnostics?: PushDiagnostics;
|
|
19
|
+
/** Original error from the native layer. */
|
|
20
|
+
override readonly cause?: unknown;
|
|
21
|
+
|
|
22
|
+
constructor(code: string, message: string, cause?: unknown) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'PushSignalError';
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.cause = cause;
|
|
27
|
+
Object.setPrototypeOf(this, PushSignalError.prototype);
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -2,12 +2,16 @@ export type {
|
|
|
2
2
|
AndroidFirebaseConfig,
|
|
3
3
|
OnMessageListener,
|
|
4
4
|
PushCredentials,
|
|
5
|
+
PushDiagnostics,
|
|
5
6
|
PushEnvironment,
|
|
6
7
|
PushMessage,
|
|
7
8
|
PushPlatform,
|
|
9
|
+
PushProvider,
|
|
8
10
|
} from './types';
|
|
11
|
+
export { PushSignalError } from './PushSignalError';
|
|
9
12
|
export {
|
|
10
13
|
getCredentials,
|
|
14
|
+
getDiagnostics,
|
|
11
15
|
initialize,
|
|
12
16
|
onMessage,
|
|
13
17
|
onNotificationPress,
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import NativePushSignal from './NativePushSignal';
|
|
2
|
+
import type { NativePushDiagnostics } from './NativePushSignal';
|
|
3
|
+
import { PushSignalError } from './PushSignalError';
|
|
2
4
|
import type {
|
|
3
5
|
AndroidFirebaseConfig,
|
|
4
6
|
OnMessageListener,
|
|
5
7
|
PushCredentials,
|
|
8
|
+
PushDiagnostics,
|
|
6
9
|
PushEnvironment,
|
|
7
10
|
PushMessage,
|
|
8
11
|
PushPlatform,
|
|
12
|
+
PushProvider,
|
|
9
13
|
} from './types';
|
|
10
14
|
|
|
11
15
|
const messageListeners = new Set<OnMessageListener>();
|
|
@@ -50,6 +54,51 @@ function normalizeCredentials(raw: {
|
|
|
50
54
|
};
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
function normalizeDiagnostics(raw: NativePushDiagnostics): PushDiagnostics {
|
|
58
|
+
return {
|
|
59
|
+
platform: raw.platform as PushPlatform,
|
|
60
|
+
gmsAvailable: raw.gmsAvailable,
|
|
61
|
+
gmsStatus: raw.gmsStatus,
|
|
62
|
+
manufacturer: raw.manufacturer,
|
|
63
|
+
brand: raw.brand,
|
|
64
|
+
model: raw.model,
|
|
65
|
+
provider: raw.provider as PushProvider,
|
|
66
|
+
providerName: raw.providerName,
|
|
67
|
+
providerInstalled: raw.providerInstalled ?? undefined,
|
|
68
|
+
hint: raw.hint ?? undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function toPushSignalError(
|
|
73
|
+
error: unknown,
|
|
74
|
+
fallbackCode: string
|
|
75
|
+
): PushSignalError {
|
|
76
|
+
const candidate = error as { code?: string; message?: string } | undefined;
|
|
77
|
+
return new PushSignalError(
|
|
78
|
+
candidate?.code ?? fallbackCode,
|
|
79
|
+
candidate?.message ?? 'PushSignal request failed',
|
|
80
|
+
error
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Attaches structured diagnostics to an error on a best-effort basis. Failing to
|
|
86
|
+
* collect them must never hide the original, already actionable error.
|
|
87
|
+
*/
|
|
88
|
+
async function enrichError(error: PushSignalError): Promise<PushSignalError> {
|
|
89
|
+
try {
|
|
90
|
+
const diagnostics = normalizeDiagnostics(
|
|
91
|
+
await NativePushSignal.getDiagnostics()
|
|
92
|
+
);
|
|
93
|
+
error.diagnostics = diagnostics;
|
|
94
|
+
error.provider = diagnostics.provider;
|
|
95
|
+
error.hint = diagnostics.hint;
|
|
96
|
+
} catch {
|
|
97
|
+
// Diagnostics are optional; keep the original error.
|
|
98
|
+
}
|
|
99
|
+
return error;
|
|
100
|
+
}
|
|
101
|
+
|
|
53
102
|
function bindNativeCallbacks() {
|
|
54
103
|
if (nativeCallbacksBound) {
|
|
55
104
|
return;
|
|
@@ -79,12 +128,27 @@ function bindNativeCallbacks() {
|
|
|
79
128
|
NativePushSignal.startListening();
|
|
80
129
|
}
|
|
81
130
|
|
|
82
|
-
export function initialize(
|
|
83
|
-
|
|
131
|
+
export async function initialize(
|
|
132
|
+
config: AndroidFirebaseConfig = {}
|
|
133
|
+
): Promise<void> {
|
|
134
|
+
try {
|
|
135
|
+
await NativePushSignal.initialize(config);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
throw await enrichError(toPushSignalError(error, 'E_INIT'));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function getCredentials(): Promise<PushCredentials> {
|
|
142
|
+
try {
|
|
143
|
+
const raw = await NativePushSignal.getCredentials();
|
|
144
|
+
return normalizeCredentials(raw);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw await enrichError(toPushSignalError(error, 'E_CREDENTIALS'));
|
|
147
|
+
}
|
|
84
148
|
}
|
|
85
149
|
|
|
86
|
-
export function
|
|
87
|
-
return NativePushSignal.
|
|
150
|
+
export async function getDiagnostics(): Promise<PushDiagnostics> {
|
|
151
|
+
return normalizeDiagnostics(await NativePushSignal.getDiagnostics());
|
|
88
152
|
}
|
|
89
153
|
|
|
90
154
|
export function onMessage(listener: OnMessageListener): () => void {
|
package/src/pushSignal.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import type {
|
|
|
2
2
|
AndroidFirebaseConfig,
|
|
3
3
|
OnMessageListener,
|
|
4
4
|
PushCredentials,
|
|
5
|
+
PushDiagnostics,
|
|
5
6
|
PushMessage,
|
|
6
7
|
} from './types';
|
|
7
8
|
|
|
@@ -13,6 +14,10 @@ export async function getCredentials(): Promise<PushCredentials> {
|
|
|
13
14
|
throw new Error('Push credentials are not supported on web');
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
export async function getDiagnostics(): Promise<PushDiagnostics> {
|
|
18
|
+
throw new Error('Push diagnostics are not supported on web');
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
export function onMessage(_listener: OnMessageListener): () => void {
|
|
17
22
|
return () => {};
|
|
18
23
|
}
|
package/src/types.ts
CHANGED
|
@@ -17,6 +17,34 @@ export interface PushMessage {
|
|
|
17
17
|
|
|
18
18
|
export type OnMessageListener = (message: PushMessage) => void | Promise<void>;
|
|
19
19
|
|
|
20
|
+
export type PushProvider =
|
|
21
|
+
| 'fcm'
|
|
22
|
+
| 'hms'
|
|
23
|
+
| 'mi_push'
|
|
24
|
+
| 'oppo_push'
|
|
25
|
+
| 'vivo_push'
|
|
26
|
+
| 'meizu_push'
|
|
27
|
+
| 'apns'
|
|
28
|
+
| 'unknown';
|
|
29
|
+
|
|
30
|
+
export interface PushDiagnostics {
|
|
31
|
+
platform: PushPlatform;
|
|
32
|
+
/** True when Google Play services can serve FCM; false on a ROM without GMS. */
|
|
33
|
+
gmsAvailable: boolean;
|
|
34
|
+
/** Raw GoogleApiAvailability status code. 0 means SUCCESS. */
|
|
35
|
+
gmsStatus: number;
|
|
36
|
+
manufacturer: string;
|
|
37
|
+
brand: string;
|
|
38
|
+
model: string;
|
|
39
|
+
provider: PushProvider;
|
|
40
|
+
/** Human-readable provider name, e.g. "HMS Push Kit". */
|
|
41
|
+
providerName: string;
|
|
42
|
+
/** True only when the provider service app was positively found on the device. */
|
|
43
|
+
providerInstalled?: boolean;
|
|
44
|
+
/** Actionable sentence explaining which service to use instead of the standard one. */
|
|
45
|
+
hint?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
20
48
|
export interface AndroidFirebaseConfig {
|
|
21
49
|
project_id?: string;
|
|
22
50
|
mobilesdk_app_id?: string;
|