fix(keepalive): 权限「去系统设置里授权后回来」这一档现在真能把服务起起来(补 W53S 登记的那一格)

问题(W53S 标出、我核过代码确认):CyreneApp 里那个起停前台服务的 LaunchedEffect 的 key 只有
`keepAliveEnabled` 与登录态,而通知权限是**现读**的 ⇒ 用户在系统设置里授权后回到 App 时它不会重跑,
设置页已经显示「已开」而服务其实没起(要等下次启动或再动一次开关)。

修法:给 AppPresence 补一条**与既有 `appInForeground` 同源**的 StateFlow(`onStart/onStop` 里
从同一个集合重算,布尔 getter 语义一字未动),让那个 effect 收它当 key —— 「回到前台」正是
「从系统设置返回」必经、且必然变化的那一位。没有新增任何依赖。
This commit is contained in:
AskaEth committed 2026-10-06 18:55:20 +08:00
1 parent 6505512c0a
commit 77fbedc350
2 files changed
+22 -1

No files matched your search

@@ -40,7 +40,10 @@ fun CyreneApp(container: AppContainer) {
* 而授权变化只有两条路——本端刚申请完(设置页那次写入会连带把这里重跑一遍)、或用户在系统 * 而授权变化只有两条路——本端刚申请完(设置页那次写入会连带把这里重跑一遍)、或用户在系统
* 设置里改过(下次启动必然重跑)。 * 设置里改过(下次启动必然重跑)。
*/ */
LaunchedEffect(prefs.keepAliveEnabled, state) { // ⚠️ key 里必须有「回到前台」这一位(W53S 登记的那一格):通知权限是**现读**的,而用户在系统
// 设置里授权后回到 App 时,只有这个状态会变 —— 少了它,UI 会说「已开」而服务其实没起。
val appInForeground by container.appPresence.appInForegroundFlow.collectAsState()
LaunchedEffect(prefs.keepAliveEnabled, state, appInForeground) {
when ( when (
keepAliveAction( keepAliveAction(
enabled = prefs.keepAliveEnabled, enabled = prefs.keepAliveEnabled,
@@ -2,6 +2,9 @@ package top.yeij.cyrene.core.notify
import java.util.Collections import java.util.Collections
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** /**
* 进程级的两个「我此刻在哪儿」的事实(W53N):**App 在不在前台**、**聊天页正显示哪个会话**。 * 进程级的两个「我此刻在哪儿」的事实(W53N):**App 在不在前台**、**聊天页正显示哪个会话**。
@@ -44,9 +47,23 @@ class AppPresence {
val appInForeground: Boolean val appInForeground: Boolean
get() = startedActivities.isNotEmpty() get() = startedActivities.isNotEmpty()
private val _appInForeground = MutableStateFlow(false)
/**
* [appInForeground] 的**可订阅**形态(W53S 登记的那一格要它)。
*
* 为什么需要第二条出口:`CyreneApp` 那个「起 / 停前台服务」的 `LaunchedEffect` 的 key 里没有
* 通知权限,于是**用户在系统设置里授权后回到 App** 时它不会重跑 —— UI 已经显示「已开」,
* 服务却没起。权限本身必须**现读**(不该缓存成状态),能当 key 的是「刚好会在这件事发生时变化」
* 的信号:**回到前台**(从系统设置返回必经 `onStart`)。所以这里把「在不在前台」补成一条流。
* 判据本身仍然只读 [appInForeground] 那个布尔——两条出口算的是**同一份事实**(同一个集合)。
*/
val appInForegroundFlow: StateFlow<Boolean> = _appInForeground.asStateFlow()
/** 一个 Activity 进入「可见」这一档(`onStart`)。 */ /** 一个 Activity 进入「可见」这一档(`onStart`)。 */
fun onActivityStarted(owner: Any) { fun onActivityStarted(owner: Any) {
startedActivities.add(owner) startedActivities.add(owner)
_appInForeground.value = appInForeground
} }
/** /**
@@ -57,6 +74,7 @@ class AppPresence {
*/ */
fun onActivityStopped(owner: Any) { fun onActivityStopped(owner: Any) {
startedActivities.remove(owner) startedActivities.remove(owner)
_appInForeground.value = appInForeground
} }
/** 聊天页刚显示(或刚换成)[sessionId];`null` = 它离开了屏幕。 */ /** 聊天页刚显示(或刚换成)[sessionId];`null` = 它离开了屏幕。 */