Files
youle_app_ohos/feature_capabilities/src/main/ets/providers/ShakeProvider.ets
T
lanterngamescn 0eabcac7e9 M5: Provider 前后台生命周期(非激活槽真正停 native 活动)
forEachForeground/forEachBackground 此前扇出但多数 Provider 未实现 → 非激活槽 native 监听仍跑。补齐:
- ShakeProvider:onBackground 停传感器、onForeground 按 H5 意图(wantShake)恢复;区分 H5 请求态与实际监听态
- LocationProvider:onBackground 停连续定位、onForeground 按 wantContinuous 恢复(单次定位无需恢复)
- NetworkProvider:onBackground 注销网络订阅、onForeground 重订阅(抽 unsubscribe)
- AudioProvider:onBackground 停语音/音效播放(非激活端不出声)
至此"同时只有一个激活"在 native 侧也落实:去激活槽停传感器/定位/网络/音频;H5 侧由 appservice('2') 自停。

WeChat resp 路由保持现状(微信整体延期;双 Web 下发起槽持续存活,边缘情形见 m3-deferred 记录)。
devecocli build + scripts/test.sh 通过。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 23:35:25 +08:00

121 lines
4.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 摇一摇能力(契约 §8.5/§9T-M3-08)。@kit.SensorServiceKit 加速度计。
* - startshake:开始监听;检测到摇动后约 1 秒出站 shakeEnd(空串)。
* - SwitchShakedata="1" 开声音/震动反馈 / 其他关。
* - stopshake:停止监听。
* 需 module.json5 声明 ohos.permission.ACCELEROMETER。
*/
import { sensor } from '@kit.SensorServiceKit';
import { vibrator } from '@kit.SensorServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { BridgeController } from 'feature_bridge';
import { InboundHandlers, OutboundHandlers } from 'contracts';
import { Logger } from 'common';
import { CapabilityContext, CapabilityProvider } from '../core/CapabilityProvider';
/** 摇动阈值(合加速度 m/s²;静止约 9.8,摇动易超 20)。 */
const SHAKE_THRESHOLD: number = 20;
/** 上报周期 100ms。 */
const INTERVAL_NS: number = 100000000;
/** shakeEnd 延迟(约 1 秒)。 */
const SHAKE_END_DELAY: number = 1000;
export class ShakeProvider implements CapabilityProvider {
readonly name: string = 'shake';
private readonly log: Logger = Logger.tag('ShakeProvider');
private bridge: BridgeController | undefined = undefined;
private listening: boolean = false;
private feedbackOn: boolean = false;
private pending: boolean = false;
private endTimer: number = -1;
private wantShake: boolean = false;
private readonly onAccel: (data: sensor.AccelerometerResponse) => void;
constructor() {
this.onAccel = (data: sensor.AccelerometerResponse) => this.handleAccel(data);
}
register(bridge: BridgeController, _ctx: CapabilityContext): void {
this.bridge = bridge;
bridge.registerHandler(InboundHandlers.StartShake, (_d: string, _cb: (resp: string) => void) => {
this.wantShake = true;
this.start();
});
bridge.registerHandler(InboundHandlers.SwitchShake, (data: string, _cb: (resp: string) => void) => {
this.feedbackOn = data === '1';
});
bridge.registerHandler(InboundHandlers.StopShake, (_d: string, _cb: (resp: string) => void) => {
this.wantShake = false;
this.stop();
});
}
/** 槽激活:若 H5 仍要摇一摇则恢复监听(M5 §7.5)。 */
onForeground(): void {
if (this.wantShake) {
this.start();
}
}
/** 槽去激活:停传感器监听(保留 H5 意图,激活时恢复)。 */
onBackground(): void {
this.stop();
}
onDestroy(): void {
this.wantShake = false;
this.stop();
}
private start(): void {
if (this.listening) {
return;
}
try {
sensor.on(sensor.SensorId.ACCELEROMETER, this.onAccel, { interval: INTERVAL_NS });
this.listening = true;
} catch (e) {
this.log.w(`sensor.on failed: ${(e as BusinessError).message}`);
}
}
private stop(): void {
if (!this.listening) {
return;
}
try {
sensor.off(sensor.SensorId.ACCELEROMETER, this.onAccel);
} catch (e) {
this.log.w(`sensor.off failed: ${(e as BusinessError).message}`);
}
this.listening = false;
// 取消未决的 shakeEnd 计时并复位节流,避免停止后仍触发出站 / 重启后首次摇动被吞
if (this.endTimer !== -1) {
clearTimeout(this.endTimer);
this.endTimer = -1;
}
this.pending = false;
}
private handleAccel(data: sensor.AccelerometerResponse): void {
if (this.pending) {
return;
}
const magnitude: number = Math.sqrt(data.x * data.x + data.y * data.y + data.z * data.z);
if (magnitude < SHAKE_THRESHOLD) {
return;
}
// 摇动触发:节流;可选反馈震动;约 1 秒后出站 shakeEnd
this.pending = true;
if (this.feedbackOn) {
vibrator.startVibration({ type: 'time', duration: 200 }, { usage: 'notification' })
.catch((e: BusinessError) => this.log.w(`shake vibrate failed: ${e.message}`));
}
this.endTimer = setTimeout(() => {
this.endTimer = -1;
this.bridge?.callHandler(OutboundHandlers.ShakeEnd, '');
this.pending = false;
}, SHAKE_END_DELAY);
}
}