Android步行计步应用中GoogleSignIn.requestPermissions弹出空白加载弹窗及Fitness API权限调用报错问题
解决Google Fit计步应用的两个核心问题
我来帮你拆解并解决遇到的这两个问题:
问题2:The user must be signed in to make this API call 错误
这个报错的核心原因是:你调用Fitness API时,用户还没完成完整的Google账号登录授权流程。当前你用GoogleSignIn.getAccountForExtension获取的只是关联Fitness的扩展账户,但并没有确保用户已经通过Google Sign-In完成了账号登录。
修复步骤:
- 先检查用户是否已登录Google账号,再检查Fitness权限
- 若未登录,先启动Google登录流程,再请求Fitness权限
修改onCreate及相关逻辑如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); fitnessOptions = FitnessOptions.builder() .addDataType(DataType.TYPE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ) .addDataType(DataType.AGGREGATE_STEP_COUNT_DELTA, FitnessOptions.ACCESS_READ) .addDataType(DataType.TYPE_CALORIES_EXPENDED, FitnessOptions.ACCESS_READ) .addDataType(DataType.AGGREGATE_CALORIES_EXPENDED, FitnessOptions.ACCESS_READ) .addDataType(DataType.TYPE_DISTANCE_DELTA, FitnessOptions.ACCESS_READ) .addDataType(DataType.AGGREGATE_DISTANCE_DELTA, FitnessOptions.ACCESS_READ) .build(); // 先处理Android 10+必需的Activity Recognition权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACTIVITY_RECOGNITION}, MY_PERMISSIONS_REQUEST_ACTIVITY_RECOGNITION); } else { checkGoogleSignInStatus(); } setContentView(R.layout.activity_start); btnPause = findViewById(R.id.btnPause); btnPause.setOnClickListener(v -> { // 这里添加暂停逻辑 }); } // 新增方法:检查Google登录及权限状态 private void checkGoogleSignInStatus() { GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this); if (account == null || !GoogleSignIn.hasPermissions(account, fitnessOptions)) { if (account == null) { // 未登录,先启动Google登录+权限请求流程 GoogleSignInClient signInClient = GoogleSignIn.getClient(this, GoogleSignInOptions.DEFAULT_SIGN_IN); signInClient.requestPermissions( this, RC_REQUEST_STEP_COUNT_AND_CONTINUE_SUBSCRIPTION, GoogleSignIn.getAccountForExtension(this, fitnessOptions), fitnessOptions); } else { // 已登录但缺少Fitness权限,单独请求权限 GoogleSignIn.requestPermissions( this, RC_REQUEST_STEP_COUNT_AND_CONTINUE_SUBSCRIPTION, account, fitnessOptions); } } else { // 已登录且权限齐全,启动数据订阅 startSubscription(DataType.TYPE_STEP_COUNT_DELTA); } } // 处理Activity Recognition权限请求结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == MY_PERMISSIONS_REQUEST_ACTIVITY_RECOGNITION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { checkGoogleSignInStatus(); } else { Toast.makeText(this, "需要Activity Recognition权限才能获取步数数据", Toast.LENGTH_SHORT).show(); } } }
问题1:调用GoogleSignIn.requestPermissions时弹出空白加载弹窗
这个空白弹窗通常是因为权限请求流程启动时,用户还未完成Google账号登录,导致流程异常。通过上面的修复,我们先确保用户完成Google登录,再请求Fitness权限,就能解决这个问题。
另外还要注意:
- 确保
AndroidManifest.xml已按照官方要求配置好Google Fit的权限、元数据及API密钥 - 测试时使用已添加Google账号的设备/模拟器,避免因无账号导致流程中断
额外代码优化建议
- 你的
getDataUsingSensor方法中,强制转换所有字段值为float可能报错,不同DataType的字段类型不同,建议做类型判断:
@Override public void onDataPoint(@NonNull DataPoint dataPoint) { for (Field field : dataPoint.getDataType().getFields()) { Value value = dataPoint.getValue(field); if (field.equals(Field.FIELD_STEPS)) { int steps = value.asInt(); tvSteps.setText(String.valueOf(steps)); } else if (field.equals(Field.FIELD_DISTANCE)) { float distance = value.asFloat(); tvDistance.setText(String.format("%.2f km", distance)); } // 其他字段同理处理 } }
- 在
onDestroy中移除传感器监听,避免内存泄漏:
private OnDataPointListener dataPointListener; // 修改getDataUsingSensor方法保存listener引用 public void getDataUsingSensor(DataType dataType) { dataPointListener = new OnDataPointListener() { @Override public void onDataPoint(@NonNull DataPoint dataPoint) { // 数据处理逻辑 } }; Fitness.getSensorsClient(this, GoogleSignIn.getLastSignedInAccount(this)) .add(new SensorRequest.Builder() .setDataType(dataType) .setSamplingRate(1, TimeUnit.SECONDS) .build(), dataPointListener); } @Override protected void onDestroy() { super.onDestroy(); if (dataPointListener != null && GoogleSignIn.getLastSignedInAccount(this) != null) { Fitness.getSensorsClient(this, GoogleSignIn.getLastSignedInAccount(this)) .remove(dataPointListener); } }
内容的提问来源于stack exchange,提问作者Sajid Khan
相关产品推荐
相关产品推荐

