Search code examples
androidfluttergoogle-fit

Google Fit API for Android


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'
}

Solution

  • 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));
    
                    }
    
    
    
    
            }
        }
    
    
    }