Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Oauth 2.0 RESULT_CANCELED while using Google Fit api

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'
}
like image 760
Harshil Pansare Avatar asked May 18 '16 02:05

Harshil Pansare


People also ask

What is Google's implementation of OAuth?

Note: Use of Google's implementation of OAuth 2.0 is governed by the OAuth 2.0 Policies. Google APIs use the OAuth 2.0 protocol for authentication and authorization. Google supports common OAuth 2.0 scenarios such as those for web server, client-side, installed, and limited-input device applications.

How do I obtain OAuth credentials from the Google API console?

Obtain OAuth 2.0 credentials from the Google API Console. Visit the Google API Console to obtain OAuth 2.0 credentials such as a client ID and client secret that are known to both Google and your application. The set of values varies based on what type of application you are building.

Why do I need to verify that my App follows OAuth?

If your app requests sensitive scopes, and doesn't meet any of the criteria for an exception (see below), you will need to verify that your app follows the API Services User Data Policy. For a complete list of Google APIs, see OAuth 2.0 Scopes for Google APIs.

Does Google oAuth work on limited input devices?

Applications on limited-input devices. The Google OAuth 2.0 endpoint supports applications that run on limited-input devices such as game consoles, video cameras, and printers. The authorization sequence begins with the application making a web service request to a Google URL for an authorization code.


3 Answers

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.

like image 182
Nathan Do Avatar answered Oct 19 '22 11:10

Nathan Do


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.

like image 4
Sebastian Avatar answered Oct 19 '22 10:10

Sebastian


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.

like image 3
Abhishek Avatar answered Oct 19 '22 10:10

Abhishek