Pubblica App Links Android e prepara la release 2.0.7.

Serve assetlinks su edge/Rails, documenta overflow Hetzner e bumpa l'AAB a 28 con simboli nativi per Play.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-04 19:44:17 +02:00
co-authored by Cursor
parent a448ad59ee
commit d5ec266437
8 changed files with 497 additions and 2 deletions
@@ -0,0 +1,16 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "com.matchlivetv.match_live_tv",
"sha256_cert_fingerprints": [
"C3:F0:89:51:0B:00:3A:FE:10:BD:ED:68:45:1B:4F:1D:B8:5A:63:EE:8A:DA:F7:2F:5A:D6:1D:97:C9:A3:95:47",
"09:69:25:CD:8B:EC:BA:75:9A:5E:49:32:E1:35:BD:F1:AF:1E:5A:29:93:E2:65:85:8A:41:E2:11:DA:64:97:F0"
]
}
}
]
+41
View File
@@ -0,0 +1,41 @@
# Android App Links / Digital Asset Links
Play Console verifica `https://www.matchlivetv.it/.well-known/assetlinks.json`.
## File
- Servito da **edge** (nginx): `infra/nginx-edge/well-known/assetlinks.json`
- Specchio in Rails public: `backend/public/.well-known/assetlinks.json`
Package: `com.matchlivetv.match_live_tv`
Path App Links: `https://www.matchlivetv.it/join…` (`pathPrefix="/join"`)
Nel JSON ci sono:
1. SHA-256 del **upload key** (`native/android/keystore/matchlivetv-upload.jks`)
2. SHA-256 del certificato **App signing** di Play (da Play Console → Integrità dellapp)
Relazioni richieste da Play per la condivisione credenziali:
- `delegate_permission/common.handle_all_urls`
- `delegate_permission/common.get_login_creds`
Se Play rigenera il JSON, sostituisci `infra/nginx-edge/well-known/assetlinks.json` (e lo specchio in `backend/public/.well-known/`) e ricarica edge.
## Deploy edge (senza rebuild Rails)
Sul server:
```bash
cd /opt/matchlivetv/infra
# dopo git pull del repo
docker compose -f docker-compose.prod.yml --env-file .env up -d edge
curl -sS -D- https://www.matchlivetv.it/.well-known/assetlinks.json | head
```
Verifica Google:
```bash
curl -sS "https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://www.matchlivetv.it&relation=delegate_permission/common.handle_all_urls"
```
Poi in Play Console → Link diretti → ripeti i controlli dominio.
+2
View File
@@ -397,6 +397,8 @@ cd infra && cp .env.example .env && docker compose up -d --build
| Documento | Contenuto |
|-----------|-----------|
| [`infrastructure/SERVER_DEPLOYMENT.md`](infrastructure/SERVER_DEPLOYMENT.md) | Bootstrap server, NPM, cron, backup |
| [`infrastructure/HETZNER_CLOUD_RELAY_OVERFLOW.md`](infrastructure/HETZNER_CLOUD_RELAY_OVERFLOW.md) | Piano overflow relay YouTube su Hetzner Cloud (picchi) |
| [`ANDROID_APP_LINKS.md`](ANDROID_APP_LINKS.md) | Digital Asset Links / deep link Play (`assetlinks.json`) |
| [`LIVE_STREAMING.md`](LIVE_STREAMING.md) | MediaMTX, pausa, HLS, ruolo ffmpeg |
| [`REPLAY_MODULE.md`](REPLAY_MODULE.md) | Garage, retention, YouTube VOD |
| [`OPS_MONITORING.md`](OPS_MONITORING.md) | ntfy, variabili ops, troubleshooting |
@@ -0,0 +1,408 @@
# Piano: overflow relay YouTube su Hetzner Cloud
**Stato:** piano / design — non implementato
**Ultimo aggiornamento:** 2026-07-29
**Contesto:** produzione attuale su host dedicato (es. Proxmox/Hetzner) con MediaMTX + Sidekiq sullo stesso box; obiettivo >10 live YouTube contemporanee senza abbandonare il middle-tier.
Documenti correlati: [`LIVE_STREAMING.md`](../LIVE_STREAMING.md), [`ARCHITECTURE.md`](../ARCHITECTURE.md), [`OPS_MONITORING.md`](../OPS_MONITORING.md).
---
## 1. Scenario
### Problema di prodotto
Match Live TV disaccoppia il telefono da YouTube:
```text
Telefono (rete mobile instabile)
│ RTMP
MediaMTX (sempre attivo, slate / alwaysAvailable)
├── HLS → sito
└── YoutubeRelay (ffmpeg) → RTMPS YouTube
```
Se cade solo il tratto telefono→MediaMTX, YouTube resta in onda (slate).
Se il telefono andasse diretto a YouTube (o a un ingest cloud senza hold), la live pubblica cadrebbe con la rete mobile. Inoltre YouTube non è pensato come “Go Live dallapp mobile” senza vincoli di canale: noi usiamo API + RTMPS dal server.
### Problema di capacità
Ogni diretta `platform=youtube` avvia un processo `ffmpeg` in Sidekiq (`Streams::YoutubeRelay`: video **copy**, audio **AAC**).
Il carico scala con **N processi**, non con gli spettatori HLS.
Sul box attuale (~4 CPU / 8 GB, stack completo sullo stesso host):
| Live YT contemporanee | Situazione attesa |
|-----------------------|-------------------|
| 14 | Comodo |
| 58 | Teso (CPU/RAM, latenza job Sidekiq) |
| ≥10 | Rischioso (relay instabili, watchdog, slate prolungate su YT) |
**Obiettivo:** mantenere MediaMTX (e Rails) sul dedicated; quando N supera la soglia comoda, **accendere capacità Hetzner Cloud solo per i relay**, per il tempo del picco, poi spegnerla.
### Cosa NON è questo piano
- Non sostituisce MediaMTX con Mux/AWS MediaLive.
- Non sposta lingest RTMP del telefono sul cloud (cold start e sticky URL sono incompatibili con “zero nodi a riposo”).
- Non è autoscaling del monolite Docker Compose intero.
---
## 2. Principio di progettazione
| Componente | Dove resta | Perché |
|------------|------------|--------|
| MediaMTX (RTMP ingest + slate + HLS) | **Dedicated sempre acceso** | URL stabile per lapp; continuità YouTube via slate |
| Rails / Postgres / Redis / Garage / edge | **Dedicated** (o gestiti fissi) | Stato, auth, replay; non sono il collo di bottiglia video live |
| `YoutubeRelay` (ffmpeg) | **Dedicated fino a soglia + overflow Cloud** | Unico pezzo che moltiplica CPU con N live YT |
| Job Sidekiq non-video (mail, ops, post-process) | Dedicated (coda separata) | Non devono competere con ffmpeg sui worker overflow |
Formula mentale:
```text
capacità_yt ≈ core_dedicati_relay + Σ core_vm_overflow_calde
```
---
## 3. Architettura target (overflow)
```text
[ telefoni RTMP ]
┌─────────────────────────┐
│ Dedicated (sempre on) │
│ MediaMTX · Rails · DB │
│ Redis · Garage · edge │
│ Sidekiq "core" │
│ (+ pochi relay locali) │
└───────────┬─────────────┘
intake RTMP/HLS │ (rete privata / tunnel / IP allowlist)
┌───────────────┼───────────────┐
▼ ▼ ▼
[relay-local] [overflow-1] [overflow-N]
Sidekiq+ffmpeg Hetzner Cloud Hetzner Cloud
YOUTUBE_RELAY=1 a ore a ore
│ │ │
└───────────────┴───────────────┘
YouTube RTMPS
```
### Ruolo delle VM overflow
Immagine minimale (o Compose snello):
- Sidekiq con `YOUTUBE_RELAY_WORKER=1`
- `ffmpeg` disponibile
- Connessione a **Redis** del dedicated (coda + lock `youtube_relay:owner:*`)
- Lettura intake da MediaMTX (RTMP preferito, HLS fallback come oggi)
- **Niente** Postgres scrittura diretta obbligatoria se i job relay usano già Redis + API; in pratica oggi Rails/Sidekiq legge Postgres → le VM overflow devono raggiungere anche DB **oppure** si isola una coda “relay-only” con worker che riceve payload già risolto (vedi §5.2)
Stato attuale del codice: `YoutubeRelay` gira in processo Sidekiq Rails completo (accesso a `StreamSession`, MediaMTX client, Redis PID/owner). Le VM overflow sono quindi **worker Sidekiq Rails**, non demoni ffmpeg nudi — almeno nella fase 1.
---
## 4. Colli di bottiglia (cosa può rompersi comunque)
Anche con overflow infinito di CPU, restano limiti. Ordine di probabilità/impatto:
### 4.1 MediaMTX sul dedicated (alto)
- N publisher RTMP + N reader (HLS siti + N ffmpeg che rileggono lo stesso path).
- Ogni relay in più è un **reader** su MediaMTX (RTMP pull o HLS).
- Sintomi: path `ready` flaky, HLS a scatti sul sito, relay che rientrano in fallback HLS, CPU MediaMTX alta anche con relay scarichi.
**Mitigazione futura (fuori da questo overflow):** secondo nodo MediaMTX o sharding path; per ora monitorare `readers`, CPU `mediamtx`, bitrate aggregato.
### 4.2 Uplink Internet del dedicated (alto)
- Telefoni → dedicated (ingresso RTMP).
- Dedicated → YouTube **se** i relay restano locali.
- Con overflow Cloud: il dedicated manda **copia dello stream** verso le VM (pull dalle VM = traffico **uscita** dal dedicated verso Hetzner Cloud), poi le VM mandano a YouTube.
Attenzione al verso:
| Dove gira il relay | Traffico tipico |
|--------------------|-----------------|
| Sul dedicated | In: telefoni. Out: N× verso YouTube |
| Su Hetzner Cloud | Out dedicated → Cloud (intake). Out Cloud → YouTube |
Se luplink casa/datacenter verso Internet è stretto, spostare i relay sul Cloud **sposta** il carico out YouTube fuori dal dedicated, ma **aggiunge** out dedicated→Cloud (stesso ordine di grandezza del video).
Vantaggio reale solo se:
- luplink del dedicated satura soprattutto per **CPU** (oggi sì), oppure
- dedicated e Cloud sono in **stessa regione Hetzner con rete privata** (traffico interno economico/veloce) e luscita verso YouTube esce dalla rete Hetzner Cloud (migliore peering).
**Decisione di rete obbligatoria prima di implementare** (vedi §6).
### 4.3 Redis / lock owner (medio)
Oggi:
- `youtube_relay:pid:%s` — PID locale al worker
- `youtube_relay:owner:%s``HOSTNAME` del worker
- `running?` considera attivo un owner remoto se TTL > 30s
Con più worker:
- Due ensure concorrenti possono avviare due ffmpeg (debounce 5s aiuta poco cross-host).
- `stop` da Rails manda job: deve raggiungere il worker **owner**, non un overflow a caso.
- Kill del PID funziona solo sulla macchina owner (`/proc`).
Serve disciplina di coda / routing (§5.3).
### 4.4 Cold start VM (medio)
Creare una CPX/CCX Hetzner: ordine di **3090+ secondi** (API + boot + pull image + Sidekiq ready).
Se la 15ª live parte e non c’è capacità, la broadcast YouTube resta “in attesa” finché non c’è worker.
**Requisito prodotto:** overflow **a caldo** = pool minimo già acceso nei weekend / fasce note, non “da zero al fischio”.
### 4.5 YouTube / account / quote (bassomedio, esterno)
- Limiti API, token OAuth, ban temporanei, ingest RTMPS rifiutato.
- Non risolvibili con più CPU; restano nel runbook ops esistente.
### 4.6 Post-process replay (basso in live, alto a fine giornata)
`UploadFromSession` / thumbnail competono su Sidekiq e disco.
I worker overflow **non** devono prendere coda `default` di merge se sono pensati solo per relay — altrimenti spegnendo le VM a fine picco uccidete job a metà.
### 4.7 Costo e idle (operativo)
VM dimenticate accese = bolletta. Serve TTL, scale-in aggressivo, alert “overflow acceso da >Xh con 0 relay”.
---
## 5. Complessità di implementazione
### 5.1 Rete: come le VM leggono MediaMTX
Opzioni (sceglierne **una** in fase 0):
| Opzione | Pro | Contro |
|---------|-----|--------|
| **A. Stessa location Hetzner + private network** (dedicated Robot + Cloud nella stessa rete) | Bassa latenza, traffico interno, modello pulito | Richiede che il dedicated sia (o diventi) in ecosistema Hetzner collegabile |
| **B. WireGuard/Tailscale** dedicated ↔ Cloud | Funziona anche da Proxmox casa | Ops tunnel, MTU, failover; latenza |
| **C. Esporre RTMP/HLS intake in lettura** (IP allowlist VM overflow) | Semplice | Superficie attacco; non esporre senza auth/TLS dove possibile |
| **D. Relay locale che pusha a Cloud** | Dedicated controlla egress | Doppia hop, più pezzi |
Raccomandazione di piano: **A se il dedicated è/andrà su Hetzner; altrimenti B**. Evitare C in chiaro su WAN.
Variabili da prevedere sulle VM:
- `MEDIAMTX_INTERNAL_RTMP_URL` → URL raggiungibile dalle VM (non `rtmp://mediamtx:1935` Docker-locale)
- `MEDIAMTX_HLS_URL` → idem
- MediaMTX API (`:9997`) raggiungibile in privato per `intake_available?` / PublisherOnline, **mai** su Internet aperto
### 5.2 Accesso Postgres e segreti
Worker Sidekiq Rails oggi necessitano:
- `DATABASE_URL` (o replica read + job che non scrivono — irrealistico allinizio)
- `REDIS_URL`
- `SECRET_KEY_BASE` / credenziali YouTube via DB
- stessi env di produzione (ridotti)
Complessità: ogni overflow è un **nodo fidato** della rete app.
Immagine Docker identica a `sidekiq` prod, env da secret manager o file scp/cloud-init, **nessuna** porta Rails pubblica sulle VM.
### 5.3 Code Sidekiq e affinità relay
Stato oggi: ensure/stop via job + processo locale con owner in Redis.
Per multi-host serve esplicitare:
1. **Coda dedicata** `youtube_relay` (solo worker con `YOUTUBE_RELAY_WORKER=1`).
2. **Cap locale**: ogni worker ha `RELAY_MAX_CONCURRENT` (es. cores1).
3. **Scheduling**:
- Fase 1 (manuale): overflow sempre in ascolto sulla coda; Sidekiq distribuisce i job; `ensure_on_worker!` no-op se a cap (re-enqueue o lascia ad altro worker).
- Fase 2: controller di capacità che alza/abbassa N VM in base a `relay_attivi` e profondità coda.
4. **Stop**: job `YoutubeRelayStopJob` deve eseguire **solo sullowner** (Sidekiq unique + check `owner == HOSTNAME`, altrimenti requeue con delay breve).
Nota: i PID in Redis non sono globalmente killabili — il modello owner è già abbozzato; va reso robusto cross-host.
### 5.4 Scale-out / scale-in (lifecycle VM)
```text
Metriche → Decisione → hcloud CLI/API → cloud-init → Sidekiq ready → in coda
↘ fallisce → alert ops, non spegnere dedicated
```
**Scale-out trigger (esempi):**
- `youtube_relay` depth > 0 per >60s **oppure**
- `relay_attivi_local >= RELAY_SOFT_CAP` **e** nuove sessioni YT in `connecting|live`
**Scale-in trigger:**
- `relay_attivi` sulle VM overflow = 0 per >1530 min **e**
- fuori dalla finestra “weekend caldo” (opzionale)
**Warm pool:** sabato 8:00 → min 12 VM già up; domenica 23:00 → min 0.
### 5.5 Idempotenza e split-brain
Scenario da evitare: dedicated e overflow avviano entrambi ffmpeg sulla stessa `stream_key` → YouTube flappa.
Mitigazioni:
- Lock Redis con fencing token / TTL heartbeat rinnovato dal processo owner ogni N secondi
- Watchdog (`YoutubeIngestWatchdogJob`) deve rispettare owner remoto (già parzialmente così via TTL)
- Un solo writer della broadcast activate
### 5.6 Observability
Senza metriche loverflow è cieco. Minimo:
| Metrica | Dove |
|---------|------|
| N relay ffmpeg vivi (local / per host) | Redis + `pgrep` / heartbeat |
| CPU MediaMTX, CPU Sidekiq | node exporter / docker stats |
| Profondità coda `youtube_relay` | Sidekiq API |
| Bitrate / errori ffmpeg per session | log già in `log/youtube_relay_*.log` |
| VM overflow accese, € stimati | tag Hetzner + cron report |
| Latenza intake Cloud (RTT dedicated↔VM) | check periodico |
Alert ntfy esistenti: estendere con `relay_overflow_saturated`, `mediamtx_cpu_high`, `overflow_vm_orphan`.
### 5.7 Sicurezza
- Firewall: VM → solo Redis, Postgres, MediaMTX (porte interne), YouTube egress 443
- Nessun SSH password; chiave o console Hetzner
- Stream key YouTube solo in DB/encrypted; non in user-data in chiaro se evitabile
- Image aggiornata; spegnimento = destroy, non “pausare” dischi dimenticati per mesi
---
## 6. Decisioni aperte (bloccare prima del codice)
| # | Domanda | Impatto |
|---|---------|---------|
| D1 | Dedicated resta su LAN casa/Proxmox o migra/affianca Hetzner Robot? | Sceglie rete A vs B (§5.1) |
| D2 | Soft cap relay sul dedicated (es. 4? 6?) | Quando scatta overflow |
| D3 | Warm pool fisso weekend vs solo reactive | Cold start vs costo |
| D4 | Tipo VM (CPX shared vs CCX dedicated CPU) | €/live e jitter AAC |
| D5 | Stessa immagine `sidekiq` vs worker slim | Tempo boot e superficie |
| D6 | Chi orchestra le VM? (script cron su dedicated, Terraform, small Go/Ruby service) | Ops ownership |
Finché D1 non è chiusa, non stimare bandwitdh né SLA del picco.
---
## 7. Dimensionamento indicativo
Ipotesi: 720p, video copy, AAC mono — **~0.30.7 vCPU** medi per relay (picchi più alti su analyze/reconnect).
| Target live YT | Dedicated (relay) | Overflow tipico | Note |
|----------------|-------------------|-----------------|------|
| ≤6 | Tutto locale | 0 | Situazione attuale “comoda” se box dedicato ai relay |
| 1015 | soft cap 46 | 1× VM 48 vCPU | Warm consigliato in giornata evento |
| 2030 | soft cap 46 | 24× VM | MediaMTX e uplink diventano critici |
| 50+ | softire anche ingest | N VM + 2° MediaMTX | Fuori scope overflow-only |
Questi numeri vanno **calibati** con un load test (N sessioni fake + ffmpeg contro slate MediaMTX) prima di promettere SLA commerciali.
---
## 8. Piano a fasi (pronti a reagire, non a over-build)
### Fase 0 — Misura e soglie (12 giorni ops)
- [ ] Dashboard/manuale: N live YT, CPU `sidekiq`, CPU `mediamtx`, uplink
- [ ] Definire `RELAY_SOFT_CAP` empirico sul dedicated
- [ ] Chiudere **D1** (rete)
- [ ] Load test controllato: 812 relay solo slate (senza telefoni) per vedere dove rompe
**Criterio go/no-go overflow:** saturazione CPU Sidekiq/ffmpeg **prima** di MediaMTX/uplink. Se saturano prima rete o MediaMTX, overflow Cloud non basta.
### Fase 1 — Overflow manuale “a caldo” (MVP ops)
- [ ] Snapshot/immagine Sidekiq relay-ready su Hetzner Cloud
- [ ] cloud-init: env, WireGuard o private net, `docker compose up sidekiq`
- [ ] Runbook: “accendi 1 VM”, verifica `YoutubeRelay` su HOSTNAME nuovo, “spegni”
- [ ] Soft cap sul dedicated: nuovi ensure preferiscono coda se locali pieni (anche patch minima)
- [ ] Alert se VM overflow up da >3h con 0 owner keys
**Reazione a incident:** operatore umano accende/spegne; nessun autoscaler ancora.
### Fase 2 — Routing coda robusto
- [ ] Coda `youtube_relay` isolata
- [ ] Heartbeat owner Redis
- [ ] Stop/ensure sticky allowner
- [ ] Cap per worker + requeue
### Fase 3 — Autoscaling controllato
- [ ] Job/cron: se saturazione → `hcloud server create` fino a `OVERFLOW_MAX`
- [ ] Scale-in solo se idle e fuori warm window
- [ ] Budget mensile + kill switch
### Fase 4 — Solo se necessario
- Secondo MediaMTX / sharding
- Audio copy se lencoder telefono è già YouTube-compatibile (meno CPU)
- Dedicated più grosso come baseline (spesso più economico delloverflow cronico ogni weekend)
---
## 9. Runbook di reazione (anche prima dellautoscaler)
### Sintomo: YouTube “in programma” / niente video con molte live
1. `docker stats` / CPU Sidekiq sul dedicated
2. Contare relay: log `[YoutubeRelay] started` vs sessioni `platform=youtube` live
3. Se CPU ~100% e MediaMTX ok → **accendere overflow** (Fase 1) o abbassare nuove live YT
4. Se MediaMTX alto / path non ready → overflow **non** aiuta; ridurre reader o spostare HLS, non aggiungere pull Cloud ciechi
### Sintomo: live YT che si spezza solo sulle VM Cloud
1. RTT e packet loss dedicated↔VM
2. Verificare che intake usi RTMP interno, non HLS pubblico via Internet
3. Controllare doppio owner / due ffmpeg sulla stessa key
### Sintomo: bolletta Cloud anomala
1. Lista server con label `matchlivetv-overflow`
2. Destroy idle
3. Abbassare warm pool
### Sintomo: job replay morti dopo scale-in
1. Verificare che overflow **non** consumi coda `default` / `recordings`
2. Riprocessare dead set Sidekiq
---
## 10. Criteri di successo
| Criterio | Misura |
|----------|--------|
| Picco gestito | ≥15 live YT contemporanee stabili in test |
| Continuità prodotto | Drop telefono → slate YouTube ancora attiva (invariato) |
| Costo | Overflow acceso solo in finestre picco; €/h documentato |
| Ops | Runbook Fase 1 eseguibile in &lt;10 min da operatore |
| Non regressione | Live solo-sito (`matchlivetv`) e replay invariati |
---
## 11. Riepilogo esecutivo
Il pezzo che manca oltre ~10 live YouTube è **CPU dei relay**, non lidea MediaMTX.
Hetzner Cloud è la leva economica giusta se:
1. scalate **solo** i worker `YoutubeRelay`,
2. tenete MediaMTX caldo sul dedicated,
3. risolvete **rete privata** dedicated↔Cloud,
4. partite da **warm pool + runbook manuale**, poi automate.
Il rischio principale non è “creare una VM”, è **leggere N volte MediaMTX e saturare uplink/MediaMTX** mentre pensate di aver risolto solo la CPU. La Fase 0 (misura) decide se loverflow è sufficiente o se serve anche più ingest/baseline hardware.
)
+1
View File
@@ -150,6 +150,7 @@ services:
volumes:
- ./nginx-edge/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx-edge/maintenance.html:/usr/share/nginx/maintenance/index.html:ro
- ./nginx-edge/well-known:/usr/share/nginx/well-known:ro
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:80/edge-health"]
interval: 15s
+7
View File
@@ -98,6 +98,13 @@ http {
return 200 "ok\n";
}
# Android App Links (Play Console / Digital Asset Links)
location = /.well-known/assetlinks.json {
default_type application/json;
add_header Cache-Control "public, max-age=300";
alias /usr/share/nginx/well-known/assetlinks.json;
}
# Health check ops: pass-through senza pagina di cortesia.
location = /up {
proxy_pass http://$rails_backend;
@@ -0,0 +1,16 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls",
"delegate_permission/common.get_login_creds"
],
"target": {
"namespace": "android_app",
"package_name": "com.matchlivetv.match_live_tv",
"sha256_cert_fingerprints": [
"C3:F0:89:51:0B:00:3A:FE:10:BD:ED:68:45:1B:4F:1D:B8:5A:63:EE:8A:DA:F7:2F:5A:D6:1D:97:C9:A3:95:47",
"09:69:25:CD:8B:EC:BA:75:9A:5E:49:32:E1:35:BD:F1:AF:1E:5A:29:93:E2:65:85:8A:41:E2:11:DA:64:97:F0"
]
}
}
]
+6 -2
View File
@@ -20,8 +20,8 @@ android {
applicationId = "com.matchlivetv.match_live_tv"
minSdk = 24
targetSdk = 36
versionCode = 27
versionName = "2.0.6-native"
versionCode = 28
versionName = "2.0.7-native"
val apiBaseUrl = project.findProperty("API_BASE_URL") as String?
?: "https://www.matchlivetv.it"
@@ -47,6 +47,10 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
// Simboli .so per crash/ANR su Play Console (evita l'avviso "native code senza debug symbols")
ndk {
debugSymbolLevel = "SYMBOL_TABLE"
}
signingConfig = if (keystorePropertiesFile.exists()) {
signingConfigs.getByName("release")
} else {