运用googleapi-client-java操作gtasks(二)

使用googleapi-client-java操作gtasks(二)
对于很多第三方的机器没有安装Google账户管理,要访问GTasks,那么可以使用OAuth 2.0的认证方式。
OAuth 2.0的认证流程:
1.得到授权码
2.使用授权码获得真正的数据访问令牌

其中数据访问令牌一般有效期为60分钟,在得到此访问令牌的时候还会得到一个刷新令牌,当访问令牌过期后可以用此刷新令牌自动获得一个新的。

1.授权码的获得:
用浏览器打开一个url,这个url是由要访问的服务以及其他一些相关信息生成的。
/*
 * https://code.google.com/oauthplayground 可以找到一个scope列表。
 */
private final static String SCOPE = "https://www.googleapis.com/auth/tasks";
/*以下信息来自于https://code.google.com/apis/console
 *创建一个Project,然后选择要激活的Service,我激活了Calendar和Tasks API
 *选择API Access,可以设置OAuth 2.0,进而得到相关信息。
 *创建id时选择for installed applications。 
 */
private final static String CLIENT_ID = "你的id.apps.googleusercontent.com";
private final static String CLIENT_SECRET = "你的secret";
private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";
    
private void requestAuthCode() {
	String authorizeUrl = new GoogleAuthorizationRequestUrl(CLIENT_ID, CALLBACK_URL, SCOPE).build();
    	Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(authorizeUrl));
    	startActivity(intent);
}

用户看到一个浏览器打开的页面,输入用户名和密码后就可以得到授权码,不过要手工复制一下,然后到程序中粘贴。
授权码是时刻在变的,即使是同一个设备同一个ap去获取同一个账户的授权码也是在变的。

2.数据访问令牌的获取
用授权码作为参数,获取后保存。
private boolean requestToken(String authCode) {
    GoogleAuthorizationCodeGrant authRequest = new GoogleAuthorizationCodeGrant(mTransport,
  		new JacksonFactory(), CLIENT_ID, CLIENT_SECRET, authCode, CALLBACK_URL);
    authRequest.useBasicAuthorization = false;
    AccessTokenResponse authResponse;
	try {
		authResponse = authRequest.execute();	//发出请求
		mAccessToken = authResponse.accessToken;
		mRefreshToken = authResponse.refreshToken;
		return true;		
	} catch( HttpResponseException he) {
		he.printStackTrace();
		return false;
	} catch (IOException e) {
		e.printStackTrace();
		return false;
	} 
}


3.读取数据
使用token构造一个可以进行访问保护资源的对象。
然后构造一个Tasks对象。
执行tasks的execute()方法就可以获得数据了。
当获取数据时,token有可能过期,这个时候会得到401的响应值,此时需要刷新一下token,然后再获取数据。
if(mAccessProtectedResource == null) {
	mAccessProtectedResource = new GoogleAccessProtectedResource(mAccessToken,
							mTransport, new JacksonFactory(), CLIENT_ID, CLIENT_SECRET, mRefreshToken);
				}
	if(mService == null) mService = new Tasks(mTransport, mAccessProtectedResource, new JacksonFactory());
	mTaskListNames.clear(); 
	try {
		List<TaskList> lists = mService.tasklists.list().execute().items;
		for(TaskList tl : lists) {
			mTaskListNames.add(tl.title);
		}
		mAdapter.notifyDataSetChanged();
	} catch(HttpResponseException he) {
		if(he.getResponse().getStatusCode() == 401) {
			//token 过期,刷新token
			try {
				mAccessProtectedResource.refreshToken();
				mAccessToken = mAccessProtectedResource.getAccessToken();
				mRefreshToken = mAccessProtectedResource.getRefreshToken();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	} catch (IOException e) {
	}


另外此种方法访问用户数据因为Client_ID没有改变,所以每个Ap的限额仍然是每日5000次,即使访问的是不同账户的数据。
那么解决限额的方法只能是交钱买更多的,或者Ap里面多内置几个Client_ID,随机选用了,当然这些Client_ID必须是隶属于不同账户的。
或者就好像(一)中提到的,让用户自己输入自己的API KEY,不过这个太专业了,一般人不好搞。
直接通过HttpClient走REST协议似乎可以不用client_id和api key,可参见:
https://code.google.com/apis/explorer 应该也不行,在获取授权码的时候就要client id

如果授权失败返回的错误码是401,如果是超限额返回的错误码是403。
另外如果使用proguard,那么要增加配置:
(来自于http://code.google.com/p/google-api-java-client/wiki/Setup)

# Needed by google-api-client to keep generic types and @Key annotations accessed via reflection

-keepclassmembers class * {
  @com.google.api.client.util.Key <fields>;
}

-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault

# Needed by Guava

-dontwarn sun.misc.Unsafe

# See https://groups.google.com/forum/#!topic/guava-discuss/YCZzeCiIVoI
-dontwarn com.google.common.collect.MinMaxPriorityQueue

PS:经试验task的title的长度最大为1024字节;note的最大长度为8192字节。