You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用上传视频至Google Drive报无法创建/tokens目录如何解决?

问题解答

关于目录创建的疑问确认

  • 你的理解正确:程序确实是在本地设备存储中创建tokens目录,和Google Drive远程服务器无关。
  • 目录作用:该目录用来持久化存储用户授权后得到的OAuth2凭证(包括access_token、refresh_token),避免每次使用Drive功能都需要用户重新登录授权。

报错原因

你直接照搬了面向桌面端Java环境的Drive官方示例,和Android系统的规则不兼容:

  1. Android应用没有权限在系统根目录直接创建/tokens目录,你写的固定路径"tokens"默认会指向根目录,触发权限不足报错。
  2. 你用的AuthorizationCodeInstalledApp、LocalServerReceiver类都是桌面端用来处理授权跳转的组件,Android系统不支持这种本地端口监听的授权逻辑,就算解决了目录问题后续也会报错。

修复方案

1. 修复tokens目录路径

将固定路径替换为Android应用专属内部存储路径,应用对该目录有完全读写权限,无需额外申请存储权限:

// 替换getCredentials方法中创建FileDataStoreFactory的逻辑
File tokenDir = new File(context.getFilesDir(), "tokens");
if (!tokenDir.exists()) {
    tokenDir.mkdirs(); // 手动创建目录,避免创建失败
}
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
        .setDataStoreFactory(new FileDataStoreFactory(tokenDir))
        .setAccessType("offline")
        .build();

2. 替换授权方式(Android环境推荐方案)

废弃桌面端授权逻辑,改用Android专属的Google Sign-In SDK完成Drive授权:

  • 先在Google Cloud控制台给你的Android应用配置包名、签名SHA1值,生成Android专属的OAuth凭证,不要用桌面端的credentials.json。
  • 集成Google Sign-In依赖,构建授权请求时申请Drive写入权限:
    你当前的权限DriveScopes.DRIVE_METADATA_READONLY是只读权限,无法完成上传,需要替换为DriveScopes.DRIVE_FILE(仅访问应用自己创建的文件)或DriveScopes.DRIVE(访问用户所有Drive文件)。

3. 修复文件大小校验逻辑

你当前的getFileSizeInMB方法直接用Uri的path创建File是错误的,Content Uri的路径不是本地真实文件路径,需要通过ContentResolver查询:

private long getFileSizeFromUri(Uri uri) {
    Cursor cursor = getContext().getContentResolver().query(uri, new String[]{OpenableColumns.SIZE}, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        long size = cursor.getLong(0);
        cursor.close();
        return size / (1024 * 1024); // 转成MB
    }
    return 0;
}

4. 视频上传代码示例

拿到用户选择的视频Uri后,通过Drive服务上传:

private void uploadVideo(Uri videoUri) throws IOException {
    ContentResolver resolver = getContext().getContentResolver();
    String mimeType = resolver.getType(videoUri);
    // 获取文件名
    String fileName = null;
    Cursor cursor = resolver.query(videoUri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        fileName = cursor.getString(0);
        cursor.close();
    }

    // 构建Drive文件元数据
    com.google.api.services.drive.model.File fileMeta = new com.google.api.services.drive.model.File();
    fileMeta.setName(fileName);

    // 读取文件流上传
    try (InputStream inputStream = resolver.openInputStream(videoUri)) {
        InputStreamContent content = new InputStreamContent(mimeType, inputStream);
        driveService.files().create(fileMeta, content)
                .setFields("id,name")
                .execute();
        Toast.makeText(getContext(), "视频上传成功", Toast.LENGTH_SHORT).show();
    }
}

注意:Drive服务初始化、上传操作都需要放在子线程执行,不要直接在主线程运行,否则会触发ANR报错。

内容的提问来源于stack exchange,提问作者vesii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 03:27:04