Android: проблема с доступом к задачам Google с помощью OAuth
Поскольку у задач Google нет общедоступного API, я хочу написать обходной путь и запросить данные, такие как браузер, а затем проанализировать результаты для дальнейшего отображения.
Для доступа к данным я реализовал аутентификацию OAuth с помощью Google, чтобы получить доступ к этому URL: https://mail.google.com/
Для OAuth я использовал библиотеку Sign-Post, и она хорошо работает.
Проблема в том, что когда я пытаюсь получить доступ к https://mail.google.com/tasks/ig с подписанным запросом, он возвращает мне страницу входа вместо желаемого списка с задачами.
Чтобы быть более конкретным, вот мой код:
public class GoogleOAuthActivity extends Activity {
private static final String TAG = GoogleOAuthActivity.class.getSimpleName();
private CommonsHttpOAuthProvider provider;
private CommonsHttpOAuthConsumer consumer;
@Override
@SuppressWarnings("unchecked")
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
provider = new CommonsHttpOAuthProvider(OAuthPrefs.GET_REQUEST_TOKEN_URL, OAuthPrefs.GET_ACCESS_TOKEN_URL,
OAuthPrefs.TOKEN_AUTHORIZATION_URL);
consumer = new CommonsHttpOAuthConsumer(OAuthPrefs.CONSUMER_KEY, OAuthPrefs.CONSUMER_SECRET);
consumer.setMessageSigner(new HmacSha1MessageSigner());
Log.v(TAG, "Starting google authentication activity");
new RequestGoogleOAuth(this, provider, consumer).execute();
}
@Override
@SuppressWarnings("unchecked")
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
final Uri uri = intent.getData();
if (uri != null && uri.getScheme().equals(OAuthPrefs.CALLBACK_SCHEME)) {
Log.v("OAUTH MAIN", "STARTING STAGE TWO");
new ConfirmGoogleOAuthTask(this, provider, consumer).execute(uri);
finish();
}
}
}
Первый этап OAuth
public class RequestGoogleOAuth extends OAuthGoogleTask {
public static final String TAG = RequestGoogleOAuth.class.getSimpleName();
public RequestGoogleOAuth(Context context, CommonsHttpOAuthProvider provider, CommonsHttpOAuthConsumer consumer) {
super(context, provider, consumer);
}
protected Object doInBackground(Object... params) {
final String TAG = getClass().getName();
try {
final String url = provider.retrieveRequestToken(consumer, OAuthPrefs.CALLBACK_URL);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
& Intent.FLAG_ACTIVITY_NO_HISTORY & Intent.FLAG_FROM_BACKGROUND);
context.startActivity(intent);
Log.v(TAG, "Request google authentication");
} catch (Exception e) {
Log.e(TAG, "ERROR during google authentication request", e);
}
return null;
}
}
Второй этап OAuth и попытка доступа к задачам Google
public class ConfirmGoogleOAuthTask extends OAuthGoogleTask {
public ConfirmGoogleOAuthTask(Context context, CommonsHttpOAuthProvider provider, CommonsHttpOAuthConsumer consumer) {
super(context, provider, consumer);
}
@Override
public Object doInBackground(Object... params) {
final Uri uri = (Uri) params[0];
final String TAG = getClass().getName();
final SharedPreferences prefs = context.getSharedPreferences(OAuthPrefs.PREF_NAME, Context.MODE_PRIVATE);
final String oauthVerifier = uri.getQueryParameter(OAuth.OAUTH_VERIFIER);
try {
provider.retrieveAccessToken(consumer, oauthVerifier);
final Editor edit = prefs.edit();
edit.putString(OAuth.OAUTH_TOKEN, consumer.getToken());
edit.putString(OAuth.OAUTH_TOKEN_SECRET, consumer.getTokenSecret());
edit.commit();
CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(OAuthPrefs.CONSUMER_KEY, OAuthPrefs.CONSUMER_SECRET);
consumer.setMessageSigner(new HmacSha1MessageSigner());
consumer.setTokenWithSecret(consumer.getToken(), consumer.getTokenSecret());
HttpClient httpClient = HttpUtils.createHttpClient();
HttpGet httpGet = new HttpGet(consumer.sign("https://mail.google.com/tasks/ig"));
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
Log.d(TAG, "Status code = " + statusCode);
if (statusCode == HttpStatus.SC_OK) {
String xml = ConvertUtils.convertStreamToString(response.getEntity().getContent(), true);
Log.d(TAG, "XML = " + xml);
}
Log.v(TAG, "Successfully receive access token");
} catch (Exception e) {
Log.e(TAG, "ERROR during request for access token", e);
}
return null;
}
}
На этой линии:
String xml = ConvertUtils.convertStreamToString(response.getEntity().getContent(), true);
Log.d(TAG, "XML = " + xml);
Я вижу, что я получаю "страницу входа"
Я думаю, что причина в том, что Google не предоставляет доступ к этой службе, и даже если я уже прошел проверку подлинности с помощью OAuth, это ограничивает мой доступ к этому ресурсу (даже если я определил область действия как https://mail.google.com/)., Я не уверен, как реализовать это прямо сейчас, но, похоже, мне нужно точно смоделировать браузер, как он взаимодействует с Google (извлекать и отправлять соответствующие файлы cookie). Но я спрашиваю, потому что я не уверен, как быть в этой ситуации, потому что, как я уже упоминал, API задач Google не имеет публичного API (мыло, отдых или любой другой), поэтому для меня не очевидно, как реализовать клиент для этого особенность...
Если у кого-то есть примеры, где приложение получает доступ к ресурсам Google без публичного API, я буду очень рад это увидеть.
Спасибо, надеюсь, кто-нибудь знает ответ!
2 ответа
[обновлено 5/11, чтобы рекомендовать API, 4/6 использовать обычный ClientLogin вместо файлов cookie]
теперь есть API Google Tasks! используйте это вместо этого, это намного проще, и ваш код будет более понятным. рассмотреть оставшуюся часть этого ответа только для потомков.
к сожалению, вы на правильном пути. пока еще нет API для задач Google, OAuth или чего-то еще, поэтому вам придется немного разобраться с HTML.:/ afaik, это то, что все остальные сторонние задачи клиенты делают прямо сейчас. Однако ClientLogin работает для аутентификации, так что это как минимум.
Вот некоторый код сценария оболочки, который делает это: http://privacylog.blogspot.com/2010/09/updated-google-tasks-api.html. подробности ниже.
первый, POST
в www.google.com/accounts/ClientLogin
как описано в http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html для получения токена авторизации. использование goanna_mobile
как имя сервиса. (это важно!)
затем, GET https://mail.google.com/tasks/m
и передать Authorization:GoogleLogin
заголовок с токеном авторизации, который вы получили выше. Вы вернете HTML. извлечь идентификаторы из отдельных списков задач. они имеют форму 04291568652951293844:0:0.
Затем вы отправите POST с телом в JSON https://mail.google.com/tasks/r/d
чтобы получить содержимое каждого списка. вот пример тела:
r={action_list:
[{action_type: get_all,
action_id: 5,
list_id: 0429158965...:0:0,
get_deleted: false,
date_start: 1969-12-31,
get_archived: true
}],
client_version: 1256686
}
важные заметки:
- latest_sync_point: 0, чтобы получить все задачи
- = в r= не является URL, закодированным в r%3D
- включите заголовок "AT: 1". без этого задачи возвращает 401 несанкционированный.
вывод больше JSON, например:
{latest_sync_point: 1263000002293000, response_time:1263077227, results:[], tasks:
[{id: 04291589652955....:0:38,
last_modified: 1263000002281,
name: foo bar
notes: ,
type: TASK,
deleted: false,
list_id: [0429158965...:0:0],
completed: false
},
{id: 0429158965295...:0:37,
last_modified: 1262929947949,
name: baz
notes: ,
type: TASK,
deleted:false,
list_id: [0429158965295...:0:0],
completed: false
},
...