export interface LocationUpdate { latitude: number longitude: number accuracy?: number speed?: number } export interface LocationControllerCallbacks { onLocation: (update: LocationUpdate) => void onStatus: (message: string) => void onError: (message: string) => void } function hasLocationPermission(settings: WechatMiniprogram.AuthSetting): boolean { const authSettings = settings as Record return !!authSettings['scope.userLocation'] } function hasBackgroundLocationPermission(settings: WechatMiniprogram.AuthSetting): boolean { const authSettings = settings as Record return !!authSettings['scope.userLocationBackground'] } export class LocationController { callbacks: LocationControllerCallbacks listening: boolean boundLocationHandler: ((result: WechatMiniprogram.OnLocationChangeCallbackResult) => void) | null constructor(callbacks: LocationControllerCallbacks) { this.callbacks = callbacks this.listening = false this.boundLocationHandler = null } start(): void { if (this.listening) { this.callbacks.onStatus('后台持续定位进行中') return } wx.getSetting({ success: (result) => { const settings = result.authSetting || {} if (hasBackgroundLocationPermission(settings)) { this.startBackgroundLocation() return } if (hasLocationPermission(settings)) { this.requestBackgroundPermissionInSettings() return } wx.authorize({ scope: 'scope.userLocation', success: () => { this.requestBackgroundPermissionInSettings() }, fail: () => { this.requestBackgroundPermissionInSettings() }, }) }, fail: (error) => { const message = error && error.errMsg ? error.errMsg : 'getSetting 失败' this.callbacks.onError(`GPS授权检查失败: ${message}`) }, }) } requestBackgroundPermissionInSettings(): void { this.callbacks.onStatus('请在授权面板开启后台定位') wx.openSetting({ success: (result) => { const settings = result.authSetting || {} if (hasBackgroundLocationPermission(settings)) { this.startBackgroundLocation() return } this.callbacks.onError('GPS启动失败: 未授予后台定位权限') }, fail: (error) => { const message = error && error.errMsg ? error.errMsg : 'openSetting 失败' this.callbacks.onError(`GPS启动失败: ${message}`) }, }) } startBackgroundLocation(): void { wx.startLocationUpdateBackground({ type: 'wgs84', success: () => { this.bindLocationListener() this.listening = true this.callbacks.onStatus('后台持续定位已启动') }, fail: (error) => { const message = error && error.errMsg ? error.errMsg : 'startLocationUpdateBackground 失败' this.callbacks.onError(`GPS启动失败: ${message}`) }, }) } stop(): void { if (!this.listening) { this.callbacks.onStatus('后台持续定位未启动') return } if (typeof wx.offLocationChange === 'function' && this.boundLocationHandler) { wx.offLocationChange(this.boundLocationHandler) } this.boundLocationHandler = null wx.stopLocationUpdate({ complete: () => { this.listening = false this.callbacks.onStatus('后台持续定位已停止') }, }) } destroy(): void { if (typeof wx.offLocationChange === 'function' && this.boundLocationHandler) { wx.offLocationChange(this.boundLocationHandler) } this.boundLocationHandler = null if (this.listening) { wx.stopLocationUpdate({ complete: () => {} }) this.listening = false } } bindLocationListener(): void { if (this.boundLocationHandler) { return } this.boundLocationHandler = (result) => { this.callbacks.onLocation({ latitude: result.latitude, longitude: result.longitude, accuracy: result.accuracy, speed: result.speed, }) } wx.onLocationChange(this.boundLocationHandler) } }