web-step-counter-pro 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -4
  2. package/step-counter.js +64 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-step-counter-pro",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "A professional-grade web step counting library with advanced anti-cheat mechanisms (GPS, Gyroscope, Rhythm Analysis).",
5
5
  "main": "step-counter.js",
6
6
  "type": "module",
@@ -23,7 +23,5 @@
23
23
  "README.md",
24
24
  "package.json"
25
25
  ],
26
- "dependencies": {
27
-
28
- }
26
+ "dependencies": {}
29
27
  }
package/step-counter.js CHANGED
@@ -49,6 +49,7 @@ export class WebStepCounter {
49
49
  gpsAccuracyLimit: 20,
50
50
  maxSpeed: 2.8,
51
51
  debug: false,
52
+ autoPauseOnBackground: true, // 新增: Capacitor 环境下切后台自动暂停传感器
52
53
  onStep: null,
53
54
  onStatus: null,
54
55
  onSensorData: null,
@@ -58,6 +59,7 @@ export class WebStepCounter {
58
59
  // 内部状态
59
60
  this.stepCount = 0;
60
61
  this.isTracking = false;
62
+ this.isPausedByBackground = false; // 新增: 标记是否因后台而暂停
61
63
  this.candidateSteps = 0;
62
64
  this.lastStepTime = 0;
63
65
  this.lastCandidateStepTime = 0;
@@ -84,13 +86,21 @@ export class WebStepCounter {
84
86
  async start() {
85
87
  if (this.isTracking) return;
86
88
 
87
- if (location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') {
89
+ const isCapacitor = !!window.Capacitor;
90
+
91
+ // 1. HTTPS 检查 (Capacitor 环境豁免)
92
+ if (!isCapacitor && location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1') {
88
93
  this._reportStatus("必须使用 HTTPS 协议", WebStepCounter.StatusType.ERROR, WebStepCounter.StatusCode.HTTPS_REQUIRED);
89
94
  return false;
90
95
  }
91
96
 
92
97
  this._reportStatus("正在请求传感器权限...", WebStepCounter.StatusType.INFO);
93
98
 
99
+ // Capacitor 优化: 绑定生命周期
100
+ if (isCapacitor && this.config.autoPauseOnBackground) {
101
+ this._initCapacitorLifecycle();
102
+ }
103
+
94
104
  const permissionGranted = await this._requestPermissions();
95
105
  if (!permissionGranted) return false;
96
106
 
@@ -109,13 +119,19 @@ export class WebStepCounter {
109
119
 
110
120
  stop() {
111
121
  this.isTracking = false;
112
- window.removeEventListener('devicemotion', this.handleMotion);
113
- window.removeEventListener('deviceorientation', this.handleOrientation);
114
- window.removeEventListener('deviceorientationabsolute', this.handleOrientation);
122
+ this._removeSensors();
115
123
 
116
124
  if (this.watchId) {
117
125
  navigator.geolocation.clearWatch(this.watchId);
126
+ this.watchId = null;
127
+ }
128
+
129
+ // 清理 Capacitor 监听
130
+ if (this.appListener) {
131
+ this.appListener.remove();
132
+ this.appListener = null;
118
133
  }
134
+
119
135
  this._reportStatus("已停止", WebStepCounter.StatusType.INFO);
120
136
  }
121
137
 
@@ -147,6 +163,49 @@ export class WebStepCounter {
147
163
 
148
164
  // --- Internal ---
149
165
 
166
+ // Capacitor 生命周期处理
167
+ _initCapacitorLifecycle() {
168
+ if (!window.Capacitor || !window.Capacitor.Plugins || !window.Capacitor.Plugins.App) return;
169
+
170
+ const App = window.Capacitor.Plugins.App;
171
+
172
+ // 监听 App 状态变化
173
+ this.appListener = App.addListener('appStateChange', ({ isActive }) => {
174
+ if (!this.isTracking) return;
175
+
176
+ if (!isActive) {
177
+ // 切到后台: 暂停传感器以省电,并防止 iOS 冻结导致的异常数据
178
+ this._reportStatus("App 进入后台,暂停计步", WebStepCounter.StatusType.INFO);
179
+ this._removeSensors();
180
+ this.isPausedByBackground = true;
181
+ } else {
182
+ // 切回前台: 恢复
183
+ if (this.isPausedByBackground) {
184
+ this._reportStatus("App 回到前台,恢复计步", WebStepCounter.StatusType.INFO);
185
+ this._addSensors();
186
+ this.isPausedByBackground = false;
187
+ }
188
+ }
189
+ });
190
+ }
191
+
192
+ _addSensors() {
193
+ window.addEventListener('devicemotion', this.handleMotion);
194
+ // 重新检查环境支持情况来决定添加哪个 Orientation 事件
195
+ if (window.DeviceOrientationEvent) {
196
+ window.addEventListener('deviceorientation', this.handleOrientation);
197
+ }
198
+ if ('ondeviceorientationabsolute' in window) {
199
+ window.addEventListener('deviceorientationabsolute', this.handleOrientation);
200
+ }
201
+ }
202
+
203
+ _removeSensors() {
204
+ window.removeEventListener('devicemotion', this.handleMotion);
205
+ window.removeEventListener('deviceorientation', this.handleOrientation);
206
+ window.removeEventListener('deviceorientationabsolute', this.handleOrientation);
207
+ }
208
+
150
209
  async _requestPermissions() {
151
210
  if (typeof DeviceMotionEvent !== 'undefined' && typeof DeviceMotionEvent.requestPermission === 'function') {
152
211
  try {
@@ -175,13 +234,7 @@ export class WebStepCounter {
175
234
  return false;
176
235
  }
177
236
  } else {
178
- window.addEventListener('devicemotion', this.handleMotion);
179
- if (window.DeviceOrientationEvent) {
180
- window.addEventListener('deviceorientation', this.handleOrientation);
181
- }
182
- if ('ondeviceorientationabsolute' in window) {
183
- window.addEventListener('deviceorientationabsolute', this.handleOrientation);
184
- }
237
+ this._addSensors();
185
238
  }
186
239
  return true;
187
240
  }