You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Fit睡眠追踪集成报错:需用户OAuth授权

解决Google Fit睡眠追踪中的ResolvableApiException: 5000错误

错误原因

这个5000: Application needs OAuth consent from the user错误直接表明:你的应用尚未获得用户的OAuth授权。Google Fit的睡眠数据属于敏感隐私数据,必须先完成用户授权流程,才能访问相关数据。你的现有代码跳过了授权步骤,直接尝试读取数据,因此触发了该异常。

解决方案

要解决这个问题,需要补充运行时权限请求和Google Fit OAuth授权的逻辑,同时处理异常中的授权引导。

1. 基础配置检查

  • 在AndroidManifest.xml中添加必要权限(Android 10及以上需要):
    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
    <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
    
  • 确保在Google Cloud Console中已启用Fit API,并配置了正确的OAuth客户端ID,同时添加https://www.googleapis.com/auth/fitness.sleep.read权限范围。

2. 完整代码修改

步骤1:添加权限检查与授权引导方法

private val REQUEST_ACTIVITY_RECOGNITION = 1001
private val REQUEST_FIT_AUTH = 1002
private val REQUEST_RESOLVE_ERROR = 1003

private fun prepareToReadSleepData() {
    // 先检查Android运行时权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION)
        != PackageManager.PERMISSION_GRANTED
    ) {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.ACTIVITY_RECOGNITION),
            REQUEST_ACTIVITY_RECOGNITION
        )
        return
    }

    // 配置Google Fit需要的权限范围
    val fitnessOptions = FitnessOptions.builder()
        .addDataType(DataType.TYPE_SLEEP_SEGMENT, FitnessOptions.ACCESS_READ)
        .addDataType(DataType.TYPE_SLEEP_SESSION, FitnessOptions.ACCESS_READ)
        .build()

    // 检查是否已获得Fit授权
    if (!GoogleSignIn.hasPermissions(getGoogleAccount(), fitnessOptions)) {
        GoogleSignIn.requestPermissions(
            this,
            REQUEST_FIT_AUTH,
            getGoogleAccount(),
            fitnessOptions
        )
    } else {
        // 权限齐全,读取睡眠数据
        readSleepData()
    }
}

步骤2:修改原读取数据方法的异常处理

更新readSleepData()中的失败监听,处理ResolvableApiException:

private fun readSleepData() {
    val request = SessionReadRequest.Builder()
        .readSessionsFromAllApps()
        .includeSleepSessions()
        .read(DataType.TYPE_SLEEP_SEGMENT)
        .setTimeInterval(periodStartMillis, periodEndMillis, TimeUnit.MILLISECONDS)
        .build()

    val sessionsClient = Fitness.getSessionsClient(this, getGoogleAccount())
    sessionsClient.readSession(request)
        .addOnSuccessListener { response ->
            for (session in response.sessions) {
                val sessionStart = session.getStartTime(TimeUnit.MILLISECONDS)
                val sessionEnd = session.getEndTime(TimeUnit.MILLISECONDS)
                Log.i(TAG, "睡眠时段:$sessionStart 至 $sessionEnd")

                val dataSets = response.getDataSet(session)
                for (dataSet in dataSets) {
                    for (point in dataSet.dataPoints) {
                        val sleepStageVal = point.getValue(Field.FIELD_SLEEP_SEGMENT_TYPE).asInt()
                        val sleepStage = SLEEP_STAGES[sleepStageVal]
                        val segmentStart = point.getStartTime(TimeUnit.MILLISECONDS)
                        val segmentEnd = point.getEndTime(TimeUnit.MILLISECONDS)
                        Log.i(TAG, "\t睡眠阶段:$sleepStage,时段:$segmentStart 至 $segmentEnd")
                    }
                }
            }
        }
        .addOnFailureListener { e ->
            Log.w(TAG, "获取睡眠数据失败", e)
            // 处理可解析的授权异常,引导用户完成授权
            if (e is ResolvableApiException) {
                e.startResolutionForResult(this, REQUEST_RESOLVE_ERROR)
            }
        }
}

步骤3:添加权限与授权的回调处理

在你的Activity中重写回调方法,处理权限请求和授权结果:

override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_ACTIVITY_RECOGNITION) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            prepareToReadSleepData()
        } else {
            Toast.makeText(this, "需要运动识别权限才能访问睡眠数据", Toast.LENGTH_SHORT).show()
        }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        REQUEST_FIT_AUTH, REQUEST_RESOLVE_ERROR -> {
            if (resultCode == RESULT_OK) {
                readSleepData()
            } else {
                Toast.makeText(this, "授权失败,无法读取睡眠数据", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

3. 使用方式

之后不要直接调用readSleepData(),而是调用prepareToReadSleepData(),它会自动完成权限检查、授权引导,再读取数据。

内容的提问来源于stack exchange,提问作者Dipan Das

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 21:36:29