accelerometerController.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. export interface AccelerometerControllerCallbacks {
  2. onSample: (x: number, y: number, z: number) => void
  3. onError: (message: string) => void
  4. }
  5. const ACCELEROMETER_START_RETRY_DELAY_MS = 120
  6. export class AccelerometerController {
  7. callbacks: AccelerometerControllerCallbacks
  8. listening: boolean
  9. starting: boolean
  10. accelerometerCallback: ((result: WechatMiniprogram.OnAccelerometerChangeCallbackResult) => void) | null
  11. retryTimer: number
  12. constructor(callbacks: AccelerometerControllerCallbacks) {
  13. this.callbacks = callbacks
  14. this.listening = false
  15. this.starting = false
  16. this.accelerometerCallback = null
  17. this.retryTimer = 0
  18. }
  19. start(): void {
  20. if (this.listening || this.starting) {
  21. return
  22. }
  23. if (typeof wx.startAccelerometer !== 'function' || typeof wx.onAccelerometerChange !== 'function') {
  24. this.callbacks.onError('当前环境不支持加速度计监听')
  25. return
  26. }
  27. this.clearRetryTimer()
  28. this.starting = true
  29. this.detachCallback()
  30. wx.stopAccelerometer({
  31. complete: () => {
  32. this.startAfterStop(false)
  33. },
  34. })
  35. }
  36. private startAfterStop(retried: boolean): void {
  37. const callback = (result: WechatMiniprogram.OnAccelerometerChangeCallbackResult) => {
  38. if (
  39. typeof result.x !== 'number'
  40. || typeof result.y !== 'number'
  41. || typeof result.z !== 'number'
  42. || Number.isNaN(result.x)
  43. || Number.isNaN(result.y)
  44. || Number.isNaN(result.z)
  45. ) {
  46. return
  47. }
  48. this.callbacks.onSample(result.x, result.y, result.z)
  49. }
  50. this.accelerometerCallback = callback
  51. wx.onAccelerometerChange(callback)
  52. wx.startAccelerometer({
  53. interval: 'ui',
  54. success: () => {
  55. this.starting = false
  56. this.listening = true
  57. },
  58. fail: (res) => {
  59. const errorMessage = res && res.errMsg ? res.errMsg : 'startAccelerometer failed'
  60. if (!retried && errorMessage.indexOf('has enable') >= 0) {
  61. this.detachCallback()
  62. this.clearRetryTimer()
  63. this.retryTimer = setTimeout(() => {
  64. this.retryTimer = 0
  65. wx.stopAccelerometer({
  66. complete: () => {
  67. this.startAfterStop(true)
  68. },
  69. })
  70. }, ACCELEROMETER_START_RETRY_DELAY_MS) as unknown as number
  71. return
  72. }
  73. this.starting = false
  74. this.detachCallback()
  75. this.callbacks.onError(errorMessage)
  76. },
  77. })
  78. }
  79. stop(): void {
  80. this.clearRetryTimer()
  81. this.detachCallback()
  82. wx.stopAccelerometer({
  83. complete: () => {},
  84. })
  85. this.starting = false
  86. this.listening = false
  87. }
  88. destroy(): void {
  89. this.stop()
  90. }
  91. private clearRetryTimer(): void {
  92. if (!this.retryTimer) {
  93. return
  94. }
  95. clearTimeout(this.retryTimer)
  96. this.retryTimer = 0
  97. }
  98. private detachCallback(): void {
  99. if (!this.accelerometerCallback) {
  100. return
  101. }
  102. if (typeof wx.offAccelerometerChange === 'function') {
  103. wx.offAccelerometerChange(this.accelerometerCallback)
  104. }
  105. this.accelerometerCallback = null
  106. }
  107. }