File di espansione APK

Google Play richiede che l'APK compresso scaricato dagli utenti non superi i 100 MB. Per la maggior parte delle app, c'è molto spazio per il codice e gli asset dell'app. Tuttavia, alcune app richiedono più spazio per grafica ad alta fedeltà, file multimediali o altri asset di grandi dimensioni. In precedenza, se le dimensioni di download compresse dell'app superavano i 100 MB, dovevi ospitare e scaricare di risorse aggiuntive quando l'utente apre l'app. L'hosting e la pubblicazione di file aggiuntivi costoso e l'esperienza utente spesso non è ideale. Per semplificare questo processo e più piacevole per gli utenti, Google Play vi consente di allegare due file di espansione di grandi dimensioni che integrare l'APK.

Google Play ospita i file di espansione dell'app e li pubblica sul dispositivo all'indirizzo senza costi. I file di espansione vengono salvati nello spazio di archiviazione condiviso del dispositivo (il Scheda SD o partizione montabile USB; chiamato anche "esterno" spazio di archiviazione) a cui può accedere l'app che li rappresentano. Sulla maggior parte dei dispositivi, Google Play scarica i file di espansione contemporaneamente scarica l'APK, quindi la tua app ha tutto ciò di cui ha bisogno quando l'utente la apre per per la prima volta. In alcuni casi, tuttavia, l'app deve scaricare i file da Google Play. all'avvio dell'app.

Se vuoi evitare di utilizzare i file di espansione e le dimensioni di download compresse dell'app sono maggiori di oltre 100 MB, devi invece caricare l'app utilizzando l'app per Android Bundle, che consente una dimensione di download compressa fino a 200 MB. Inoltre, poiché l'uso gli app bundle rinviano la generazione degli APK e la firma su Google Play, gli utenti scaricano APK ottimizzati con ma solo il codice e le risorse necessarie all'esecuzione dell'app. Non devi creare, firmare e gestire più APK o file di espansione, mentre gli utenti ricevono download più piccoli e ottimizzati.

Panoramica

Ogni volta che carichi un APK utilizzando Google Play Console, hai la possibilità di: aggiungi uno o due file di espansione all'APK. Ogni file può avere dimensioni massime di 2 GB e il formato che preferisci ma consigliamo di utilizzare un file compresso per risparmiare larghezza di banda durante il download. Concettualmente, ogni file di espansione svolge un ruolo diverso:

  • Il file di espansione main rappresenta file di espansione principale per le risorse aggiuntive richieste dall'app.
  • Il file di espansione patch è facoltativo ed è destinato ai piccoli aggiornamenti della file di espansione principale.

Puoi utilizzare i due file di espansione come preferisci, ma ti consigliamo di usare il principale il file di espansione pubblica gli asset principali e dovrebbe essere aggiornato raramente, se necessario; l'espansione delle patch deve essere più piccolo e fungere da "fornitore di patch" e viene aggiornato con ogni 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 elemento versionCode aggiornato nel file manifest. (La 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 ciascun file come preferisci.

Formato nome file

Ogni file di espansione caricato può essere nel formato che preferisci (ZIP, PDF, MP4 e così via). Puoi anche usa lo strumento JOBB per incapsulare e criptare un set di file di risorse e patch successive per quel set. A prescindere 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 è costituito da tre componenti:

main o patch
Specifica se il file è il file di espansione principale o di espansione patch. Possono esserci un solo file principale e un file di patch per ogni APK.
<expansion-version>
Si tratta di un numero intero che corrisponde al codice di versione dell'APK con cui viene eseguita l'espansione per la prima associata (corrisponde alla android:versionCode dell'app) ).

"Prima" è sottolineata perché, sebbene Play Console ti consenta Riutilizzare un file di espansione caricato con un nuovo APK, il nome del file di espansione non cambia. conserva la versione applicata quando il file è stato caricato per la prima volta.

<package-name>
Il nome del pacchetto in stile Java della tua app.

Ad esempio, supponiamo che la versione dell'APK sia 314159 e che il nome del pacchetto sia com.example.app. Se carica un file di espansione principale, il file viene rinominato in:

main.314159.com.example.app.obb

Posizione archiviazione

Quando Google Play scarica i file di espansione su un dispositivo, li salva nella cartella posizione di archiviazione condivisa. Per garantire il corretto comportamento, non devi eliminare, spostare o rinominare il file di espansione. Nel caso in cui l'app debba eseguire il download da Google Play devi salvare i file nella stessa esatta posizione.

Il metodo getObbDir() restituisce la posizione specifica per i tuoi file di espansione nel seguente formato:

<shared-storage>/Android/obb/<package-name>/

Per ogni app, questa directory non contiene mai più di due file di espansione. Uno è il file di espansione principale e l'altro il file di espansione patch (se necessario). Indietro vengono sovrascritte quando aggiorni l'app con nuovi file di espansione. Da Android 4.4 (livello API 19), le app possono leggere file di espansione OBB senza unità di archiviazione esterna autorizzazione. Tuttavia, alcune implementazioni di Android 6.0 (livello API 23) e versioni successive richiedono ancora quindi dovrai dichiarare READ_EXTERNAL_STORAGE nel file manifest dell'app e chiedi l'autorizzazione all'indirizzo il runtime come segue:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Per Android 6 e versioni successive, è necessario richiedere l'autorizzazione per l'archiviazione esterna in fase di runtime. Tuttavia, alcune implementazioni di Android non richiedono l'autorizzazione per leggere i file OBB. La Il seguente snippet di codice mostra come verificare l'accesso in lettura prima di richiedere un'unità di archiviazione esterna autorizzazione:

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 Successivamente, OBB file di espansione e non salvare i dati non pacchettizzati. nella stessa directory. Salva i file non pacchettizzati nella directory specificato da getExternalFilesDir(). Tuttavia, se possibile, è consigliabile utilizzare un formato file di espansione che consente di leggere direttamente il file, invece di doverli scomporre. Ad esempio, abbiamo fornito una libreria progetto denominato APK Expansion Zip Library che legge direttamente i tuoi dati dal file ZIP.

Attenzione: a differenza dei file APK, tutti i file salvati sullo spazio di archiviazione condiviso possono essere letti dall'utente e da altre app.

Suggerimento:se pacchettizzi i file multimediali in un file ZIP, puoi utilizzare per riprodurre i file con controlli di offset e lunghezza (come MediaPlayer.setDataSource() e SoundPool.load()) senza devi togliere il file ZIP. Affinché questa operazione funzioni, non devi eseguire una compressione aggiuntiva i 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 compresso:
zip -n .mp4;.ogg main_expansion media_files

Procedura di download

Nella maggior parte dei casi, Google Play scarica e salva contemporaneamente i file di espansione scarica l'APK sul dispositivo. Tuttavia, in alcuni casi Google Play non può scaricare i file di espansione oppure l'utente potrebbe aver eliminato l'espansione scaricata 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 da un livello generale è simile al seguente:

  1. L'utente sceglie di installare la tua app da Google Play.
  2. Se Google Play riesce a scaricare i file di espansione (come accade per la maggior parte dispositivi), li scarica insieme all'APK.

    Se Google Play non riesce a scaricare i file di espansione, scarica i file Solo APK.

  3. Quando l'utente avvia l'app, quest'ultima deve controllare se i file di espansione sono già salvati sul dispositivo.
    1. Se sì, la tua app è pronta per l'uso.
    2. 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 di Google Play utilizzando il servizio di licenza delle 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 appropriata.

Attenzione:è fondamentale includere il codice necessario per scarica i file di espansione da Google Play nel caso in cui i file non siano già presenti nella dispositivo all'avvio dell'app. Come discusso nella sezione seguente sul download dei file di espansione, abbiamo messo a tua disposizione una libreria che semplifica notevolmente questo processo ed esegue il download da un servizio con una quantità minima codice da parte tua.

Elenco di controllo per lo sviluppo

Di seguito è riportato un riepilogo delle attività da eseguire per utilizzare i file di espansione con dell'app:

  1. Innanzitutto, determina se le dimensioni di download compresse dell'app devono essere superiori a 100 MB. Lo spazio è prezioso e dovresti ridurre al minimo le dimensioni totali di download. Se la tua app utilizza più di 100 MB per fornire più versioni delle risorse grafiche su più schermi densità, prendi in considerazione invece la pubblicazione di più APK in cui ogni APK contiene solo gli asset necessari per le schermate scelte come target. Per ottenere risultati ottimali quando quando pubblichi su Google Play, carica un Android App Bundle, include tutto il codice compilato e le risorse dell'app, ma rimanda la generazione dell'APK e l'accesso a Google Gioca.
  2. Determina quali risorse dell'app separare dall'APK e pacchettizzarle in un da utilizzare come file di espansione principale.

    Normalmente, dovresti usare il secondo file di espansione patch solo quando esegui aggiornamenti a nel file di espansione principale. Tuttavia, se le risorse superano il limite di 2 GB per l'istanza principale di espansione, puoi utilizzare il file patch per gli altri asset.

  3. Sviluppa l'app in modo che utilizzi le risorse dei file di espansione nella posizione dello spazio di archiviazione condiviso 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, poi leggili mediante il file zip di espansione dell'APK Raccolta.

  4. Aggiungi logica all'attività principale dell'app per verificare se i file di espansione sul dispositivo all'avvio. Se i file non sono presenti sul dispositivo, utilizza il servizio di licenza delle app di Google Play per richiedere URL per i 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 lo strumento Library per implementare il comportamento di download.

    Se crei un tuo servizio di download invece di utilizzare la libreria, tieni presente che non devono modificare il nome dei file di espansione e devono essere salvati nel posizione di archiviazione.

Una volta terminato lo sviluppo dell'app, segui la guida per Testare I tuoi file di espansione.

Regole e limitazioni

L'aggiunta di file di espansione APK è una funzione disponibile quando carichi l'app utilizzando in Play Console. Quando carichi l'app per la prima volta o aggiorni una che utilizza file di espansione, devi conoscere le regole e le limitazioni seguenti:

  1. Ogni file di espansione non può superare i 2 GB.
  2. Per scaricare i file di espansione da Google Play, l'utente deve avere acquisito la tua app da Google Play. Google Play non fornisci gli URL dei file di espansione, se l'app è stata installata in altri modi.
  3. Quando esegui il download dalla tua app, l'URL che Google Play fornisce per ogni file è univoco per ogni download e ogni file scade poco dopo l'invio alla tua app.
  4. Se aggiorni la tua app con un nuovo APK o carichi più APK per lo stesso APK. puoi selezionare i file di espansione caricati per un APK precedente. La il nome del file di espansione non cambia; la versione ricevuta dall'APK viene conservata per a cui il file era originariamente associato.
  5. Se utilizzi file di espansione insieme a più APK per: fornire file di espansione diversi per dispositivi diversi, devi comunque caricare APK separati per ogni dispositivo, in modo da offrire una versionCode e dichiarare filtri diversi per ogni APK.
  6. Non puoi inviare un aggiornamento dell'app modificando i file di espansione solo devi caricare un nuovo APK per aggiornare l'app. Se solo le modifiche riguardano le risorse presenti nei file di espansione, puoi aggiornare l'APK semplicemente modificando versionCode (e forse anche versionName).

  7. Non salvare altri dati nel tuo obb/ di Cloud Shell. Se devi decomprimere alcuni dati, salvali nella posizione specificata da getExternalFilesDir().
  8. Non eliminare o rinominare il file di espansione .obb (a meno che non eseguire un aggiornamento). Questa operazione comporterà l'esecuzione ripetuta di Google Play (o dell'app stessa) scarica il file di espansione.
  9. Quando aggiorni manualmente un file di espansione, devi eliminare il file di espansione precedente.

Scaricare i file di espansione

Nella maggior parte dei casi, Google Play scarica e salva i file di espansione sul dispositivo volta che installa o aggiorna l'APK. In questo modo, i file di espansione sono disponibili quando viene lanciata per la prima volta. In alcuni casi, però, è necessario che l'app scarichi di espansione stessa richiedendoli da un URL che ti è stato fornito in risposta dal servizio di licenza delle app di Google Play.

La logica di base necessaria per scaricare i file di espansione è la seguente:

  1. All'avvio dell'app, cerca i file di espansione nella posizione dello spazio di archiviazione condiviso (nella Android/obb/<package-name>/).
    1. Se i file di espansione sono presenti, è tutto pronto e l'app può continuare.
    2. Se i file di espansione non sono presenti:
        .
      1. Esegui una richiesta tramite il servizio di licenze delle app di Google Play per recuperare il tuo nomi, dimensioni e URL dei file di espansione dell'app.
      2. Utilizza gli URL forniti da Google Play per scaricare i file di espansione e salvare i file di espansione. Devi salvare i file nello spazio di archiviazione condiviso (Android/obb/<package-name>/) e utilizza lo stesso nome esatto del file fornito in base alla risposta di Google Play.

        Nota:l'URL fornito da Google Play per i tuoi file di espansione sono univoci per ogni download e ogni file scade poco dopo l'assegnazione la tua app.

Se la tua app è senza costi (non a pagamento), è probabile che tu non abbia utilizzato il servizio di licenza delle app. È principalmente progettati per consentirti di applicare norme sulle licenze per la tua app e assicurati che l'utente abbia il diritto di utilizzare l'app (è stato pagata legalmente su Google Play). Per facilitare la la funzionalità dei file di espansione, il servizio di licenze è stato migliorato alla tua app che include l'URL dei file di espansione dell'app ospitati su Google Play. Perciò, anche se la tua app è senza costi per gli utenti, devi includere il License Verification Library (LVL) per utilizzare i file di espansione APK. Naturalmente, se la tua app è senza costi, non devi imporre la verifica della licenza: devi solo libreria per eseguire la richiesta che restituisce l'URL dei file di espansione.

Nota: a prescindere dal fatto che la tua app sia senza costi o meno, Google Play restituisce gli URL del file di espansione solo se l'utente ha acquisito la tua app da Google Play.

Oltre al file LVL, è necessario un set di codice che scarica i file di espansione tramite una connessione HTTP e li salva nella posizione corretta nello spazio di archiviazione condiviso del dispositivo. Durante la creazione di questa procedura nella tua app, devi affrontare diversi problemi considerazione:

  • Lo spazio sul dispositivo potrebbe non essere sufficiente per i file di espansione, pertanto dovresti controllare prima di iniziare il download e avvisa l'utente se lo spazio non è sufficiente.
  • Il download di file deve avvenire in un servizio in background per evitare di bloccare l'utente un'interazione e consenti all'utente di uscire dall'app durante il download.
  • Durante la richiesta e il download possono verificarsi diversi errori che devi gestire con eleganza.
  • La connettività di rete può cambiare durante il download, quindi dovresti gestire tali modifiche e Se l'operazione viene interrotta, riprendi il download quando possibile.
  • Mentre il download avviene in background, dovresti fornire una notifica che ti informa che indica l'avanzamento del download, avvisa l'utente al termine dell'operazione e riporta l'utente alla l'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 licenze, scarica i file di espansione, esegue tutte le attività elencate sopra e consente perfino di mettere in pausa e riprendere scaricare l'app. Aggiungendo la Downloader Library e alcuni hook di codice alla tua app, quasi tutte le scaricare i file di espansione sono già stati codificati per te. Di conseguenza, per fornire il miglior esperienza utente con il minimo sforzo da parte tua, ti consigliamo di utilizzare la libreria di downloader per scarica i file di espansione. Le informazioni nelle sezioni seguenti spiegano come integrare dalla raccolta nella tua app.

Se preferisci sviluppare una tua soluzione per scaricare i file di espansione utilizzando l'interfaccia gli URL di Google Play, devi seguire le istruzioni dell'app Licenze per eseguire una richiesta di licenza, quindi recuperare i nomi dei file di espansione. dimensioni e URL degli extra della risposta. Devi usare la classe APKExpansionPolicy (inclusa nella Libreria di verifica delle licenze) come licenza. che acquisisce i nomi, le dimensioni e gli URL dei file di espansione dal servizio di licenze.

Informazioni su Downloader Library

Per utilizzare file di espansione APK con la tua app e offrire la migliore esperienza utente con impegno minimo da parte tua, ti consigliamo di utilizzare la libreria di download inclusa nella Pacchetto della libreria di espansione APK di Google Play. Questa raccolta scarica i file di espansione in un servizio in background, mostra una notifica all'utente con lo stato del download, gestisce la rete connettività, riprende il download quando possibile e altro ancora.

Per implementare il download dei file di espansione utilizzando la libreria di downloader, è sufficiente:

  • Estendi una sottoclasse Service e una sottoclasse BroadcastReceiver speciali, ciascuna delle quali richiede solo alcune righe di codice create da te.
  • Aggiungi all'attività principale una logica per verificare se i file di espansione hanno sono già stati scaricati e, in caso contrario, richiama il processo di download e visualizza una dell'interfaccia utente di avanzamento.
  • Implementare un'interfaccia di callback con alcuni metodi nell'attività principale che riceve aggiornamenti sull'avanzamento del download.

Le sezioni seguenti spiegano come configurare la tua app usando la libreria di downloader.

Preparazione all'utilizzo della libreria di downloader

Per utilizzare la libreria di downloader, devi: scaricare due pacchetti da SDK Manager e aggiungere le librerie appropriate dell'app.

Innanzitutto, apri Android SDK Manager. (Strumenti > SDK Manager) e in Aspetto e Comportamento > Impostazioni di sistema > SDK Android, seleziona nella scheda SDK Tools (Strumenti SDK) per selezionare e scaricare:

  • Pacchetto Raccolta di licenze di Google Play
  • Pacchetto Raccolta di espansione dell'APK di Google Play

Crea un nuovo modulo della libreria per la libreria di verifica delle licenze e il downloader Raccolta. Per ogni libreria:

  1. Seleziona File > Nuovo > Nuovo modulo.
  2. Nella finestra Crea nuovo modulo, seleziona Raccolta Android, e poi seleziona Avanti.
  3. Specifica un nome dell'app/della libreria, ad esempio "Libreria licenze Google Play". e "Libreria di download di Google Play", scegli Livello minimo di SDK e seleziona Fine.
  4. Seleziona File > Struttura del progetto.
  5. Seleziona la scheda Proprietà in Libreria Repository, inserisci la libreria dalla directory <sdk>/extras/google/ (play_licensing/ per la libreria di verifica della licenza o play_apk_expansion/downloader_library/ per la libreria dei downloader).
  6. Seleziona OK per creare il nuovo modulo.

Nota: la libreria dei downloader dipende dalla licenza Libreria di verifica. Assicurati di aggiungere la licenza Libreria Verifica alle proprietà del progetto della libreria di downloader.

In alternativa, aggiorna il progetto da una riga di comando in modo da includere le librerie:

  1. Cambia directory nella directory <sdk>/tools/.
  2. Esegui android update project con l'opzione --library per aggiungere entrambi gli elementi LVL e la libreria di downloader 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 della licenza e della libreria di downloader al tuo potrai integrare rapidamente la possibilità di scaricare file di espansione su Google Play. Il formato che scegli per i file di espansione e la modalità di lettura dello spazio di archiviazione condiviso è un'implementazione separata che dovreste prendere in considerazione in base alle vostre le esigenze dell'app.

Suggerimento: il pacchetto di espansione APK include un esempio app che mostra come utilizzare la libreria di downloader in un'app. L'esempio utilizza una terza libreria disponibile nel pacchetto di espansione APK chiamato APK Expansion Zip Library. Se hai intenzione di utilizzando i file ZIP per i file di espansione, ti consigliamo di aggiungere anche la libreria ZIP di espansione dell'APK a la tua app. Per ulteriori informazioni, consulta la sezione di seguito. sull'utilizzo della libreria ZIP di espansione APK.

Dichiarazione delle autorizzazioni utente

Per scaricare i file di espansione, la Raccolta per il downloader richiede diverse autorizzazioni che devi dichiarare nel file manifest dell'app. Loro 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 l'API. livello 4, ma la libreria Zip di espansione dell'APK richiede il livello API 5.

Implementazione del servizio di downloader

Per eseguire download in background, la libreria di downloader fornisce i suoi propria sottoclasse Service denominata DownloaderService da estendere. Nella oltre a scaricare automaticamente i file di espansione, DownloaderService:

  • Registra un BroadcastReceiver che rimane in ascolto delle modifiche all'elemento connettività di rete del dispositivo (CONNECTIVITY_ACTION broadcast) per mettere in pausa il download quando necessario (ad esempio a causa di una perdita di connettività) e riprendi il download quando possibile (la connettività viene acquisita).
  • Pianifica un allarme alle ore RTC_WAKEUP per riprovare il download i casi in cui il servizio viene interrotto.
  • Crea un Notification personalizzato che mostra l'avanzamento del download e errori o modifiche allo stato.
  • Consente all'app di mettere in pausa e riprendere il download manualmente.
  • Verifica che l'archiviazione condivisa sia montata e disponibile, che i file non esistano già. e che ci sia spazio sufficiente prima di scaricare i file di espansione. Avvisa quindi l'utente se una di queste condizioni non è vera.

Devi solo creare una classe nell'app che espanda la classe DownloaderService e sostituire tre metodi per fornire dettagli specifici dell'app:

getPublicKey()
Deve restituire una stringa che sia la chiave pubblica RSA codificata in Base64 per il tuo publisher disponibile nella pagina del profilo di Play Console (consulta la sezione Configurazione delle licenze).
getSALT()
Ciò deve restituire un array di byte casuali utilizzati da Policy con le licenze crea una Obfuscator. Il sale garantisce che la tua SharedPreferences offuscata del file in cui vengono salvati i dati delle licenze sarà univoco e non rilevabile.
getAlarmReceiverClassName()
È necessario restituire il nome della classe BroadcastReceiver in l'app che dovrebbe ricevere l'allarme che indica che il download è stato riavviato (il che potrebbe verificarsi se il servizio di downloader si arresta 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 BASE64_PUBLIC_KEY essere la chiave pubblica appartenente al tuo account publisher. Puoi trovare la chiave nella sezione Console sotto le informazioni del tuo profilo. Questa operazione è necessaria anche durante i test i tuoi download.

Ricordati di dichiarare il servizio nel file manifest:

<app ...>
    <service android:name=".SampleDownloaderService" />
    ...
</app>

Implementazione del ricevitore dell'allarme

Per monitorare l'avanzamento del download del file e, se necessario, riavviarlo, DownloaderService programma una sveglia alle RTC_WAKEUP che consegna un Intent a un BroadcastReceiver nel tuo dell'app. Devi definire il valore BroadcastReceiver per chiamare un'API dalla libreria di downloader che controlla lo stato del download e si 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 la quale devi restituire il nome. nel metodo getAlarmReceiverClassName() del tuo servizio (vedi la sezione precedente).

Ricordati di dichiarare il destinatario nel file manifest:

<app ...>
    <receiver android:name=".SampleAlarmReceiver" />
    ...
</app>

Avvio del download

L'attività principale nella tua app (quella avviata dall'icona in Avvio applicazioni) è responsabile di verificare se i file di espansione sono già sul dispositivo e di avviare se non lo sono.

Per avviare il download utilizzando la libreria di downloader è necessario quanto segue delle procedure:

  1. Controlla se i file sono stati scaricati.

    La libreria Downloader include alcune API nella classe Helper per assistenza in questa procedura:

    • 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 la classe seguente metodo nel metodo onCreate() dell'attività per controllare 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 XAPKFile contiene il numero di versione e le dimensioni del file di un file di espansione e un valore booleano per indicare se si tratta del file di espansione principale. (Guarda l'esempio corso SampleDownloaderActivity dell'app per i dettagli.)

    Se questo metodo restituisce false, l'app deve iniziare il download.

  2. Avvia il download chiamando il metodo statico DownloaderClientMarshaller.startDownloadServiceIfRequired(Context c, PendingIntent notificationClient, Class<?> serviceClass).

    Il metodo richiede i seguenti parametri:

    • context: il Context della tua app.
    • notificationClient: un PendingIntent per avviare la attività. Viene utilizzato in Notification che DownloaderService per mostrare l'avanzamento del download. Quando l'utente seleziona la notifica, il sistema richiama il PendingIntent che fornisci qui e dovrebbe aprire l'attività che mostra l'avanzamento del download (di solito la stessa attività in cui è stato avviato).
    • serviceClass: l'oggetto Class per l'implementazione delle DownloaderService, 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: viene restituito se i file sono già oppure un download è già in corso.
    • LVL_CHECK_REQUIRED: viene restituito se la verifica della licenza è necessaria per acquisire gli URL dei file di espansione.
    • DOWNLOAD_REQUIRED: viene restituito se gli URL dei file di espansione sono già noti. ma non sono stati scaricati.

    Il comportamento di LVL_CHECK_REQUIRED e DOWNLOAD_REQUIRED è essenzialmente e normalmente non devi preoccuparti di questi cambiamenti. Nella tua attività principale che chiama startDownloadServiceIfRequired(), puoi semplicemente controllare se la risposta è NO_DOWNLOAD_REQUIRED. Se la risposta è diversa da NO_DOWNLOAD_REQUIRED, la Libreria downloader avvia il download e dovresti aggiornare l'interfaccia utente delle attività con visualizzare l'avanzamento del download (vedi il passaggio successivo). Se la risposta è NO_DOWNLOAD_REQUIRED, i file sono disponibili e l'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
    }
    
  3. Quando il metodo startDownloadServiceIfRequired() restituisce un valore other rispetto a NO_DOWNLOAD_REQUIRED, crea un'istanza di IStub chiamata DownloaderClientMarshaller.CreateStub(IDownloaderClient client, Class<?> downloaderService). Il IStub fornisce un collegamento tra la tua attività al downloader in modo che la tua attività riceva un avviso sull'avanzamento del download.

    Per creare un'istanza del tuo IStub chiamando il numero CreateStub(), devi passarlo un'implementazione dell'interfaccia IDownloaderClient e di DownloaderService implementazione. La prossima sezione sulla ricezione dell'avanzamento dei download illustra l'interfaccia IDownloaderClient, che di solito dovresti implementare nella classe Activity, in modo da poter aggiornare la UI delle attività quando lo stato del download cambia.

    Ti consigliamo di chiamare CreateStub() per creare un'istanza del tuo IStub durante il metodo onCreate() dell'attività, dopo il giorno startDownloadServiceIfRequired() avvia il download.

    Ad esempio, nell'esempio di codice precedente di onCreate(), puoi rispondere al risultato startDownloadServiceIfRequired() 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;
            }
    

    Una volta restituito il metodo onCreate(), la tua attività riceve una chiamata al numero onResume(), che è dove dovresti allora chiama connect() su IStub, passando il Context della tua app. Al contrario, devi richiamare disconnect() nel callback onStop() della tua 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 di connect() su IStub vincola la tua attività a DownloaderService in modo che la tua attività riceva richiamate riguardo alle modifiche al download tramite l'interfaccia IDownloaderClient.

Avanzamento del download in corso...

Per ricevere aggiornamenti relativi all'avanzamento del download e interagire con DownloaderService, devi implementare l'interfaccia IDownloaderClient di Downloader Library. In genere, l'attività utilizzata per avviare il download deve implementare questa interfaccia per mostrare 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 per il IStub nella tua attività, riceverai una chiamata a questo che trasmette un oggetto Messenger connesso alla tua istanza di DownloaderService. Inviare richieste al servizio, ad esempio per mettere in pausa e riprendere download, devi chiamare DownloaderServiceMarshaller.CreateProxy() per ricevere l'interfaccia IDownloaderService collegata al servizio.

Un'implementazione consigliata ha questo 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 IDownloaderService inizializzato, puoi inviare comandi all'oggetto servizio di downloader, ad esempio per mettere in pausa e riprendere il download (requestPauseDownload() e requestContinueDownload()).

onDownloadStateChanged(int newState)
Il servizio di download chiama questo evento quando si verifica un cambiamento dello stato di download, ad esempio il download inizia o termina.

Il valore newState sarà uno dei vari possibili valori specificati in da una delle costanti STATE_* della classe IDownloaderClient.

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 in bundle con il downloader Raccolta. Ad esempio, la stringa "Download in pausa perché sei in roaming" corrisponde a STATE_PAUSED_ROAMING.

onDownloadProgress(DownloadProgressInfo progress)
Il servizio di download chiama questo per distribuire un oggetto DownloadProgressInfo, che descrive varie informazioni sull'avanzamento del download, tra cui il tempo rimanente stimato, la velocità attuale, l'avanzamento complessivo e il totale per poter aggiornare l'interfaccia utente di avanzamento del download.

Suggerimento:per esempi di queste richiamate che aggiornano il download avanzamento, controlla SampleDownloaderActivity nell'app di esempio fornita con Pacchetto di espansione APK.

Alcuni metodi pubblici per l'interfaccia IDownloaderService che potrebbero esserti utili sono:

requestPauseDownload()
Sospende il download.
requestContinueDownload()
Riprende un download in pausa.
setDownloadFlags(int flags)
Consente di impostare le preferenze utente per i tipi di rete su cui è possibile scaricare i file. La l'implementazione attuale supporta un flag, FLAGS_DOWNLOAD_OVER_CELLULAR, ma puoi aggiungere altri. Per impostazione predefinita, questo flag non è abilitato, quindi l'utente deve essere connesso a una rete Wi-Fi per eseguire il download file di espansione. Potresti indicare una preferenza utente per attivare i download su rete mobile. In tal 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 downloader invece di utilizzare Google Play Libreria dei downloader, devi comunque utilizzare il APKExpansionPolicy fornito nella libreria di verifica della licenza. Il corso APKExpansionPolicy è quasi identico a ServerManagedPolicy (disponibile nel Libreria di verifica delle licenze di Google Play), ma include funzionalità di gestione aggiuntive per l'espansione dell'APK risposte extra dei file.

Nota: se utilizzi la Libreria Downloader come discusso nella sezione precedente, che esegue tutte le interazioni con APKExpansionPolicy, pertanto non devi utilizzare per questo corso.

Il corso include metodi per aiutarti a ottenere le informazioni necessarie sui file di espansione:

  • getExpansionURLCount()
  • getExpansionURL(int index)
  • getExpansionFileName(int index)
  • getExpansionFileSize(int index)

Per ulteriori informazioni su come utilizzare APKExpansionPolicy quando non utilizzando Downloader Library, consulta la documentazione sull'aggiunta di licenze all'app. che spiega come implementare criteri di licenza come questo.

Lettura del file di espansione

Dopo aver salvato i file di espansione APK sul dispositivo, la modalità di lettura dei file dipende dal tipo di file utilizzato. Come discusso nella panoramica, di espansione possono essere qualsiasi tipo di file desiderato, ma vengono rinominati utilizzando un particolare formato per il nome file e vengono salvati <shared-storage>/Android/obb/<package-name>/.

Indipendentemente da come leggi i file, devi sempre controllare innanzitutto che l'interfaccia spazio di archiviazione disponibile per la lettura. È possibile che l'utente abbia lo spazio di archiviazione montato su computer tramite USB o che abbia effettivamente rimosso la scheda SD.

Nota: all'avvio dell'app dovresti sempre controllare se lo spazio di archiviazione esterno sia disponibile e leggibile chiamando getExternalStorageState(). Viene restituita una delle numerose stringhe possibili che rappresentano lo stato dell'unità di archiviazione esterna. Affinché sia leggibile dal tuo app, il valore restituito deve essere MEDIA_MOUNTED.

Recupero dei nomi dei file

Come descritto nella panoramica, i file di espansione APK vengono salvati utilizzando un formato di nome file specifico:

[main|patch].<expansion-version>.<package-name>.obb

Per individuare la posizione e i nomi dei file di espansione, devi utilizzare lo 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 a 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 passandolo alla tua app Context e la versione del file di espansione desiderata.

Esistono molti modi per determinare il numero di versione del file di espansione. Un modo semplice è salva la versione in un file SharedPreferences all'inizio del download, eseguendo una query sul nome del file di espansione con il metodo getExpansionFileName(int index) della classe APKExpansionPolicy. Puoi quindi ottenere il codice di versione leggendo il file SharedPreferences quando vuoi accedere all'espansione .

Per ulteriori informazioni sulla lettura dallo spazio di archiviazione condiviso, consulta la sezione Archiviazione dei dati. documentazione.

Utilizzo della libreria ZIP di espansione APK

Il pacchetto di espansione APK di Google Market include una libreria chiamata APK Espansione Zip Library (disponibile in <sdk>/extras/google/google_market_apk_expansion/zip_file/). Questa è una libreria facoltativa ti aiuta a leggere l'espansione quando vengono salvati come file ZIP. Questa libreria ti consente di leggere facilmente le risorse i file di espansione ZIP come file system virtuale.

La libreria ZIP di espansione dell'APK include i corsi e le API seguenti:

APKExpansionSupport
Offre 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 del file per entrambe le espansioni .
getAPKExpansionZipFile(Context ctx, int mainVersion, int patchVersion)
Restituisci un valore ZipResourceFile che rappresenta la somma sia del file principale che patch. In altre parole, se specifichi sia mainVersion sia patchVersion, viene restituito un ZipResourceFile che fornisce accesso in lettura a tutti i dati, con i dati del file patch uniti sopra il file principale.
ZipResourceFile
Rappresenta un file ZIP nello spazio di archiviazione condiviso ed esegue tutte le operazioni per fornire un basato sui tuoi file ZIP. Puoi ottenere un'istanza utilizzando APKExpansionSupport.getAPKExpansionZipFile() o con ZipResourceFile, passando il valore percorso del file di espansione. Questo corso include una varietà di metodi utili, ma in genere non hanno bisogno di accedere alla maggior parte di questi. Due metodi importanti sono:
getInputStream(String assetPath)
Fornisce un InputStream per leggere un file all'interno del file ZIP. La assetPath deve essere il percorso del file desiderato rispetto a la radice dei contenuti del file ZIP.
getAssetFileDescriptor(String assetPath)
Fornisce un AssetFileDescriptor per un file all'interno di ZIP. assetPath deve essere il percorso del file desiderato, relativo a la radice dei contenuti del file ZIP. Ciò è utile per alcune API Android che richiedono AssetFileDescriptor, ad esempio alcune API MediaPlayer.
APEZProvider
Per la maggior parte delle app non è necessario utilizzare questo corso. Questa classe definisce un ContentProvider che sottopone i dati ai file ZIP attraverso un contenuto il provider Uri per fornire l'accesso ai file per alcune API Android che è previsto l'accesso di Uri ai file multimediali. Ad esempio, questo è utile se vuoi riproduci un video con VideoView.setVideoURI().

Ignorare la compressione ZIP dei file multimediali

Se utilizzi i file di espansione per archiviare i file multimediali, il file ZIP ti consente comunque utilizza le chiamate di riproduzione di contenuti multimediali Android che offrono controlli di offset e lunghezza (come MediaPlayer.setDataSource() e SoundPool.load()). Per se questa operazione funziona, non devi eseguire una compressione aggiuntiva dei file multimediali durante la creazione del file ZIP pacchetti. Ad esempio, se usi lo strumento zip, dovresti usare -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 dell'APK, la lettura di un file dal file ZIP di solito richiede l'elemento seguenti:

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 consente di accedere a qualsiasi file presente nel file di espansione principale di espansione delle patch, leggendo da una mappa unita di tutti i file di entrambi i file. Tutto quello devi specificare il metodo getAPKExpansionFile() è android.content.Context dell'app e il numero di versione sia per il file di espansione principale sia per la patch file di espansione.

Se preferisci leggere da uno specifico file di espansione, 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 CRC. Se utilizzi questo campione come base per una tua implementazione, è necessario dichiarare le dimensioni in byte dell'espansione file nell'array xAPKS.

Test dei file di espansione

Prima di pubblicare un'app, dovresti verificare due aspetti: la lettura dello file di espansione e scaricarli.

Test delle letture dei file in corso...

Prima di caricare l'app su Google Play, devi dovrebbe testare la capacità dell'app di leggere i file dallo spazio di archiviazione condiviso. Tutto ciò che devi fare è aggiungere i file nella posizione appropriata sullo spazio di archiviazione condiviso del dispositivo e avviare la dell'app:

  1. 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 nella directory Android/obb/com.example.android/ dello spazio di archiviazione condiviso. (collega il dispositivo di test sul computer per montare lo spazio di archiviazione condiviso e crearlo manualmente .)

  2. Aggiungi manualmente i file di espansione alla directory. Assicurati di rinominare i file in corrispondere al formato del nome file utilizzato da Google Play.

    Ad esempio, indipendentemente dal tipo di file, il file di espansione principale per l'app com.example.android deve essere main.0300110.com.example.android.obb. Il codice di versione può essere qualsiasi valore desideri. Ricorda:

    • Il file di espansione principale inizia sempre con main, mentre il file patch inizia con patch.
    • Il nome del pacchetto corrisponde sempre a quello dell'APK a cui è allegato il file su Google Play.
  3. Ora che i file di espansione sono 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 decomprimili. i dati in una posizione diversa). Così facendo, Google Play (o la tua app stessa) scarica ripetutamente il file di espansione.
  • Non salvare altri dati nel tuo obb/ di Cloud Shell. Se devi decomprimere alcuni dati, salvali nella posizione specificata da getExternalFilesDir().

Test dei download di file

Perché a volte l'app deve scaricare manualmente i file di espansione quando viene si apre, è importante testare questa procedura per assicurarti che la tua app possa eseguire query degli URL, scarica i file e salvali sul dispositivo.

Per testare l'implementazione della procedura di download manuale nella tua app: puoi pubblicarlo nel canale di test interno, in modo che sia disponibile solo tester autorizzati. Se tutto funziona come previsto, la tua app dovrebbe il download dei file di espansione non appena inizia l'attività principale.

Nota: in precedenza potevi testare un'app Caricare una "bozza" non pubblicata completamente gestita. Questa funzionalità non è più supportati. Devi invece pubblicarlo in un test interno, chiuso o aperto traccia. Per ulteriori informazioni, vedi Le bozze di app non sono Supporto più lungo.

Aggiornamento dell'app

Uno dei grandi vantaggi dell'utilizzo dei file di espansione su Google Play è la possibilità di aggiornare l'app senza dover scaricare nuovamente tutti gli asset originali. Poiché Google Play consente di fornire due file di espansione per ogni APK, puoi usare il secondo file come "patch" che fornisce aggiornamenti e nuove risorse. In questo modo si evitano scaricare di nuovo il file di espansione principale, che potrebbe essere costoso e di grandi dimensioni per gli utenti.

Il file di espansione patch è tecnicamente uguale al file di espansione principale e nessuno dei due il sistema Android e Google Play eseguono l'applicazione effettiva delle patch tra l'espansione principale e quella della patch. . Il codice dell'app deve eseguire automaticamente le patch necessarie.

Se utilizzi i file ZIP come file di espansione, il file Zip di espansione dell'APK La libreria inclusa nel pacchetto di espansione APK include la possibilità di unire tuo con il file di espansione principale.

Nota:anche se devi solo apportare modifiche alla patch devi comunque aggiornare l'APK per consentire a Google Play di eseguire un aggiornamento. Se non sono necessarie modifiche al codice nell'app, ti basta aggiornare versionCode nella del file manifest.

A condizione che non modifichi il file di espansione principale associato all'APK. nella Play Console, gli utenti che avevano già installato la tua app non scarica il file di espansione principale. Gli utenti esistenti ricevono solo l'APK aggiornato e la nuova patch file di espansione (conserva il file di espansione principale precedente).

Di seguito sono riportati alcuni problemi da tenere presenti in merito agli aggiornamenti ai file di espansione:

  • L'app può contenere solo due file di espansione alla volta. Un'espansione principale e un file di espansione patch. Durante un aggiornamento di un file, Google Play elimina il file precedente (così come la tua app quando esegui aggiornamenti manuali).
  • Quando aggiungi un file di espansione patch, il sistema Android non applica effettivamente le patch o file di espansione principale. Devi progettare l'app in modo che supporti i dati delle 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 al file di espansione principale. puoi leggere facilmente tutti i dati del file di espansione.