fix(android): parse optional userNotification fields for dual/user schedule

parseUserNotificationConfig used getBoolean/getString for title, body, sound,
vibration, and priority; missing keys threw JSONException though TS marks them
optional. Add optBooleanOrNull/optStringOrNull (same pattern as optIntOrNull) and
defer to existing NotifyReceiver/DualScheduleHelper defaults.

Document in README; extend CHANGELOG [2.1.3].
This commit is contained in:
Jose Olarte III
2026-03-20 21:19:27 +08:00
parent 4dd1aea002
commit 5f12b69d2a
3 changed files with 17 additions and 6 deletions

View File

@@ -10,10 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- **Android**: `scheduleDualNotification` / `parseContentFetchConfig` no longer requires `timeout`, `retryAttempts`, and `retryDelay` in `contentFetch` (optional fields per TypeScript). Omitted values defer to `FetchWorker` defaults.
- **Android**: `parseUserNotificationConfig` no longer uses strict `getBoolean` / `getString` for optional `userNotification` fields (`title`, `body`, `sound`, `vibration`, `priority`). Omitted keys no longer throw `JSONException`; native scheduling applies existing defaults (`NotifyReceiver` / `DualScheduleHelper`).
### Documentation
- **README**: Note default behavior when those `contentFetch` fields are omitted.
- **README**: Notes for omitted `contentFetch` and optional `userNotification` fields on Android.
## [1.1.6] - 2026-02-16

View File

@@ -322,6 +322,8 @@ await DailyNotification.scheduleDualNotification({
If `contentFetch` omits `timeout`, `retryAttempts`, or `retryDelay`, Android applies defaults when scheduling fetch work (currently 30000 ms, 3 attempts, 1000 ms between attempts; see `FetchWorker`).
If `userNotification` omits optional fields (`title`, `body`, `sound`, `vibration`, `priority`), Android parses them as omitted; scheduling uses the same defaults as `NotifyReceiver` / `DualScheduleHelper` (e.g. sound and vibration default to on, priority to `normal` where applicable).
### Callback Methods
#### `registerCallback(name, config)`

View File

@@ -2401,6 +2401,14 @@ open class DailyNotificationPlugin : Plugin() {
private fun JSObject.optIntOrNull(key: String): Int? =
if (has(key) && !isNull(key)) optInt(key) else null
/** Optional boolean: absent or JSON-null → null (aligns with TS optional fields). */
private fun JSObject.optBooleanOrNull(key: String): Boolean? =
if (has(key) && !isNull(key)) optBoolean(key) else null
/** Optional string: absent or JSON-null → null. Present empty string is preserved. */
private fun JSObject.optStringOrNull(key: String): String? =
if (has(key) && !isNull(key)) optString(key) else null
private fun parseContentFetchConfig(configJson: JSObject): ContentFetchConfig {
val callbacksObj = configJson.getJSObject("callbacks")
return ContentFetchConfig(
@@ -2422,11 +2430,11 @@ open class DailyNotificationPlugin : Plugin() {
return UserNotificationConfig(
enabled = configJson.getBoolean("enabled") ?: true,
schedule = configJson.getString("schedule") ?: "0 9 * * *",
title = configJson.getString("title"),
body = configJson.getString("body"),
sound = configJson.getBoolean("sound"),
vibration = configJson.getBoolean("vibration"),
priority = configJson.getString("priority")
title = configJson.optStringOrNull("title"),
body = configJson.optStringOrNull("body"),
sound = configJson.optBooleanOrNull("sound"),
vibration = configJson.optBooleanOrNull("vibration"),
priority = configJson.optStringOrNull("priority")
)
}