Android: Google authentication

11,622

Solution 1

yes, you can access information in the accountManager and authenticate the user using registered google account (for example) without her entering password.

the code below is a functional mix and match from examples by nick johnson and by tencent

start with your main activity:

    package com.tg.auth;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class ZAuth02aActivity extends ListActivity {
    protected AccountManager accountManager;
    protected Intent intent;
    String TAG = "TGtracker";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        accountManager = AccountManager.get(getApplicationContext());
        Account[] accounts = accountManager.getAccountsByType("com.google");
        this.setListAdapter(new ArrayAdapter<Account>(this, R.layout.list_item, accounts));        

    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Account account = (Account)getListView().getItemAtPosition(position);
        Intent intent = new Intent(this, AppInfo.class);
        intent.putExtra("account", account);
        startActivity(intent);
    }
}

create an AppInfo class:

    package com.tg.auth;


import org.apache.http.impl.client.DefaultHttpClient;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class AppInfo extends Activity {
    DefaultHttpClient http_client = new DefaultHttpClient();
    Activity activity;
    String TAG = "TGtracker";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.app_info);
        activity = this;

    }

    @Override
    protected void onResume() {
        super.onResume();
        //Log.v(TAG, "resuming activity");
        AccountManager accountManager = AccountManager.get(getApplicationContext());
        //if result is null, you might not have a valid internet connection
        Log.i(TAG, "got token, yipee: "+updateToken(accountManager, true));
    }


    private String updateToken(AccountManager am, boolean invalidateToken) {
        String authToken = "null";
        try {
            Account[] accounts = am.getAccountsByType("com.google");
            AccountManagerFuture<Bundle> accountManagerFuture;
            if(activity == null){//this is used when calling from an interval thread
                accountManagerFuture = am.getAuthToken(accounts[0], "android", false, null, null);
            } else {
                accountManagerFuture = am.getAuthToken(accounts[0], "android", null, activity, null, null);
            }
            Bundle authTokenBundle = accountManagerFuture.getResult();
            authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN).toString();
            Log.v(TAG, "newToken preinvalidate: "+authToken);

            if(invalidateToken) {
                am.invalidateAuthToken("com.google", authToken);
                authToken = updateToken(am, false);

            }
        } catch (IOException e) {
            Log.e(TAG, "the exception was: "+e.toString());
            e.printStackTrace();
        }
        return authToken;
    }
}

use a manifest file, somewhat like this (must declare activities + permissions):

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tg.auth"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="7" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS"></uses-permission>
    <uses-permission android:name="android.permission.GET_ACCOUNTS"></uses-permission>
    <uses-permission android:name="android.permission.USE_CREDENTIALS"></uses-permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".ZAuth02aActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".AppInfo"></activity>
    </application>

</manifest>

use nick johnson's layout files that you can download here

Solution 2

You can use the build in AccountManager:

  Account[] accounts = accountManager.getAccountsByType("com.google");

Then extract the account you want from the returned list. The next step would be to call AccountManager.getAuthToken.

Once you have the authToken, you can pass it on to Google APIs by calling:

api.setUserToken(token);

as opposed to the setUserCredentials that require the user and password.

Share:
11,622
endryha
Author by

endryha

Updated on July 25, 2022

Comments

  • endryha
    endryha almost 2 years

    I want to ask, what is the best way to authenticate user with his Google account already configured on the phone. I have looked at the ClientLogin first, but it's not what I want because it requires users to enter login/password in my application. I can do it with OAuth but there I should ask user to enter his credentials in browser what is not preferable too. I want to use AccountManager (I've observed that it contains method getPassword for particular account but it didn't work for me), if it's possible to use somehow AccountManager + ClientLogin or AccountManager + OAuth tell me please. In result I want to have capabilities to log in with user Google account without asking his login/password (with confirmation on android device of course) I am not sure that it's possible but if there exists some way to implement this please point me how...

  • endryha
    endryha over 13 years
    I have read this already... to be more specific I understand how to do it with OAuth mechanism which is good way to authenticate with other services like a twitter, but google accounts already supported in android phone, and I want to ommit that step where user should enter his credentials and leave just confirmation that my application will use his account to retrieve data... what else... I plan to retrieve data not from app engine but from google tasks
  • Richard Russell
    Richard Russell about 11 years
    When I try this, I get an error that getResult() can't be run on the main thread from this line: Bundle authTokenBundle = accountManagerFuture.getResult(); I'm working on figuring out why and how to resolve this.