You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android平台使用Python(Kivy框架)保存文件时遭遇Errno 13权限拒绝问题

解决Kivy Android应用下载MP3到Download文件夹时的Errno 13权限拒绝问题

这个权限拒绝的坑在Kivy开发Android应用时太常见了,本质是Android的权限管控机制在起作用——哪怕你要写入的是公开的Download目录,也不能直接跳过权限申请就操作,尤其是Android 6.0(API 23)及以上的系统,必须动态申请权限才行。下面给你一步步的解决方案:

1. 先配置必要的权限与依赖

Android要求应用必须明确申请WRITE_EXTERNAL_STORAGE权限才能写入外部存储,同时下载需要INTERNET权限。如果用buildozer打包,先在buildozer.spec里做以下配置:

  • 添加plyer依赖(用来处理动态权限申请):
requirements = python3,kivy,plyer
  • 声明所需权限:
android.permissions = WRITE_EXTERNAL_STORAGE, INTERNET

2. 修改代码:先申请权限再执行下载

把下载逻辑和权限申请绑定,确保拿到权限后再操作文件:

import requests
from plyer import permissions
from kivy.app import App
from kivy.uix.button import Button

class MP3Downloader(App):
    def build(self):
        download_btn = Button(text="Download MP3")
        download_btn.bind(on_press=self.start_download)
        return download_btn

    def start_download(self, instance):
        # 先检查是否已有权限
        if permissions.check_permission('WRITE_EXTERNAL_STORAGE'):
            self.download_and_save()
        else:
            # 动态申请权限,回调处理结果
            permissions.request_permissions(
                ['WRITE_EXTERNAL_STORAGE'],
                self.handle_permission_result
            )

    def handle_permission_result(self, permissions_list, results):
        # 所有权限通过才继续执行
        if all(results):
            self.download_and_save()
        else:
            print("权限被拒绝,无法完成下载")

    def download_and_save(self):
        target_link = 'https://www.yt-download.org/download/IFtwhMK64H8/mp3/128/1630338605/f2803874069bf196561631cea2b1b11c2b1d2f9555e2baf751eb28b46d484bb5/0.mp3'
        try:
            response = requests.get(target_link)
            # 写入Download文件夹
            with open('/storage/emulated/0/Download/file.mp3', 'wb') as f:
                f.write(response.content)
            print("下载完成!")
        except Exception as e:
            print(f"下载过程出错: {str(e)}")

if __name__ == '__main__':
    MP3Downloader().run()

3. Android 10+的适配方案(Scoped Storage)

如果你的应用目标SDK是29及以上,Android的Scoped Storage机制会限制直接写入公共目录,这时候推荐用MediaStore来插入文件,更符合系统规范且无需额外权限:

from android.media import MediaStore
from android.os import Environment
from kivy.app import App
import requests

def save_to_download(content, filename):
    # 获取Download目录的MediaStore URI
    download_uri = MediaStore.Downloads.EXTERNAL_CONTENT_URI
    # 配置文件元数据
    file_details = {
        MediaStore.Downloads.DISPLAY_NAME: filename,
        MediaStore.Downloads.MIME_TYPE: 'audio/mpeg',
        MediaStore.Downloads.RELATIVE_PATH: Environment.DIRECTORY_DOWNLOADS
    }
    # 获取ContentResolver操作MediaStore
    resolver = App.get_running_app().content_resolver
    # 插入文件记录到系统媒体库
    file_uri = resolver.insert(download_uri, file_details)
    # 写入文件内容
    with resolver.openOutputStream(file_uri, 'w') as output_stream:
        output_stream.write(content)
    return file_uri

# 在download_and_save里替换原open写法:
response = requests.get(target_link)
save_to_download(response.content, 'file.mp3')

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

火山引擎 最新活动