使用Google Sheets API的Kivy/Buildozer安卓应用启动崩溃求助
问题描述
我在小米Redmi Note 12 Pro上运行用Buildozer打包的Kivy应用,该应用需要调用Google Sheets API实现按钮点击写入数据到谷歌表格的功能。应用在本地调试正常,但打包部署到手机后启动就崩溃,移除Google Sheets相关功能则无此问题。
相关代码片段如下:
import os from google.oauth2.credentials import Credentials from google.auth.transport.requests import Request from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build # 初始化服务的函数 def GetService(api_name, api_version, *scopes): SCOPES = [scope for scope in scopes[0]] creds = None if os.path.exists("token.json"): creds = Credentials.from_authorized_user_file("token.json", SCOPES) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file( "credentials.json", SCOPES ) creds = flow.run_local_server(port = 0) with open("token.json", "w") as token: token.write(creds.to_json()) try: service = build(api_name, api_version, credentials = creds) print("Successfully connected to the google sheets api.") return service except Exception as e: print("Could not connect to the google sheets api!") print(e) return None # 应用启动时初始化的内容 self.api_name = "sheets" self.api_version = "v4" self.scopes = ["https://www.googleapis.com/auth/spreadsheets"] self.sheet_id = "id of my spreadsheet" self.sheet_name = "name of my sheet" self.service = GetService(self.api_name, self.api_version, self.scopes) self.my_sheet = self.service.spreadsheets().get(spreadsheetId = self.sheet_id).execute() # 按钮点击时添加行的函数 def AddRow(self, current_date, val1, val2, val3, current_time): # 获取现有行数 row_numb = self.service.spreadsheets().values().get( spreadsheetId = self.sheet_id, majorDimension = "ROWS", range = f"{self.sheet_name}A1:A1000" ).execute() row_numb = len(row_numb["values"]) + 1 # 准备插入的新行数据 insert_vals = ( (current_date, val1, val2, val3, "", current_time, ""), () ) value_range_body = { "majorDimension": "ROWS", "values": insert_vals } self.service.spreadsheets().values().update( spreadsheetId = self.sheet_id, valueInputOption = "USER_ENTERED", range = self.sheet_name + f"A{row_numb}", body = value_range_body ).execute() return None
应用使用了credentials.json和token.json文件,已将其添加到源文件中,也尝试调整过buildozer.spec的依赖和权限,但问题仍未解决。请问是否仅通过修改.spec文件即可修复?若可以,在默认文件上需做哪些最小变更才能让应用正常运行?
解决方案
仅修改buildozer.spec文件无法完全解决问题,因为代码中存在安卓环境不兼容的逻辑,但.spec文件的调整是运行基础,以下是必要的最小变更:
一、buildozer.spec的核心修改
- 添加网络权限
在android.permissions字段中补充联网权限,谷歌API需要网络请求:
android.permissions = INTERNET
- 补充依赖库
在requirements字段中加入谷歌API相关依赖,确保打包时包含这些库:
requirements = python3,kivy,google-auth,google-auth-oauthlib,google-api-python-client,requests
- 确保JSON文件被打包
确认source.include_exts包含.json后缀,保证credentials.json和token.json被打包进APK:
source.include_exts = py,png,jpg,kv,atlas,json
- 指定兼容的安卓API级别
设置为28及以上的API级别,避免兼容性问题:
android.api = 33
二、代码层面必须调整的逻辑
崩溃的核心原因是代码中flow.run_local_server()是为桌面环境设计的,安卓无法启动本地服务器完成OAuth授权。需要调整为安卓兼容的授权方式:
- 预先在桌面环境生成有效的
token.json(确保包含有效refresh_token),打包时直接包含该文件; - 移除桌面授权流程,仅保留通过refresh_token自动刷新token的逻辑。
调整后的GetService函数示例:
def GetService(api_name, api_version, *scopes): SCOPES = [scope for scope in scopes[0]] creds = None # 安卓环境下直接读取打包好的token.json if os.path.exists("token.json"): creds = Credentials.from_authorized_user_file("token.json", SCOPES) if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: # 仅通过refresh_token刷新,跳过桌面授权流程 creds.refresh(Request()) with open("token.json", "w") as token: token.write(creds.to_json()) else: # 安卓环境无法完成授权,直接返回None或提示用户在桌面生成token print("无法在安卓上完成授权,请先在桌面生成有效token.json") return None try: service = build(api_name, api_version, credentials=creds) print("Successfully connected to the google sheets api.") return service except Exception as e: print("Could not connect to the google sheets api!") print(e) return None
另外注意:安卓应用的工作目录是私有内部存储,确保JSON文件被放置在正确路径,或通过user_data_dir获取应用私有存储路径来读取文件。
内容的提问来源于stack exchange,提问作者iamklager
相关产品推荐
相关产品推荐

