Android整合Google的文章太少了,写一篇记录一下自己所踩的坑
先放官方问文档:
GoogleDrive
其次就是得有个google账号,这部分略过
接下来是 Retrofit2.0实现Google Drive:
首先:okhttp不能少
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.6'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.0'
自己根据官网整一下6个json基类吧,放上来太多了不美观分别是:UploadResult 、Token、User、DriveFiles、DriveFile、About
以下找不到的静态stirng基本就是Google申请的一些私人内容了我就不提供了
public class DriveHelper {
private String TOKEN_KEY = "google_token";
private String mAuthCode;
private DriveApi mDriveApi;
private String mAccessToken;
private String mRefreshToken;
public DriveHelper() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL_API)
.addConverterFactory(GsonConverterFactory.create())
.build();
mDriveApi = retrofit.create(DriveApi.class);
}
public void setAuthCode(String authCode) {
try {
mAuthCode = URLDecoder.decode(authCode, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 获取AccessToken
*
* @param callback 回调
*/
public void getToken(final StateCallback callback) {
Call<Token> call = mDriveApi.getToken(mAuthCode, CLIENT_ID,
CLIENT_SECRET, REDIRECT_URI, "authorization_code");
call.enqueue(new Callback<Token>() {
@Override
public void onResponse(Call<Token> call, Response<Token> response) {
String message = DriveUtils.printResponse("getToken", response);
if (message == null) {
Token token = response.body();
mAccessToken = token.getAccessToken();
mRefreshToken = token.getAccessToken();
SharePreferenceUtil.getInstance().commitString(TOKEN_KEY, mRefreshToken);
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<Token> call, Throwable t) {
String message = DriveUtils.printFailure("getToken", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 刷新AccessToken
*
* @param callback 回调
*/
public void refreshToken(final StateCallback callback) {
mRefreshToken = SharePreferenceUtil.getInstance().getString(TOKEN_KEY, "");
if (mRefreshToken.equals("")) {
if (callback != null) {
callback.onFailure("");
}
return;
}
checkRefreshToken();
Call<Token> call = mDriveApi.refreshToken(mRefreshToken, CLIENT_ID, CLIENT_SECRET, "refresh_token");
call.enqueue(new Callback<Token>() {
@Override
public void onResponse(Call<Token> call, Response<Token> response) {
String message = DriveUtils.printResponse("refreshToken", response);
if (message == null) {
Token token = response.body();
mAccessToken = token.getAccessToken();
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<Token> call, Throwable t) {
String message = DriveUtils.printFailure("refreshToken", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 注销AccessToken
*
* @param callback 回调
*/
public void revokeToken(final StateCallback callback) {
SharePreferenceUtil.getInstance().commitString(TOKEN_KEY, "");
checkAccessToken();
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL_ACCOUNT)
.addConverterFactory(GsonConverterFactory.create()).build();
Call<Void> call = retrofit.create(DriveApi.class).revokeToken(mAccessToken);
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
String message = DriveUtils.printResponse("revokeToken", response);
if (message == null) {
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
String message = DriveUtils.printFailure("revokeToken", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 获取用户Google Drive账号信息
*
* @param callback 回调
*/
public void getAbout(final StateCallback callback) {
Call<About> call = mDriveApi.getAbout(getAuthToken(),
"kind, user, maxUploadSize, appInstalled");
call.enqueue(new Callback<About>() {
@Override
public void onResponse(Call<About> call, Response<About> response) {
String message = DriveUtils.printResponse("getAbout", response);
if (message == null) {
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<About> call, Throwable t) {
String message = DriveUtils.printFailure("getAbout", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 根据关键字搜索文件列表
*
* @param word 搜索关键字
* @param callback 回调
*/
public void searchFiles(String word, final ListCallback callback) {
// 根据关键字搜索文件
Call<DriveFiles> call = mDriveApi.getFiles(getAuthToken(),
"modifiedTime", 1000, null, String.format("name contains '%s'", word));
call.enqueue(new Callback<DriveFiles>() {
@Override
public void onResponse(Call<DriveFiles> call, Response<DriveFiles> response) {
String message = DriveUtils.printResponse("searchFiles", response);
if (message == null) {
if (callback != null) {
callback.onSuccess(response.body().getFiles());
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<DriveFiles> call, Throwable t) {
String message = DriveUtils.printFailure("searchFiles", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 根据父目录ID获取子文件列表
*
* @param folderId 父目录ID
* @param callback 回调
*/
public void listFiles(String folderId, final ListCallback callback) {
// 根据父目录的ID搜索文件
Call<DriveFiles> call = mDriveApi.getFiles(getAuthToken(),
"name", 1000, null, String.format("'%s' in parents", folderId));
call.enqueue(new Callback<DriveFiles>() {
@Override
public void onResponse(Call<DriveFiles> call, Response<DriveFiles> response) {
String message = DriveUtils.printResponse("listFiles", response);
if (message == null) {
if (callback != null) {
callback.onSuccess(response.body().getFiles());
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<DriveFiles> call, Throwable t) {
String message = DriveUtils.printFailure("listFiles", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 根据文件ID获取文件信息
*
* @param fileId 文件ID
* @param callback 回调
*/
public void getFile(String fileId, final StateCallback callback) {
Call<DriveFile> call = mDriveApi.getFile(getAuthToken(), fileId);
call.enqueue(new Callback<DriveFile>() {
@Override
public void onResponse(Call<DriveFile> call, Response<DriveFile> response) {
String message = DriveUtils.printResponse("getFile", response);
if (message == null) {
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<DriveFile> call, Throwable t) {
String message = DriveUtils.printFailure("getFile", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 从Google Drive下载文件
*
* @param fileId 需要下载的文件ID
* @param dstFile 下载文件到本地的路径
* @param callback 回调
*/
public void downloadFile(String fileId, final File dstFile, final StateCallback callback) {
Call<ResponseBody> call = mDriveApi.downloadFile(getAuthToken(), fileId);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
String message = DriveUtils.printResponse("downloadFile", response);
if (message == null) {
BufferedInputStream bis = new BufferedInputStream(response.body().byteStream());
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(dstFile));
int length;
byte[] buffer = new byte[1024];
while ((length = bis.read(buffer)) != -1) {
bos.write(buffer, 0, length);
}
bos.flush();
if (callback != null) {
callback.onSuccess();
}
} catch (IOException e) {
e.printStackTrace();
if (callback != null) {
callback.onFailure(Log.getStackTraceString(e));
}
} finally {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
String message = DriveUtils.printFailure("downloadFile", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
public void uploadFile(File srcFile, String folderId, StateCallback callback) {
if (mAccessToken != null)
uploadFile(srcFile, srcFile.getName(), folderId, callback);
else {
ToastUtils.show(R.string.network_storage_do_not_login, Utils.INSTANCE.getApp().getApplicationContext());
}
}
/**
* 上传文件到指定目录
*
* @param srcFile 本地需要上传的文件
* @param title 上传文件名称
* @param folderId 上传文件父目录ID
* @param callback 回调
*/
public void uploadFile(File srcFile, String title, final String folderId, final StateCallback callback) {
MediaType contentType = MediaType.parse("application/json; charset=UTF-8");
String content = "{\"name\": \"" + title + "\"}";
MultipartBody.Part metaPart = MultipartBody.Part.create(RequestBody.create(contentType, content));
String mimeType = CommonUtils.getMimeType(srcFile);
MultipartBody.Part dataPart = MultipartBody.Part.create(RequestBody.create(MediaType.parse(mimeType), srcFile));
Call<UploadResult> call = mDriveApi.uploadFile(getAuthToken(), metaPart, dataPart);
call.enqueue(new Callback<UploadResult>() {
@Override
public void onResponse(Call<UploadResult> call, Response<UploadResult> response) {
String message = DriveUtils.printResponse("uploadFile", response);
if (message == null) {
moveFile(response.body().getId(), folderId, new StateCallback() {
@Override
public void onSuccess() {
if (callback != null) {
callback.onSuccess();
}
}
@Override
public void onFailure(String msg) {
if (callback != null) {
callback.onFailure(msg);
}
}
});
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<UploadResult> call, Throwable t) {
String message = DriveUtils.printFailure("uploadFile", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 从根目录移动文件
*
* @param fileId 需要移动的文件ID
* @param dstFolderId 目标目录ID
* @param callback 回调
*/
public void moveFile(String fileId, String dstFolderId, StateCallback callback) {
moveFile(fileId, dstFolderId, ROOT_DRIVE_ID, callback);
}
/**
* 移动文件
*
* @param fileId 需要移动的文件ID
* @param dstFolderId 目标目录ID
* @param srcFolderId 源目录ID
* @param callback 回调
*/
public void moveFile(String fileId, String dstFolderId, String srcFolderId, final StateCallback callback) {
Call<DriveFile> call = mDriveApi.moveFile(getAuthToken(), fileId, dstFolderId, srcFolderId);
call.enqueue(new Callback<DriveFile>() {
@Override
public void onResponse(Call<DriveFile> call, Response<DriveFile> response) {
String message = DriveUtils.printResponse("moveFile", response);
if (message == null) {
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<DriveFile> call, Throwable t) {
String message = DriveUtils.printFailure("moveFile", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 复制
*/
public void copyFile(String fileId, final StateCallback callback) {
Call<DriveFile> call = mDriveApi.copyFile(getAuthToken(), fileId);
call.enqueue(new Callback<DriveFile>() {
@Override
public void onResponse(Call<DriveFile> call, Response<DriveFile> response) {
String message = DriveUtils.printResponse("copyFile", response);
if (message == null) {
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<DriveFile> call, Throwable t) {
String message = DriveUtils.printFailure("copyFile", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
/**
* 删除文件
*
* @param fileId 需要删除的文件ID
* @param callback 回调
*/
public void deleteFile(String fileId, final StateCallback callback) {
Call<Void> call = mDriveApi.deleteFile(getAuthToken(), fileId);
call.enqueue(new Callback<Void>() {
@Override
public void onResponse(Call<Void> call, Response<Void> response) {
String message = DriveUtils.printResponse("deleteFile", response);
if (message == null) {
if (callback != null) {
callback.onSuccess();
}
} else {
if (callback != null) {
callback.onFailure(message);
}
}
}
@Override
public void onFailure(Call<Void> call, Throwable t) {
String message = DriveUtils.printFailure("deleteFile", t);
if (callback != null) {
callback.onFailure(message);
}
}
});
}
private String getAuthToken() {
checkAccessToken();
return String.format(AUTH_TOKEN, mAccessToken);
}
private void checkRefreshToken() {
if (mRefreshToken == null) {
throw new IllegalStateException("Refresh token is null!");
}
}
private void checkAccessToken() {
if (mAccessToken == null) {
throw new IllegalStateException("Access token is null!");
}
}
}
DriveApi 类:
public interface DriveApi {
/**
* https://developers.google.com/identity/protocols/OAuth2InstalledApp
*/
@POST("/oauth2/v4/token")
@FormUrlEncoded
Call<Token> getToken(
@Field("code") String code,
@Field("client_id") String clientId,
@Field("client_secret") String clientSecret,
@Field("redirect_uri") String redirectUri,
@Field("grant_type") String grantType
);
/**
* https://developers.google.com/identity/protocols/OAuth2InstalledApp
*/
@POST("/oauth2/v4/token")
@FormUrlEncoded
Call<Token> refreshToken(
@Field("refresh_token") String refreshToken,
@Field("client_id") String clientId,
@Field("client_secret") String clientSecret,
@Field("grant_type") String grantType
);
/**
* https://accounts.google.com/o/oauth2/revoke?token={token}
*/
@GET("/o/oauth2/revoke")
Call<Void> revokeToken(
@Query("token") String token
);
/**
* https://developers.google.com/drive/v3/reference/about
*/
@GET("/drive/v3/about")
Call<About> getAbout(
@Header("Authorization") String authToken,
@Query("fields") String fields
);
/**
* https://developers.google.com/drive/v3/reference/files/list
*/
@GET("/drive/v3/files")
Call<DriveFiles> getFiles(
@Header("Authorization") String authToken,
@Query("orderBy") String orderBy,
@Query("pageSize") int pageSize,
@Query("pageToken") String pageToken,
@Query("q") String q
);
/**
* https://developers.google.com/drive/v3/reference/files/get
*/
@GET("/drive/v3/files/fileId")
Call<DriveFile> getFile(
@Header("Authorization") String authToken,
@Query("fileId") String driveId
);
/**
* https://developers.google.com/drive/v3/web/manage-downloads
*/
@GET("/drive/v3/files/{fileId}?alt=media")
Call<ResponseBody> downloadFile(
@Header("Authorization") String authToken,
@Path(value = "fileId") String fileId
);
/**
* https://developers.google.com/drive/v3/web/multipart-upload
*/
@POST("/upload/drive/v3/files?uploadType=multipart")
@Multipart
Call<UploadResult> uploadFile(
@Header("Authorization") String authToken,
@Part MultipartBody.Part metaPart,
@Part MultipartBody.Part dataPart
);
/**
* https://developers.google.com/drive/v3/reference/files/update
*/
@PATCH("/drive/v3/files/{fileId}")
Call<DriveFile> moveFile(
@Header("Authorization") String authToken,
@Path(value = "fileId") String fileId,
@Query("addParents") String addParents,
@Query("removeParents") String removeParents
);
/**
* https://developers.google.com/drive/v3/reference/files/delete
*/
@DELETE("/drive/v3/files/{fileId}")
Call<Void> deleteFile(
@Header("Authorization") String authToken,
@Path(value = "fileId") String fileId
);
/**
* https://www.googleapis.com/drive/v3/files/fileId/copy
*/
@POST("/drive/v3/files/{fileId}/copy")
Call<DriveFile> copyFile(
@Header("Authorization") String authToken,
@Path(value = "fileId") String fileId
);
}
public final class DriveUtils {
private DriveUtils() {
}
public static String getAuthUri() {
return String.format(Constants.AUTH_URL, Constants.CLIENT_ID);
}
public static String printResponse(String msg, Response<?> response) {
CommonUtils.D(msg, "onResponse", response.toString());
if (response.isSuccessful()) {
CommonUtils.E(msg, "success", response.body());
return null;
} else {
String errorMessage = null;
try {
errorMessage = response.errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
CommonUtils.W(msg, "failure", errorMessage);
return msg + " failed: " + errorMessage;
}
}
public static String printFailure(String msg, Throwable t) {
String message = Log.getStackTraceString(t);
CommonUtils.W(msg, "onFailure", message);
return msg + " failed: " + message;
}
}
public final class CommonUtils {
private static final String TAG = "StephenLee";
private static final String DIVIDER = " - ";
private static boolean isDebug = true;
private CommonUtils() {
}
public static String getExtension(File file) {
return getExtension(file.getName());
}
public static String getExtension(String fileName) {
String lowerName = fileName.toLowerCase();
if (!lowerName.contains("."))
return "";
return lowerName.substring(lowerName.lastIndexOf(".") + 1);
}
public static String getMimeType(File file) {
MimeTypeMap map = MimeTypeMap.getSingleton();
String mimeType = map.getMimeTypeFromExtension(getExtension(file));
if (TextUtils.isEmpty(mimeType))
return "*/*";
return mimeType;
}
public static void setDebug(boolean isDebug) {
CommonUtils.isDebug = isDebug;
}
public static void V(Object... args) {
println(Log.VERBOSE, args);
}
public static void D(Object... args) {
println(Log.DEBUG, args);
}
public static void I(Object... args) {
println(Log.INFO, args);
}
public static void W(Object... args) {
println(Log.WARN, args);
}
public static void E(Object... args) {
println(Log.ERROR, args);
}
private static void println(int priority, Object... args) {
if (args == null || args.length == 0) {
println(priority, Arrays.toString(args));
return;
}
StringBuilder sb = new StringBuilder();
sb.append(args[0]);
for (int i = 1; i < args.length; i++) {
sb.append(DIVIDER).append(args[i]);
}
println(priority, sb.toString());
}
private static void println(int priority, String msg) {
if (isDebug) {
Log.println(priority, TAG, msg);
}
}
}
网上demo应该也有,基本只有上传下载这两个功能
目前API可行的功能:上传(不可上传文件夹)/下载/删除/复制/剪切功能
无:创建文件夹/重命名