From 25a1d3abf814e644c1948ea243818db094d044bb Mon Sep 17 00:00:00 2001 From: sey8n <306442043+sey8n@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:21:24 +0900 Subject: [PATCH] fix: escape app names in app icons JSON MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit createAppIconsJson inserted app labels into the JSON without escaping. A label that contains a line break or a quote produces invalid JSON, so the Mac app fails to decode the whole appIcons message and drops it without any visible error. Every sync fails the same way, which leaves the Apps grid and the per-app notification list on the Mac empty. Example: the launcher label of kr.co.dgb.dgbm is "iM뱅크\n(아이엠)". Use the existing escape() helper for app names, and make escape() also handle tabs and the other control characters JSON does not allow unescaped. --- .../com/sameerasw/airsync/utils/JsonUtil.kt | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/sameerasw/airsync/utils/JsonUtil.kt b/app/src/main/java/com/sameerasw/airsync/utils/JsonUtil.kt index fca3916b..8f0ef93c 100644 --- a/app/src/main/java/com/sameerasw/airsync/utils/JsonUtil.kt +++ b/app/src/main/java/com/sameerasw/airsync/utils/JsonUtil.kt @@ -138,11 +138,23 @@ object JsonUtil { } private fun escape(value: String): String { - return value - .replace("\\", "\\\\") - .replace("\"", "\\\"") - .replace("\n", "\\n") - .replace("\r", "\\r") + val sb = StringBuilder(value.length) + for (c in value) { + when (c) { + '\\' -> sb.append("\\\\") + '"' -> sb.append("\\\"") + '\n' -> sb.append("\\n") + '\r' -> sb.append("\\r") + '\t' -> sb.append("\\t") + // Other control characters are not allowed unescaped in JSON strings + else -> if (c < ' ') { + sb.append("\\u").append(c.code.toString(16).padStart(4, '0')) + } else { + sb.append(c) + } + } + } + return sb.toString() } /** @@ -227,7 +239,7 @@ object JsonUtil { val iconData = iconMap[app.packageName] ?: "" """ "${app.packageName}": { - "name": "${app.appName}", + "name": "${escape(app.appName)}", "icon": "$iconData", "listening": ${app.isEnabled}, "systemApp": ${app.isSystemApp}