0

0

Android Kivy 应用中正确申请存储权限的完整实践指南

霞舞

霞舞

发布时间:2026-02-24 22:24:10

|

687人浏览过

|

来源于php中文网

原创

Android Kivy 应用中正确申请存储权限的完整实践指南

本文详解在 kivy + python for android(p4a)环境中,如何合规、可靠地申请并使用外部存储读写权限,解决 permissionerror: [errno 13] permission denied 问题,并避免因权限调用时机不当导致的崩溃或静默失败。

本文详解在 kivy + python for android(p4a)环境中,如何合规、可靠地申请并使用外部存储读写权限,解决 permissionerror: [errno 13] permission denied 问题,并避免因权限调用时机不当导致的崩溃或静默失败。

在 Android 6.0(API 23)及以上版本中,READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 属于危险权限(dangerous permissions),仅在 buildozer.spec 中声明是远远不够的——必须在运行时显式请求用户授权,且必须在任何访问外部存储的操作之前完成授权。你遇到的 PermissionError 正是因为代码在未获授权前就尝试创建目录(folder_path.mkdir(...)),而此时系统已拒绝访问 /storage/emulated/0/。

✅ 正确的权限申请时机:启动早期 + 异步等待

关键原则:权限请求必须发生在 UI 初始化之前,且需确保授权完成后再执行文件操作。你原代码中将 request_permissions(...) 放在 build() 方法内存在两大缺陷:

清程爱画
清程爱画

AI图像与视频生成平台,拥有超丰富的工作流社区和多种图像生成模式。

下载
  • build() 在 Kivy 主循环启动后才执行,此时部分底层 Android API 可能尚未就绪;
  • request_permissions() 是异步操作,立即返回,但实际授权结果需通过回调处理;而你的 mkdir 和 open() 紧随其后同步执行,必然失败。

正确的做法是:在 MyApp().run() 调用前,先发起权限请求,并利用回调驱动后续逻辑

✅ 推荐实现方案(含错误处理与兼容性)

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.utils import platform
from pathlib import Path
import os

# 仅在 Android 平台导入 Android 模块(避免桌面端报错)
if platform == "android":
    from android.permissions import request_permissions, check_permission, Permission
    from android.storage import primary_external_storage_path
    from jnius import autoclass
    PythonActivity = autoclass('org.kivy.android.PythonActivity')

class MyApp(App):
    def build(self):
        # 权限检查:若已授权,直接构建 UI;否则显示提示或延迟加载
        if platform == "android":
            if not self._check_storage_permissions():
                # 权限未授予,返回占位 Label 提示用户等待
                return Label(text="正在请求存储权限...\n请稍候", halign="center", valign="middle")

        # ✅ 此处确保权限已就绪,可安全访问存储
        text = f"1{App.get_running_app().user_data_dir}\n"
        self.label = Label(text=text, halign="left", valign="top")
        self.label.text_size = (self.label.width * 0.9, None)

        if platform == "android":
            folder_path = Path(primary_external_storage_path(), "my_kivy_app_folder")
            try:
                folder_path.mkdir(parents=True, exist_ok=True)
                file_path = folder_path / "test.txt"
                with open(file_path, "w", encoding="utf-8") as f:
                    f.write("Hello from Kivy on Android! ?\n")
                self.label.text += f"✅ 已写入: {file_path}\n"
            except PermissionError as e:
                self.label.text += f"❌ 权限被拒绝: {e}\n"
            except Exception as e:
                self.label.text += f"⚠️ 写入异常: {e}\n"
        else:
            file_path = Path.home() / "test_kivy.txt"
            with open(file_path, "w", encoding="utf-8") as f:
                f.write("Hello from desktop!\n")
            self.label.text += f"✅ 已写入: {file_path}\n"

        return self.label

    def _check_storage_permissions(self):
        """检查是否已拥有读写外部存储权限"""
        return (
            check_permission(Permission.READ_EXTERNAL_STORAGE) and
            check_permission(Permission.WRITE_EXTERNAL_STORAGE)
        )

# === 主入口:权限请求前置 ===
if __name__ == '__main__':
    if platform == "android":
        # ? 关键:在 App.run() 前请求权限
        def on_permissions_granted(permissions, grant_results):
            # grant_results 是布尔列表,对应 permissions 的授权状态
            if all(grant_results):
                print("✅ 所有存储权限已授予")
                MyApp().run()
            else:
                print("❌ 用户拒绝了部分权限,应用将无法访问外部存储")

        # 发起请求(注意:此调用会触发系统弹窗)
        request_permissions(
            [Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE],
            on_permissions_granted
        )
    else:
        MyApp().run()

⚠️ 重要注意事项

  • Android 10+(API 29)及更高版本限制:从 Android 10 开始,WRITE_EXTERNAL_STORAGE 对应用私有目录外的路径不再提供宽泛写入能力(Scoped Storage)。如需访问公共目录(如 DCIM/, Downloads/),应改用 MediaStore API 或申请 MANAGE_EXTERNAL_STORAGE(需 Google Play 审核批准)。对于应用专属文件,推荐优先使用 app_storage_path() 或 get_files_dir()(通过 android.storage 或 jnius 获取),无需额外权限。
  • buildozer.spec 配置需匹配:确保 android.permissions 包含对应权限(注意大小写和命名空间):
    android.permissions = READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE
  • 不要忽略回调:永远不要假设 request_permissions() 同步成功;务必通过回调函数判断授权结果。
  • 测试建议:在真机上测试,模拟器可能权限行为不一致;首次安装后手动进入「设置 → 应用 → 权限」验证状态。

✅ 总结

解决 Kivy Android 存储权限问题的核心在于:声明 + 运行时请求 + 回调驱动 + 时机前置。将权限请求移至 App.run() 之前,并严格依据授权结果决定后续流程,即可彻底规避 PermissionError。同时,关注 Android 版本演进对存储模型的影响,合理选择存储路径策略,是构建健壮跨平台移动应用的关键一步。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
android开发三大框架
android开发三大框架

android开发三大框架是XUtil框架、volley框架、ImageLoader框架。本专题为大家提供android开发三大框架相关的各种文章、以及下载和课程。

324

2023.08.14

android是什么系统
android是什么系统

Android是一种功能强大、灵活可定制、应用丰富、多任务处理能力强、兼容性好、网络连接能力强的操作系统。本专题为大家提供android相关的文章、下载、课程内容,供大家免费下载体验。

1794

2023.08.22

android权限限制怎么解开
android权限限制怎么解开

android权限限制可以使用Root权限、第三方权限管理应用程序、ADB命令和Xposed框架解开。详细介绍:1、Root权限,通过获取Root权限,用户可以解锁所有权限,并对系统进行自定义和修改;2、第三方权限管理应用程序,用户可以轻松地控制和管理应用程序的权限;3、ADB命令,用户可以在设备上执行各种操作,包括解锁权限;4、Xposed框架,用户可以在不修改系统文件的情况下修改应用程序的行为和权限。

2104

2023.09.19

android重启应用的方法有哪些
android重启应用的方法有哪些

android重启应用有通过Intent、PendingIntent、系统服务、Runtime等方法。本专题为大家提供Android相关的文章、下载、课程内容,供大家免费下载体验。

283

2023.10.18

Android语音播放功能实现方法
Android语音播放功能实现方法

实现方法有使用MediaPlayer实现、使用SoundPool实现两种。可以根据具体的需求选择适合的方法进行实现。想了解更多语音播放的相关内容,可以阅读本专题下面的文章。

378

2024.03.01

Golang 生态工具与框架:扩展开发能力
Golang 生态工具与框架:扩展开发能力

《Golang 生态工具与框架》系统梳理 Go 语言在实际工程中的主流工具链与框架选型思路,涵盖 Web 框架、RPC 通信、依赖管理、测试工具、代码生成与项目结构设计等内容。通过真实项目场景解析不同工具的适用边界与组合方式,帮助开发者构建高效、可维护的 Go 工程体系,并提升团队协作与交付效率。

1

2026.02.24

Golang 性能优化专题:提升应用效率
Golang 性能优化专题:提升应用效率

《Golang 性能优化专题》聚焦 Go 应用在高并发与大规模服务中的性能问题,从 profiling、内存分配、Goroutine 调度、GC 机制到 I/O 与锁竞争逐层分析。结合真实案例讲解定位瓶颈的方法与优化策略,帮助开发者建立系统化性能调优思维,在保证代码可维护性的同时显著提升服务吞吐与稳定性。

2

2026.02.24

Golang 面试题精选:高频问题与解答
Golang 面试题精选:高频问题与解答

Golang 面试题精选》系统整理企业常见 Go 技术面试问题,覆盖语言基础、并发模型、内存与调度机制、网络编程、工程实践与性能优化等核心知识点。每道题不仅给出答案,还拆解背后的设计原理与考察思路,帮助读者建立完整知识结构,在面试与实际开发中都能更从容应对复杂问题。

1

2026.02.24

Golang 运行与部署实战:从本地到云端
Golang 运行与部署实战:从本地到云端

《Golang 运行与部署实战》围绕 Go 应用从开发完成到稳定上线的完整流程展开,系统讲解编译构建、环境配置、日志与配置管理、容器化部署以及常见运维问题处理。结合真实项目场景,拆解自动化构建与持续部署思路,帮助开发者建立可靠的发布流程,提升服务稳定性与可维护性。

3

2026.02.24

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 18.7万人学习

Java 教程
Java 教程

共578课时 | 71.5万人学习

Uniapp从零开始实现新闻资讯应用
Uniapp从零开始实现新闻资讯应用

共64课时 | 6.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号