Google Play richiede che l'APK compresso scaricato dagli utenti non superi i 100 MB. Per la maggior parte delle app, questo spazio è sufficiente per tutto il codice e gli asset dell'app. Tuttavia, alcune app richiedono più spazio per grafica ad alta fedeltà, file multimediali o altre risorse di grandi dimensioni. In precedenza, se le dimensioni compresse del download dell'app superavano i 100 MB, dovevi ospitare e scaricare le risorse aggiuntive autonomamente quando l'utente apriva l'app. L'hosting e la pubblicazione dei file aggiuntivi possono essere costosi e l'esperienza utente spesso non è ideale. Per semplificare questo processo e renderlo più piacevole per gli utenti, Google Play ti consente di allegare due file di espansione di grandi dimensioni che integrano l'APK.
Google Play ospita i file di espansione della tua app e li pubblica sul dispositivo senza costi per te. I file di espansione vengono salvati nell'archivio condiviso del dispositivo (la scheda SD o la partizione montabile USB, nota anche come archivio "esterno") a cui l'app può accedere. Sulla maggior parte dei dispositivi, Google Play scarica i file di espansione contemporaneamente all'APK, in modo che l'app abbia tutto ciò di cui ha bisogno quando l'utente la apre per la prima volta. In alcuni casi, tuttavia, l'app deve scaricare i file da Google Play all'avvio.
Se vuoi evitare di utilizzare i file di espansione e le dimensioni compresse del download dell'app sono superiori a 100 MB, devi caricare l'app utilizzando Android App Bundles, che consente dimensioni compresse del download fino a 500 MB. Inoltre, poiché l'utilizzo degli app bundle rimanda la generazione e la firma degli APK a Google Play, gli utenti scaricano APK ottimizzati con solo il codice e le risorse necessari per eseguire l'app. Non devi creare, firmare e gestire più APK o file di espansione e gli utenti ottengono download più piccoli e ottimizzati.
Panoramica
Ogni volta che carichi un APK utilizzando Google Play Console, hai la possibilità di aggiungere uno o due file di espansione all'APK. Ogni file può avere dimensioni massime pari a 2 GB e può essere in qualsiasi formato tu scelga, ma ti consigliamo di utilizzare un file compresso per risparmiare larghezza di banda durante il download. A livello concettuale, ogni file di espansione svolge un ruolo diverso:
- Il file di espansione principale è il file di espansione principale per le risorse aggiuntive richieste dalla tua app.
- Il file di espansione patch è facoltativo e destinato a piccoli aggiornamenti del file di espansione principale.
Anche se puoi utilizzare i due file di espansione nel modo che preferisci, ti consigliamo di utilizzare il file di espansione principale per distribuire le risorse principali e di aggiornarlo raramente, se non mai. Il file di espansione patch deve essere più piccolo e fungere da "vettore di patch", venendo aggiornato a ogni release principale o in base alle necessità.
Tuttavia, anche se l'aggiornamento dell'app richiede solo un nuovo file di espansione patch, devi comunque
caricare un nuovo APK con un versionCode aggiornato nel manifest. (Play Console non consente di caricare un file di espansione in un APK esistente.)
Nota: il file di espansione patch è semanticamente uguale al file di espansione principale. Puoi utilizzare ogni file nel modo che preferisci.
Formato del nome file
Ogni file di espansione che carichi può essere in qualsiasi formato tu scelga (ZIP, PDF, MP4 e così via). Puoi anche utilizzare lo strumento JOBB per incapsulare e criptare un insieme di file di risorse e le patch successive per quell'insieme. Indipendentemente dal tipo di file, Google Play li considera blob binari opachi e rinomina i file utilizzando il seguente schema:
[main|patch].<expansion-version>.<package-name>.obb
Questo schema è composto da tre componenti:
mainopatch- Specifica se il file è il file di espansione principale o patch. Può esserci un solo file principale e un solo file patch per ogni APK.
<expansion-version>- Si tratta di un numero intero che corrisponde al codice di versione dell'APK a cui l'espansione è
associata per la prima volta (corrisponde al valore
android:versionCodedell'app).L'aggettivo"primo" è enfatizzato perché, sebbene Play Console ti consenta di riutilizzare un file di espansione caricato con un nuovo APK, il nome del file di espansione non cambia: mantiene la versione applicata al momento del primo caricamento.
<package-name>- Il nome del pacchetto in stile Java della tua app.
Ad esempio, supponiamo che la versione dell'APK sia 314159 e il nome del pacchetto sia com.example.app. Se carichi un file di espansione principale, il file viene rinominato in:
main.314159.com.example.app.obb
Località di archiviazione
Quando Google Play scarica i file di espansione su un dispositivo, li salva nella posizione di archiviazione condivisa del sistema. Per garantire il corretto funzionamento, non devi eliminare, spostare o rinominare i file di espansione. Nel caso in cui l'app debba eseguire il download da Google Play, devi salvare i file nella stessa posizione.
Il metodo getObbDir() restituisce la posizione specifica
dei file di espansione nel seguente formato:
<shared-storage>/Android/obb/<package-name>/
<shared-storage>è il percorso allo spazio di archiviazione condiviso, disponibile dagetExternalStorageDirectory().<package-name>è il nome del pacchetto in stile Java della tua app, disponibile sugetPackageName().
Per ogni app, in questa directory non sono mai presenti più di due file di espansione.
Uno è il file di espansione principale e l'altro è il file di espansione patch (se necessario). Le versioni
precedenti vengono sovrascritte quando aggiorni l'app con nuovi file di espansione. A partire da Android
4.4 (livello API 19), le app possono leggere i file di espansione OBB senza l'autorizzazione di archiviazione
esterna. Tuttavia, alcune implementazioni di Android 6.0 (livello API 23) e versioni successive richiedono ancora
l'autorizzazione, pertanto dovrai dichiarare l'autorizzazione
READ_EXTERNAL_STORAGE nel manifest dell'app e chiedere l'autorizzazione in fase di
runtime nel seguente modo:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Per Android 6 e versioni successive, l'autorizzazione di accesso alla memoria esterna deve essere richiesta in fase di runtime. Tuttavia, alcune implementazioni di Android non richiedono l'autorizzazione per leggere i file OBB. Il seguente snippet di codice mostra come verificare l'accesso in lettura prima di chiedere l'autorizzazione di archiviazione esterna:
Kotlin
val obb = File(obb_filename) var open_failed = false try { BufferedReader(FileReader(obb)).also { br -> ReadObbFile(br) } } catch (e: IOException) { open_failed = true } if (open_failed) { // request READ_EXTERNAL_STORAGE permission before reading OBB file ReadObbFileWithPermission() }
Java
File obb = new File(obb_filename); boolean open_failed = false; try { BufferedReader br = new BufferedReader(new FileReader(obb)); open_failed = false; ReadObbFile(br); } catch (IOException e) { open_failed = true; } if (open_failed) { // request READ_EXTERNAL_STORAGE permission before reading OBB file ReadObbFileWithPermission(); }
Se devi decomprimere i contenuti dei file di espansione, non eliminare i file di espansione OBB in un secondo momento e non salvare i dati decompressi nella stessa directory. Salva i file decompressi nella directory
specificata da getExternalFilesDir(). Tuttavia,
se possibile, è meglio utilizzare un formato di file di espansione che consenta di leggere direttamente dal
file anziché richiedere di decomprimere i dati. Ad esempio, abbiamo fornito un progetto di libreria
chiamato APK Expansion Zip Library che legge i dati direttamente
dal file ZIP.
Attenzione: a differenza dei file APK, tutti i file salvati nello spazio di archiviazione condiviso possono essere letti dall'utente e da altre app.
Suggerimento:se comprimi i file multimediali in un file ZIP, puoi utilizzare le chiamate di riproduzione multimediale sui file con controlli di offset e lunghezza (ad esempio MediaPlayer.setDataSource() e SoundPool.load()) senza dover decomprimere il file ZIP. Affinché questa operazione funzioni, non devi eseguire una compressione aggiuntiva sui file multimediali durante la creazione dei pacchetti ZIP. Ad esempio, quando utilizzi lo strumento zip,
devi utilizzare l'opzione -n per specificare i suffissi dei file che non devono essere
compressi:
zip -n .mp4;.ogg main_expansion media_files
Procedura di download
La maggior parte delle volte, Google Play scarica e salva i file di espansione contemporaneamente all'APK sul dispositivo. Tuttavia, in alcuni casi Google Play non può scaricare i file di espansione oppure l'utente potrebbe aver eliminato i file di espansione scaricati in precedenza. Per gestire queste situazioni, l'app deve essere in grado di scaricare i file all'avvio dell'attività principale, utilizzando un URL fornito da Google Play.
Il processo di download a livello generale è il seguente:
- L'utente sceglie di installare la tua app da Google Play.
- Se Google Play è in grado di scaricare i file di espansione (come avviene per la maggior parte dei
dispositivi), li scarica insieme all'APK.
Se Google Play non riesce a scaricare i file di espansione, scarica solo l'APK.
- Quando l'utente avvia l'app, questa deve verificare se i file di espansione sono
già salvati sul dispositivo.
- In caso affermativo, la tua app è pronta.
- In caso contrario, l'app deve scaricare i file di espansione tramite HTTP da Google Play. La tua app deve inviare una richiesta al client Google Play utilizzando il servizio di licenze app di Google Play, che risponde con il nome, le dimensioni del file e l'URL di ogni file di espansione. Con queste informazioni, scarica i file e salvali nella posizione di archiviazione corretta.
Attenzione:è fondamentale includere il codice necessario per scaricare i file di espansione da Google Play nel caso in cui i file non siano già presenti sul dispositivo all'avvio dell'app. Come descritto nella sezione seguente sul download dei file di espansione, abbiamo messo a tua disposizione una libreria che semplifica notevolmente questa procedura ed esegue il download da un servizio con una quantità minima di codice da parte tua.
Elenco di controllo per lo sviluppo
Ecco un riepilogo delle attività da svolgere per utilizzare i file di espansione con la tua app:
- Innanzitutto, determina se le dimensioni compresse del download dell'app devono essere superiori a 100 MB. Lo spazio è prezioso e devi ridurre al minimo le dimensioni totali del download. Se la tua app utilizza più di 100 MB per fornire più versioni degli asset grafici per più densità dello schermo, valuta la possibilità di pubblicare più APK in cui ogni APK contiene solo gli asset necessari per gli schermi a cui è destinato. Per ottenere risultati ottimali durante la pubblicazione su Google Play, carica un Android App Bundle, che include tutto il codice e le risorse compilati della tua app, ma rimanda la generazione e la firma dell'APK a Google Play.
- Determina quali risorse dell'app separare dall'APK e comprimile in un
file da utilizzare come file di espansione principale.
In genere, devi utilizzare il secondo file di espansione patch solo quando esegui aggiornamenti al file di espansione principale. Tuttavia, se le risorse superano il limite di 2 GB per il file di espansione principale, puoi utilizzare il file patch per il resto degli asset.
- Sviluppa l'app in modo che utilizzi le risorse dei file di espansione nella
posizione di archiviazione condivisa del dispositivo.
Ricorda che non devi eliminare, spostare o rinominare i file di espansione.
Se la tua app non richiede un formato specifico, ti consigliamo di creare file ZIP per i file di espansione, quindi di leggerli utilizzando la libreria ZIP di espansione APK.
- Aggiungi alla principale attività della tua app una logica che controlli se i file di espansione
sono presenti sul dispositivo all'avvio. Se i file non sono sul dispositivo, utilizza il servizio di gestione licenze app di Google Play per richiedere gli URL
dei file di espansione, quindi scaricali e salvali.
Per ridurre notevolmente la quantità di codice da scrivere e garantire una buona esperienza utente durante il download, ti consigliamo di utilizzare la libreria Downloader per implementare il comportamento di download.
Se crei un tuo servizio di download anziché utilizzare la libreria, tieni presente che non devi modificare il nome dei file di espansione e devi salvarli nella posizione di archiviazione corretta.
Una volta terminato lo sviluppo dell'app, segui la guida per testare i file di espansione.
Regole e limitazioni
L'aggiunta di file di espansione APK è una funzionalità disponibile quando carichi l'app utilizzando Play Console. Quando carichi la tua app per la prima volta o aggiorni un'app che utilizza file di espansione, devi essere a conoscenza delle seguenti regole e limitazioni:
- Ogni file di espansione non può superare i 2 GB.
- Per scaricare i file di espansione da Google Play, l'utente deve aver acquisito la tua app da Google Play. Google Play non fornirà gli URL dei file di espansione se l'app è stata installata con altri mezzi.
- Quando esegui il download dall'app, l'URL che Google Play fornisce per ogni file è univoco per ogni download e ogni URL scade poco dopo essere stato fornito alla tua app.
- Se aggiorni l'app con un nuovo APK o carichi più APK per la stessa app, puoi selezionare i file di espansione che hai caricato per un APK precedente. Il nome del file di espansione non cambia: mantiene la versione ricevuta dall'APK a cui il file era originariamente associato.
- Se utilizzi i file di espansione in combinazione con più APK per
fornire file di espansione diversi per dispositivi diversi, devi comunque caricare APK separati
per ogni dispositivo per fornire un valore
versionCodeunico e dichiarare filtri diversi per ogni APK. - Non puoi rilasciare un aggiornamento della tua app modificando solo i file di espansione. Devi caricare un nuovo APK per aggiornare l'app. Se le modifiche riguardano solo gli asset nei file di espansione, puoi aggiornare l'APK semplicemente modificando
versionCode(e magari ancheversionName). - Non salvare altri dati nella directory
obb/. Se devi decomprimere alcuni dati, salvali nella posizione specificata dagetExternalFilesDir(). - Non eliminare o rinominare il file di espansione
.obb(a meno che tu non stia eseguendo un aggiornamento). In questo modo, Google Play (o la tua app) scaricherà ripetutamente il file di espansione. - Quando aggiorni manualmente un file di espansione, devi eliminare il file di espansione precedente.
Download dei file di espansione
Nella maggior parte dei casi, Google Play scarica e salva i file di espansione sul dispositivo contemporaneamente all'installazione o all'aggiornamento dell'APK. In questo modo, i file di espansione sono disponibili quando l'app viene avviata per la prima volta. Tuttavia, in alcuni casi l'app deve scaricare i file di espansione autonomamente richiedendoli da un URL fornito in una risposta dal servizio di licenze app di Google Play.
La logica di base necessaria per scaricare i file di espansione è la seguente:
- Quando l'app viene avviata, cerca i file di espansione nella posizione di archiviazione condivisa (nella directory
Android/obb/<package-name>/).- Se i file di espansione sono presenti, non devi fare altro e la tua app può continuare.
- Se i file di espansione non sono presenti:
- Esegui una richiesta utilizzando la licenza app di Google Play per ottenere i nomi, le dimensioni e gli URL dei file di espansione della tua app.
- Utilizza gli URL forniti da Google Play per scaricare i file di espansione e salvarli. Devi salvare i file nella posizione di archiviazione condivisa
(
Android/obb/<package-name>/) e utilizzare il nome file esatto fornito dalla risposta di Google Play.Nota:l'URL che Google Play fornisce per i tuoi file di espansione è univoco per ogni download e scade poco dopo essere stato fornito alla tua app.
Se la tua app è senza costi (non a pagamento), probabilmente non hai utilizzato il servizio di gestione licenze app. È progettata principalmente per consentirti di applicare le norme sulle licenze per la tua app e assicurarti che l'utente abbia il diritto di utilizzare la tua app (l'abbia pagata legittimamente su Google Play). Per facilitare la funzionalità dei file di espansione, il servizio di gestione delle licenze è stato migliorato per fornire una risposta alla tua app che include l'URL dei file di espansione dell'app ospitati su Google Play. Pertanto, anche se la tua app è senza costi per gli utenti, devi includere la libreria di verifica delle licenze (LVL) per utilizzare i file di espansione APK. Naturalmente, se la tua app è senza costi, non devi applicare la verifica della licenza. Ti serve solo la libreria per eseguire la richiesta che restituisce l'URL dei file di espansione.
Nota: indipendentemente dal fatto che la tua app sia senza costi o meno, Google Play restituisce gli URL dei file di espansione solo se l'utente ha acquisito la tua app da Google Play.
Oltre alla LVL, hai bisogno di un insieme di codici che scarichino i file di espansione tramite una connessione HTTP e li salvino nella posizione corretta della memoria condivisa del dispositivo. Quando integri questa procedura nella tua app, devi tenere in considerazione diversi aspetti:
- Il dispositivo potrebbe non avere spazio sufficiente per i file di espansione, quindi devi controllare prima di iniziare il download e avvisare l'utente se lo spazio non è sufficiente.
- I download di file devono avvenire in un servizio in background per evitare di bloccare l'interazione dell'utente e consentirgli di uscire dall'app durante il completamento del download.
- Durante la richiesta e il download potrebbero verificarsi diversi errori che devi gestire in modo appropriato.
- La connettività di rete può cambiare durante il download, quindi devi gestire queste modifiche e, se interrotto, riprendere il download quando possibile.
- Mentre il download viene eseguito in background, devi fornire una notifica che indichi l'avanzamento del download, avvisi l'utente al termine e lo riporti alla tua app quando viene selezionata.
Per semplificare questo lavoro, abbiamo creato la libreria Downloader, che richiede gli URL dei file di espansione tramite il servizio di gestione delle licenze, scarica i file di espansione, esegue tutte le attività elencate sopra e consente persino di mettere in pausa e riprendere l'attività di download. Se aggiungi la libreria Downloader e alcuni hook di codice alla tua app, quasi tutto il lavoro di download dei file di espansione è già codificato per te. Pertanto, per offrire la migliore esperienza utente con il minimo sforzo da parte tua, ti consigliamo di utilizzare la libreria Downloader per scaricare i file di espansione. Le informazioni nelle sezioni seguenti spiegano come integrare la libreria nella tua app.
Se preferisci sviluppare una soluzione personalizzata per scaricare i file di espansione utilizzando gli URL di Google Play, devi seguire la documentazione relativa alla licensing
dell'app per eseguire una richiesta di licenza, quindi recuperare i nomi, le dimensioni e gli URL dei file di espansione dalle informazioni extra della risposta. Devi utilizzare la classe APKExpansionPolicy (inclusa nella libreria di verifica delle licenze) come criterio di licenza, che acquisisce i nomi, le dimensioni e gli URL dei file di espansione dal servizio di licenze.
Informazioni sulla libreria Downloader
Per utilizzare i file di espansione APK con la tua app e offrire la migliore esperienza utente con il minimo sforzo da parte tua, ti consigliamo di utilizzare la libreria Downloader inclusa nel pacchetto della libreria di espansione APK di Google Play. Questa libreria scarica i file di espansione in un servizio in background, mostra una notifica all'utente con lo stato del download, gestisce la perdita di connettività di rete, riprende il download quando possibile e altro ancora.
Per implementare i download dei file di espansione utilizzando la libreria Downloader, devi solo:
- Estendi una sottoclasse
Servicee una sottoclasseBroadcastReceiverche richiedono solo poche righe di codice. - Aggiungi una logica all'attività principale che verifichi se i file di espansione sono già stati scaricati e, in caso contrario, richiami la procedura di download e visualizzi un'interfaccia utente di avanzamento.
- Implementa un'interfaccia di callback con alcuni metodi nell'attività principale che riceve aggiornamenti sullo stato di avanzamento del download.
Le sezioni seguenti spiegano come configurare l'app utilizzando la libreria Downloader.
Preparazione all'utilizzo della libreria Downloader
Per utilizzare la libreria Downloader, devi scaricare due pacchetti da SDK Manager e aggiungere le librerie appropriate alla tua app.
Per prima cosa, apri SDK Manager di Android (Tools > SDK Manager) e, in Appearance & Behavior > System Settings > SDK Android, seleziona la scheda Strumenti SDK per selezionare e scaricare:
- Pacchetto della libreria di gestione delle licenze di Google Play
- Pacchetto della libreria di espansione APK di Google Play
Crea un nuovo modulo della libreria per la libreria di verifica delle licenze e la libreria Downloader. Per ogni biblioteca:
- Seleziona File > Nuovo > Nuovo modulo.
- Nella finestra Crea nuovo modulo, seleziona Libreria Android, quindi seleziona Avanti.
- Specifica un nome di app/libreria, ad esempio "Libreria di licenze Google Play" e "Libreria di download di Google Play", scegli Livello SDK minimo, quindi seleziona Fine.
- Seleziona File > Struttura del progetto.
- Seleziona la scheda Proprietà e, in Repository
raccolta, inserisci la raccolta dalla directory
<sdk>/extras/google/(play_licensing/per la libreria di verifica delle licenze oplay_apk_expansion/downloader_library/per la libreria Downloader). - Seleziona Ok per creare il nuovo modulo.
Nota:la libreria Downloader dipende dalla libreria di verifica delle licenze. Assicurati di aggiungere la libreria di verifica delle licenze alle proprietà del progetto della libreria Downloader.
In alternativa, da una riga di comando, aggiorna il progetto in modo da includere le librerie:
- Passa alla directory
<sdk>/tools/. - Esegui
android update projectcon l'opzione--libraryper aggiungere sia la libreria LVL che quella di download al tuo progetto. Ad esempio:android update project --path ~/Android/MyApp \ --library ~/android_sdk/extras/google/market_licensing \ --library ~/android_sdk/extras/google/market_apk_expansion/downloader_library
Con l'aggiunta della libreria di verifica delle licenze e della libreria Downloader alla tua app, potrai integrare rapidamente la possibilità di scaricare file di espansione da Google Play. Il formato che scegli per i file di espansione e il modo in cui li leggi dallo spazio di archiviazione condiviso sono un'implementazione separata che devi prendere in considerazione in base alle esigenze della tua app.
Suggerimento: il pacchetto di espansione APK include un'app di esempio che mostra come utilizzare la libreria Downloader in un'app. L'esempio utilizza una libreria di terze parti disponibile nel pacchetto di espansione APK chiamata libreria di compressione APK. Se prevedi di utilizzare file ZIP per i file di espansione, ti consigliamo di aggiungere anche la libreria di compressione ZIP di espansione APK alla tua app. Per ulteriori informazioni, consulta la sezione seguente sull'utilizzo della libreria di compressione ZIP di espansione APK.
Dichiarazione delle autorizzazioni utente
Per scaricare i file di espansione, la libreria Downloader richiede diverse autorizzazioni che devi dichiarare nel file manifest dell'app. Sono:
<manifest ...> <!-- Required to access Google Play Licensing --> <uses-permission android:name="com.android.vending.CHECK_LICENSE" /> <!-- Required to download files from Google Play --> <uses-permission android:name="android.permission.INTERNET" /> <!-- Required to keep CPU alive while downloading files (NOT to keep screen awake) --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- Required to poll the state of the network connection and respond to changes --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- Required to check whether Wi-Fi is enabled --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <!-- Required to read and write the expansion files on shared storage --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
Nota:per impostazione predefinita, la libreria Downloader richiede il livello API 4, mentre la libreria APK Expansion Zip richiede il livello API 5.
Implementazione del servizio di download
Per eseguire i download in background, la libreria Downloader fornisce una propria
sottoclasse Service chiamata DownloaderService che devi estendere. Oltre a scaricare i file di espansione, DownloaderService:
- Registra un
BroadcastReceiverche ascolta le modifiche alla connettività di rete del dispositivo (la trasmissioneCONNECTIVITY_ACTION) per mettere in pausa il download quando necessario (ad esempio a causa della perdita di connettività) e riprenderlo quando possibile (viene acquisita la connettività). - Pianifica un allarme
RTC_WAKEUPper riprovare a scaricare i casi in cui il servizio viene interrotto. - Crea un
Notificationpersonalizzato che mostra l'avanzamento del download e eventuali errori o modifiche di stato. - Consente all'app di mettere in pausa e riprendere manualmente il download.
- Verifica che lo spazio di archiviazione condiviso sia montato e disponibile, che i file non esistano già e che ci sia spazio sufficiente, il tutto prima di scaricare i file di espansione. e avvisa l'utente se una di queste condizioni non è vera.
Tutto ciò che devi fare è creare una classe nella tua app che estenda la classe DownloaderService ed eseguire l'override di tre metodi per fornire dettagli sull'app specifici:
getPublicKey()- Deve restituire una stringa che è la chiave pubblica RSA codificata in base64 per il tuo account publisher, disponibile nella pagina del profilo di Play Console (vedi Configurazione per la licenza).
getSALT()- Deve restituire un array di byte casuali che la licenza
Policyutilizza per creare unObfuscator. Il sale garantisce che il fileSharedPreferencesoffuscato in cui vengono salvati i dati di licenza sia unico e non rilevabile. getAlarmReceiverClassName()- Deve restituire il nome della classe di
BroadcastReceivernella tua app che deve ricevere l'allarme che indica che il download deve essere riavviato (il che potrebbe accadere se il servizio di download si interrompe in modo imprevisto).
Ad esempio, ecco un'implementazione completa di DownloaderService:
Kotlin
// You must use the public key belonging to your publisher account const val BASE64_PUBLIC_KEY = "YourLVLKey" // You should also modify this salt val SALT = byteArrayOf( 1, 42, -12, -1, 54, 98, -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84 ) class SampleDownloaderService : DownloaderService() { override fun getPublicKey(): String = BASE64_PUBLIC_KEY override fun getSALT(): ByteArray = SALT override fun getAlarmReceiverClassName(): String = SampleAlarmReceiver::class.java.name }
Java
public class SampleDownloaderService extends DownloaderService { // You must use the public key belonging to your publisher account public static final String BASE64_PUBLIC_KEY = "YourLVLKey"; // You should also modify this salt public static final byte[] SALT = new byte[] { 1, 42, -12, -1, 54, 98, -100, -12, 43, 2, -8, -4, 9, 5, -106, -107, -33, 45, -1, 84 }; @Override public String getPublicKey() { return BASE64_PUBLIC_KEY; } @Override public byte[] getSALT() { return SALT; } @Override public String getAlarmReceiverClassName() { return SampleAlarmReceiver.class.getName(); } }
Avviso:devi aggiornare il valore di BASE64_PUBLIC_KEY
in modo che corrisponda alla chiave pubblica del tuo account editore. Puoi trovare la chiave in Developer Console
nella sezione delle informazioni del profilo. Questa operazione è necessaria anche durante il test
dei download.
Ricordati di dichiarare il servizio nel file manifest:
<app ...> <service android:name=".SampleDownloaderService" /> ... </app>
Implementazione del ricevitore di allarmi
Per monitorare l'avanzamento dei download dei file e riavviarli se necessario, l'app
DownloaderService pianifica una sveglia RTC_WAKEUP che
invia un Intent a un BroadcastReceiver nella tua
app. Devi definire l'BroadcastReceiver per chiamare un'API
dalla libreria Downloader che controlla lo stato del download e lo riavvia
se necessario.
Devi semplicemente eseguire l'override del metodo onReceive() per chiamare DownloaderClientMarshaller.startDownloadServiceIfRequired().
Ad esempio:
Kotlin
class SampleAlarmReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { try { DownloaderClientMarshaller.startDownloadServiceIfRequired( context, intent, SampleDownloaderService::class.java ) } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } } }
Java
public class SampleAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { try { DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, SampleDownloaderService.class); } catch (NameNotFoundException e) { e.printStackTrace(); } } }
Tieni presente che questa è la classe per cui devi restituire il nome
nel metodo getAlarmReceiverClassName() del tuo servizio (vedi la sezione precedente).
Ricorda di dichiarare il ricevitore nel file manifest:
<app ...> <receiver android:name=".SampleAlarmReceiver" /> ... </app>
Avvio del download
L'attività principale della tua app (quella avviata dall'icona in Avvio applicazioni) è responsabile della verifica della presenza dei file di espansione sul dispositivo e dell'avvio del download in caso contrario.
L'avvio del download utilizzando la libreria Downloader richiede le seguenti procedure:
- Controlla se i file sono stati scaricati.
La libreria Downloader include alcune API nella classe
Helperper facilitare questo processo:getExpansionAPKFileName(Context, c, boolean mainFile, int versionCode)doesFileExist(Context c, String fileName, long fileSize)
Ad esempio, l'app di esempio fornita nel pacchetto di espansione APK chiama il seguente metodo nel metodo
onCreate()dell'attività per verificare se i file di espansione esistono già sul dispositivo:Kotlin
fun expansionFilesDelivered(): Boolean { xAPKS.forEach { xf -> Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion).also { fileName -> if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false)) return false } } return true }
Java
boolean expansionFilesDelivered() { for (XAPKFile xf : xAPKS) { String fileName = Helpers.getExpansionAPKFileName(this, xf.isBase, xf.fileVersion); if (!Helpers.doesFileExist(this, fileName, xf.fileSize, false)) return false; } return true; }
In questo caso, ogni oggetto
XAPKFilecontiene il numero di versione e le dimensioni del file di un file di espansione noto e un valore booleano che indica se si tratta del file di espansione principale. Per maggiori dettagli, consulta la classeSampleDownloaderActivitydell'app di esempio.Se questo metodo restituisce false, l'app deve avviare il download.
- Avvia il download chiamando il metodo statico
DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass).Il metodo accetta i seguenti parametri:
context: ilContextdella tua app.notificationClient: unPendingIntentper avviare l'attività principale. Viene utilizzato inNotificationcreato daDownloaderServiceper mostrare l'avanzamento del download. Quando l'utente seleziona la notifica, il sistema richiama l'PendingIntentche fornisci qui e dovrebbe aprire l'attività che mostra l'avanzamento del download (di solito la stessa attività che ha avviato il download).serviceClass: l'oggettoClassper l'implementazione diDownloaderService, necessario per avviare il servizio e iniziare il download, se necessario.
Il metodo restituisce un numero intero che indica se il download è necessario o meno. I valori possibili sono:
NO_DOWNLOAD_REQUIRED: restituito se i file esistono già o se è già in corso un download.LVL_CHECK_REQUIRED: restituito se è necessaria una verifica della licenza per acquisire gli URL dei file di espansione.DOWNLOAD_REQUIRED: restituito se gli URL dei file di espansione sono già noti, ma non sono stati scaricati.
Il comportamento di
LVL_CHECK_REQUIREDeDOWNLOAD_REQUIREDè essenzialmente lo stesso e in genere non devi preoccuparti. Nell'attività principale che chiamastartDownloadServiceIfRequired(), puoi semplicemente controllare se la risposta èNO_DOWNLOAD_REQUIRED. Se la risposta è diversa daNO_DOWNLOAD_REQUIRED, la libreria Downloader avvia il download e devi aggiornare l'interfaccia utente dell'attività per visualizzare l'avanzamento del download (vedi il passaggio successivo). Se la risposta èNO_DOWNLOAD_REQUIRED, i file sono disponibili e la tua app può essere avviata.Ad esempio:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Check if expansion files are available before going any further if (!expansionFilesDelivered()) { val pendingIntent = // Build an Intent to start this activity from the Notification Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP }.let { notifierIntent -> PendingIntent.getActivity( this, 0, notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT ) } // Start the download service (if required) val startResult: Int = DownloaderClientMarshaller.startDownloadServiceIfRequired( this, pendingIntent, SampleDownloaderService::class.java ) // If download has started, initialize this activity to show // download progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // This is where you do set up to display the download // progress (next step) ... return } // If the download wasn't necessary, fall through to start the app } startApp() // Expansion files are available, start the app }
Java
@Override public void onCreate(Bundle savedInstanceState) { // Check if expansion files are available before going any further if (!expansionFilesDelivered()) { // Build an Intent to start this activity from the Notification Intent notifierIntent = new Intent(this, MainActivity.getClass()); notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); ... PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT); // Start the download service (if required) int startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(this, pendingIntent, SampleDownloaderService.class); // If download has started, initialize this activity to show // download progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // This is where you do set up to display the download // progress (next step) ... return; } // If the download wasn't necessary, fall through to start the app } startApp(); // Expansion files are available, start the app }
- Quando il metodo
startDownloadServiceIfRequired()restituisce un valore diverso daNO_DOWNLOAD_REQUIRED, crea un'istanza diIStubchiamandoDownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService).IStubfornisce un binding tra la tua attività e il servizio di download in modo che la tua attività riceva callback sullo stato di avanzamento del download.Per creare un'istanza di
IStubchiamandoCreateStub(), devi trasmettergli un'implementazione dell'interfacciaIDownloaderCliente la tua implementazione diDownloaderService. La sezione successiva su Ricezione dell'avanzamento del download descrive l'interfacciaIDownloaderClient, che in genere devi implementare nella classeActivityper poter aggiornare la UI dell'attività quando lo stato del download cambia.Ti consigliamo di chiamare
CreateStub()per creare un'istanza diIStubdurante il metodoonCreate()dell'attività, dopo chestartDownloadServiceIfRequired()avvia il download.Ad esempio, nel campione di codice precedente per
onCreate(), puoi rispondere al risultatostartDownloadServiceIfRequired()in questo modo:Kotlin
// Start the download service (if required) val startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired( this@MainActivity, pendingIntent, SampleDownloaderService::class.java ) // If download has started, initialize activity to show progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // Instantiate a member instance of IStub downloaderClientStub = DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService::class.java) // Inflate layout that shows download progress setContentView(R.layout.downloader_ui) return }
Java
// Start the download service (if required) int startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(this, pendingIntent, SampleDownloaderService.class); // If download has started, initialize activity to show progress if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // Instantiate a member instance of IStub downloaderClientStub = DownloaderClientMarshaller.CreateStub(this, SampleDownloaderService.class); // Inflate layout that shows download progress setContentView(R.layout.downloader_ui); return; }
Dopo la restituzione del metodo
onCreate(), la tua attività riceve una chiamata aonResume(), dove devi chiamareconnect()suIStub, passando l'Contextdella tua app. Al contrario, devi chiamaredisconnect()nel callbackonStop()dell'attività.Kotlin
override fun onResume() { downloaderClientStub?.connect(this) super.onResume() } override fun onStop() { downloaderClientStub?.disconnect(this) super.onStop() }
Java
@Override protected void onResume() { if (null != downloaderClientStub) { downloaderClientStub.connect(this); } super.onResume(); } @Override protected void onStop() { if (null != downloaderClientStub) { downloaderClientStub.disconnect(this); } super.onStop(); }
La chiamata a
connect()suIStubassocia la tua attività aDownloaderServicein modo che la tua attività riceva callback relativi alle modifiche allo stato del download tramite l'interfacciaIDownloaderClient.
Ricezione dell'avanzamento del download
Per ricevere aggiornamenti sullo stato di avanzamento del download e interagire con DownloaderService, devi implementare l'interfaccia IDownloaderClient della libreria Downloader.
In genere, l'attività che utilizzi per avviare il download deve implementare questa interfaccia per
visualizzare l'avanzamento del download e inviare richieste al servizio.
I metodi di interfaccia richiesti per IDownloaderClient sono:
onServiceConnected(Messenger m)- Dopo aver creato un'istanza di
IStubnell'attività, riceverai una chiamata a questo metodo, che passa un oggettoMessengerconnesso alla tua istanza diDownloaderService. Per inviare richieste al servizio, ad esempio per mettere in pausa e riprendere i download, devi chiamareDownloaderServiceMarshaller.CreateProxy()per ricevere l'interfacciaIDownloaderServiceconnessa al servizio.Un'implementazione consigliata ha il seguente aspetto:
Kotlin
private var remoteService: IDownloaderService? = null ... override fun onServiceConnected(m: Messenger) { remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply { downloaderClientStub?.messenger?.also { messenger -> onClientUpdated(messenger) } } }
Java
private IDownloaderService remoteService; ... @Override public void onServiceConnected(Messenger m) { remoteService = DownloaderServiceMarshaller.CreateProxy(m); remoteService.onClientUpdated(downloaderClientStub.getMessenger()); }
Con l'oggetto
IDownloaderServiceinizializzato, puoi inviare comandi al servizio di download, ad esempio per mettere in pausa e riprendere il download (requestPauseDownload()erequestContinueDownload()). onDownloadStateChanged(int newState)- Il servizio di download chiama questo metodo quando si verifica una modifica dello stato del download, ad esempio
quando il download inizia o termina.
Il valore di
newStatesarà uno dei vari valori possibili specificati da una delle costantiSTATE_*della classeIDownloaderClient.Per fornire un messaggio utile ai tuoi utenti, puoi richiedere una stringa corrispondente per ogni stato chiamando
Helpers.getDownloaderStringResourceIDFromState(). Questo restituisce l'ID risorsa per una delle stringhe incluse nella libreria Downloader. Ad esempio, la stringa "Download in pausa perché sei in roaming" corrisponde aSTATE_PAUSED_ROAMING. onDownloadProgress(DownloadProgressInfo progress)- Il servizio di download chiama questo metodo per fornire un oggetto
DownloadProgressInfo, che descrive varie informazioni sull'avanzamento del download, tra cui il tempo stimato rimanente, la velocità attuale, l'avanzamento complessivo e il totale, in modo da poter aggiornare la UI di avanzamento del download.
Suggerimento:per esempi di questi callback che aggiornano l'interfaccia utente di avanzamento del download, consulta SampleDownloaderActivity nell'app di esempio fornita con il pacchetto di espansione APK.
Alcuni metodi pubblici per l'interfaccia IDownloaderService che potresti trovare utili sono:
requestPauseDownload()- Mette in pausa il download.
requestContinueDownload()- Riprende un download in pausa.
setDownloadFlags(int flags)- Imposta le preferenze dell'utente per i tipi di rete su cui è possibile scaricare i file. L'implementazione
attuale supporta un flag,
FLAGS_DOWNLOAD_OVER_CELLULAR, ma puoi aggiungerne altri. Per impostazione predefinita, questo flag non è abilitato, quindi l'utente deve essere connesso alla rete Wi-Fi per scaricare i file di espansione. Potresti voler fornire una preferenza utente per attivare i download tramite la rete cellulare. In questo caso, puoi chiamare:Kotlin
remoteService = DownloaderServiceMarshaller.CreateProxy(m).apply { ... setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR) }
Java
remoteService .setDownloadFlags(IDownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR);
Utilizzo di APKExpansionPolicy
Se decidi di creare un tuo servizio di download anziché utilizzare la libreria Downloader di Google Play, devi comunque utilizzare APKExpansionPolicy fornito nella libreria di verifica delle licenze. La classe APKExpansionPolicy è quasi identica a ServerManagedPolicy (disponibile nella
libreria di verifica delle licenze di Google Play), ma include una gestione aggiuntiva per le informazioni extra della risposta del file
di espansione APK.
Nota:se utilizzi la libreria Downloader come descritto nella sezione precedente, la
libreria esegue tutta l'interazione con APKExpansionPolicy, quindi non devi utilizzare
questa classe direttamente.
La classe include metodi che ti aiutano a ottenere le informazioni necessarie sui file di espansione disponibili:
getExpansionURLCount()getExpansionURL(int index)getExpansionFileName(int index)getExpansionFileSize(int index)
Per saperne di più su come utilizzare APKExpansionPolicy quando non utilizzi la libreria Downloader, consulta la documentazione relativa all'aggiunta di licenze alla tua app, che spiega come implementare una norma sulle licenze come questa.
Lettura del file di espansione
Una volta salvati i file di espansione APK sul dispositivo, la modalità di lettura dei file
dipende dal tipo di file che hai utilizzato. Come descritto nella panoramica, i file di espansione possono essere di qualsiasi tipo, ma vengono rinominati utilizzando un particolare formato del nome file e vengono salvati in <shared-storage>/Android/obb/<package-name>/.
Indipendentemente da come leggi i file, devi sempre verificare che l'archiviazione esterna sia disponibile per la lettura. È possibile che l'utente abbia montato lo spazio di archiviazione su un computer tramite USB o abbia effettivamente rimosso la scheda SD.
Nota:all'avvio dell'app, devi sempre verificare se
lo spazio di archiviazione esterno è disponibile e leggibile chiamando getExternalStorageState(). Restituisce una delle varie stringhe possibili
che rappresentano lo stato dell'archiviazione esterna. Affinché sia leggibile dalla tua
app, il valore restituito deve essere MEDIA_MOUNTED.
Ottenere i nomi dei file
Come descritto nella panoramica, i file di espansione APK vengono salvati utilizzando un formato specifico per il nome file:
[main|patch].<expansion-version>.<package-name>.obb
Per ottenere la posizione e i nomi dei file di espansione, devi utilizzare i metodi
getExternalStorageDirectory() e getPackageName() per creare il percorso dei file.
Ecco un metodo che puoi utilizzare nella tua app per ottenere un array contenente il percorso completo di entrambi i file di espansione:
Kotlin
fun getAPKExpansionFiles(ctx: Context, mainVersion: Int, patchVersion: Int): Array<String> { val packageName = ctx.packageName val ret = mutableListOf<String>() if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) { // Build the full path to the app's expansion files val root = Environment.getExternalStorageDirectory() val expPath = File(root.toString() + EXP_PATH + packageName) // Check that expansion file path exists if (expPath.exists()) { if (mainVersion > 0) { val strMainPath = "$expPath${File.separator}main.$mainVersion.$packageName.obb" val main = File(strMainPath) if (main.isFile) { ret += strMainPath } } if (patchVersion > 0) { val strPatchPath = "$expPath${File.separator}patch.$mainVersion.$packageName.obb" val main = File(strPatchPath) if (main.isFile) { ret += strPatchPath } } } } return ret.toTypedArray() }
Java
// The shared path to all app expansion files private final static String EXP_PATH = "/Android/obb/"; static String[] getAPKExpansionFiles(Context ctx, int mainVersion, int patchVersion) { String packageName = ctx.getPackageName(); Vector<String> ret = new Vector<String>(); if (Environment.getExternalStorageState() .equals(Environment.MEDIA_MOUNTED)) { // Build the full path to the app's expansion files File root = Environment.getExternalStorageDirectory(); File expPath = new File(root.toString() + EXP_PATH + packageName); // Check that expansion file path exists if (expPath.exists()) { if ( mainVersion > 0 ) { String strMainPath = expPath + File.separator + "main." + mainVersion + "." + packageName + ".obb"; File main = new File(strMainPath); if ( main.isFile() ) { ret.add(strMainPath); } } if ( patchVersion > 0 ) { String strPatchPath = expPath + File.separator + "patch." + mainVersion + "." + packageName + ".obb"; File main = new File(strPatchPath); if ( main.isFile() ) { ret.add(strPatchPath); } } } } String[] retArray = new String[ret.size()]; ret.toArray(retArray); return retArray; }
Puoi chiamare questo metodo passando l'Context della tua app
e la versione del file di espansione che preferisci.
Esistono molti modi per determinare il numero di versione del file di espansione. Un modo semplice è salvare la versione in un file SharedPreferences quando inizia il download, eseguendo una query sul nome del file di espansione con il metodo getExpansionFileName(int index) della classe APKExpansionPolicy. Puoi quindi ottenere il codice versione leggendo il file SharedPreferences quando vuoi accedere al file di espansione.
Per saperne di più sulla lettura dall'archivio condiviso, consulta la documentazione Data Storage.
Utilizzo della libreria ZIP di espansione APK
Il pacchetto di espansione APK di Google Market include una libreria chiamata Libreria zip di espansione APK (che si trova in <sdk>/extras/google/google_market_apk_expansion/zip_file/). Si tratta di una libreria facoltativa che ti aiuta a leggere i file di espansione quando vengono salvati come file ZIP. L'utilizzo di questa libreria ti consente di leggere facilmente le risorse dai file di espansione ZIP come file system virtuale.
La libreria ZIP di espansione APK include le seguenti classi e API:
APKExpansionSupport- Fornisce alcuni metodi per accedere ai nomi dei file di espansione e ai file ZIP:
getAPKExpansionFiles()- Lo stesso metodo mostrato sopra che restituisce il percorso completo dei file di espansione.
getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion)- Restituisce un
ZipResourceFileche rappresenta la somma del file principale e del file patch. ovvero, se specifichi siamainVersionsiapatchVersion, viene restituito unZipResourceFileche fornisce l'accesso in lettura a tutti i dati, con i dati del file patch uniti a quelli del file principale.
ZipResourceFile- Rappresenta un file ZIP nello spazio di archiviazione condiviso ed esegue tutto il lavoro per fornire un file system virtuale basato sui file ZIP. Puoi ottenere un'istanza utilizzando
APKExpansionSupport.getAPKExpansionZipFile()oZipResourceFilepassando il percorso del file di espansione. Questa classe include una serie di metodi utili, ma in genere non è necessario accedere alla maggior parte di questi. Ecco alcuni metodi importanti:getInputStream(String assetPath)- Fornisce un
InputStreamper leggere un file all'interno del file ZIP.assetPathdeve essere il percorso del file desiderato, relativo alla radice dei contenuti del file ZIP. getAssetFileDescriptor(String assetPath)- Fornisce un
AssetFileDescriptorper un file all'interno del file ZIP.assetPathdeve essere il percorso del file desiderato, relativo alla radice dei contenuti del file ZIP. Ciò è utile per alcune API Android che richiedono unAssetFileDescriptor, ad esempio alcune APIMediaPlayer.
APEZProvider- La maggior parte delle app non ha bisogno di utilizzare questa classe. Questa classe definisce un
ContentProviderche esegue il marshalling dei dati dai file ZIP tramite un content providerUriper fornire l'accesso ai file per determinate API Android che prevedono l'accessoUriai file multimediali. Ad esempio, questa funzionalità è utile se vuoi riprodurre un video conVideoView.setVideoURI().
Ignorare la compressione ZIP dei file multimediali
Se utilizzi i file di espansione per archiviare file multimediali, un file ZIP ti consente comunque di utilizzare le chiamate di riproduzione multimediale Android che forniscono controlli di offset e lunghezza (ad esempio MediaPlayer.setDataSource() e SoundPool.load()). Affinché ciò funzioni, non devi eseguire una compressione aggiuntiva dei file multimediali durante la creazione dei pacchetti ZIP. Ad esempio, quando utilizzi lo strumento zip, devi utilizzare l'opzione -n
per specificare i suffissi dei file che non devono essere compressi:
zip -n .mp4;.ogg main_expansion media_files
Lettura da un file ZIP
Quando utilizzi la libreria ZIP di espansione APK, la lettura di un file dal file ZIP richiede in genere quanto segue:
Kotlin
// Get a ZipResourceFile representing a merger of both the main and patch files val expansionFile = APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion) // Get an input stream for a known file inside the expansion file ZIPs expansionFile.getInputStream(pathToFileInsideZip).use { ... }
Java
// Get a ZipResourceFile representing a merger of both the main and patch files ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(appContext, mainVersion, patchVersion); // Get an input stream for a known file inside the expansion file ZIPs InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);
Il codice riportato sopra fornisce l'accesso a qualsiasi file presente nel file di espansione principale o nel file di espansione patch, leggendo da una mappa unita di tutti i file di entrambi i file. Per fornire il metodo getAPKExpansionFile(), devi solo indicare l'android.content.Context della tua app e il numero di versione sia per il file di espansione principale sia per il file di espansione patch.
Se preferisci leggere da un file di espansione specifico, puoi utilizzare il costruttore ZipResourceFile con il percorso del file di espansione desiderato:
Kotlin
// Get a ZipResourceFile representing a specific expansion file val expansionFile = ZipResourceFile(filePathToMyZip) // Get an input stream for a known file inside the expansion file ZIPs expansionFile.getInputStream(pathToFileInsideZip).use { ... }
Java
// Get a ZipResourceFile representing a specific expansion file ZipResourceFile expansionFile = new ZipResourceFile(filePathToMyZip); // Get an input stream for a known file inside the expansion file ZIPs InputStream fileStream = expansionFile.getInputStream(pathToFileInsideZip);
Per ulteriori informazioni sull'utilizzo di questa libreria per i file di espansione, consulta
la classe SampleDownloaderActivity dell'app di esempio, che include codice aggiuntivo per
verificare i file scaricati utilizzando il controllo ciclico di ridondanza (CRC). Tieni presente che se utilizzi questo esempio come base per la tua implementazione, devi dichiarare le dimensioni in byte dei file di espansione nell'array xAPKS.
Testare i file di espansione
Prima di pubblicare l'app, devi testare due aspetti: la lettura dei file di espansione e il download dei file.
Test delle letture dei file
Prima di caricare l'app su Google Play, devi testare la sua capacità di leggere i file dallo spazio di archiviazione condiviso. Tutto quello che devi fare è aggiungere i file nella posizione appropriata nell'archivio condiviso del dispositivo e avviare l'app:
- Sul dispositivo, crea la directory appropriata nello spazio di archiviazione condiviso in cui Google
Play salverà i tuoi file.
Ad esempio, se il nome del pacchetto è
com.example.android, devi creare la directoryAndroid/obb/com.example.android/nello spazio di archiviazione condiviso. (Collega il dispositivo di test al computer per montare lo spazio di archiviazione condiviso e creare manualmente questa directory.) - Aggiungi manualmente i file di espansione a questa directory. Assicurati di rinominare i file in modo che
corrispondano al formato del nome file che Google Play utilizzerà.
Ad esempio, indipendentemente dal tipo di file, il file di espansione principale per l'app
com.example.androiddeve esseremain.0300110.com.example.android.obb. Il codice versione può essere qualsiasi valore. Ricorda:- Il file di espansione principale inizia sempre con
maine il file patch inizia conpatch. - Il nome del pacchetto corrisponde sempre a quello dell'APK a cui è allegato il file su Google Play.
- Il file di espansione principale inizia sempre con
- Ora che i file di espansione si trovano sul dispositivo, puoi installare ed eseguire l'app per testare i file di espansione.
Ecco alcuni promemoria sulla gestione dei file di espansione:
- Non eliminare o rinominare i file di espansione
.obb(anche se decomprimi i dati in una posizione diversa). In questo modo, Google Play (o la tua app) scaricherà ripetutamente il file di espansione. - Non salvare altri dati nella directory
obb/. Se devi decomprimere alcuni dati, salvali nella posizione specificata dagetExternalFilesDir().
Test dei download di file
Poiché a volte l'app deve scaricare manualmente i file di espansione quando viene aperta per la prima volta, è importante testare questa procedura per assicurarsi che l'app possa eseguire correttamente query per gli URL, scaricare i file e salvarli sul dispositivo.
Per testare l'implementazione della procedura di download manuale della tua app, puoi pubblicarla nel canale di test interno, in modo che sia disponibile solo per i tester autorizzati. Se tutto funziona come previsto, l'app dovrebbe iniziare a scaricare i file di espansione non appena viene avviata l'attività principale.
Nota:in precedenza era possibile testare un'app caricando una versione "bozza" non pubblicata. Questa funzionalità non è più supportata. Devi invece pubblicarla in un canale di test interno, chiuso o aperto. Per ulteriori informazioni, vedi Le app bozza non sono più supportate.
Aggiornamento dell'app
Uno dei grandi vantaggi dell'utilizzo dei file di espansione su Google Play è la possibilità di aggiornare l'app senza scaricare nuovamente tutti gli asset originali. Poiché Google Play ti consente di fornire due file di espansione con ogni APK, puoi utilizzare il secondo file come "patch" che fornisce aggiornamenti e nuove risorse. In questo modo si evita la necessità di scaricare nuovamente il file di espansione principale, che potrebbe essere di grandi dimensioni e costoso per gli utenti.
Il file di espansione patch è tecnicamente uguale al file di espansione principale e né il sistema Android né Google Play eseguono l'applicazione di patch tra i file di espansione principale e patch. Il codice dell'app deve eseguire autonomamente le patch necessarie.
Se utilizzi file ZIP come file di espansione, la libreria APK Expansion Zip inclusa nel pacchetto di espansione APK include la possibilità di unire il file patch con il file di espansione principale.
Nota:anche se devi apportare modifiche solo al file di espansione della patch, devi comunque aggiornare l'APK affinché Google Play esegua un aggiornamento.
Se non sono necessarie modifiche al codice nell'app, devi semplicemente aggiornare versionCode nel
manifest.
Se non modifichi il file di espansione principale associato all'APK in Play Console, gli utenti che hanno installato in precedenza la tua app non scaricheranno il file di espansione principale. Gli utenti esistenti ricevono solo l'APK aggiornato e il nuovo file di espansione patch (mantenendo il precedente file di espansione principale).
Ecco alcuni problemi da tenere presente in merito agli aggiornamenti dei file di espansione:
- Possono esserci solo due file di espansione per la tua app alla volta. Un file di espansione principale e un file di espansione patch. Durante un aggiornamento di un file, Google Play elimina la versione precedente (e così deve fare la tua app quando esegue aggiornamenti manuali).
- Quando aggiungi un file di espansione patch, il sistema Android non applica patch alla tua app o al file di espansione principale. Devi progettare la tua app in modo che supporti i dati della patch. Tuttavia, il pacchetto di espansione APK include una libreria per l'utilizzo di file ZIP come file di espansione, che unisce i dati del file patch nel file di espansione principale in modo da poter leggere facilmente tutti i dati del file di espansione.