← Volver al listado de tecnologías

Empaquetado con Buildozer

Por: SiempreListo
kivybuildozerandroidiosempaquetado

¿Qué es Buildozer?

Herramienta que automatiza el empaquetado de apps Kivy para Android e iOS.

Instalación

pip install buildozer

# Dependencias Linux (Ubuntu/Debian)
sudo apt-get install -y \
    python3-pip \
    build-essential \
    git \
    python3 \
    python3-dev \
    ffmpeg \
    libsdl2-dev \
    libsdl2-image-dev \
    libsdl2-mixer-dev \
    libsdl2-ttf-dev \
    libportmidi-dev \
    libswscale-dev \
    libavformat-dev \
    libavcodec-dev \
    zlib1g-dev \
    libgstreamer1.0 \
    gstreamer1.0-plugins-base \
    gstreamer1.0-plugins-good \
    openjdk-17-jdk \
    autoconf \
    automake \
    libtool \
    pkg-config

Iniciar Proyecto

cd mi_proyecto
buildozer init

Esto crea buildozer.spec con la configuración.

Archivo buildozer.spec

Configuración Básica

[app]
# Nombre de la app
title = Mi App

# Nombre del paquete
package.name = miapp

# Dominio del paquete (inverso)
package.domain = org.ejemplo

# Código fuente
source.dir = .
source.include_exts = py,png,jpg,kv,atlas,json

# Versión
version = 1.0.0

# Requisitos
requirements = python3,kivy

# Orientación: portrait, landscape, all
orientation = portrait

# Pantalla completa
fullscreen = 0

Configuración Android

[app]
# Permisos Android
android.permissions = INTERNET,CAMERA,ACCESS_FINE_LOCATION

# API levels
android.minapi = 21
android.api = 33
android.ndk = 25b

# Arquitecturas
android.archs = arm64-v8a, armeabi-v7a

# Modo release o debug
# android.release_artifact = aab  # Para Play Store

Iconos y Splash

[app]
# Icono (512x512 recomendado)
icon.filename = %(source.dir)s/assets/icon.png

# Splash screen
presplash.filename = %(source.dir)s/assets/presplash.png

Comandos Buildozer

Compilar APK Debug

buildozer android debug

Compilar y Desplegar

buildozer android debug deploy run

Ver Logs

buildozer android logcat

Limpiar Build

buildozer android clean

APK Release

buildozer android release

AAB para Play Store

# En buildozer.spec:
# android.release_artifact = aab

buildozer android release

Estructura de Proyecto

mi_app/
├── main.py           # Punto de entrada (obligatorio)
├── buildozer.spec
├── assets/
│   ├── icon.png      # 512x512
│   ├── presplash.png # 512x512
│   ├── images/
│   └── fonts/
├── screens/
│   └── *.py
└── requirements.txt

Requirements Comunes

# Básico
requirements = python3,kivy

# Con KivyMD
requirements = python3,kivy,kivymd

# Con librerías adicionales
requirements = python3,kivy,pillow,requests,pyjnius

# Kivy Garden
requirements = python3,kivy,kivy_garden.mapview

Permisos Android

PermisoUso
INTERNETConexión a red
CAMERAAcceso a cámara
ACCESS_FINE_LOCATIONGPS preciso
ACCESS_COARSE_LOCATIONGPS aproximado
WRITE_EXTERNAL_STORAGEEscribir archivos
READ_EXTERNAL_STORAGELeer archivos
VIBRATEVibración
RECORD_AUDIOMicrófono
android.permissions = INTERNET,CAMERA,WRITE_EXTERNAL_STORAGE

Usar Docker

Evita problemas de dependencias usando Docker:

docker pull kivy/buildozer

docker run --interactive --tty --rm \
    --volume "$HOME/.buildozer":/home/user/.buildozer \
    --volume "$PWD":/home/user/hostcwd \
    kivy/buildozer android debug

GitHub Actions

# .github/workflows/build.yml
name: Build APK

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Build APK
      uses: ArtemSBulgakov/buildozer-action@v1
      with:
        command: buildozer android debug

    - name: Upload APK
      uses: actions/upload-artifact@v3
      with:
        name: apk
        path: bin/*.apk

Firmar APK Release

Crear Keystore

keytool -genkey -v \
    -keystore mi-keystore.jks \
    -keyalg RSA \
    -keysize 2048 \
    -validity 10000 \
    -alias mi-alias

Configurar en buildozer.spec

[app]
android.keystore = mi-keystore.jks
android.keyalias = mi-alias
# No incluir passwords en el spec, usar variables de entorno

Variables de Entorno

export P4A_RELEASE_KEYSTORE_PASSWD=tu_password
export P4A_RELEASE_KEYALIAS_PASSWD=tu_password

buildozer android release

Solución de Problemas

Error: SDK/NDK no encontrado

# Instalar automáticamente
buildozer android debug
# La primera vez descarga SDK/NDK

Error: Java version

# Usar Java 17
sudo update-alternatives --config java

Error: Recipe failed

# Limpiar y reconstruir
buildozer android clean
rm -rf .buildozer
buildozer android debug

Ver más detalles

buildozer -v android debug

Optimización de APK

[app]
# Solo arquitectura necesaria
android.archs = arm64-v8a

# Excluir archivos innecesarios
source.exclude_exts = spec,md,txt

# Excluir patrones
source.exclude_patterns = tests/*,docs/*,*.pyc

iOS con Kivy-iOS

# Solo en macOS
pip install kivy-ios

# Crear proyecto Xcode
toolchain create MiApp ~/mi_proyecto

# Compilar
toolchain build kivy

Recursos

RecursoURL
Buildozer Docshttps://buildozer.readthedocs.io/
Python-for-Androidhttps://python-for-android.readthedocs.io/
Kivy iOShttps://github.com/kivy/kivy-ios
GitHub Actionhttps://github.com/ArtemSBulgakov/buildozer-action

Testing de Configuración

# test_buildozer.py
import unittest
import os

class TestBuildozer(unittest.TestCase):
    def test_spec_existe(self):
        self.assertTrue(os.path.exists('buildozer.spec'))

    def test_main_existe(self):
        self.assertTrue(os.path.exists('main.py'))

    def test_spec_tiene_campos_requeridos(self):
        with open('buildozer.spec', 'r') as f:
            contenido = f.read()
        campos = ['title', 'package.name', 'package.domain', 'requirements']
        for campo in campos:
            self.assertIn(campo, contenido, f'Falta {campo}')

    def test_requirements_incluye_kivy(self):
        with open('buildozer.spec', 'r') as f:
            for linea in f:
                if linea.startswith('requirements'):
                    self.assertIn('kivy', linea.lower())
                    break

if __name__ == '__main__':
    unittest.main()

Probar en Dispositivo con ADB

# Instalar APK debug
adb install -r bin/*-debug.apk

# Ver información del APK instalado
adb shell dumpsys package com.ejemplo.miapp | head -50

# Verificar permisos solicitados
adb shell dumpsys package com.ejemplo.miapp | grep permission

# Limpiar datos de la app (útil para testing)
adb shell pm clear com.ejemplo.miapp

# Desinstalar app
adb uninstall com.ejemplo.miapp

# Ver tamaño de la app instalada
adb shell du -h /data/app/*/com.ejemplo.miapp*

Resumen