locationController.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. export interface LocationUpdate {
  2. latitude: number
  3. longitude: number
  4. accuracy?: number
  5. speed?: number
  6. }
  7. export interface LocationControllerCallbacks {
  8. onLocation: (update: LocationUpdate) => void
  9. onStatus: (message: string) => void
  10. onError: (message: string) => void
  11. }
  12. function hasLocationPermission(settings: WechatMiniprogram.AuthSetting): boolean {
  13. const authSettings = settings as Record<string, boolean | undefined>
  14. return !!authSettings['scope.userLocation']
  15. }
  16. function hasBackgroundLocationPermission(settings: WechatMiniprogram.AuthSetting): boolean {
  17. const authSettings = settings as Record<string, boolean | undefined>
  18. return !!authSettings['scope.userLocationBackground']
  19. }
  20. export class LocationController {
  21. callbacks: LocationControllerCallbacks
  22. listening: boolean
  23. boundLocationHandler: ((result: WechatMiniprogram.OnLocationChangeCallbackResult) => void) | null
  24. constructor(callbacks: LocationControllerCallbacks) {
  25. this.callbacks = callbacks
  26. this.listening = false
  27. this.boundLocationHandler = null
  28. }
  29. start(): void {
  30. if (this.listening) {
  31. this.callbacks.onStatus('后台持续定位进行中')
  32. return
  33. }
  34. wx.getSetting({
  35. success: (result) => {
  36. const settings = result.authSetting || {}
  37. if (hasBackgroundLocationPermission(settings)) {
  38. this.startBackgroundLocation()
  39. return
  40. }
  41. if (hasLocationPermission(settings)) {
  42. this.requestBackgroundPermissionInSettings()
  43. return
  44. }
  45. wx.authorize({
  46. scope: 'scope.userLocation',
  47. success: () => {
  48. this.requestBackgroundPermissionInSettings()
  49. },
  50. fail: () => {
  51. this.requestBackgroundPermissionInSettings()
  52. },
  53. })
  54. },
  55. fail: (error) => {
  56. const message = error && error.errMsg ? error.errMsg : 'getSetting 失败'
  57. this.callbacks.onError(`GPS授权检查失败: ${message}`)
  58. },
  59. })
  60. }
  61. requestBackgroundPermissionInSettings(): void {
  62. this.callbacks.onStatus('请在授权面板开启后台定位')
  63. wx.openSetting({
  64. success: (result) => {
  65. const settings = result.authSetting || {}
  66. if (hasBackgroundLocationPermission(settings)) {
  67. this.startBackgroundLocation()
  68. return
  69. }
  70. this.callbacks.onError('GPS启动失败: 未授予后台定位权限')
  71. },
  72. fail: (error) => {
  73. const message = error && error.errMsg ? error.errMsg : 'openSetting 失败'
  74. this.callbacks.onError(`GPS启动失败: ${message}`)
  75. },
  76. })
  77. }
  78. startBackgroundLocation(): void {
  79. wx.startLocationUpdateBackground({
  80. success: () => {
  81. this.bindLocationListener()
  82. this.listening = true
  83. this.callbacks.onStatus('后台持续定位已启动')
  84. },
  85. fail: (error) => {
  86. const message = error && error.errMsg ? error.errMsg : 'startLocationUpdateBackground 失败'
  87. this.callbacks.onError(`GPS启动失败: ${message}`)
  88. },
  89. })
  90. }
  91. stop(): void {
  92. if (!this.listening) {
  93. this.callbacks.onStatus('后台持续定位未启动')
  94. return
  95. }
  96. if (typeof wx.offLocationChange === 'function' && this.boundLocationHandler) {
  97. wx.offLocationChange(this.boundLocationHandler)
  98. }
  99. this.boundLocationHandler = null
  100. wx.stopLocationUpdate({
  101. complete: () => {
  102. this.listening = false
  103. this.callbacks.onStatus('后台持续定位已停止')
  104. },
  105. })
  106. }
  107. destroy(): void {
  108. if (typeof wx.offLocationChange === 'function' && this.boundLocationHandler) {
  109. wx.offLocationChange(this.boundLocationHandler)
  110. }
  111. this.boundLocationHandler = null
  112. if (this.listening) {
  113. wx.stopLocationUpdate({ complete: () => {} })
  114. this.listening = false
  115. }
  116. }
  117. bindLocationListener(): void {
  118. if (this.boundLocationHandler) {
  119. return
  120. }
  121. this.boundLocationHandler = (result) => {
  122. this.callbacks.onLocation({
  123. latitude: result.latitude,
  124. longitude: result.longitude,
  125. accuracy: result.accuracy,
  126. speed: result.speed,
  127. })
  128. }
  129. wx.onLocationChange(this.boundLocationHandler)
  130. }
  131. }