使用 buildozer 从 kivy.py 构建 Android 应用程序包时遇到问题

问题描述 投票:0回答:1

我是编程新手。我从来没有编码过,但在 IA 的帮助下,我想从用 Kivy 编写的 Python 代码创建一个 apk。

这是我的脚本:

from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.metrics import dp
from kivymd.app import MDApp
from kivymd.uix.pickers import MDDockedDatePicker, MDModalInputDatePicker
from kivymd.uix.pickers import MDModalDatePicker
from kivymd.uix.snackbar import MDSnackbar, MDSnackbarText, MDSnackbarSupportingText
from datetime import timedelta
from functools import partial
from kivy.clock import Clock
from datetime import datetime
import ssl
ssl._create_default_https_context = ssl._create_unverified_context

KV = '''
MDScreen:
    md_bg_color: 1, 1, 1, 1  # Blanco

    ScrollView:
        do_scroll_x: False
        do_scroll_y: True

        GridLayout:
            cols: 1
            size_hint_y: None
            height: self.minimum_height
            spacing: dp(20)  # Espaciado entre filas
            padding: dp(20)  # Padding alrededor del contenido

            MDLabel:
                text: "Fecha de inicio y fin:"
                size_hint_y: None
                height: self.texture_size[1]

            MDTextField:
                id: field_start_end
                mode: "outlined"
                size_hint_y: None
                height: dp(48)
                on_focus: app.show_modal_date_picker(self)

            MDButton:
                text: "Seleccionar días festivos"
                size_hint_y: None
                height: dp(48)
                on_release: app.show_date_picker(self)

            MDLabel:
                text: "Fechas seleccionadas:"
                size_hint_y: None
                height: self.texture_size[1]

            MDTextField:
                id: festivos_seleccionados
                mode: "outlined"
                size_hint_y: None
                height: dp(48)
                readonly: False
                on_text: app.on_festivos_text_changed(self)

            GridLayout:
                cols: 3
                size_hint_y: 1
                height: self.minimum_height

                MDLabel:
                    text: "Selecciona los días de clase y las horas por día:"

            GridLayout:
                cols: 3
                size_hint_y: None
                height: self.minimum_height

                MDLabel:
                    text: "Lunes"

                MDCheckbox:
                    id: checkbox_lunes
                    size_hint_x: 6
                    width: dp(48)
                    on_active: app.toggle_day("lunes", self.active)

                MDTextField:
                    id: horas_lunes
                    mode: "filled"
                    text: "1"
                    size_hint_x: None
                    width: dp(48)
                    on_text: app.update_horas("lunes", self.text)

            GridLayout:
                cols: 3
                size_hint_y: None
                height: dp(48)

                MDLabel:
                    text: "Martes"

                MDCheckbox:
                    id: checkbox_martes
                    size_hint_x: 6
                    width: dp(48)
                    on_active: app.toggle_day("martes", self.active)

                MDTextField:
                    id: horas_martes
                    mode: "filled"
                    text: "1"
                    size_hint_x: None
                    width: dp(48)
                    on_text: app.update_horas("martes", self.text)

            GridLayout:
                cols: 3
                size_hint_y: None
                height: dp(48)

                MDLabel:
                    text: "Miércoles"

                MDCheckbox:
                    id: checkbox_miercoles
                    size_hint_x: 6
                    width: dp(48)
                    on_active: app.toggle_day("miercoles", self.active)

                MDTextField:
                    id: horas_miercoles
                    mode: "filled"
                    text: "1"
                    size_hint_x: None
                    width: dp(48)
                    on_text: app.update_horas("miercoles", self.text)

            GridLayout:
                cols: 3
                size_hint_y: None
                height: dp(48)

                MDLabel:
                    text: "Jueves"

                MDCheckbox:
                    id: checkbox_jueves
                    size_hint_x: 6
                    width: dp(48)
                    on_active: app.toggle_day("jueves", self.active)

                MDTextField:
                    id: horas_jueves
                    mode: "filled"
                    text: "1"
                    size_hint_x: None
                    width: dp(48)
                    on_text: app.update_horas("jueves", self.text)

            GridLayout:
                cols: 3
                size_hint_y: None
                height: dp(48)

                MDLabel:
                    text: "Viernes"

                MDCheckbox:
                    id: checkbox_viernes
                    size_hint_x: 6
                    width: dp(48)
                    on_active: app.toggle_day("viernes", self.active)

                MDTextField:
                    id: horas_viernes
                    mode: "filled"
                    text: "1"
                    size_hint_x: None
                    width: dp(48)
                    on_text: app.update_horas("viernes", self.text)

            MDTextField:
                id: counter_label
                text: "Total sesiones: 0"
                size_hint_y: None
                height: dp(100)
'''

class Calculadora(MDApp):
    def build(self):
        self.theme_cls.primary_palette = "Olive"
        self.start_date = None
        self.end_date = None
        self.festivos = []

        self.festivos_picker = MDDockedDatePicker(
            on_select_day=self.on_select_festivo
        )

        root = Builder.load_string(KV)
        root.ids.festivos_seleccionados.bind(text=lambda instance, value: self.on_festivos_text_changed(instance))

        return root

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.dias_seleccionados = {
            "lunes": False,
            "martes": False,
            "miercoles": False,
            "jueves": False,
            "viernes": False,
        }
        self.horas_por_dia = {
        "lunes": 1,
        "martes": 1,
        "miercoles": 1,
        "jueves": 1,
        "viernes": 1,
        "sabado": 1,
        "domingo": 1,
    }

    def update_horas(self, dia, horas):
        try:
            horas_int = int(horas)
            self.horas_por_dia[dia] = horas_int
            self.update_counter()
        except ValueError:
            pass

    def toggle_day(self, checkbox_id, active):
        self.dias_seleccionados[checkbox_id] = active
        self.update_counter()

    def get_weekday_name(self, date):
        weekday_names = {
            0: "lunes",
            1: "martes",
            2: "miercoles",
            3: "jueves",
            4: "viernes",
            5: "sabado",
            6: "domingo"  # Agregar esta línea
        }
        return weekday_names[date.weekday()]

    def update_counter(self):
        if self.start_date and self.end_date:
            dias_seleccionados = [dia for dia, seleccionado in self.dias_seleccionados.items() if seleccionado]

            if not dias_seleccionados:
                self.root.ids.counter_label.text = "Total sesiones: 0"
                return

            filtered_dates = [
                date for date in self.date_range(self.start_date, self.end_date)
                if self.get_weekday_name(date) in dias_seleccionados and date not in self.festivos
            ]
            
            dias_lectivos = sum(self.horas_por_dia[self.get_weekday_name(date)] for date in filtered_dates)

            self.root.ids.counter_label.text = f"Total sesiones:({', '.join(dias_seleccionados)}): {dias_lectivos}"
        else:
            self.root.ids.counter_label.text = "Total sesiones: 0"
                        
    def date_range(self, start_date, end_date):
        # Generar una lista de fechas desde 'start_date' hasta 'end_date'
        return [start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)]

    def on_select_month(self, instance_date_picker, number_month):
        # Aquí puedes agregar el código que desees ejecutar cuando se seleccione un mes
        pass
                
    def on_ok(self, instance_date_picker):
        dates = instance_date_picker.get_date()
        if dates:
            self.start_date, self.end_date = dates
            self.root.ids.field_start_end.text = f"{self.start_date.strftime('%d/%m/%Y')} - {self.end_date.strftime('%d/%m/%Y')}"
            self.update_counter()
            
    def on_select_start_end_date(self, instance, value):
        pass

    def on_edit(self, instance_date_picker):
        instance_date_picker.dismiss()
        Clock.schedule_once(self.show_date_picker, 0.2)

    def show_date_picker(self, instance):  # Elimina los argumentos focus y date_type
        def on_edit(*args):
            self.festivos_picker.dismiss()
            Clock.schedule_once(self.show_date_picker, 0.2)

        self.festivos_picker.bind(on_edit=on_edit)
        self.festivos_picker.bind(on_select_day=self.on_select_day)
        self.festivos_picker.bind(on_select_year=self.on_select_year)
        self.festivos_picker.bind(on_select_month=self.on_select_month)
        self.festivos_picker.bind(on_cancel=self.on_cancel)
        self.festivos_picker.bind(on_ok=partial(self.on_ok_festivo, value=None))
        self.festivos_picker.open()

    def on_ok_festivo(self, instance_date_picker, value):
        date_selected = instance_date_picker.get_date()
        if date_selected:
            self.festivos.append(date_selected[0])
            self.update_festivos_text()
            self.update_counter()

        instance_date_picker.bind(on_ok=self.on_ok)
        instance_date_picker.bind(on_select_month=self.on_select_month)

        def on_edit(*args):
            instance_date_picker.dismiss()
            Clock.schedule_once(self.show_modal_date_picker, 0.2)

                
    def on_select_festivo(self, instance, date):
        if date in self.festivos:
            self.festivos.remove(date)
        else:
            if date not in self.festivos:
                self.festivos.append(date)
        self.update_festivos_text()
        self.update_counter()

    def on_festivos_text_changed(self, instance):
        value = instance.text
        fechas_validas = []

        # Iterar sobre las fechas en el campo de texto
        for fecha_str in value.split(","):
            fecha_str = fecha_str.strip()
            if fecha_str:
                try:
                    fecha = datetime.strptime(fecha_str, "%Y-%m-%d").date()
                    fechas_validas.append(fecha)
                except ValueError:
                    # Ignorar fechas con formato incorrecto
                    pass

        # Actualizar la lista self.festivos con las fechas válidas
        self.festivos = fechas_validas

        # Actualizar el contador de días lectivos
        self.update_counter()

    def update_festivos_text(self):
        self.root.ids.festivos_seleccionados.text = ", ".join(str(date) for date in self.festivos)

    def on_select_day(self, instance_date_picker, number_day):
        date_selected = instance_date_picker.get_date()[0]
        self.festivos.append(date_selected)
        self.update_counter()
        self.root.ids.festivos_seleccionados.text = ", ".join(str(date) for date in self.festivos)

    def on_select_year(self, instance_date_picker, number_year):
        # Implementa aquí el código que desees ejecutar cuando se seleccione un año
        pass

    def on_cancel(self, instance_date_picker):
        # Implementa aquí el código que desees ejecutar cuando se cancele la selección de fecha
        instance_date_picker.dismiss()

    def on_edit_start_end(self, instance_date_picker):
        instance_date_picker.dismiss()

    def show_modal_date_picker(self, focus):
        if not focus:
            return

        modal_date_picker = MDModalInputDatePicker(mode="range")
        modal_date_picker.bind(on_success=self.on_select_start_end_date)
        modal_date_picker.bind(on_ok=self.on_ok)
        modal_date_picker.bind(on_cancel=self.on_cancel)
        modal_date_picker.open()

Calculadora().run()

代码与“briefcase dev”完美运行

当我尝试构建 android aab 文件时,我被卡住了。

我尝试过“公文包”和“buildozer”。而我却一事无成。

在我上次的尝试中,我遇到了这个错误:

Error: Could not find or load main class com.android.sdklib.tool.sdkmanager.SdkManagerCli
Caused by: java.lang.ClassNotFoundException: com.android.sdklib.tool.sdkmanager.SdkManagerCli
# Command failed: ['/Users/mario/.buildozer/android/platform/android-sdk/tools/bin/sdkmanager', '--sdk_root=/Users/mario/.buildozer/android/platform/android-sdk', 'platform-tools']
# ENVIRONMENT:
#     __CFBundleIdentifier = 'com.apple.Terminal'
#     TMPDIR = '/var/folders/9n/cy3cympn6dx_5x9lvs5bw30w0000gn/T/'
#     XPC_FLAGS = '0x0'
#     TERM = 'xterm-256color'
#     SSH_AUTH_SOCK = '/private/tmp/com.apple.launchd.2RsjG5Aghf/Listeners'
#     XPC_SERVICE_NAME = '0'
#     TERM_PROGRAM = 'Apple_Terminal'
#     TERM_PROGRAM_VERSION = '453'
#     TERM_SESSION_ID = '9CEBEB5D-E86D-4374-8A0E-CA1E708DE3D4'
#     SHELL = '/bin/zsh'
#     HOME = '/Users/mario'
#     LOGNAME = 'mario'
#     USER = 'mario'
#     PATH = '/Users/mario/.buildozer/android/platform/apache-ant-1.9.4/bin:/Users/mario/Calculadora/venv/bin:/Library/Frameworks/Python.framework/Versions/3.12/bin/python3/bin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.12/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/Users/mario/.cargo/bin:/Users/mario/Documents/Python/Proyecto/Calculadora/dist'
#     SHLVL = '1'
#     PWD = '/Users/mario/Calculadora'
#     OLDPWD = '/Users/mario'
#     HOMEBREW_PREFIX = '/opt/homebrew'
#     HOMEBREW_CELLAR = '/opt/homebrew/Cellar'
#     HOMEBREW_REPOSITORY = '/opt/homebrew'
#     MANPATH = '/opt/homebrew/share/man::'
#     INFOPATH = '/opt/homebrew/share/info:'
#     OPENAI_API_KEY = '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'
#     VIRTUAL_ENV = '/Users/mario/Calculadora/venv'
#     PS1 = '(venv) %n@%m %1~ %# '
#     LANG = 'es_ES.UTF-8'
#     _ = '/Users/mario/Calculadora/venv/bin/buildozer'
#     __CF_USER_TEXT_ENCODING = '0x1F5:0x0:0x8'
# 
# Buildozer failed to execute the last command
# The error might be hidden in the log above this error
# Please read the full log, and search for it before
# raising an issue with buildozer itself.
# In case of a bug report, please add a full log with log_level = 2

我尝试删除所有内容并重新安装。

我在 Windows 中尝试过相同的过程。

有虚拟环境但没有...

python macos kivymd
1个回答
0
投票

首先,确保在Windows上测试您的应用程序,以确保顺利运行,不会出现错误。然后,探索使用 Buildozer 作为构建工具,并参考其文档以获取指导。如果您只专注于 Android 测试,请首先创建一个带有 GUI 的简单应用程序,因为在不使用 GUI 的情况下尝试可能会导致大量错误,这些错误可能会令人难以承受。

© www.soinside.com 2019 - 2024. All rights reserved.