Проблемы OAuth2 API Календаря Google на Android Honeycomb

Я работаю над приложением Android Honeycomb (v3.0), которое требует связи с API календаря Google. Я хотел бы разрешить моему приложению доступ к данным календаря определенной учетной записи Google, чтобы читать и создавать события.

К сожалению, столкнулся с проблемой авторизации по OAuth2. Вот что у меня есть до сих пор:

1) Учетная запись Google, к календарю которой я хочу получить доступ, зарегистрирована на устройстве Android, с которым я работаю.

2) Я включил API календаря в консоли API Google в учетной записи.

3) Я могу получить доступ к этой учетной записи, используя следующий код:

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) Теперь я хотел бы получить AuthToken для использования при общении с календарем. Я следовал этому руководству, но преобразовал все для работы с Google Calendar вместо Google Tasks. Я успешно извлекаю authToken из AccountManager с учетной записью, которую хочу использовать, используя getAuthToken с AUTH_TOKEN_TYPE == "oauth2:https://www.googleapis.com/auth/calendar".

5) Вот тут и начинаются проблемы. Я сейчас в этом месте:

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) Вот исключение, возвращаемое последней строкой:

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) Согласно этому видео Google API (подождите минуту или около того, чтобы перейти к соответствующему контенту), причиной этого исключения может быть тот факт, что я не включил доступ к API в консоли API Google для учетной записи. Однако, если вы посмотрите на 2), вы увидите, что я так и сделал.

8) Мне кажется, проблема в том, что я не смог правильно установить ключ доступа к простому API, потому что метод Calendar.setKey устарел. В учебнике Google Tasks, на который я ссылался ранее, ключ устанавливается с помощью Tasks.accessKey = "key". Однако я не уверен, как заставить это работать с API календаря. Я пробовал несколько учетных записей Google, и все они оказались за исключением 5).

9) Я хотел бы отметить, что традиционный метод использования OAuth2 у меня работал. Вот код, который я использовал для этого:

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) Наконец, мой вопрос: я хотел бы использовать учетную запись из AccountManager на самом устройстве, чтобы получить рабочий токен OAuth2 для использования с API Календаря Google. Второй метод для меня бесполезен, потому что пользователю придется вручную заходить в свой веб-браузер и получать код авторизации, что неудобно для пользователя. У кого-нибудь есть идеи? Извините за длинный пост и спасибо!


comment
привет, я столкнулся с аналогичной проблемой, я использовал эти фрагменты кода, чтобы запустить приложение календаря, но затем я получаю 403, ошибка доступа запрещена, не могли бы вы помочь, что мне делать в Android? хотя я тоже не использую номер 8 как вариант. пожалуйста помогите.   -  person Rat-a-tat-a-tat Ratatouille    schedule 14.05.2014
comment
Что используете как вариант? Вы проверили ответ @eltrl?   -  person BVB    schedule 14.05.2014


Ответы (2)


Попробуйте добавить JsonHttpRequestInitializer в сборщик и установить там свой ключ:

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();
person eltrl    schedule 10.12.2011
comment
Спасибо, но я получаю следующую ошибку в Eclipse: The method setJsonHttpRequestInitializer(JsonHttpRequestInitializer) in the type Calendar.Builder is not applicable for the arguments (new JsonHttpRequestInitializer(){}) - person BVB; 13.12.2011
comment
О боже, я исправил ошибку (проблема с импортом) и все заработало! Огромное спасибо! - person BVB; 13.12.2011
comment
Нет проблем, эти вещи не так просто диагностировать, учитывая текущее (бета) состояние документации. - person eltrl; 13.12.2011

Чтобы ответить № 10: мне в основном приходилось делать то же, что и вам, работая с TaskSample, а затем использовать образец календаря Android GData, доступный здесь: 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, чтобы получить AuthToken из самого AccountManager:

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();
}
person nicordesigns    schedule 23.12.2011