首页 文章

Android Calendar API上的Google Calendar API OAuth2令人烦恼

提问于
浏览
7

我正在开发Android Honeycomb(v3.0)应用程序,该应用程序需要与Google Calendar API进行通信 . 我想允许我的应用访问特定Google帐户的日历数据,以便阅读和创建活动 .

不幸的是,我使用OAuth2遇到了授权问题 . 这是我到目前为止所拥有的:

1)我想访问其日历的Google帐户是在我正在使用的Android设备中注册的 .

2)我在帐户的Google API控制台中启用了Calendar API .

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 . 我跟着这个tutorial,但是将所有内容转换为Google日历而不是Google Tasks . 我使用 getAuthTokenAUTH_TOKEN_TYPE == "oauth2:https://www.googleapis.com/auth/calendar" 成功从我想要使用的帐户 AccountManager 中检索 authToken .

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 Video(等待一分钟左右来获取适用的内容),此异常的原因可能是我未在Google API控制台中为该帐户启用API访问 . 但是,如果你看2),你可以看到我确实这样做了 .

8)对我来说,似乎问题是我无法正确设置Simple API访问密钥,因为不推荐使用 Calendar.setKey 方法 . 在我之前链接的Google Tasks教程中,使用 Tasks.accessKey = "key" 设置密钥 . 不过,我不知道如何使用Calendar 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中的帐户,以便检索用于Google Calendar API的有效OAuth2令牌 . 第二种方法对我没用,因为用户必须手动转到他们的Web浏览器并获取授权代码,这对用户不友好 . 有人有主意吗?为长篇帖子道歉,谢谢!

2 回答

  • 4

    回答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从AccountManager本身获取AuthToken:

    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();
    }
    
  • 1

    尝试将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();
    

相关问题