基于Google Drive实现双安卓设备字符串共享的Java方案
安卓端用Java读写Google Drive文件实现双向字符串共享
前置准备
- 在Google Cloud Console创建项目,启用Google Drive API,生成匹配安卓包名与SHA-1签名的OAuth 2.0客户端ID。
- 在安卓项目的
build.gradle(Module)中添加Drive依赖:dependencies { implementation 'com.google.android.gms:play-services-drive:17.0.0' } - 配置
AndroidManifest.xml,添加必要权限与Drive服务声明:<uses-permission android:name="android.permission.INTERNET" /> <application ...> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <service android:name="com.google.android.gms.drive.DriveApiService" android:exported="true" android:permission="com.google.android.gms.permission.DRIVE_SERVICE" /> </application>
授权获取Drive客户端
首先完成用户授权,拿到可操作Drive的客户端实例:
private static final int REQUEST_CODE_SIGN_IN = 1001; private Drive mDriveClient; private GoogleSignInClient buildGoogleSignInClient() { GoogleSignInOptions signInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(new Scope(DriveScopes.DRIVE_FILE)) // 仅请求文件级权限,更安全 .requestEmail() .build(); return GoogleSignIn.getClient(this, signInOptions); } // 启动授权流程 private void requestSignIn() { startActivityForResult(buildGoogleSignInClient().getSignInIntent(), REQUEST_CODE_SIGN_IN); } // 处理授权结果 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE_SIGN_IN) { Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); handleSignInResult(task); } } private void handleSignInResult(Task<GoogleSignInAccount> completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); mDriveClient = Drive.get(this, account); // 授权成功,可执行后续读写操作 } catch (ApiException e) { Log.e(TAG, "Sign-in failed: " + e.getStatusCode()); } }
读取Google Drive中的TXT文件
先按文件名查找目标文件,再读取文本内容:
private void readSharedTxt() { if (mDriveClient == null) return; // 构建查询条件:查找未被删除的"SharedString.txt"文件 Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, "SharedString.txt")) .addFilter(Filters.eq(SearchableField.TRASHED, false)) .build(); mDriveClient.files().list(query) .setFields("files(id, name)") .executeAsync(new ResultCallback<DriveFiles.ListResult>() { @Override public void onResult(@NonNull DriveFiles.ListResult result) { if (!result.getStatus().isSuccess()) { Log.e(TAG, "Failed to find file: " + result.getStatus().getStatusCode()); return; } List<DriveFile> files = result.getFiles(); if (files.isEmpty()) { // 文件不存在,创建新文件 createSharedTxt(""); return; } DriveFile targetFile = files.get(0); // 以只读模式打开文件流 targetFile.open(mDriveClient, DriveFile.MODE_READ_ONLY, null) .executeAsync(new ResultCallback<DriveContents>() { @Override public void onResult(@NonNull DriveContents result) { if (!result.getStatus().isSuccess()) { Log.e(TAG, "Failed to open file: " + result.getStatus().getStatusCode()); return; } // 读取文本内容 InputStream inputStream = result.getInputStream(); String content = new BufferedReader(new InputStreamReader(inputStream)) .lines().collect(Collectors.joining("\n")); // 这里更新UI显示共享字符串 // 关闭文件流 result.discard(mDriveClient); } }); } }); }
写入/更新TXT文件内容
找到目标文件后,写入新的共享字符串:
private void writeSharedTxt(String newContent) { if (mDriveClient == null) return; Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, "SharedString.txt")) .addFilter(Filters.eq(SearchableField.TRASHED, false)) .build(); mDriveClient.files().list(query) .setFields("files(id, name)") .executeAsync(new ResultCallback<DriveFiles.ListResult>() { @Override public void onResult(@NonNull DriveFiles.ListResult result) { if (!result.getStatus().isSuccess()) { Log.e(TAG, "Failed to find file: " + result.getStatus().getStatusCode()); return; } List<DriveFile> files = result.getFiles(); DriveFile targetFile; if (files.isEmpty()) { targetFile = createSharedTxt(newContent); return; } targetFile = files.get(0); // 以写入模式打开文件流 targetFile.open(mDriveClient, DriveFile.MODE_WRITE_ONLY, null) .executeAsync(new ResultCallback<DriveContents>() { @Override public void onResult(@NonNull DriveContents result) { if (!result.getStatus().isSuccess()) { Log.e(TAG, "Failed to open file for write: " + result.getStatus().getStatusCode()); return; } // 写入新内容 OutputStream outputStream = result.getOutputStream(); try { outputStream.write(newContent.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { Log.e(TAG, "Write failed: " + e.getMessage()); } // 提交文件更改 targetFile.commit(mDriveClient, result, null) .executeAsync(new ResultCallback<Void>() { @Override public void onResult(@NonNull Void result) { Log.d(TAG, "File updated successfully"); // 可触发另一设备同步,比如用WorkManager定时拉取或推送通知 } }); } }); } }); } // 创建新的共享TXT文件 private DriveFile createSharedTxt(String initialContent) { MetadataChangeSet changeSet = new MetadataChangeSet.Builder() .setTitle("SharedString.txt") .setMimeType("text/plain") .build(); mDriveClient.getRootFolder().createFile(mDriveClient, changeSet, null) .executeAsync(new ResultCallback<DriveFile>() { @Override public void onResult(@NonNull DriveFile result) { if (result.getStatus().isSuccess()) { // 创建成功后写入初始内容 writeSharedTxt(initialContent); } else { Log.e(TAG, "Failed to create file: " + result.getStatus().getStatusCode()); } } }); return result; }
双向同步关键注意事项
- 冲突处理:两部设备可能同时修改文件,建议在TXT中加入版本号或时间戳,写入前对比版本,避免覆盖对方修改。
- 同步触发:可用WorkManager定时拉取文件更新,或配置Drive API推送通知实现实时同步。
- 权限控制:仅请求
DRIVE_FILE范围权限,不要申请全Drive权限,提升应用安全性。
内容的提问来源于stack exchange,提问作者IdoSC
相关产品推荐
相关产品推荐

