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) <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,8 @@ android {
|
|||||||
applicationId = "com.a2i.forwarder"
|
applicationId = "com.a2i.forwarder"
|
||||||
minSdk = 34
|
minSdk = 34
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 14
|
versionCode = 15
|
||||||
versionName = "1.7.1"
|
versionName = "1.7.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import okhttp3.OkHttpClient
|
|||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import org.json.JSONObject
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.TimeUnit
|
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)。
|
* 对瞬时 IOException 自动重试 3 次(退避 600/1200ms)。
|
||||||
*/
|
*/
|
||||||
object NtfySender {
|
object NtfySender {
|
||||||
@@ -30,13 +32,15 @@ object NtfySender {
|
|||||||
title: String, body: String,
|
title: String, body: String,
|
||||||
): Result<Unit> = withContext(Dispatchers.IO) {
|
): Result<Unit> = withContext(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val url = server.trim().removeSuffix("/") + "/" + topic.trim()
|
val payload = JSONObject()
|
||||||
val req = Request.Builder().url(url)
|
.put("topic", topic.trim())
|
||||||
.header("Title", title.take(200))
|
.put("title", title.take(200))
|
||||||
.apply {
|
.put("message", body.take(4000))
|
||||||
if (token.isNotBlank()) header("Authorization", "Bearer $token")
|
.toString()
|
||||||
}
|
val req = Request.Builder()
|
||||||
.put(body.take(4000).toRequestBody(TEXT_PLAIN))
|
.url(server.trim().removeSuffix("/"))
|
||||||
|
.apply { if (token.isNotBlank()) header("Authorization", "Bearer $token") }
|
||||||
|
.post(payload.toRequestBody(JSON))
|
||||||
.build()
|
.build()
|
||||||
doPushWithRetry(req)
|
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 const val MAX_ATTEMPTS = 3
|
||||||
private val BACKOFF_MS = longArrayOf(600L, 1200L)
|
private val BACKOFF_MS = longArrayOf(600L, 1200L)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user