본문 바로가기

Android

Android에서 GoogleFit 걸음수 데이터 조회하기




Google Fit

요즘 출시되는 스마트폰에는 기본적으로 있는 기능 중 하나로 걸음수는 빼놓을 수 없다. 건강이 중요시 되는 시대에 스마트폰 뿐만 아니라 걸음수를 포함한 여러가지 건강정보를 제공해주는 웨어러블 디바이스도 여러가지 출시되고 있다. Samsung Health, Fitbit, Apple Health(아이폰 사용한지 좀 되서.. 이름이..), Shaomi 등등 여러가지 플랫폼 제공회사들이 존재하는대 이중에 Google도 존재한다. 안드로이드 스마트폰 문만 아니라 안드로이드 계열의 웨어러블 디바이스에서 모두 제공한다. Google Fit(Web) Google Fit(Android)

Google Fit on Android

스마트폰 혹은 웨어러블 디바이스에서 측정하는 건강 정보는 Sensor Adapters들과 연결되어 데이터를 전송하고 Google Play services안에 포함되어있는 Android Fitness API를 사용해 Google Cloud에 데이터를 주기적으로 전송하고 건강 정보를 앱에 조회할 수 있다.

Android Fitness API

Android Fitness API 홈페이지

위 링크를 타고들어가면 Android Fitness API 관련 정보들을 찾아볼 수 있다.

API를 사용해 앱 내부에서 걸음수를 조회하기 위해선 4가지 단계를 걸쳐야한다.

  1. 구글 계정 로그인
  2. Android SDK 중 Google Play services
  3. Google OAuth 2.0 client ID
  4. Configure project

4가지 단계 링크를 열고 들어가면 간단하게 확인 할 수 있다. OAuth 2.0 ID를 얻는 과정에서 내가 만든 앱의 패키지명과 SHA-1키를 입력해야 내가 만든 앱에서 데이터를 조회할 수 있도록 권한이 부여된다. (아무런 설정을 하지 않는다면 권한이 불허되면서 데이터 조회 에러 발생함)

Getting Step Count

이제 안드로이드에서 걸음수를 조회하는 코드를 작성해보자. 모든 코드는 MainActivity.java에서 작성하는 것을 기본으로 설정한다.

// 필요한 권한들 정의
FitnessOptions fitnessOptions =
    FitnessOptions.builder()
        .addDataType(DataType.TYPE_STEP_COUNT_CUMULATIVE)
        .addDataType(DataType.TYPE_STEP_COUNT_DELTA)
        .build();

onCreate 내부에서 걸음수를 조회하기 위해 필요한 피트니스 권한 객체를 생성한다. 이는 구글 로그인시 옵션으로 요청하기 위해 생성한다. 걸음수만을 조회하기 위해 TYPE_STEP_COUNT_CUMULATIVE, TYPE_STEP_COUNT_DELTA만을 요청한다. TYPE_STEP_COUNT_CUMULATIVE는 누적걸음수를 한번에 조회하기 위해 필요한 권한이고, TYPE_STEP_COUNT_DELTA는 단위시간별 걸음수를 확인하기 위해 필요한 권한이다. 사용자의 필요에 따라 둘 중 하나만 요청해도 무방하다.

if(!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions)) {
    GoogleSignIn.requestPermissions(
        this,
        REQUEST_OAUTH_REQUEST_CODE,
        GoogleSignIn.getLastSignedInAccount(this),
        fitnessOptions);
} else {
    Fitness.getRecordingClient(this, 
        GoogleSignIn.getLastSignedInAccount(this))
            .subscribe(DataType.TYPE_STEP_COUNT_CUMULATIVE)
            .addOnCompleteListener(
                new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if (task.isSuccessful()) {
                            Log.i(TAG, "Successfully subscribed!");
                        } else {
                            Log.w(TAG, "There was a problem subscribing.", task.getException());
                        }
                    }
                });
}

앱이 실행되고 나서 구글 계정에 권한이 있는지 hanPermissions함수를 사용해 확인한다. 이때 앞에서 생성한 권한 옵션 객체 fitnessOptions을 인자로 사용한다. 걸음수 조회 관련 권한이 없다면 권한을 요청하고 요청 결과를 onActivityResult 에서 확인한다. 이미 계정에 권한이 존재한다면 건강 데이터를 subscribe한다.

subscribe는 구글 클라우드 데이터 저장소와 동기화 시키는 것이다. Stream형태의 데이터를 지속적으로 받아서 처리하는 방법이 일반적인 방법이다. 하지만 Google Fit에서는 Stream형태의 데이터를 지원하지 않고 구글 클라우드 데이터 저장소와 동기화 시키는 작업을 하고 원하는 시간에 정보를 바로 조회할 수 있도록 한다. subscribe가 성공하면 subscribe한 데이터 형태에 대해서는 조회가 가능해진다.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // 로그인 성공시
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == REQUEST_OAUTH_REQUEST_CODE) {
            subscribe();
            readData();
        }
    }
}

권한을 얻고나면 onActivityResult 가 콜백함수로 호출된다. 권한을 성공했는지 판별한 뒤 권한을 얻었다면 subscribe하고 readData()함수를 통해 걸음수 데이터를 조회한다.

    private void readData() {
        final Calendar cal = Calendar.getInstance();
        Date now = Calendar.getInstance().getTime();
        cal.setTime(now);

        // 시작 시간
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 
            cal.get(Calendar.DAY_OF_MONTH), 6, 0, 0);
        long startTime = cal.getTimeInMillis();

        // 종료 시간
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), 
            cal.get(Calendar.DAY_OF_MONTH), 22, 0, 0);
        long endTime = cal.getTimeInMillis();

        Fitness.getHistoryClient(this, 
            GoogleSignIn.getLastSignedInAccount(this))
                .readData(new DataReadRequest.Builder()
                .read(DataType.TYPE_STEP_COUNT_DELTA) // Raw 걸음 수
                .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                .build())
            .addOnSuccessListener(new OnSuccessListener<DataReadResponse>() {
                @Override
                public void onSuccess(DataReadResponse response) {
                    DataSet dataSet = response.getDataSet(DataType.TYPE_STEP_COUNT_DELTA);
                    Log.i(TAG, "Data returned for Data type: " + dataSet.getDataType().getName());

                    for (DataPoint dp : dataSet.getDataPoints()) {
                        Log.i(TAG, "Data point:");
                        Log.i(TAG, "\tType: " + dp.getDataType().getName());

                        Log.i(TAG, "\tStart: " + milli2string(dp.getStartTime(TimeUnit.MILLISECONDS)));
                        Log.i(TAG, "\tEnd: " + milli2string(dp.getEndTime(TimeUnit.MILLISECONDS)));
                        for (Field field : dp.getDataType().getFields()) {
                            Log.i(TAG, "\tField: " + field.getName() + " Value: " + dp.getValue(field));
                        }
                    }
                }
            });
    }

API 중 getHistoryClient 함수를 사용해 데이터를 조회한다. 조회할 데이터는 걸음 수 이므로 권한 옵션을 설정한 TYPE_STEP_COUNT_DELTA 과 동일한 DataType를 입력한다. 자신이 원하는 시간대를 조회하기 위해 시간설정은 milliseconds로 계산한다. 자바에서는 Calendar 클래스에서 날짜를 정의한 뒤 milliseconds로 변환할 수 있다. 위 코드에서는 오늘의 오전6시 ~ 오후10시 까지로 설정하였다.

결과 데이터는 구글에서 정의한 DataReadResponse형태로 전달되고 이를 확인하기위해 로그를 찍어 확인한다.

logcat에서 결과 데이터를 확인할 수 있다. 데이터의 형테는 [시작시간, 끝시간, 값] 형태로 되어있다. 구글에서는 걸음수 데이터가 걸을때마다 생성되고 걸음이 없다면 데이터를 생성하지 않는다.

Conclusion

Google Fit데이터 중 걸음수를 가져오는 얘기를 정리하였다. 기본적으로 걸음수를 제공하는 것이고 구글에서는 생각보다 많은 Fitness정보를 제공한다. 걸음수, 몸무게, 키, 활동(축구,농구,걷기,뛰기등), 이동거리, 이동좌표 등등

이들을 조회하기 위해선 처음 로그인에 사용하는 권한, subscribe, read시 사용하는 DataType만 변경해주면 조회가 가능하다.

여러가지 데이터를 사용하면 재미있는 것들을 해볼 수 있을 것 같다.