4

Google Fit and Flutter

I am following this documentation from Google: Google Fit

I don't understand step 5. I am not an Android developer and I have no idea where to locate the code. Step 5

For example, it says:

Before you can invoke methods from the Google Fit APIs, you must connect to one or more of the following API clients, which are part of Google Play services:

  • Sensors Client
  • Recording Client
  • History Client
  • Sessions Client
  • Goals Client
  • BLE Client
  • Config Client

Now, I try to connect the first one SensorsClient

But I don't know where to locate the code, which file? I am a flutter developer and I need help in step 5.

build.grandle

dependencies {
    implementation 'com.google.android.gms:play-services-fitness:18.0.0'
    implementation 'com.google.android.gms:play-services-auth:17.0.0'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
Community
  • 1
  • 1
desancheztorres
  • 353
  • 1
  • 6
  • 13
  • The code to make the connection request is mentioned in the link that you have mentioned in your description. https://developers.google.com/android/reference/com/google/android/gms/fitness/SensorsClient . Are you looking for anything else apart from the code to get the access. – Anudeep Jan 03 '20 at 13:33
  • I have no idea to connect the sensors, the documentation is made for Android Developers not for Flutter Developers so what I don't understand is how to connect the sensors, which file I have to include the code? – desancheztorres Jan 03 '20 at 13:40
  • https://pub.dev/packages/sensors – rstrelba Jan 03 '20 at 13:45

1 Answers1

6

Use Google Fit Rest Api in Flutter.

Google manages the data through data sources. To see all the data sources:

https://www.googleapis.com/fitness/v1/users/me/dataSources

To get Number of Steps: https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate Request body:

{    
    "aggregateBy" : [{    
        "dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"    
    }],    
    "bucketByTime": { "durationMillis": 86400000 }, // This is 24 hours    
    "startTimeMillis": 1546210381932,   // Start time    
    "endTimeMillis": 1547210381932  // End Time    
} 

You can use fitKit which is Flutter plugin for reading health and fitness data. Wraps HealthKit on iOS and GoogleFit on Android.

    import 'package:fit_kit/fit_kit.dart';

void read() async {
  final results = await FitKit.read(
    DataType.HEART_RATE,
    dateFrom: DateTime.now().subtract(Duration(days: 5)),
    dateTo: DateTime.now(),
  );
}

void readLast() async {
  final result = await FitKit.readLast(DataType.HEIGHT);
}

void readAll() async {
  if (await FitKit.requestPermissions(DataType.values)) {
    for (DataType type in DataType.values) {
      final results = await FitKit.read(
        type,
        dateFrom: DateTime.now().subtract(Duration(days: 5)),
        dateTo: DateTime.now(),
      );
    }
  }
}

If you are writing custom platform-specific code

Before you can invoke methods from the Google Fit APIs, you must connect to one or more of the following API clients, which are part of Google Play services:

  1. Sensors Client : Client which exposes different sources of fitness data in local and connected devices, and delivers live events to listeners.
  2. Recording Client : Client which enables low-power, always-on background collection of sensor data into the Google Fit store.
  3. History Client : Client for inserting, deleting, and reading data in Google Fit.
  4. Sessions Client : Client for creating and managing sessions of user activity in Google Fit.
  5. Goals Client : Client for reading fitness Goals created by users in Google Fit. BLE Client
  6. Config Client : Client for accessing custom data types and settings in Google Fit.

You must connect one of above.

    DataReadRequest readRequest = new DataReadRequest.Builder()
                .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
                .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                .bucketByTime(1, TimeUnit.DAYS)
                .enableServerQueries()
                .build();
// History Client 
        Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
                .readData(readRequest)
                .addOnSuccessListener(new OnSuccessListener<DataReadResponse>() {
                    @Override
                    public void onSuccess(DataReadResponse dataReadResponse) {
                        Log.d(TAG, "onSuccess()");
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.e(TAG, "onFailure()", e);
                    }
                })
                .addOnCompleteListener(new OnCompleteListener<DataReadResponse>() {
                    @Override
                    public void onComplete(@NonNull Task<DataReadResponse> task) {
                        Log.d(TAG, "onComplete()");
                    }
                });

Example for getting Heart Rate from History Client:

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInResult;
import com.google.android.gms.fitness.Fitness;
import com.google.android.gms.fitness.FitnessOptions;
import com.google.android.gms.fitness.data.Bucket;
import com.google.android.gms.fitness.data.DataPoint;
import com.google.android.gms.fitness.data.DataSet;
import com.google.android.gms.fitness.data.DataType;
import com.google.android.gms.fitness.data.Field;
import com.google.android.gms.fitness.request.DataReadRequest;
import com.google.android.gms.fitness.result.DataReadResponse;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;


import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class googleFitData extends AppCompatActivity {

    private static final String TAG = "googleFitData";
    private static final int GOOGLE_FIT_PERMISSIONS_REQUEST_CODE = 2;
    private static final int PERMISSIONS_REQUEST_ACTIVITY_RECOGNITION = 3;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_smart_wacth);


        String[] PERMISSIONS = {
                Manifest.permission.ACTIVITY_RECOGNITION
        };


        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION)
                    != PackageManager.PERMISSION_GRANTED) {

                ActivityCompat.requestPermissions(this,
                        PERMISSIONS,
                        PERMISSIONS_REQUEST_ACTIVITY_RECOGNITION);
            }
        } else {
            googleSignin();

        }


    }

    public void googleSignin() {
        FitnessOptions fitnessOptions = FitnessOptions.builder()
                .addDataType(DataType.TYPE_HEART_RATE_BPM, FitnessOptions.ACCESS_READ)
                .build();
        if (!GoogleSignIn.hasPermissions(GoogleSignIn.getLastSignedInAccount(this), fitnessOptions)) {
            GoogleSignIn.requestPermissions(
                    this, // your activity
                    GOOGLE_FIT_PERMISSIONS_REQUEST_CODE,
                    GoogleSignIn.getLastSignedInAccount(this),
                    fitnessOptions);
        } else {
            accessGoogleFit();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK) {
            if (GOOGLE_FIT_PERMISSIONS_REQUEST_CODE == requestCode) {

                accessGoogleFit();
            }
            if (PERMISSIONS_REQUEST_ACTIVITY_RECOGNITION == requestCode) {

                accessGoogleFit();
            }
        } else {
            GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);

        }

    }

    private void accessGoogleFit() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        long endTime = cal.getTimeInMillis();
        cal.add(Calendar.YEAR, -1);
        long startTime = cal.getTimeInMillis();


        DataReadRequest readRequest = new DataReadRequest.Builder()
                .read(DataType.TYPE_HEART_RATE_BPM)
                .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                .bucketByTime(365, TimeUnit.DAYS)
                .build();


        Fitness.getHistoryClient(this, GoogleSignIn.getLastSignedInAccount(this))
                .readData(readRequest)
                .addOnSuccessListener(new OnSuccessListener<DataReadResponse>() {
                    @Override
                    public void onSuccess(DataReadResponse dataReadResponse) {
                        Log.d(TAG, "onSuccess()");

                        for (Bucket bucket : dataReadResponse.getBuckets()) {
                            Log.e("History", "Data returned for Data type: " + bucket.getDataSets());

                            List<DataSet> dataSets = bucket.getDataSets();
                            for (DataSet dataSet : dataSets) {
                                showDataSet(dataSet);
                            }
                        }
                    }
                })
                .addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.e(TAG, "onFailure()", e);
                    }
                })
                .addOnCompleteListener(new OnCompleteListener<DataReadResponse>() {
                    @Override
                    public void onComplete(@NonNull Task<DataReadResponse> task) {
                        Log.d(TAG, "onComplete()");
                    }
                });
    }

    private void showDataSet(DataSet dataSet) {
        DateFormat dateFormat = DateFormat.getDateInstance();
        DateFormat timeFormat = DateFormat.getTimeInstance();

        for (DataPoint dp : dataSet.getDataPoints()) {
            Log.e("History", "Data point:");
            Log.e("History", "\tType: " + dp.getDataType().getName());
            Log.e("History", "\tStart: " + dateFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
            Log.e("History", "\tEnd: " + dateFormat.format(dp.getEndTime(TimeUnit.MILLISECONDS)) + " " + timeFormat.format(dp.getStartTime(TimeUnit.MILLISECONDS)));
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());


                for (Field field : dp.getDataType().getFields()) {

                    Log.e("History", "\tField: " + field.getName() +
                            " Value: " + dp.getValue(field));

                }




        }
    }


}
Junaid
  • 1,301
  • 1
  • 15
  • 21
  • Where is this code, which file? Android project? MainFile? DataReadRequest readRequest = new DataReadRequest.Builder() .... Tis is my problem where can I locate the code above? It's because I am not a Android Developer. – desancheztorres Jan 13 '20 at 09:41
  • I am working on Flutter, I have no idea about Android native, that's why I can't understand the step 5 on the doc. – desancheztorres Jan 13 '20 at 14:20
  • 1
    Check tha answer i have added example – Junaid Jan 13 '20 at 14:30
  • 1
    Read further details about each client : https://developers.google.com/android/reference/com/google/android/gms/fitness/Fitness – Junaid Jan 13 '20 at 14:31
  • 1
    @John so in order to use "DataType.TYPE_HEART_RATE_BPM" do we need to get the app verified by google? – grooot Feb 03 '21 at 07:04
  • No i used it without google app verification – Junaid Feb 03 '21 at 07:05