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

基于Samsung Health SDK获取Galaxy Watch 4 Classic心率数据遇阻求助

三星Galaxy Watch 4 Classic心率传感器访问问题解决

问题背景

尝试在Android Studio中访问三星Galaxy Watch 4 Classic的心率传感器,并将数据显示在TextView中,使用Samsung Health SDK时始终无法正常连接,出现服务连接失败错误。

现有代码

Manifest配置

<uses-permission android:name="com.samsung.android.health.permission.read" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Activity代码

package com.example.test;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;

import com.example.test.databinding.ActivityVitalsBinding;
import com.samsung.android.sdk.healthdata.HealthDataStore;
import com.samsung.android.sdk.healthdata.HealthConstants;
import com.samsung.android.sdk.healthdata.HealthDataResolver;
import com.samsung.android.sdk.healthdata.HealthDataResolver.Filter;
import com.samsung.android.sdk.healthdata.HealthPermissionManager;
import com.samsung.android.sdk.healthdata.HealthResultHolder;
import com.samsung.android.sdk.healthdata.HealthResultHolder.ResultListener;

import java.util.Arrays;
import java.util.HashSet;


public class VitalsActivity extends Activity {

    private HealthDataStore healthDataStore;
    private ActivityVitalsBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityVitalsBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

       healthDataStore = new HealthDataStore(this, new HealthDataStore.ConnectionListener() {
        @Override
        public void onConnected() {
            System.out.println("Connected successfully");
        }

        @Override
        public void onConnectionFailed(HealthConnectionErrorResult healthConnectionErrorResult) {
            System.out.println("couldn't connect");
        }

        @Override
        public void onDisconnected() {

        }
    });
    healthDataStore.connectService();
    }

private void requestHeartRatePermission() {
    HealthPermissionManager.PermissionKey key =
            new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ);

    HealthPermissionManager permissionManager = new HealthPermissionManager(healthDataStore);

    permissionManager.requestPermissions(new HashSet<HealthPermissionManager.PermissionKey>(Arrays.asList(key)))
            .setResultListener(new ResultListener<HealthPermissionManager.PermissionResult>() {
                @Override
                public void onResult(HealthPermissionManager.PermissionResult result) {
                    if (result.equals(true)) {
                        readHeartRateData();
                    } else {
                        System.out.println("access denied");
                    }
                }
            });
}

private void readHeartRateData() {
    HealthDataResolver resolver = new HealthDataResolver(healthDataStore, null);

    HealthDataResolver.ReadRequest request = new HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.HeartRate.HEALTH_DATA_TYPE)
            .build();

    resolver.read(request)
            .setResultListener(result -> {
                try (Cursor cursor = result.getResultCursor()) {
                    if (cursor != null && cursor.moveToFirst()) {
                        int heartRateIndex = cursor.getColumnIndex(HealthConstants.HeartRate.HEART_RATE);
                        if (heartRateIndex != -1) {
                            int heartRate = cursor.getInt(heartRateIndex);
                            System.out.println("current heartrate: " + heartRate);
                        } else {
                            System.out.println("couldn't find heartrate-column");
                        }
                    }
                } catch (Exception e) {
                    System.out.println("error while reading heartrate-data");
                }
            });
}
}

错误日志

E/HealthDataStore: disconnectService: Context instance is invalid
D/HealthDataStore: Trying to connect with Health Service fails (error code: 2)
D/HealthDataStore: Check SupportedDevice
D/HealthSDK-DeviceUtil: Server URL : https://hub.samsungapps.com/product/appCheck.as?appInfo=com.sec.android.app.shealth@0&deviceId=sdk_gwear_x86&mnc=260&csc=FAIL&openApi=30&mcc=310
D/HealthSDK-DeviceUtil: Downloading Samsung Health is unavailable (0)

解决方案

1. 切换实体设备测试

日志中deviceId=sdk_gwear_x86表明当前使用模拟器,Samsung Health SDK不支持模拟器运行。必须使用实体Galaxy Watch 4 Classic设备,且设备需安装最新版Samsung Health应用并完成登录。

2. 完善Manifest配置

添加健康数据类型声明的meta-data,同时确保权限申请完整:

<meta-data
    android:name="com.samsung.android.healthdata.health_data_types"
    android:value="com.samsung.health.heart_rate"/>

3. 修正连接与权限逻辑

  • 在onConnected回调中触发权限请求,当前代码未调用requestHeartRatePermission():
@Override
public void onConnected() {
    Log.d("HealthStore", "Connected successfully");
    requestHeartRatePermission();
}
  • 修正权限结果判断逻辑,原代码result.equals(true)判断错误,应检查授权集合:
@Override
public void onResult(HealthPermissionManager.PermissionResult result) {
    HealthPermissionManager.PermissionKey key =
            new HealthPermissionManager.PermissionKey(HealthConstants.HeartRate.HEALTH_DATA_TYPE, HealthPermissionManager.PermissionType.READ);
    if (result.getGrantedPermissions().contains(key)) {
        readHeartRateData();
    } else {
        Log.e("Permission", "access denied");
    }
}

4. 实现实时心率监听(替代历史数据读取)

原代码仅读取历史数据,若要获取实时心率,需使用HealthDataObserver监听数据变化:

private HealthDataObserver heartRateObserver;

private void registerHeartRateObserver() {
    heartRateObserver = new HealthDataObserver(null) {
        @Override
        public void onChange(String dataType) {
            readLatestHeartRateData();
        }
    };
    HealthDataObserver.addObserver(healthDataStore, HealthConstants.HeartRate.HEALTH_DATA_TYPE, heartRateObserver);
}

private void readLatestHeartRateData() {
    HealthDataResolver resolver = new HealthDataResolver(healthDataStore, null);
    HealthDataResolver.ReadRequest request = new HealthDataResolver.ReadRequest.Builder()
            .setDataType(HealthConstants.HeartRate.HEALTH_DATA_TYPE)
            .setSort(HealthConstants.HeartRate.CREATE_TIME, HealthDataResolver.Sort.DESC)
            .setLimit(1)
            .build();

    resolver.read(request).setResultListener(result -> {
        try (Cursor cursor = result.getResultCursor()) {
            if (cursor != null && cursor.moveToFirst()) {
                int heartRate = cursor.getInt(cursor.getColumnIndex(HealthConstants.HeartRate.HEART_RATE));
                runOnUiThread(() -> binding.yourTextViewId.setText(String.valueOf(heartRate)));
                Log.d("HeartRate", "Current heart rate: " + heartRate);
            }
        } catch (Exception e) {
            Log.e("HeartRate", "Read error", e);
        }
    });
}

// 在onDestroy中移除观察者
@Override
protected void onDestroy() {
    super.onDestroy();
    if (heartRateObserver != null) {
        HealthDataObserver.removeObserver(healthDataStore, heartRateObserver);
    }
    if (healthDataStore != null) {
        healthDataStore.disconnectService();
    }
}

记得在权限授予成功后调用registerHeartRateObserver()。

5. 验证应用签名

Samsung Health SDK要求应用使用三星开发者后台注册的签名进行签名,调试签名无法通过服务验证。确保应用签名与开发者后台配置一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 15:27:05