export interface AccelerometerControllerCallbacks { onSample: (x: number, y: number, z: number) => void onError: (message: string) => void } const ACCELEROMETER_START_RETRY_DELAY_MS = 120 export class AccelerometerController { callbacks: AccelerometerControllerCallbacks listening: boolean starting: boolean accelerometerCallback: ((result: WechatMiniprogram.OnAccelerometerChangeCallbackResult) => void) | null retryTimer: number constructor(callbacks: AccelerometerControllerCallbacks) { this.callbacks = callbacks this.listening = false this.starting = false this.accelerometerCallback = null this.retryTimer = 0 } start(): void { if (this.listening || this.starting) { return } if (typeof wx.startAccelerometer !== 'function' || typeof wx.onAccelerometerChange !== 'function') { this.callbacks.onError('当前环境不支持加速度计监听') return } this.clearRetryTimer() this.starting = true this.detachCallback() wx.stopAccelerometer({ complete: () => { this.startAfterStop(false) }, }) } private startAfterStop(retried: boolean): void { const callback = (result: WechatMiniprogram.OnAccelerometerChangeCallbackResult) => { if ( typeof result.x !== 'number' || typeof result.y !== 'number' || typeof result.z !== 'number' || Number.isNaN(result.x) || Number.isNaN(result.y) || Number.isNaN(result.z) ) { return } this.callbacks.onSample(result.x, result.y, result.z) } this.accelerometerCallback = callback wx.onAccelerometerChange(callback) wx.startAccelerometer({ interval: 'ui', success: () => { this.starting = false this.listening = true }, fail: (res) => { const errorMessage = res && res.errMsg ? res.errMsg : 'startAccelerometer failed' if (!retried && errorMessage.indexOf('has enable') >= 0) { this.detachCallback() this.clearRetryTimer() this.retryTimer = setTimeout(() => { this.retryTimer = 0 wx.stopAccelerometer({ complete: () => { this.startAfterStop(true) }, }) }, ACCELEROMETER_START_RETRY_DELAY_MS) as unknown as number return } this.starting = false this.detachCallback() this.callbacks.onError(errorMessage) }, }) } stop(): void { this.clearRetryTimer() this.detachCallback() wx.stopAccelerometer({ complete: () => {}, }) this.starting = false this.listening = false } destroy(): void { this.stop() } private clearRetryTimer(): void { if (!this.retryTimer) { return } clearTimeout(this.retryTimer) this.retryTimer = 0 } private detachCallback(): void { if (!this.accelerometerCallback) { return } if (typeof wx.offAccelerometerChange === 'function') { wx.offAccelerometerChange(this.accelerometerCallback) } this.accelerometerCallback = null } }