我是编程新手。我从来没有编码过,但在 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 中尝试过相同的过程。
有虚拟环境但没有...
首先,确保在Windows上测试您的应用程序,以确保顺利运行,不会出现错误。然后,探索使用 Buildozer 作为构建工具,并参考其文档以获取指导。如果您只专注于 Android 测试,请首先创建一个带有 GUI 的简单应用程序,因为在不使用 GUI 的情况下尝试可能会导致大量错误,这些错误可能会令人难以承受。