7

Estoy trabajando en una aplicación Android Honeycomb (v3.0) que requiere la comunicación con Google Calendar API. Me gustaría permitir que mi aplicación acceda a los datos de calendario de una cuenta de Google en particular para leer y crear eventos.Google Calendar API OAuth2 Problemas en Android Honeycomb

Lamentablemente, tuve un problema con la autorización utilizando OAuth2. Esto es lo que tengo hasta ahora:

1) La cuenta de Google cuyo calendario me gustaría acceder está registrada dentro del dispositivo Android con el que estoy trabajando.

2) Active la API de calendario dentro de la Consola de API de Google en la cuenta.

3) Soy capaz de acceder a esta cuenta utilizando el código siguiente:

AccountManager accountManager = AccountManager.get(this.getBaseContext()); 
Account[] accounts = accountManager.getAccountsByType("com.google"); 
Account acc = accounts[0]; // The device only has one account on it 

4) Ahora me gustaría obtener un token de autenticación para su uso en la comunicación con el calendario. Seguí este tutorial, pero convertí todo para que funcione con Google Calendar en lugar de Google Tasks. Recuperé con éxito un authToken del AccountManager con la cuenta que me gustaría usar usando getAuthToken con AUTH_TOKEN_TYPE == "oauth2:https://www.googleapis.com/auth/calendar".

5) Aquí es donde comienzan los problemas. Ahora estoy en este punto:

AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(tokens[0]); // this is the correct token 
HttpTransport transport = AndroidHttp.newCompatibleTransport(); 
Calendar service = Calendar.builder(transport, new JacksonFactory()) 
    .setApplicationName("My Application's Name") 
    .setHttpRequestInitializer(accessProtectedResource) 
    .build(); 
service.setKey("myCalendarSimpleAPIAccessKey"); // This is deprecated??? 
Events events = service.events().list("primary").execute(); // Causes an exception! 

6) Aquí está la excepción devuelto por la última línea:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden 
{ 
    "code" : 403, 
    "errors" : [ { 
    "domain" : "usageLimits", 
    "message" : "Daily Limit Exceeded. Please sign up", 
    "reason" : "dailyLimitExceededUnreg", 
    "extendedHelp" : "https://code.google.com/apis/console" 
    } ], 
    "message" : "Daily Limit Exceeded. Please sign up" 
} 

7) De acuerdo con este Google API Video (espere un minuto más o menos para llegar al contenido aplicable), una razón para esta excepción puede ser el hecho de que no habilité el acceso a la API dentro de la Consola de API de Google para la cuenta. Sin embargo, si miras a 2), puedes ver que sí lo hice.

8) Para mí, parece que el problema es que no pude establecer la clave de acceso API simple correctamente, porque el método Calendar.setKey está en desuso. En el tutorial de tareas de Google que he vinculado anteriormente, la clave se establece usando Tasks.accessKey = "key". Aunque no estoy seguro de cómo hacerlo funcionar con la API de Calendar. He intentado con varias cuentas de Google, y todas surgieron con la excepción de 5).

9) Me gustaría señalar que el método tradicional de usar OAuth2 me funcionó. Aquí está el código que utilicé para que:

HttpTransport TRANSPORT = new NetHttpTransport(); 
JsonFactory JSON_FACTORY = new JacksonFactory(); 
String SCOPE = "https://www.googleapis.com/auth/calendar"; 
String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob"; 
String CLIENT_ID = "myClientID"; 
String CLIENT_SECRET = "myClientSecret"; 
String authorizeUrl = new GoogleAuthorizationRequestUrl(CLIENT_ID, CALLBACK_URL, SCOPE).build(); 
String authorizationCode = "???"; // At this point, I have to manually go to the authorizeUrl and grab the authorization code from there to paste it in here while in debug mode 

GoogleAuthorizationCodeGrant authRequest = new GoogleAuthorizationCodeGrant(TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authorizationCode, CALLBACK_URL); 
authRequest.useBasicAuthorization = false; 
AccessTokenResponse authResponse = authRequest.execute(); 
String accessToken = authResponse.accessToken; // gets the correct token 

GoogleAccessProtectedResource access = new GoogleAccessProtectedResource(accessToken, TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authResponse.refreshToken); 
HttpRequestFactory rf = TRANSPORT.createRequestFactory(access); 
AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(accessToken); 
HttpTransport transport = AndroidHttp.newCompatibleTransport(); 

Calendar service = Calendar.builder(transport, new JacksonFactory()) 
    .setApplicationName("My Application's Name") 
    .setHttpRequestInitializer(accessProtectedResource) 
    .build(); 

Events events = service.events().list("primary").execute(); // this works! 

10) Por último, mi pregunta: me gustaría utilizar la cuenta del administrador de cuentas en el propio dispositivo con el fin de recuperar un símbolo OAuth2 de trabajo para su uso con el Calendario de Google API. El segundo método no es útil para mí, porque el usuario tendrá que ir manualmente a su navegador web y obtener el código de autorización, que no es fácil de usar. ¿Alguien tiene alguna idea? Disculpas por la publicación larga, ¡y gracias!

+0

hola, estoy frente a un problema similar, he usado esta fragmentos de código para obtener una aplicación en ejecución calendario, pero cuando me siento un 403 , acceso prohibido error, co uld por favor ayuda, ¿qué debo hacer en Android? aunque tampoco estoy usando el número 8 como una opción. por favor hlp. –

+0

¿Qué estás usando como una opción? ¿Has consultado la respuesta de @ eltrl? – BVB

Respuesta

4

trate de añadir un JsonHttpRequestInitializer al constructor y el establecimiento de su clave existe:

Calendar service = Calendar.builder(transport, new JacksonFactory()) 
.setApplicationName("My Application's Name") 
.setHttpRequestInitializer(accessProtectedResource) 
.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() { 
    public void initialize(JsonHttpRequest request) { 
     CalendarRequest calRequest = (CalendarRequest) request; 
     calRequest.setKey("myCalendarSimpleAPIAccessKey"); 
    } 

}).build(); 
+0

Gracias, pero obtengo el siguiente error en Eclipse: 'El método setJsonHttpRequestInitializer (JsonHttpRequestInitializer) en el tipo Calendar.Builder no es aplicable para los argumentos (nuevo JsonHttpRequestInitializer() {})' – BVB

+0

Ay, arreglé el error (problema de importación) y funcionó! ¡Muchas gracias! – BVB

+1

No hay problema, estas cosas no son muy triviales de diagnosticar dado el estado actual (beta) de la documentación. – eltrl

1

Para responder nº 10: básicamente, he tenido que hacer lo que tenía que hacer el trabajo con la TaskSample y luego usar el Android GData Calendario de la muestra disponible aquí: http://code.google.com/p/google-api-java-client/source/browse/calendar-android-sample/src/main/java/com/google/api/client/sample/calendar/android/CalendarSample.java?repo=samples para obtener el token de autenticación del propio administrador de cuentas:

accountManager = new GoogleAccountManager(this); 
settings = this.getSharedPreferences(PREF, 0); 
gotAccount(); 

private void gotAccount() { 
     Account account = accountManager.getAccountByName(accountName); 
     if (account != null) { 
      if (settings.getString(PREF_AUTH_TOKEN, null) == null) { 
       accountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE, 
         true, new AccountManagerCallback<Bundle>() { 

          @Override 
          public void run(AccountManagerFuture<Bundle> future) { 
           try { 
            Bundle bundle = future.getResult(); 
            if (bundle 
              .containsKey(AccountManager.KEY_INTENT)) { 
             Intent intent = bundle 
               .getParcelable(AccountManager.KEY_INTENT); 
             int flags = intent.getFlags(); 
             flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK; 
             intent.setFlags(flags); 
             startActivityForResult(intent, 
               REQUEST_AUTHENTICATE); 
            } else if (bundle 
              .containsKey(AccountManager.KEY_AUTHTOKEN)) { 
             setAuthToken(bundle 
               .getString(AccountManager.KEY_AUTHTOKEN)); 
             // executeRefreshCalendars(); 
            } 
           } catch (Exception e) { 
            handleException(e); 
           } 
          } 
         }, null); 
      } else { 
       // executeRefreshCalendars(); 
      } 
      return; 
     } 
     chooseAccount(); 
    } 

private void chooseAccount() { 
    accountManager.manager.getAuthTokenByFeatures(
      GoogleAccountManager.ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null, 
      ExportClockOption.this, null, null, 
      new AccountManagerCallback<Bundle>() { 

       @Override 
       public void run(AccountManagerFuture<Bundle> future) { 
        Bundle bundle; 
        try { 
         bundle = future.getResult(); 
         setAccountName(bundle 
           .getString(AccountManager.KEY_ACCOUNT_NAME)); 
         setAuthToken(bundle 
           .getString(AccountManager.KEY_AUTHTOKEN)); 
         // executeRefreshCalendars(); 
        } catch (OperationCanceledException e) { 
         // user canceled 
        } catch (AuthenticatorException e) { 
         handleException(e); 
        } catch (IOException e) { 
         handleException(e); 
        } 
       } 
      }, null); 
} 

void setAuthToken(String authToken) { 
    SharedPreferences.Editor editor = settings.edit(); 
    editor.putString(PREF_AUTH_TOKEN, authToken); 
    editor.commit(); 
    createCalendarService(authToken); 
    try { 
     Events events = service.events().list("primary").execute(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 

private void createCalendarService(String authToken) { 
    accessProtectedResource = new GoogleAccessProtectedResource(authToken); 

    Log.i(TAG, "accessProtectedResource.getAccessToken() = " 
      + accessProtectedResource.getAccessToken()); 
    JacksonFactory jsonFactory = new JacksonFactory(); 
    service = com.google.api.services.calendar.Calendar 
      .builder(transport, jsonFactory) 
      .setApplicationName("Time Journal") 
      .setJsonHttpRequestInitializer(
        new JsonHttpRequestInitializer() { 
         @Override 
         public void initialize(JsonHttpRequest request) { 
          CalendarRequest calendarRequest = (CalendarRequest) request; 
          calendarRequest 
            .setKey("<YOUR SIMPLE API KEY>"); 
         } 
        }).setHttpRequestInitializer(accessProtectedResource) 
      .build(); 
} 
Cuestiones relacionadas