v83: 后台定期同步(四层调度,策略照 SyncCalendar)
用户原话:「另外,要有定期同步的功能,就是家书app在后台,也能自动同步
数据,这样打开app,基本上数据就是最新的。同步的策略,去synccalendar找,
里面有办法。」
四层调度(缺一层就会在某种场景下"永远不同步"):
1. 前台:onForeground 时若距上次同步超过 5 分钟,补一次
2. 退后台:requestSuspendDelay 短时任务(单次≤3分钟、单日10分钟配额)
3. 延迟任务:workScheduler(周期 2 小时 —— 系统按活跃分组压制,
请求更短不报错但不生效)
4. 桌面卡片:updateDuration:1(=30 分钟,唯一不受压制的通道,
每天上限 50 次);先推卡片再触发同步
关键约束(写错了都不报错,只是静默失效):
- WorkSchedulerExtensionAbility 单次回调上限 2 分钟,必须在 finally 里 stopWork
- 后台扩展跑在独立进程,EntryAbility.onCreate 的初始化一步都没跑过
⇒ prepare() 必须补齐 token store / module token / FbDb.open
- 回前台必须 cancelSuspendDelay 归还配额,否则两三天后用光
- workInfo 要带 isPersisted,否则重启后任务永久消失
- abilityName 必须与 module.json5 声明一致,对不上时 startWork 不报错但不回调
- ApplicationInfo 没有 bundleName 字段,包名在 .name
其他:
- 卡片驱动的同步有节流(CARD_MIN_GAP_MS 25 分钟 < 卡片刷新 30 分钟,
反了就是每次刷新都被跳过、一次都不跑)
- 设置页新增「同步」分组:开关 + 上次同步时间 + 说明
同时修:首页日程红线左侧缺一块(nowLayer 从 Row{圆点;线} 改成单个
Column 满宽 —— Row 里圆点占行首,线只能从第 5vp 起画)
守卫 1106/0、v83 反向验证 10/10 全中、已装机。
This commit is contained in:
@@ -26,6 +26,7 @@ import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { FbCardData, fbCardBuild } from '../data/FbCardData';
|
||||
import { FB_CARD_FORMS } from '../data/FbCardForms';
|
||||
import { FB_BG_SYNC } from '../common/FbBackgroundSync';
|
||||
|
||||
const DOMAIN: number = 0x0000;
|
||||
const TAG: string = 'FbForm';
|
||||
@@ -80,6 +81,24 @@ export default class FbFormAbility extends FormExtensionAbility {
|
||||
|
||||
onUpdateForm(formId: string): void {
|
||||
hilog.info(DOMAIN, TAG, '系统定时刷新:%{public}s', formId);
|
||||
/* 🔴🔴 v83(用户 2026-10-23「要有定期同步的功能,家书app在后台,也能自动同步数据」):
|
||||
**借卡片定时刷新这个时机跑一轮后台同步。**
|
||||
|
||||
为什么只有这里能做到"约 30 分钟一次":
|
||||
`workScheduler` 的周期被系统按"应用活跃分组"压制(活跃≥2h / 常用≥24h),
|
||||
请求更短不报错但**不生效**;而卡片配了 `updateDuration: 1`(单位 30 分钟)后,
|
||||
系统会每 30 分钟回调一次本方法,**不受活跃分组压制**(每天上限 50 次)。
|
||||
⇒ 这是那条"打开 app 数据就是最新的"真正落地的通道。
|
||||
|
||||
⚠️ **必须先推卡片、再同步**:
|
||||
推送只依赖本地缓存/一次轻量请求,几秒内就能完成;
|
||||
同步要跑 12 个模块,很可能在"进程只活 10 秒"的窗口里被砍。
|
||||
顺序反了就会变成"同步把时间用光、卡片这次没刷新"——
|
||||
用户看到的是"卡片一直转圈",比慢一步更糟。
|
||||
⚠️ **不 await**:`onUpdateForm` 返回后进程只剩约 10 秒,
|
||||
await 只会把两者一起拖死。同步自己内部有节流与预算(见 FbBackgroundSync)。
|
||||
⚠️ 节流:系统刷新可能漂移或重入,`runThrottledByCard` 内部用时间戳挡了一道,
|
||||
并且**先写时间戳再跑**,避免卡片进程与主进程并发拉同一批数据。 */
|
||||
// ⚠️ 必须按**这张卡自己的偏移**重建,否则定时刷新会把用户翻走的日期拽回今天
|
||||
FB_CARD_FORMS.getOffset(this.context, formId).then((off: number): void => {
|
||||
this.push(formId, off);
|
||||
@@ -87,6 +106,11 @@ export default class FbFormAbility extends FormExtensionAbility {
|
||||
hilog.warn(DOMAIN, TAG, '读卡片偏移失败:%{public}s', err.message);
|
||||
this.push(formId, 0);
|
||||
});
|
||||
/* ⚠️ 这一句必须放在**推送之后**(原因见上面的 ①:卡片刷新只有几秒的窗口,
|
||||
不能被 12 个模块的同步挤掉)。两条都是"发起即返回",不会互相阻塞。 */
|
||||
FB_BG_SYNC.runThrottledByCard(this.context).catch((err: BusinessError): void => {
|
||||
hilog.warn(DOMAIN, TAG, '卡片驱动的后台同步失败(不影响卡片本身):%{public}s', err.message);
|
||||
});
|
||||
}
|
||||
|
||||
onFormEvent(formId: string, message: string): void {
|
||||
|
||||
Reference in New Issue
Block a user