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环境:
- 添加Gradle依赖:
implementation 'com.google.android.gms:play-services-drive:17.0.0' - 配置Android类型的OAuth客户端ID,按照官方文档实现授权、文件选择与上传逻辑,完全规避Python层的网络适配问题。
内容的提问来源于stack exchange,提问作者pips
相关产品推荐
相关产品推荐

