9

I am trying to use google fit api in my android app. I followed this guide and created SHA-1 certificate using keytool.exe in my jdk 1.8 bin folder. I have now created Oauth Client IDenter image description here.

In my app, I get RESULT_CANCELED here:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if( requestCode == REQUEST_OAUTH ) {
        authInProgress = false;
        if( resultCode == RESULT_OK ) {
            if( !mClient.isConnecting() && !mClient.isConnected() ) {
                mClient.connect();
            }
        } else if( resultCode == RESULT_CANCELED ) {/// HERE
            Toast.makeText(MainActivity.this,"RESULT_CANCELED",Toast.LENGTH_SHORT).show();
            Log.e("GoogleFit", "RESULT_CANCELED");
            Log.e("GoogleFit", data.getExtras().toString());
        }
    }else if(requestCode == CALL_END){
        if (resultCode == Activity.RESULT_OK){
            //pass
        }else{

        }
    } else {
        Log.e("GoogleFit", "requestCode NOT request_oauth");
    }
}

Trying to figure out the problem from last two days. I have added correct play services library in android studio as: compile 'com.google.android.gms:play-services-fitness:8.4.0'

Building Client:

private void buildFitnessClient() {

    if (mClient == null && checkPermissions()) {
        Log.i(TAG, "Building Fitness Client");
        mClient = new GoogleApiClient.Builder(this)
                .addApi(Fitness.SENSORS_API)
                .addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
        mClient.connect();
    }
}

Callbacks:

/**
 * GOOGLE FIT METHODS
 */
@Override
public void onConnected(@Nullable Bundle bundle) {
    DataSourcesRequest dataSourceRequest = new DataSourcesRequest.Builder()
            .setDataTypes( DataType.TYPE_STEP_COUNT_CUMULATIVE )
            .setDataSourceTypes( DataSource.TYPE_RAW )
            .build();

    ResultCallback<DataSourcesResult> dataSourcesResultCallback = new ResultCallback<DataSourcesResult>() {
        @Override
        public void onResult(DataSourcesResult dataSourcesResult) {
            for( DataSource dataSource : dataSourcesResult.getDataSources() ) {
                if( DataType.TYPE_STEP_COUNT_CUMULATIVE.equals( dataSource.getDataType() ) ) {
                    registerFitnessDataListener(dataSource, DataType.TYPE_STEP_COUNT_CUMULATIVE);
                }
            }
        }
    };

    Fitness.SensorsApi.findDataSources(mClient, dataSourceRequest)
            .setResultCallback(dataSourcesResultCallback);
}
@Override
public void onConnectionSuspended(int i) {

}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    if( !authInProgress ) {
        try {
            authInProgress = true;
            connectionResult.startResolutionForResult( MainActivity.this, REQUEST_OAUTH );
        } catch(IntentSender.SendIntentException e ) {

        }
    } else {
        Log.e( "GoogleFit", "authInProgress" );
    }
}
@Override
public void onDataPoint(DataPoint dataPoint) {
    for( final Field field : dataPoint.getDataType().getFields() ) {
        final Value value = dataPoint.getValue( field );
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), "Field: " + field.getName() + " Value: " + value, Toast.LENGTH_SHORT).show();
                HealthRecordFragment.mStepsWalking.setText(value.toString());
            }
        });
    }
}

In Gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.xxxx.xxxx"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    signingConfigs {
        release {
            storeFile file("C:\\Users\\xxxxx\\AndroidStudioProjects\\HBEAT2\\app\\hbeat_android")
            storePassword "password"
            keyAlias "hbeat_android"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.google.android.gms:play-services-fitness:8.4.0'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile "com.android.support:design:23.2.1"
    compile 'com.github.rahatarmanahmed:circularprogressview:2.4.0'
    compile 'de.timroes.android:EnhancedListView:0.3.0'
}
Harshil Pansare
  • 1,057
  • 11
  • 33

7 Answers7

22

I've encountered this problem just now. Took me a few hours to figure out, so i would like to point out for those who make the same mistake.

My Google API client cannot connect only on Production, everything works fine on Development environment.

This is because my app was set up to use "App Signing". With this, if you created the Oauth Client ID using the Production Keystore's SHA1 (or Upload Certificate's SHA1 in the picture), it will not be used, because google will remove this certificate and change to the "App Signing" certificate

App Signing

So what we need to do to fix the problem is: Simply create a new OAuth Client ID with this new SHA1 like so:

enter image description here

The issue is quite easy to encounter because most of the tutorials will tell you to find your Production SHA1 and use it in the API console. But except for if you use "App signing" then it won't work anymore.

Nathan Do
  • 1,875
  • 18
  • 22
  • I was stuck at this issue for 3 days. Thanks a lot! – kirtan403 Dec 08 '17 at 10:41
  • 2
    Thanks so much! This help me! I stucked about 3 days, cause I use Firebase UI Auth, it returned errorCode=4 (PROVIDER ERROR) and I don't know the reason. So I try to use Firebase Auth SDK with Google and errorCode=16 (RESULT_CANCELED) and this topic help me. – Hiep Mai Thanh Sep 22 '18 at 07:28
  • 1
    Thank you Nathan Do. You nail it when you say 'most of tutorials will tell you...'. The 'Google Cloud Client ID for Android' section seems also kind of misleading as it displays the command line to get the fingerprint, while there's no word on the right Google Play console key certificate to use. – webargus May 19 '21 at 22:14
4

One reason to get RESULT_CANCELED is if your package name is diferent than the one you define in your app.

Double check that you are not setting another applicationId in your build.gradle that could be different than package defined in your manifest.

Sebastian
  • 2,578
  • 19
  • 28
3

If the above solutions doesn't help you, then you should definitely consider this solution once. I literally struggled a lot to figure this out. So I think, my findings will help others to avoid same struggle and frustration.

I've followed the google guidelines to set up the GFit authentication. But upon finishing it, I noticed that when my app ask for user's permission, it pops up the authentication screen. But when the user selects one account, it just returns RESULT_CANCELED in onActivityResult() instead of RESULT_OK. The reason behind that was certificate mismatch. I used my project's keystore file to generate the SHA-1 fingerprint which is required for OAuth token generation. But the build that I was deploying was a debug one. When I tried with the release build, it worked perfectly. The reason behind that was, Android Studio by default used a debug.keystore file to sign the debug builds which is different from the project's keystore file. That's why it didn't work in the debug mode. When I changed the debug configuration for my project to use my project's keystore file, it worked like a charm. So, I recommend to check this usecase first. Most of the cases, this is the actual issue. You can find another StackOverflow question here which is addresses this issue.

To know more about how to change/modify the signing configurations for your builds, please refer to this.

Abhishek
  • 805
  • 15
  • 22
1

I ran into this problem recently as well. I'm not sure what the problem was but it may stem from Google's updates to the GoogleAPIClient library and authentication procedures.

I had to update my own authentication flow to the latest documentation for Google Sign-Ins (Android) from this: https://developers.google.com/identity/sign-in/android/sign-in#before_you_begin

I'm also using

    compile 'com.google.android.gms:play-services-auth:9.0.0'
    compile 'com.google.android.gms:play-services-fitness:9.0.0'

for the libraries. Here's a snippet of my code:

//runs an automated Google Fit connect sequence
public static GoogleApiClient googleFitBuild(Activity activity, GoogleApiClient.ConnectionCallbacks connectionCallbacks, GoogleApiClient.OnConnectionFailedListener failedListener){
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            //.requestServerAuthCode(activity.getString(R.string.server_client_id), false)
            .requestEmail()
            .requestScopes(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE), new Scope(Scopes.FITNESS_BODY_READ_WRITE),
                    new Scope(Scopes.FITNESS_NUTRITION_READ_WRITE), new Scope(Scopes.FITNESS_LOCATION_READ_WRITE))
            .build();
    return new GoogleApiClient.Builder(activity)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .addConnectionCallbacks(connectionCallbacks)
                .addOnConnectionFailedListener(failedListener)
                //.addApi(Plus.API)
                .addApi(Fitness.CONFIG_API)
                .addApi(Fitness.HISTORY_API)
                .addApi(Fitness.SESSIONS_API)
                .addApi(Fitness.RECORDING_API)
                .addApi(Fitness.BLE_API)
                .addApi(Fitness.SENSORS_API)
                .build();
}

//runs an automated Google Fit connect sequence
public static void googleFitConnect(final Activity activity, final GoogleApiClient mGoogleApiClient){
    if(!mGoogleApiClient.isConnected() && !mGoogleApiClient.isConnecting()) {
        mGoogleApiClient.registerConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
            @Override
            public void onConnected(Bundle bundle) {
                Log.i(TAG, "Google API connected");
                Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
                activity.startActivityForResult(signInIntent, FragmentLogin.REQUEST_OAUTH);
            }
            @Override
            public void onConnectionSuspended(int i) {

            }
        });
        mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL);
    }
}

GoogleApiClient googleApiClient = googleFitBuild(activity, (MainActivity)activity, (MainActivity)activity);
googleFitConnect(activity, googleApiClient);

I also had something close to the OP's code working before but it suddenly decided to stop working... frustrating to say the least.

c0deblooded
  • 1,527
  • 1
  • 15
  • 19
  • `GoogleApiClient googleApiClient = googleFitBuild(activity, (MainActivity)activity, (MainActivity)activity);` this line is giving an error as its arguments do not match the function arguments – suku Jun 07 '16 at 11:47
  • The last 2 arguments need to be a class (likely an Activity or Fragment) that implements both GoogleApiClient.ConnectionCallbacks and GoogleApiClient.OnConnectionFailedListener – c0deblooded Jun 07 '16 at 22:11
  • googleFitBuild and googleFitConnect should be called in onStart. When they are called in onCreate, the output is still RESULT_CANCELED. – suku Jun 09 '16 at 05:19
1

In my case, I changed the apk name but failed to update it in the OAuth credentials console. Then my onActivityResult code gave me RESULT_CANCELLED. As soon as I corrected the apk name, everything started working again.

Opus1217
  • 593
  • 3
  • 14
  • I had the same problem. In my case I had changed my workstation and the signature of debug.keystore changed, therefore, the credentials had to be updated. Thanks for putting me in the right direction! – davis Mar 18 '17 at 10:51
1

I had similar issue and solve it by unifing the version number for both fitness and auth dependencies in the build.gradle file.

implementation "com.google.android.gms:play-services-fitness:18.0.0"
implementation "com.google.android.gms:play-services-auth:18.0.0"

Previously I was using auth:17.0.0 and that caused the feature to fail on random bases (yes, it was working sometimes and failing on others).

So I think it is worth checking your dependancies if the solutions above didn't help.

omzer
  • 378
  • 3
  • 9
0

I had this same issue and the error was that I was using building flavors (full, mock) which finally changes the package name. So, in the console, I had to put the package's flavor, not the manifest's one. Hope this helps :)

jpenna
  • 4,833
  • 4
  • 21
  • 31