GitDroidStore es una mini-store Android que descarga un único catálogo estático, obtiene los APK desde GitHub Releases, verifica su integridad y firma digital y solicita su instalación mediante PackageInstaller.Session.
Repositorio oficial: CctrGy/GitDroidStore. El maker configurado de forma predeterminada es CctrGy.
Para que GitDroidStore reconozca un repositorio como una aplicación instalable debe cumplir todos estos requisitos:
- El repositorio de GitHub debe ser público.
- Debe tener al menos una GitHub Release publicada.
- La última Release debe contener un asset llamado exactamente
app.apk. - El asset debe estar completamente subido y tener estado
uploaded. app.apkdebe ser un APK Android válido y estar firmado digitalmente.- La raíz de la rama predeterminada debe contener un
version.jsonválido para permitir una primera instalación segura. - El certificado real del APK debe coincidir con
certificateSha256. - Si se declaran
packageNameosha256, también deben coincidir con el APK publicado.
Los borradores y las prereleases no se consideran la última versión porque el generador del catálogo consulta:
GET https://api.github.com/repos/<usuario>/<repositorio>/releases/latest
La aplicación Android no recorre repositorios ni consulta la API de GitHub. En cada actualización realiza una sola descarga pública:
https://raw.githubusercontent.com/CctrGy/GitDroidStore/main/catalog.json
catalog.json reúne todas las aplicaciones reconocidas, sus versiones, iconos, hashes y enlaces app.apk. El propietario configurado en Ajustes permite usar también un fork compatible; por ejemplo, el propietario otro-maker apunta a:
https://raw.githubusercontent.com/otro-maker/GitDroidStore/main/catalog.json
El archivo tiene el esquema schemaVersion: 1. Cada entrada incluye, entre otros campos, owner, repo, displayName, description, packageName, versionName, versionCode, sha256, certificateSha256, apkUrl, iconUrl y remoteSha. GitDroidStore valida que los APK pertenezcan a GitHub Releases y que los iconos procedan de raw.githubusercontent.com antes de utilizarlos.
El workflow .github/workflows/update-catalog.yml ejecuta scripts/generate_catalog.py con el GITHUB_TOKEN interno de GitHub Actions. Por tanto, las consultas de descubrimiento se hacen centralmente y los móviles nunca consumen el límite público de la API.
El catálogo se regenera:
- al publicar, editar o eliminar una Release de
GitDroidStore; - cada seis horas, para descubrir Releases nuevas en el resto de repositorios de
CctrGy; - manualmente desde la pestaña Actions;
- al recibir un evento
repository_dispatchde tipocatalog-update.
El generador conserva generatedAt cuando las aplicaciones no han cambiado, por lo que la Action no crea commits vacíos. Para actualizar el catálogo inmediatamente después de publicar en otro repositorio, ejecuta manualmente la Action o envía repository_dispatch; de lo contrario, aparecerá en la siguiente comprobación programada.
El catálogo debe permanecer público. Ni descargar catalog.json ni descargar un app.apk de una Release pública requiere token o acreditación.
Los metadatos se guardan en la raíz del repositorio; el APK no se guarda en Git:
MiAplicacion/
├── version.json obligatorio para la primera instalación
├── icon.png opcional
├── appname.txt opcional
└── código fuente opcional para GitDroidStore
Cada versión del APK se adjunta a una Release:
Releases
├── v1.0.0
│ └── app.apk
├── v1.1.0
│ └── app.apk
└── v2.0.0
└── app.apk
El nombre app.apk distingue mayúsculas y minúsculas. Nombres como App.apk, mi-app.apk o app-release.apk no serán reconocidos.
Ejemplo completo:
{
"packageName": "com.example.myapp",
"versionName": "1.2.0",
"versionCode": 12,
"sha256": "93d709f7c42b0c2f0f0b62103bfeeb51f92d36c9dc89bf66da07f67cb46f24f7",
"certificateSha256": "f4ca57320b90ab1d0121d2db5fa3f8a177da3f091bf396bf55666559a782f1b7"
}- Recomendado.
- Debe ser el
applicationIdreal incluido dentro del APK. - Ejemplo:
com.example.myapp. - Si se declara y no coincide con el APK descargado, la instalación se bloquea.
- No debe cambiar entre actualizaciones. Cambiarlo crea una aplicación Android diferente.
- Recomendado para mostrar una versión amigable, como
1.2.0. - Si se omite, GitDroidStore utiliza el tag de la Release y elimina un prefijo
vminúsculo. Por ejemplo,v1.2.0se muestra como1.2.0. - Es informativo; Android decide las actualizaciones utilizando
versionCode.
- Recomendado para detectar actualizaciones antes de descargar el APK.
- Debe ser un número entero positivo.
- Debe coincidir con el
versionCodeusado al compilar el APK. - Cada actualización debe utilizar un número superior al anterior:
1,2,3, etc. - GitDroidStore bloquea un APK cuyo
versionCodereal sea inferior al de la aplicación instalada.
- Opcional cuando GitHub proporciona el campo
digestdel asset de la Release. - Es el SHA-256 del archivo
app.apkcompleto, no el del certificado. - Debe escribirse en hexadecimal; se aceptan mayúsculas, minúsculas y separadores
:. - Si GitHub proporciona un digest y
version.jsondeclara otro diferente, el repositorio se descarta. - Tras descargar, GitDroidStore vuelve a calcular el SHA-256 y bloquea el archivo si no coincide.
En PowerShell puede calcularse con:
(Get-FileHash .\app.apk -Algorithm SHA256).Hash.ToLowerInvariant()En Linux o macOS:
sha256sum app.apk- Obligatorio para la primera instalación.
- Es el SHA-256 del certificado con el que se firmó el APK; no es el hash del archivo APK.
- Actúa como ancla de confianza: evita que alguien que controle el repositorio sustituya la aplicación por otro APK firmado con una clave distinta.
- Todas las actualizaciones deben conservar la misma clave de firma.
- GitDroidStore compara este valor con el certificado real del APK y, cuando la aplicación ya está instalada, también con el certificado de la versión instalada.
- Actualmente GitDroidStore no admite rotación de claves. No cambies el keystore sin implementar antes una política de migración.
Puede obtenerse con apksigner, incluido en Android SDK Build Tools:
apksigner verify --print-certs app.apkBusca una línea semejante a:
Signer #1 certificate SHA-256 digest: f4ca57320b90ab1d0121d2db5fa3f8a177da3f091bf396bf55666559a782f1b7
También puede consultarse directamente desde el keystore:
keytool -list -v -keystore mi-clave.jks -alias mi-aliasNo publiques el archivo .jks, .keystore, sus contraseñas ni ninguna clave privada. Solo se publica la huella SHA-256 del certificado.
Contiene únicamente el nombre amigable de la aplicación:
Mi Aplicación
GitDroidStore utiliza como máximo los primeros 100 caracteres. Si el archivo falta o está vacío, usa el nombre del repositorio.
Es la imagen que GitDroidStore muestra en la tarjeta de la aplicación dentro de la pantalla Inicio. Este icono es independiente del asset app.apk: GitDroidStore no descarga el APK ni extrae automáticamente su launcher icon para construir el catálogo.
Coloca una imagen cuadrada llamada exactamente icon.png en la raíz de la rama predeterminada:
MiAplicacion/
├── icon.png
├── version.json
├── appname.txt
└── resto del proyecto
Configuración recomendada:
- Nombre exacto:
icon.png. - Ubicación: raíz de la rama predeterminada, normalmente
main. - Formato recomendado: PNG.
- Proporción: cuadrada,
1:1. - Resolución recomendada:
512×512o1024×1024píxeles. - Resolución máxima admitida:
2048×2048píxeles. - Tamaño máximo del archivo: 2 MB.
- Mantén el símbolo principal centrado y con margen, porque la interfaz recorta la imagen con esquinas redondeadas.
- El archivo debe ser público y descargable desde
raw.githubusercontent.commediante HTTPS.
Ejemplo de URL que GitDroidStore obtiene automáticamente:
https://raw.githubusercontent.com/<usuario>/<repositorio>/main/icon.png
No es necesario añadir la URL a version.json.
GitDroidStore puede decodificar:
.png.webp.jpg.jpeg
No admite como icono de catálogo:
- SVG.
- XML de Android, incluidos adaptive icons como
ic_launcher.xml. - ICO.
- GIF animado.
- Imágenes guardadas únicamente como assets de una GitHub Release.
- URLs de servidores externos que no sean
raw.githubusercontent.com.
Si no existe /icon.png, el generador del catálogo inspecciona el árbol completo del repositorio y puntúa los candidatos por este orden:
ic_launcher.pngoic_launcher.webp.icon.pngoicon.webpen otra carpeta.- Nombres que contengan
app-iconodeveloper-icon. - Nombres que contengan
launcher. - Otros nombres que contengan
icon.
Por ejemplo, estas ubicaciones pueden reconocerse automáticamente:
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
docs/play-store-assets/developer-icon-512.png
assets/app-icon.webp
La búsqueda alternativa es una comodidad, no una garantía: si existen varias imágenes candidatas con la misma prioridad, GitDroidStore puede no elegir la deseada. Para obtener un resultado determinista utiliza siempre /icon.png.
- La tarjeta muestra la imagen a
56 dpcon recorteContentScale.Cropy esquinas redondeadas. - Antes de decodificarla se comprueba el tamaño declarado y también el número real de bytes descargados.
- Después se comprueba que ancho y alto estén entre 1 y 2048 píxeles.
- Si la descarga falla, el formato no puede decodificarse o se excede algún límite, se muestra el icono Android genérico.
- Para ver un icono recién añadido o sustituido, pulsa Actualizar en la pantalla Inicio.
El proyecto Android debe configurar además su propio launcher icon en AndroidManifest.xml, pero eso no sustituye a icon.png para GitDroidStore:
<application
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round" />Puedes exportar la misma imagen visual tanto a los recursos mipmap-* de Android como a /icon.png, pero cada ubicación cumple una función diferente:
android:icon: icono mostrado por el launcher del teléfono después de instalar la app./icon.png: icono mostrado por GitDroidStore antes de descargar o instalar el APK.
Lista de comprobación:
- Existe
/icon.pngen la rama predeterminada. - Es un PNG cuadrado y válido.
- No supera 2 MB.
- No supera 2048×2048 píxeles.
- El contenido importante tiene margen alrededor.
- La URL pública de GitHub responde correctamente.
- Se ha pulsado Actualizar en GitDroidStore después de publicarlo.
- Compila el APK en modo release.
- Firma el APK con el keystore permanente de esa aplicación.
- Comprueba el APK con
apksigner verify --print-certs app.apk. - Calcula su SHA-256.
- Actualiza
version.jsonen la rama predeterminada. - Crea un tag, por ejemplo
v1.2.0. - Crea una GitHub Release para ese tag.
- Adjunta el APK con el nombre exacto
app.apk. - Publica la Release; no la dejes como borrador ni prerelease.
No reemplaces silenciosamente el APK de una Release antigua. Publica una Release nueva para conservar un historial verificable.
GitDroidStore ejecuta estas comprobaciones:
Repositorio público
↓
Última Release publicada
↓
Asset app.apk en estado uploaded
↓
URL HTTPS oficial de GitHub Releases
↓
Descarga y cálculo SHA-256
↓
APK Android válido y firmado
↓
packageName coincide, si fue declarado
↓
SHA-256 coincide con GitHub/version.json
↓
certificateSha256 coincide con el APK
↓
Certificado coincide con la app instalada
↓
versionCode no es inferior al instalado
↓
PackageInstaller.Session
El APK temporal se elimina si cualquiera de estas comprobaciones falla.
- El repositorio es privado.
- No existe ninguna Release publicada.
- Solo existen borradores o prereleases.
- La última Release no contiene
app.apk. - El asset tiene otro nombre o todavía no está completamente subido.
- La URL del asset no pertenece a GitHub Releases.
- El SHA-256 de
version.jsoncontradice al digest proporcionado por GitHub. - El catálogo todavía no se ha regenerado después de publicar la Release.
- El archivo descargado no es un APK válido.
- El APK no está firmado.
- Falta
certificateSha256durante la primera instalación. - El certificado real no coincide con
certificateSha256. - La firma no coincide con la aplicación instalada.
- El SHA-256 calculado no coincide con el esperado.
- El
packageNamedeclarado no coincide con el APK. - Se intenta instalar un
versionCodeinferior al instalado. - Android o la política del dispositivo bloquean la instalación.
GitDroidStore utiliza exactamente el mismo sistema para actualizarse. El repositorio CctrGy/GitDroidStore debe publicar su APK firmado como app.apk en una Release y mantener version.json en la raíz. Todas las versiones deben conservar la misma clave de firma y el package name com.gitdroidstore.
El permiso REQUEST_INSTALL_PACKAGES permite que el usuario autorice GitDroidStore como origen de instalación. No concede instalación silenciosa a una aplicación convencional. Android puede devolver STATUS_PENDING_USER_ACTION y exigir una confirmación del sistema.
La instalación completamente silenciosa solo está disponible normalmente para un device owner, un profile owner afiliado o una aplicación privilegiada del sistema.
Requisitos para compilar este proyecto:
- JDK 17.
- Gradle 9.5 o posterior compatible.
- Android Gradle Plugin 9.3.
- Android SDK Platform 37.
- Android SDK Build Tools 36.0.0.
- Android 8.0 (API 26) como versión mínima del dispositivo.
La aplicación móvil no solicita ningún token de GitHub. La generación central utiliza únicamente el GITHUB_TOKEN efímero proporcionado por GitHub Actions.