From 94422fbd7648d802de8ffb485f2ecbd2c0c78e02 Mon Sep 17 00:00:00 2001 From: Song <168455@qq.com> Date: Thu, 9 Jul 2026 20:32:26 +0800 Subject: [PATCH] fix: ntfy use JSON publish API (raw body was treated as attachment) ntfy.sh now treats any request body (PUT/POST, text/plain) as a file attachment, so messages never showed in the app. Switch to ntfy's JSON publish API: POST / with {topic,title,message}. version 1.7.1 -> 1.7.2 (code 14 -> 15) Co-Authored-By: Claude Opus 4.8 (1M context) --- app/build.gradle.kts | 4 ++-- .../java/com/a2i/forwarder/core/NtfySender.kt | 22 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0e40644..394a1eb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "com.a2i.forwarder" minSdk = 34 targetSdk = 36 - versionCode = 14 - versionName = "1.7.1" + versionCode = 15 + versionName = "1.7.2" } signingConfigs { diff --git a/app/src/main/java/com/a2i/forwarder/core/NtfySender.kt b/app/src/main/java/com/a2i/forwarder/core/NtfySender.kt index 1358404..eff4dbd 100644 --- a/app/src/main/java/com/a2i/forwarder/core/NtfySender.kt +++ b/app/src/main/java/com/a2i/forwarder/core/NtfySender.kt @@ -10,11 +10,13 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody +import org.json.JSONObject import java.io.IOException import java.util.concurrent.TimeUnit /** - * ntfy 推送:POST {server}/{topic},可选 Bearer auth。 + * ntfy 推送:用 JSON publish API(POST / with {topic,title,message})。 + * 注:raw body 会被 ntfy 当附件,必须用 JSON API 或 Message header。 * 对瞬时 IOException 自动重试 3 次(退避 600/1200ms)。 */ object NtfySender { @@ -30,13 +32,15 @@ object NtfySender { title: String, body: String, ): Result = withContext(Dispatchers.IO) { runCatching { - val url = server.trim().removeSuffix("/") + "/" + topic.trim() - val req = Request.Builder().url(url) - .header("Title", title.take(200)) - .apply { - if (token.isNotBlank()) header("Authorization", "Bearer $token") - } - .put(body.take(4000).toRequestBody(TEXT_PLAIN)) + val payload = JSONObject() + .put("topic", topic.trim()) + .put("title", title.take(200)) + .put("message", body.take(4000)) + .toString() + val req = Request.Builder() + .url(server.trim().removeSuffix("/")) + .apply { if (token.isNotBlank()) header("Authorization", "Bearer $token") } + .post(payload.toRequestBody(JSON)) .build() doPushWithRetry(req) } @@ -68,7 +72,7 @@ object NtfySender { } } - private val TEXT_PLAIN = "text/plain; charset=utf-8".toMediaType() + private val JSON = "application/json; charset=utf-8".toMediaType() private const val MAX_ATTEMPTS = 3 private val BACKOFF_MS = longArrayOf(600L, 1200L) }