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

Android应用中Chaquopy+PyDrive连接Google Drive时本地服务器启动失败

解决Android+Chaquopy+PyDrive本地服务器授权失败问题

问题核心原因

Android应用的网络环境是沙箱化的,外部应用(如系统浏览器)无法访问当前应用内启动的localhost服务器,而LocalWebserverAuth依赖浏览器向本地服务器回调授权码,这在Android环境下天然不兼容,PC端能正常运行是因为没有沙箱隔离限制。


方案一:适配Android的PyDrive手动授权流程

优先解决原方法的适配问题,改用手动提取授权码的方式替代本地服务器回调:

1. 修改Python脚本

替换LocalWebserverAuth为命令行授权模式,拆分授权流程为「获取授权URL」「用授权码完成认证」「执行上传」三个步骤:

from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import os
import sys

def get_auth_url():
    # 修正client_secrets.json路径:Chaquopy会把assets目录加入Python路径
    client_secret_path = os.path.join(os.environ["PYTHONPATH"], "client_secrets.json")
    GoogleAuth.DEFAULT_SETTINGS["client_config_file"] = client_secret_path
    
    gauth = GoogleAuth()
    # 跳过本地服务器,直接获取授权URL
    auth_url = gauth.GetAuthUrl()
    return auth_url, gauth

def authenticate_with_code(gauth, auth_code):
    gauth.Auth(auth_code)
    # 保存凭证到应用私有目录,避免重复授权
    cred_path = os.path.join(os.environ["HOME"], "drive_credentials.json")
    gauth.SaveCredentialsFile(cred_path)
    return gauth

def upload_dataset(gauth, local_file_path, drive_file_name):
    drive = GoogleDrive(gauth)
    file = drive.CreateFile({"title": drive_file_name})
    file.SetContentFile(local_file_path)
    file.Upload()
    return file["id"]

2. Java层处理授权与上传

通过WebView加载授权URL,拦截回调链接提取授权码,再完成认证和上传:

import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.chaquo.python.Python;
import com.chaquo.python.PyObject;

public class MainActivity extends AppCompatActivity {
    private PyObject gauthInstance;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void onClickUploadDataset(View view) {
        Python py = Python.getInstance();
        PyObject uploadModule = py.getModule("upload_dataset");

        // 获取授权URL和gauth对象
        PyObject authResult = uploadModule.callAttr("get_auth_url");
        String authUrl = authResult.get(0).toString();
        gauthInstance = authResult.get(1);

        // 初始化WebView加载授权页面
        WebView authWebView = new WebView(this);
        authWebView.getSettings().setJavaScriptEnabled(true);
        authWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                String callbackUrl = request.getUrl().toString();
                // 拦截Google OAuth回调URL(需与Google控制台配置一致)
                if (callbackUrl.startsWith("http://localhost:8080/")) {
                    // 提取授权码参数
                    String authCode = callbackUrl.split("code=")[1].split("&")[0];
                    // 完成认证
                    PyObject authenticatedGauth = uploadModule.callAttr("authenticate_with_code", gauthInstance, authCode);
                    
                    // 执行上传(示例:上传手机内的test.txt到Drive)
                    String localFilePath = getFilesDir() + "/test.txt";
                    String driveFileName = "android_upload_test.txt";
                    PyObject fileId = uploadModule.callAttr("upload_dataset", authenticatedGauth, localFilePath, driveFileName);
                    
                    Toast.makeText(MainActivity.this, "上传完成,文件ID:" + fileId.toString(), Toast.LENGTH_LONG).show();
                    
                    // 销毁WebView
                    ((ViewGroup) authWebView.getParent()).removeView(authWebView);
                    return true;
                }
                return super.shouldOverrideUrlLoading(view, request);
            }
        });
        authWebView.loadUrl(authUrl);
        setContentView(authWebView);
    }
}

3. 配置注意事项

  • 在AndroidManifest.xml添加网络权限:
    <uses-permission android:name="android.permission.INTERNET" />
    
  • 将client_secrets.json放入src/main/assets目录,确保Chaquopy能读取到。
  • Google控制台的OAuth客户端ID需配置为「Desktop app」类型,重定向URI保持http://localhost:8080/。

方案二:替代方案——使用Google Drive Android SDK

如果不需要依赖Python,官方SDK更适配Android环境:

  1. 添加Gradle依赖:
    implementation 'com.google.android.gms:play-services-drive:17.0.0'
    
  2. 配置Android类型的OAuth客户端ID,按照官方文档实现授权、文件选择与上传逻辑,完全规避Python层的网络适配问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 08:30:08