更新记录

1.0.0(2026-03-12)

  • Android:新增 strategy 引擎策略参数,支持 autopreferHealthConnectpreferSensorhealthConnectOnlysensorOnly
  • Android:查询、授权、实时监听统一改为 resolver 路由,getTodayStepCount() 现在会按授权状态在 Health ConnectSensor 之间回退
  • Android:将插件 minSdkVersion 提升到 26,以满足 androidx.health.connect:connect-client 的构建要求并修复云打包失败
  • Android / iOS:结果与授权对象新增 resolvedEnginerequestedStrategyavailableEngines 字段
  • Android / iOS / Harmony:新增 getAvailableEngines() 能力探测接口
  • Android:新增 ForegroundService 持有 TYPE_STEP_COUNTER 监听,支持应用退到后台后继续采集并持久化今日步数
  • Android:监听通知改为前台服务模型,task.stop() 会同步停止服务并移除通知
  • Android:补充 FOREGROUND_SERVICEFOREGROUND_SERVICE_HEALTH 与服务组件声明,并更新插件权限文档
  • Android:补充 POST_NOTIFICATIONS 权限声明、通知状态查询与通知设置入口,requestAuthorization() 现会顺序请求步数权限与通知权限

平台兼容性

uni-app(4.87)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(4.87)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - -

hans-step-counter

hans-step-counter 是一个同时支持 uni-appuni-app x 的步数插件,提供 Android 和 iOS 的步数授权、今日步数查询与实时监听能力。

适用范围

项目 说明
框架 uni-app / uni-app x
HBuilderX ^3.6.8
Android 8.0+ (API 26+)
iOS 12.0+
Harmony 1.0.0 暂不支持

能力列表

  • 检测设备是否支持步数能力
  • 获取当前可用引擎和授权状态
  • 请求步数相关权限
  • 查询今日步数
  • 监听步数变化
  • 打开系统设置页
  • 打开 Android 通知设置页
  • 打开或关闭插件日志

引入方式

经典 uni-app.vue 页面和 uni-app x.uvue 页面都可以按下面方式引入:

import {
  isStepCounterSupported,
  getAvailableEngines,
  getAuthorizationStatus,
  requestAuthorization,
  getTodayStepCount,
  startStepCountUpdates,
  openAppSettings,
  openNotificationSettings,
  setLogEnabled,
  isLogEnabled,
  RequestAuthorizationOptions,
  GetTodayStepCountOptions,
  StartStepCountUpdatesOptions,
  StepCounterAuthorizationResult,
  StepCountResult,
  StepCountChange,
  StepCounterFail,
} from '@/uni_modules/hans-step-counter'

快速开始

1. 检查支持情况

const supported = isStepCounterSupported()
const engines = getAvailableEngines()
const auth = getAuthorizationStatus()

console.log('supported', supported)
console.log('engines', engines)
console.log('auth', auth.status)

getAvailableEngines() 返回值:

  • Android:['healthConnect']['sensor']['healthConnect', 'sensor']
  • iOS:['pedometer']
  • Harmony:[]

2. 请求授权

const authOptions: RequestAuthorizationOptions = {
  strategy: 'preferSensor',
  success: (res: StepCounterAuthorizationResult) => {
    console.log('auth success', res.status, res.resolvedEngine, res.availableEngines)
  },
  fail: (err: StepCounterFail) => {
    console.error('auth fail', err.errCode, err.errMsg)
  },
}

requestAuthorization(authOptions)

3. 查询今日步数

const stepOptions: GetTodayStepCountOptions = {
  strategy: 'preferHealthConnect',
  success: (res: StepCountResult) => {
    console.log('today steps', res.steps)
    console.log('engine', res.resolvedEngine)
    console.log('accurate', res.isAccurate)
    console.log('trackedFromTime', res.trackedFromTime)
    console.log('note', res.note)
  },
  fail: (err: StepCounterFail) => {
    console.error('query fail', err.errCode, err.errMsg)
  },
}

getTodayStepCount(stepOptions)

4. 监听步数变化

const updateOptions: StartStepCountUpdatesOptions = {
  strategy: 'sensorOnly',
  emitCurrent: true,
  onChange: (res: StepCountChange) => {
    console.log('total', res.totalSteps)
    console.log('delta', res.deltaSteps)
    console.log('engine', res.resolvedEngine)
  },
  fail: (err: StepCounterFail) => {
    console.error('listen fail', err.errCode, err.errMsg)
  },
}

const task = startStepCountUpdates(updateOptions)

task.stop()

5. 打开设置和日志

setLogEnabled(true)
console.log('log enabled', isLogEnabled())

openAppSettings()
openNotificationSettings()

openNotificationSettings() 主要用于 Android 前台服务通知不可见或被用户关闭时的引导。

API 概览

setLogEnabled(enabled: boolean): void
isLogEnabled(): boolean
isStepCounterSupported(): boolean
getAvailableEngines(): Array<StepCounterEngine>
getAuthorizationStatus(): StepCounterAuthorizationResult
requestAuthorization(options: RequestAuthorizationOptions): void
getTodayStepCount(options: GetTodayStepCountOptions): void
startStepCountUpdates(options: StartStepCountUpdatesOptions): StepCounterTask
openAppSettings(): void
openNotificationSettings(): void

类型定义

以下类型以 utssdk/interface.uts 为准。

字面量类型

type StepCounterPlatform = 'android' | 'ios' | 'harmony'
type StepCounterSource = 'sensor' | 'healthConnect' | 'pedometer' | 'stub'
type StepCounterEngine = 'sensor' | 'healthConnect' | 'pedometer'
type StepCounterStrategy =
  | 'auto'
  | 'preferHealthConnect'
  | 'preferSensor'
  | 'healthConnectOnly'
  | 'sensorOnly'

type StepCounterAuthorizationStatus =
  | 'authorized'
  | 'denied'
  | 'notDetermined'
  | 'restricted'
  | 'unsupported'

type StepCounterErrorCode =
  | 9011001
  | 9011002
  | 9011003
  | 9011004
  | 9011005
  | 9011006
  | 9011007
  | 9011008
  | 9011009
  | 9011010

Options 类型

type RequestAuthorizationOptions = {
  strategy?: StepCounterStrategy | null
  success?: (res: StepCounterAuthorizationResult) => void
  fail?: (err: StepCounterFail) => void
  complete?: (res: any) => void
}

type GetTodayStepCountOptions = {
  strategy?: StepCounterStrategy | null
  success?: (res: StepCountResult) => void
  fail?: (err: StepCounterFail) => void
  complete?: (res: any) => void
}

type StartStepCountUpdatesOptions = {
  strategy?: StepCounterStrategy | null
  emitCurrent?: boolean
  onChange: (res: StepCountChange) => void
  fail?: (err: StepCounterFail) => void
}

返回类型

interface StepCounterTask {
  stop(): void
}

interface StepCounterFail extends IUniError {
  errCode: StepCounterErrorCode
}

type StepCounterAuthorizationResult = {
  status: StepCounterAuthorizationStatus
  platform: StepCounterPlatform
  isSupported: boolean
  resolvedEngine: StepCounterEngine | null
  requestedStrategy: StepCounterStrategy | null
  availableEngines: Array<StepCounterEngine>
  permissionRequired: boolean
  permissionDeclared: boolean
  doNotAskAgain: boolean | null
  notificationPermissionRequired: boolean
  notificationPermissionDeclared: boolean
  notificationStatus: StepCounterAuthorizationStatus
  notificationDoNotAskAgain: boolean | null
  notificationsEnabled: boolean
  notificationChannelEnabled: boolean | null
}

type StepCountResult = {
  steps: number
  startTime: number
  endTime: number
  platform: StepCounterPlatform
  source: StepCounterSource
  resolvedEngine: StepCounterEngine
  requestedStrategy: StepCounterStrategy | null
  distance: number | null
  floorsAscended: number | null
  floorsDescended: number | null
  trackedFromTime: number | null
  isAccurate: boolean
  note: string | null
}

type StepCountChange = {
  totalSteps: number
  deltaSteps: number
  timestamp: number
  platform: StepCounterPlatform
  source: StepCounterSource
  resolvedEngine: StepCounterEngine
  requestedStrategy: StepCounterStrategy | null
  trackedFromTime: number | null
  isAccurate: boolean
  note: string | null
}

时间和可空字段约定

  • startTimeendTimetimestamptrackedFromTime 都是 Unix 时间戳毫秒值
  • trackedFromTime == null 表示插件无法给出可信起点
  • requestedStrategy == null 只会出现在少量内部兜底场景,业务侧通常会拿到具体值或 auto
  • distancefloorsAscendedfloorsDescended 目前主要由 iOS CMPedometer 提供,Android 侧通常为 null

API 说明

setLogEnabled(enabled)

setLogEnabled(enabled: boolean): void
  • 入参 enabledboolean
  • true 开启插件日志,false 关闭

isLogEnabled()

isLogEnabled(): boolean
  • 返回当前日志开关状态

isStepCounterSupported()

isStepCounterSupported(): boolean
  • 仅表示设备和当前平台是否存在可用步数能力
  • 不代表权限已经授权

getAvailableEngines()

getAvailableEngines(): Array<StepCounterEngine>
  • 返回当前设备可用引擎列表
  • Android 可能返回 sensorhealthConnect 或两者都有
  • iOS 仅可能返回 pedometer

getAuthorizationStatus()

getAuthorizationStatus(): StepCounterAuthorizationResult
  • 返回当前默认策略下的授权状态快照
  • 不会主动弹权限框
  • Android 返回值里会同时带上通知权限和通知渠道状态

requestAuthorization(options)

requestAuthorization(options: RequestAuthorizationOptions): void

options 字段:

字段 类型 必填 说明
strategy StepCounterStrategy \| null 选择授权目标引擎,未传时按 auto
success (res: StepCounterAuthorizationResult) => void 授权流程成功结束或返回当前状态时回调
fail (err: StepCounterFail) => void 授权流程异常时回调
complete (res: any) => void 无论成功或失败都会回调

说明:

  • Android auto 默认优先申请 sensor
  • iOS 始终走 pedometerstrategy 仅保留在返回值里
  • Harmony 当前会直接走 success,返回 status: 'unsupported'
  • complete 成功时收到 StepCounterAuthorizationResult,失败时收到 StepCounterFail

调用示例:

requestAuthorization({
  strategy: 'preferSensor',
  success: (res: StepCounterAuthorizationResult) => {
    console.log(res.status)
    console.log(res.resolvedEngine)
    console.log(res.notificationStatus)
  },
  fail: (err: StepCounterFail) => {
    console.error(err.errCode, err.errMsg)
  },
  complete: (res: any) => {
    console.log('complete', res)
  },
})

getTodayStepCount(options)

getTodayStepCount(options: GetTodayStepCountOptions): void

options 字段:

字段 类型 必填 说明
strategy StepCounterStrategy \| null 查询时的引擎策略,未传时按 auto
success (res: StepCountResult) => void 查询成功回调
fail (err: StepCounterFail) => void 查询失败回调
complete (res: any) => void 无论成功或失败都会回调

说明:

  • Android auto 默认优先使用 healthConnect,不可用时回退 sensor
  • iOS 始终使用 pedometer
  • Harmony 当前直接失败,错误码为 9011001
  • complete 成功时收到 StepCountResult,失败时收到 StepCounterFail

startStepCountUpdates(options)

startStepCountUpdates(options: StartStepCountUpdatesOptions): StepCounterTask

options 字段:

字段 类型 必填 说明
strategy StepCounterStrategy \| null 监听时的引擎策略,未传时按 auto
emitCurrent boolean 是否在启动后立即回调一次当前值,默认 true
onChange (res: StepCountChange) => void 步数变化回调
fail (err: StepCounterFail) => void 启动失败或监听过程出错时回调

说明:

  • 返回值始终是 StepCounterTask,不需要监听时调用 task.stop()
  • Android 实时监听仅支持 sensor
  • iOS 使用 CMPedometer 实时更新
  • Harmony 当前直接触发 fail
  • 如果指定 healthConnectOnly 去调用实时监听,Android 会因为该引擎不支持实时更新而失败

openAppSettings()

openAppSettings(): void
  • 打开当前应用系统设置页
  • 适用于权限被永久拒绝后的引导

openNotificationSettings()

openNotificationSettings(): void
  • Android:打开通知设置页
  • iOS:当前实现会回退到应用设置页
  • 主要用于 Android 前台服务通知被关闭时的引导

Strategy 说明

以下接口支持传入 strategy

  • requestAuthorization()
  • getTodayStepCount()
  • startStepCountUpdates()

可选值:

  • auto
  • preferHealthConnect
  • preferSensor
  • healthConnectOnly
  • sensorOnly

Android 下默认 auto 行为如下:

  • requestAuthorization():优先申请 sensor
  • getTodayStepCount():优先使用 healthConnect,不可用时回退 sensor
  • startStepCountUpdates():优先使用 sensor

接入建议:

  • 只关心查询今日总步数:优先 autopreferHealthConnect
  • 需要实时监听和后台持续累计:优先 autopreferSensor
  • 明确只接受某一种引擎:使用 healthConnectOnlysensorOnly

返回结果字段说明

StepCounterAuthorizationResult

字段 类型 说明
status StepCounterAuthorizationStatus 当前授权状态
platform StepCounterPlatform 当前平台
isSupported boolean 当前平台和设备是否支持
resolvedEngine StepCounterEngine \| null 当前策略最终命中的引擎
requestedStrategy StepCounterStrategy \| null 本次使用的策略
availableEngines Array<StepCounterEngine> 当前设备可用引擎列表
permissionRequired boolean 当前引擎是否需要权限
permissionDeclared boolean 原生权限是否已在工程中声明
doNotAskAgain boolean \| null Android 是否更适合直接去系统设置
notificationPermissionRequired boolean Android 通知权限是否需要单独申请
notificationPermissionDeclared boolean Android 是否声明了通知权限
notificationStatus StepCounterAuthorizationStatus Android 通知权限状态;其他平台通常为 unsupported
notificationDoNotAskAgain boolean \| null Android 通知权限是否被用户永久拒绝
notificationsEnabled boolean Android 系统通知总开关是否打开
notificationChannelEnabled boolean \| null Android 前台服务通知渠道是否启用

StepCountResult

字段 类型 说明
steps number 今日累计步数
startTime number 本次统计区间起点,毫秒时间戳
endTime number 本次统计区间终点,毫秒时间戳
platform StepCounterPlatform 当前平台
source StepCounterSource 数据来源
resolvedEngine StepCounterEngine 实际使用的引擎
requestedStrategy StepCounterStrategy \| null 本次查询使用的策略
distance number \| null 距离,iOS 下通常是米
floorsAscended number \| null 上楼层数,iOS 可用
floorsDescended number \| null 下楼层数,iOS 可用
trackedFromTime number \| null 当前结果可信的起始时间
isAccurate boolean 是否可视为完整统计
note string \| null 补充说明,建议只用于展示或日志

StepCountChange

字段 类型 说明
totalSteps number 当前累计总步数
deltaSteps number 相对上一次回调新增的步数
timestamp number 本次事件时间,毫秒时间戳
platform StepCounterPlatform 当前平台
source StepCounterSource 数据来源
resolvedEngine StepCounterEngine 实际使用的引擎
requestedStrategy StepCounterStrategy \| null 本次监听使用的策略
trackedFromTime number \| null 当前累计可信的起始时间
isAccurate boolean 是否可视为完整统计
note string \| null 补充说明,建议只用于展示或日志

精度字段使用建议

以下场景下,步数结果可能不是完整的全天统计:

  • 当天较晚才第一次启动插件
  • 跨午夜期间没有持续观测
  • 设备重启或传感器累计值被系统重置

建议页面按以下方式处理:

  • isAccurate == false:给用户展示“统计可能不完整”的提示
  • trackedFromTime != null:可提示“当前统计从某个时间点开始”
  • note != null:只用于展示和日志,不建议业务逻辑依赖文案内容

Android 使用说明

权限

插件已声明以下 Android 权限:

  • android.permission.ACTIVITY_RECOGNITION
  • android.permission.POST_NOTIFICATIONS
  • android.permission.FOREGROUND_SERVICE
  • android.permission.FOREGROUND_SERVICE_HEALTH
  • android.permission.health.READ_STEPS

说明:

  • sensor 路径会使用步数传感器和前台服务
  • healthConnect 路径会拉起 Health Connect 授权页
  • Android 13+ 在 sensor 路径下会顺序请求活动识别权限和通知权限
  • 如果业务指定 healthConnectOnly 或优先使用 healthConnect,请先确认设备已安装并可用 Health Connect,否则可能返回 90110099011010

后台监听

  • Android 下调用 startStepCountUpdates() 会启动前台服务并显示持续通知
  • task.stop() 会停止监听并移除通知
  • 页面退到后台后,页面回调可能暂停,但原生层仍会继续累计和持久化
  • 如果有多个页面或多个消费者,建议在应用层只维护一个原生监听任务,再自行分发事件

iOS 使用说明

  • 插件已声明 NSMotionUsageDescription
  • 首次读取步数或启动监听前,应先调用 requestAuthorization()
  • iOS 使用 CMPedometer 提供查询和实时步数更新能力
  • distancefloorsAscendedfloorsDescended 只有系统提供时才会返回

Harmony 说明

  • 当前版本仅提供占位实现,不支持真实步数能力
  • isStepCounterSupported() 恒为 false
  • requestAuthorization() 会返回 status: 'unsupported'
  • getTodayStepCount()startStepCountUpdates() 会以 9011001 失败

错误码

错误码 含义
9011001 当前平台不支持
9011002 当前设备没有可用步数引擎,或当前操作没有可用实时监听引擎
9011003 Android 活动识别权限未授权
9011004 iOS 运动与健身权限不可用、未授权或受限
9011005 传入参数无效
9011006 启动步数监听失败
9011007 查询步数失败
9011008 插件内部错误
9011009 Health Connect 未安装或需要升级
9011010 Health Connect 未授权或同步不可用

隐私、权限声明

1. 本插件需要申请的系统权限列表:

Android 需要 android.permission.ACTIVITY_RECOGNITION、android.permission.POST_NOTIFICATIONS、android.permission.FOREGROUND_SERVICE、android.permission.FOREGROUND_SERVICE_HEALTH 与 android.permission.health.READ_STEPS,并会显示前台服务通知;iOS 需要 NSMotionUsageDescription;Harmony 当前版本未正式支持。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件会读取设备步数数据(Android 传感器或 Health Connect、iOS Motion & Fitness),仅用于返回步数结果,不包含账号体系与远程上传。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。