Configura la pubblicazione on demand

I moduli delle caratteristiche consentono di separare determinate funzionalità e risorse dal modulo di base dell'app e includerle nell'app bundle. Tramite Play Feature Delivery, gli utenti possono, ad esempio, scaricare e installare in un secondo momento questi componenti on demand dopo aver già installato l'APK di base dell'app.

Ad esempio, prendi in considerazione un'app di messaggistica che includa funzionalità per l'acquisizione e l'invio di messaggi con immagini, ma solo una piccola percentuale di utenti invia messaggi con immagine. Può essere utile includere messaggi con immagini come modulo di funzionalità scaricabile. In questo modo, il download iniziale dell'app risulta ridotto per tutti gli utenti e solo gli utenti che inviano messaggi con immagini devono scaricare il componente aggiuntivo.

Tieni presente che questo tipo di modularizzazione richiede uno sforzo maggiore ed eventualmente il refactoring del codice esistente della tua app, quindi valuta con attenzione quali funzionalità della tua app trarrebbero il massimo vantaggio dalla disponibilità per gli utenti on demand. Per comprendere meglio i casi d'uso ottimali e le linee guida per le funzionalità on demand, leggi le best practice per l'esperienza utente per la distribuzione on demand.

Se vuoi modularizzare gradualmente le funzionalità delle app nel tempo, senza abilitare opzioni di distribuzione avanzate, ad esempio la pubblicazione on demand, configura la distribuzione al momento dell'installazione.

Questa pagina ti aiuta ad aggiungere un modulo delle funzionalità al progetto dell'app e a configurarlo per la distribuzione on demand. Prima di iniziare, assicurati di utilizzare Android Studio 3.5 o versioni successive e il plug-in Android per Gradle 3.5.0 o versioni successive.

Configura un nuovo modulo per la distribuzione on demand

Il modo più semplice per creare un nuovo modulo di funzionalità è utilizzare Android Studio 3.5 o una versione successiva. Poiché i moduli delle funzionalità hanno una dipendenza intrinseca dal modulo dell'app di base, puoi aggiungerli solo ai progetti di app esistenti.

Per aggiungere un modulo delle funzionalità al progetto dell'app utilizzando Android Studio, procedi come segue:

  1. Se non l'hai ancora fatto, apri il progetto dell'app nell'IDE.
  2. Seleziona File > Nuovo > Nuovo modulo dalla barra dei menu.
  3. Nella finestra di dialogo Crea nuovo modulo, seleziona Modulo delle funzionalità dinamiche e fai clic su Avanti.
  4. Nella sezione Configura il tuo nuovo modulo, completa quanto segue:
    1. Seleziona il modulo di applicazione di base per il progetto dell'app dal menu a discesa.
    2. Specifica un Nome modulo. L'IDE utilizza questo nome per identificare il modulo come sottoprogetto Gradle nel file delle impostazioni di Gradle. Quando crei l'app bundle, Gradle utilizza l'ultimo elemento del nome del sottoprogetto per inserire l'attributo <manifest split> nel manifest del modulo delle funzionalità.
    3. Specifica il nome del pacchetto del modulo. Per impostazione predefinita, Android Studio suggerisce un nome del pacchetto che combina il nome del pacchetto principale del modulo di base e il nome del modulo specificato nel passaggio precedente.
    4. Seleziona il Livello API minimo che il modulo deve supportare. Questo valore deve corrispondere a quello del modulo di base.
  5. Fai clic su Avanti.
  6. Nella sezione Opzioni di download del modulo, completa i seguenti passaggi:

    1. Specifica il Titolo del modulo utilizzando fino a 50 caratteri. La piattaforma utilizza questo titolo per identificare il modulo per gli utenti quando, ad esempio, per confermare se l'utente vuole scaricare il modulo. Per questo motivo, il modulo di base dell'app deve includere il titolo del modulo come una risorsa stringa, che puoi tradurre. Quando crei il modulo utilizzando Android Studio, l'IDE aggiunge automaticamente la risorsa stringa al modulo di base e inserisce la seguente voce nel manifest del modulo delle funzionalità:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. Nel menu a discesa in Inclusione al momento dell'installazione, seleziona Non includere il modulo al momento dell'installazione. Android Studio inserisce quanto segue nel manifest del modulo per riflettere la tua scelta:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. Seleziona la casella accanto a Fusing se vuoi che il modulo sia disponibile per i dispositivi con Android 4.4 (livello API 20) e versioni precedenti e inclusi in APK multipli. Ciò significa che puoi abilitare il comportamento on demand per questo modulo e disattivare l'unione per ometterlo dai dispositivi che non supportano il download e l'installazione di APK divisi. Android Studio inserisce quanto segue nel manifest del modulo per riflettere la tua scelta:

      <dist:module ...>
          <dist:fusing dist:include="true | false" />
      </dist:module>
      
  7. Fai clic su Fine.

Dopo che Android Studio ha completato la creazione del modulo, controllane i contenuti dal riquadro Progetto (seleziona Visualizza > Finestre degli strumenti > Progetto dalla barra dei menu). Il codice, le risorse e l'organizzazione predefiniti devono essere simili a quelli del modulo standard dell'app.

Dovrai poi implementare la funzionalità di installazione on demand utilizzando la libreria Play Feature Delivery.

Includi la libreria di Feature Delivery di Play nel tuo progetto

Prima di iniziare, devi aggiungere la libreria di Delivery Feature Delivery di Play al tuo progetto.

Richiedi un modulo on demand

Quando l'app deve utilizzare un modulo delle funzionalità, può richiederne uno mentre è in primo piano tramite la classe SplitInstallManager. Quando effettui una richiesta, l'app deve specificare il nome del modulo come definito dall'elemento split nel file manifest del modulo target. Quando crei un modulo di funzionalità utilizzando Android Studio, il sistema di compilazione utilizza il nome del modulo fornito per inserire questa proprietà nel manifest del modulo al momento della compilazione. Per ulteriori informazioni, consulta la sezione sui manifest dei moduli delle caratteristiche.

Ad esempio, prendiamo in considerazione un'app che dispone di un modulo on demand per acquisire e inviare messaggi con immagini utilizzando la fotocamera del dispositivo e questo modulo on demand specifica split="pictureMessages" nel file manifest. Il seguente esempio utilizza SplitInstallManager per richiedere il modulo pictureMessages (insieme a un modulo aggiuntivo per alcuni filtri promozionali):

Kotlin

// Creates an instance of SplitInstallManager.
val splitInstallManager = SplitInstallManagerFactory.create(context)

// Creates a request to install a module.
val request =
    SplitInstallRequest
        .newBuilder()
        // You can download multiple on demand modules per
        // request by invoking the following method for each
        // module you want to install.
        .addModule("pictureMessages")
        .addModule("promotionalFilters")
        .build()

splitInstallManager
    // Submits the request to install the module through the
    // asynchronous startInstall() task. Your app needs to be
    // in the foreground to submit the request.
    .startInstall(request)
    // You should also be able to gracefully handle
    // request state changes and errors. To learn more, go to
    // the section about how to Monitor the request state.
    .addOnSuccessListener { sessionId -> ... }
    .addOnFailureListener { exception ->  ... }

Java

// Creates an instance of SplitInstallManager.
SplitInstallManager splitInstallManager =
    SplitInstallManagerFactory.create(context);

// Creates a request to install a module.
SplitInstallRequest request =
    SplitInstallRequest
        .newBuilder()
        // You can download multiple on demand modules per
        // request by invoking the following method for each
        // module you want to install.
        .addModule("pictureMessages")
        .addModule("promotionalFilters")
        .build();

splitInstallManager
    // Submits the request to install the module through the
    // asynchronous startInstall() task. Your app needs to be
    // in the foreground to submit the request.
    .startInstall(request)
    // You should also be able to gracefully handle
    // request state changes and errors. To learn more, go to
    // the section about how to Monitor the request state.
    .addOnSuccessListener(sessionId -> { ... })
    .addOnFailureListener(exception -> { ... });

Quando la tua app richiede un modulo on demand, la libreria di distribuzione delle caratteristiche di Google Play utilizza una strategia "infuocato". In altre parole, invia la richiesta di download del modulo alla piattaforma, ma non monitora se l'installazione è riuscita. Per far progredire il percorso dell'utente dopo l'installazione o per gestire correttamente gli errori, assicurati di monitorare lo stato della richiesta.

Nota: puoi richiedere un modulo delle funzionalità già installato sul dispositivo. L'API considera immediatamente la richiesta completata se rileva che il modulo è già installato. Inoltre, dopo l'installazione di un modulo, Google Play lo mantiene aggiornato automaticamente. In altre parole, quando carichi una nuova versione dell'app bundle, la piattaforma aggiorna tutti gli APK installati che appartengono all'app. Per saperne di più, consulta Gestire gli aggiornamenti delle app.

Per avere accesso al codice e alle risorse del modulo, l'app deve abilitare SplitCompat. Tieni presente che SplitCompat non è obbligatorio per le app istantanee Android.

Rimanda l'installazione dei moduli on demand

Se non hai bisogno che la tua app scarichi e installi immediatamente un modulo on demand, puoi posticipare l'installazione quando l'app sarà in background. Ad esempio, se vuoi precaricare del materiale promozionale per un lancio successivo della tua app.

Puoi specificare un modulo da scaricare in un secondo momento utilizzando il metodo deferredInstall(), come mostrato di seguito. Inoltre, a differenza di SplitInstallManager.startInstall(), non è necessario che la tua app sia in primo piano per avviare una richiesta di installazione differita.

Kotlin

// Requests an on demand module to be downloaded when the app enters
// the background. You can specify more than one module at a time.
splitInstallManager.deferredInstall(listOf("promotionalFilters"))

Java

// Requests an on demand module to be downloaded when the app enters
// the background. You can specify more than one module at a time.
splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));

Le richieste di installazioni differite vengono eseguite secondo il criterio del "best effort" e non è possibile monitorarne l'avanzamento. Quindi, prima di provare ad accedere a un modulo specificato per l'installazione differita, devi verificare che il modulo sia stato installato. Se vuoi che il modulo sia disponibile immediatamente, utilizza SplitInstallManager.startInstall() per richiederlo, come mostrato nella sezione precedente.

Monitora lo stato della richiesta

Per poter aggiornare una barra di avanzamento, attivare un intent dopo l'installazione o gestire agevolmente un errore di richiesta, devi rimanere in ascolto degli aggiornamenti di stato relativi all'attività SplitInstallManager.startInstall() asincrona. Prima di poter iniziare a ricevere aggiornamenti per la richiesta di installazione, registra un ascoltatore e ottieni l'ID sessione per la richiesta, come mostrato di seguito.

Kotlin

// Initializes a variable to later track the session ID for a given request.
var mySessionId = 0

// Creates a listener for request status updates.
val listener = SplitInstallStateUpdatedListener { state ->
    if (state.sessionId() == mySessionId) {
      // Read the status of the request to handle the state update.
    }
}

// Registers the listener.
splitInstallManager.registerListener(listener)

...

splitInstallManager
    .startInstall(request)
    // When the platform accepts your request to download
    // an on demand module, it binds it to the following session ID.
    // You use this ID to track further status updates for the request.
    .addOnSuccessListener { sessionId -> mySessionId = sessionId }
    // You should also add the following listener to handle any errors
    // processing the request.
    .addOnFailureListener { exception ->
        // Handle request errors.
    }

// When your app no longer requires further updates, unregister the listener.
splitInstallManager.unregisterListener(listener)

Java

// Initializes a variable to later track the session ID for a given request.
int mySessionId = 0;

// Creates a listener for request status updates.
SplitInstallStateUpdatedListener listener = state -> {
    if (state.sessionId() == mySessionId) {
      // Read the status of the request to handle the state update.
    }
};

// Registers the listener.
splitInstallManager.registerListener(listener);

...

splitInstallManager
    .startInstall(request)
    // When the platform accepts your request to download
    // an on demand module, it binds it to the following session ID.
    // You use this ID to track further status updates for the request.
    .addOnSuccessListener(sessionId -> { mySessionId = sessionId; })
    // You should also add the following listener to handle any errors
    // processing the request.
    .addOnFailureListener(exception -> {
        // Handle request errors.
    });

// When your app no longer requires further updates, unregister the listener.
splitInstallManager.unregisterListener(listener);

Gestire gli errori delle richieste

Tieni presente che a volte l'installazione on demand dei moduli delle funzionalità può non riuscire, proprio come l'installazione delle app non sempre va a buon fine. La mancata installazione può essere dovuta a problemi quali spazio di archiviazione insufficiente, nessuna connettività di rete o l'utente non ha eseguito l'accesso al Google Play Store. Per suggerimenti su come gestire queste situazioni in modo efficiente dal punto di vista dell'utente, consulta le nostre linee guida per l'esperienza utente per la distribuzione on demand.

A livello di codice, devi gestire gli errori di download o installazione di un modulo utilizzando addOnFailureListener(), come mostrato di seguito:

Kotlin

splitInstallManager
    .startInstall(request)
    .addOnFailureListener { exception ->
        when ((exception as SplitInstallException).errorCode) {
            SplitInstallErrorCode.NETWORK_ERROR -> {
                // Display a message that requests the user to establish a
                // network connection.
            }
            SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED -> checkForActiveDownloads()
            ...
        }
    }

fun checkForActiveDownloads() {
    splitInstallManager
        // Returns a SplitInstallSessionState object for each active session as a List.
        .sessionStates
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // Check for active sessions.
                for (state in task.result) {
                    if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
                        // Cancel the request, or request a deferred installation.
                    }
                }
            }
        }
}

Java

splitInstallManager
    .startInstall(request)
    .addOnFailureListener(exception -> {
        switch (((SplitInstallException) exception).getErrorCode()) {
            case SplitInstallErrorCode.NETWORK_ERROR:
                // Display a message that requests the user to establish a
                // network connection.
                break;
            case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED:
                checkForActiveDownloads();
            ...
    });

void checkForActiveDownloads() {
    splitInstallManager
        // Returns a SplitInstallSessionState object for each active session as a List.
        .getSessionStates()
        .addOnCompleteListener( task -> {
            if (task.isSuccessful()) {
                // Check for active sessions.
                for (SplitInstallSessionState state : task.getResult()) {
                    if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
                        // Cancel the request, or request a deferred installation.
                    }
                }
            }
        });
}

Nella tabella seguente sono descritti gli stati di errore che la tua app potrebbe dover gestire:

Codice di errore Descrizione Azione suggerita
ACTIVE_SESSIONS_LIMIT_EXCEEDED La richiesta è stata rifiutata perché esiste almeno una richiesta attualmente in fase di download. Controlla se sono presenti richieste ancora in fase di download, come mostrato nell'esempio sopra.
MODULE_UNAVAILABLE Google Play non riesce a trovare il modulo richiesto in base alla versione corrente installata dell'app, del dispositivo e dell'account Google Play dell'utente. Se l'utente non ha accesso al modulo, inviagli una notifica.
RICHIESTA_NON_VALIDA Google Play ha ricevuto la richiesta, ma non è valida. Verifica che le informazioni incluse nella richiesta siano complete e accurate.
SESSION_NOT_FOUND Impossibile trovare una sessione per un determinato ID sessione. Se stai cercando di monitorare lo stato di una richiesta in base al relativo ID sessione, assicurati che l'ID sessione sia corretto.
API_NOT_AVAILABLE La libreria di Delivery Feature Delivery di Play non è supportata sul dispositivo corrente. Ciò significa che il dispositivo non può scaricare e installare funzionalità on demand. Per i dispositivi con Android 4.4 (livello API 20) o versioni precedenti, ti consigliamo di includere i moduli delle funzionalità al momento dell'installazione utilizzando la proprietà manifest dist:fusing. Per saperne di più, consulta ulteriori informazioni sul manifest del modulo delle funzionalità.
ERRORE_RETE Richiesta non riuscita a causa di un errore di rete. Chiedi all'utente di stabilire una connessione di rete o di passare a un'altra rete.
ACCESSO_NEGATO L'app non è in grado di registrare la richiesta a causa di autorizzazioni insufficienti. In genere questo accade quando l'app è in background. Prova a eseguire la richiesta quando l'app torna in primo piano.
INCOMPATIBLE_WITH_EXISTING_SESSION La richiesta contiene uno o più moduli che sono già stati richiesti, ma non sono ancora stati installati. Crea una nuova richiesta che non includa i moduli già richiesti dalla tua app o attendi il completamento dell'installazione di tutti i moduli attualmente richiesti prima di riprovare.

Tieni presente che la richiesta di un modulo già installato non risolve un errore.

SERVICE_DIED Il servizio responsabile della gestione della richiesta è stato disattivato. Riprova a inviare la richiesta.

Il tuo SplitInstallStateUpdatedListener riceve un SplitInstallSessionState con questo codice di errore, stato FAILED e ID sessione -1.

SPAZIO_DI_SPAZIO_INSUFFICIENTE Lo spazio di archiviazione libero sul dispositivo non è sufficiente per installare il modulo delle funzionalità. Comunica all'utente che non dispone di spazio di archiviazione sufficiente per installare questa funzionalità.
SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR SplitCompat non può caricare il modulo della funzionalità. Questi errori dovrebbero risolversi automaticamente al riavvio successivo dell'app.
PLAY_STORE_NOT_FOUND L'app Play Store non è installata sul dispositivo. Comunica all'utente che per scaricare questa funzionalità è necessaria l'app Play Store.
APP_NON_PROPRIA L'app non è stata installata da Google Play e la funzionalità non può essere scaricata. Questo errore si può verificare solo per le installazioni differite. Se vuoi che l'utente acquisisca l'app su Google Play, utilizza startInstall(), che può ottenere la conferma dell'utente necessaria.
ERRORE_INTERNO Si è verificato un errore interno nel Play Store. Riprova a inviare la richiesta.

Se un utente richiede il download di un modulo on demand e si verifica un errore, puoi visualizzare una finestra di dialogo che fornisca due opzioni per l'utente: Riprova (che tenta di nuovo la richiesta) e Annulla (che abbandona la richiesta). Per ulteriore assistenza, dovresti anche fornire il link della Guida che indirizza gli utenti al Centro assistenza Google Play.

Gestire gli aggiornamenti dello stato

Dopo aver registrato un listener e registrato l'ID sessione per la tua richiesta, utilizza StateUpdatedListener.onStateUpdate() per gestire le modifiche dello stato, come mostrato di seguito.

Kotlin

override fun onStateUpdate(state : SplitInstallSessionState) {
    if (state.status() == SplitInstallSessionStatus.FAILED
        && state.errorCode() == SplitInstallErrorCode.SERVICE_DIED) {
       // Retry the request.
       return
    }
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            SplitInstallSessionStatus.DOWNLOADING -> {
              val totalBytes = state.totalBytesToDownload()
              val progress = state.bytesDownloaded()
              // Update progress bar.
            }
            SplitInstallSessionStatus.INSTALLED -> {

              // After a module is installed, you can start accessing its content or
              // fire an intent to start an activity in the installed module.
              // For other use cases, see access code and resources from installed modules.

              // If the request is an on demand module for an Android Instant App
              // running on Android 8.0 (API level 26) or higher, you need to
              // update the app context using the SplitInstallHelper API.
            }
        }
    }
}

Java

@Override
public void onStateUpdate(SplitInstallSessionState state) {
    if (state.status() == SplitInstallSessionStatus.FAILED
        && state.errorCode() == SplitInstallErrorCode.SERVICE_DIES) {
       // Retry the request.
       return;
    }
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            case SplitInstallSessionStatus.DOWNLOADING:
              int totalBytes = state.totalBytesToDownload();
              int progress = state.bytesDownloaded();
              // Update progress bar.
              break;

            case SplitInstallSessionStatus.INSTALLED:

              // After a module is installed, you can start accessing its content or
              // fire an intent to start an activity in the installed module.
              // For other use cases, see access code and resources from installed modules.

              // If the request is an on demand module for an Android Instant App
              // running on Android 8.0 (API level 26) or higher, you need to
              // update the app context using the SplitInstallHelper API.
        }
    }
}

Gli stati possibili per la richiesta di installazione sono descritti nella tabella seguente.

Stato richiesta Descrizione Azione suggerita
IN ATTESA La richiesta è stata accettata e il download dovrebbe iniziare a breve. Inizializza i componenti dell'interfaccia utente, ad esempio una barra di avanzamento, per fornire all'utente un feedback sul download.
REQUIRES_USER_CONFERMA Il download richiede la conferma dell'utente. Più di solito questo stato si verifica se l'app non è stata installata tramite Google Play. Chiedi all'utente di confermare il download della funzionalità tramite Google Play. Per scoprire di più, vai alla sezione su come ottenere la conferma dell'utente.
DOWNLOAD Download in corso. Se fornisci una barra di avanzamento del download, utilizza i metodi SplitInstallSessionState.bytesDownloaded() e SplitInstallSessionState.totalBytesToDownload() per aggiornare l'interfaccia utente (vedi l'esempio di codice sopra questa tabella).
SCARICATI Il dispositivo ha scaricato il modulo, ma l'installazione non è ancora iniziata. Le app devono abilitare SplitCompat per avere accesso ai moduli scaricati ed evitare di visualizzare questo stato. Questa operazione è necessaria per accedere al codice e alle risorse del modulo delle funzionalità.
INSTALLAZIONE Il dispositivo sta installando il modulo. Aggiorna la barra di avanzamento. In genere questo stato è breve.
INSTALLATA Il modulo è installato sul dispositivo. Accedi al codice e alla risorsa nel modulo per continuare il percorso dell'utente.

Se il modulo riguarda un'app istantanea Android con Android 8.0 (livello API 26) o versioni successive, devi usare splitInstallHelper per aggiornare i componenti dell'app con il nuovo modulo.

CONVALIDA NON RIUSCITA La richiesta non è riuscita prima dell'installazione del modulo sul dispositivo. Chiedi all'utente di riprovare o annullarla.
ANNULLAMENTO Il dispositivo sta per annullare la richiesta. Per scoprire di più, consulta la sezione su come annullare una richiesta di installazione.
CANCELLATO La richiesta è stata annullata.

Ottenere conferma dell'utente

In alcuni casi, Google Play potrebbe richiedere la conferma dell'utente prima di soddisfare una richiesta di download. Ad esempio, se l'app non è stata installata da Google Play o se stai tentando di eseguire un download di grandi dimensioni tramite dati mobili. In questi casi, lo stato dei report delle richieste è REQUIRES_USER_CONFIRMATION e l'app deve ottenere la conferma dell'utente prima che il dispositivo possa scaricare e installare i moduli della richiesta. Per ottenere conferma, l'app deve chiedere all'utente di procedere nel seguente modo:

Kotlin

override fun onSessionStateUpdate(state: SplitInstallSessionState) {
    if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
        // Displays a confirmation for the user to confirm the request.
        splitInstallManager.startConfirmationDialogForResult(
          state,
          // an activity result launcher registered via registerForActivityResult
          activityResultLauncher)
    }
    ...
 }

Java

@Override void onSessionStateUpdate(SplitInstallSessionState state) {
    if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
        // Displays a confirmation for the user to confirm the request.
        splitInstallManager.startConfirmationDialogForResult(
          state,
          // an activity result launcher registered via registerForActivityResult
          activityResultLauncher);
    }
    ...
 }

Puoi registrare un'app per l'avvio dei risultati di attività utilizzando il contratto integrato ActivityResultContracts.StartIntentSenderForResult. Vedi API dei risultati delle attività.

Lo stato della richiesta viene aggiornato in base alla risposta dell'utente:

  • Se l'utente accetta la conferma, lo stato della richiesta diventa PENDING e il download prosegue.
  • Se l'utente nega la conferma, lo stato della richiesta diventa CANCELED.
  • Se l'utente non effettua una selezione prima che la finestra di dialogo venga eliminata, lo stato della richiesta rimane REQUIRES_USER_CONFIRMATION. L'app può chiedere all'utente di completare nuovamente la richiesta.

Per ricevere un callback con la risposta dell'utente, puoi ignorare l'ActivityResultCallback come mostrato di seguito.

Kotlin

registerForActivityResult(StartIntentSenderForResult()) { result: ActivityResult -> {
        // Handle the user's decision. For example, if the user selects "Cancel",
        // you may want to disable certain functionality that depends on the module.
    }
}

Java

registerForActivityResult(
    new ActivityResultContracts.StartIntentSenderForResult(),
    new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            // Handle the user's decision. For example, if the user selects "Cancel",
            // you may want to disable certain functionality that depends on the module.
        }
    });

Annullare una richiesta di installazione

Se la tua app deve annullare una richiesta prima di essere installata, può richiamare il metodo cancelInstall() utilizzando l'ID sessione della richiesta, come mostrato di seguito.

Kotlin

splitInstallManager
    // Cancels the request for the given session ID.
    .cancelInstall(mySessionId)

Java

splitInstallManager
    // Cancels the request for the given session ID.
    .cancelInstall(mySessionId);

Accedi ai moduli

Per accedere al codice e alle risorse di un modulo scaricato dopo averlo scaricato, l'app deve abilitare la libreria SplitCompat sia per l'app sia per ogni attività nei moduli delle funzionalità scaricati dall'app.

Tuttavia, tieni presente che la piattaforma è soggetta alle seguenti restrizioni per quanto riguarda l'accesso ai contenuti di un modulo per un certo periodo di tempo (in alcuni casi, giorni) dopo il download del modulo:

  • La piattaforma non può applicare nuove voci del manifest introdotte dal modulo.
  • La piattaforma non può accedere alle risorse del modulo per i componenti dell'interfaccia utente di sistema, come le notifiche. Se devi usare queste risorse immediatamente, puoi includerle nel modulo di base dell'app.

Attiva SplitCompat

Affinché l'app possa accedere a codice e risorse da un modulo scaricato, devi abilitare SplitCompat utilizzando solo uno dei metodi descritti nelle seguenti sezioni.

Dopo aver abilitato SplitCompat per la tua app, devi anche abilitare SplitCompat per ogni attività nei moduli delle funzionalità a cui vuoi che l'app abbia accesso.

Dichiara SplitCompatApplication nel file manifest

Il modo più semplice per abilitare SplitCompat è dichiarare SplitCompatApplication come sottoclasse Application nel file manifest dell'app, come mostrato di seguito:

<application
    ...
    android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>

Dopo aver installato l'app su un dispositivo, puoi accedere automaticamente al codice e alle risorse dei moduli delle funzionalità scaricati.

Richiama SplitCompat in fase di runtime

Puoi anche attivare SplitCompat in attività o servizi specifici in fase di runtime. È necessario abilitare SplitCompat in questo modo per avviare le attività incluse nei moduli delle caratteristiche. Per farlo, esegui l'override di attachBaseContext come mostrato di seguito.

Se disponi di una classe Application personalizzata, estendela a SplitCompatApplication per attivare SplitCompat per la tua app, come mostrato di seguito:

Kotlin

class MyApplication : SplitCompatApplication() {
    ...
}

Java

public class MyApplication extends SplitCompatApplication {
    ...
}

SplitCompatApplication sostituisce semplicemente ContextWrapper.attachBaseContext() per includere SplitCompat.install(Context applicationContext). Se non vuoi che la classe Application estenda SplitCompatApplication, puoi sostituire manualmente il metodo attachBaseContext() come segue:

Kotlin

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of future on demand modules using SplitCompat.
    SplitCompat.install(this);
}

Se il modulo on demand è compatibile sia con le app istantanee sia con le app installate, puoi richiamare SplitCompat in modo condizionale come segue:

Kotlin

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    if (!InstantApps.isInstantApp(this)) {
        SplitCompat.install(this)
    }
}

Java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    if (!InstantApps.isInstantApp(this)) {
        SplitCompat.install(this);
    }
}

Abilita SplitCompat per le attività del modulo

Dopo aver abilitato SplitCompat per l'app di base, devi abilitare SplitCompat per ogni attività scaricata dall'app in un modulo delle funzionalità. Per farlo, utilizza il metodo SplitCompat.installActivity(), come segue:

Kotlin

override fun attachBaseContext(base: Context) {
    super.attachBaseContext(base)
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // Emulates installation of on demand modules using SplitCompat.
    SplitCompat.installActivity(this);
}

Componenti di accesso definiti nei moduli delle funzionalità

Avvia un'attività definita in un modulo della funzionalità

Puoi avviare le attività definite nei moduli delle funzionalità utilizzando startActivity() dopo aver abilitato SplitCompat.

Kotlin

startActivity(Intent()
  .setClassName("com.package", "com.package.module.MyActivity")
  .setFlags(...))

Java

startActivity(new Intent()
  .setClassName("com.package", "com.package.module.MyActivity")
  .setFlags(...));

Il primo parametro per setClassName è il nome del pacchetto dell'app e il secondo parametro è il nome completo della classe dell'attività.

Quando hai un'attività in un modulo di funzionalità che hai scaricato on demand, devi abilitare SplitCompat nell'attività.

Avvia un servizio definito in un modulo della funzionalità

Puoi avviare i servizi definiti nei moduli delle funzionalità utilizzando startService() dopo aver abilitato SplitCompat.

Kotlin

startService(Intent()
  .setClassName("com.package", "com.package.module.MyService")
  .setFlags(...))

Java

startService(new Intent()
  .setClassName("com.package", "com.package.module.MyService")
  .setFlags(...));

Esporta un componente definito in un modulo della funzionalità

Non devi includere componenti Android esportati all'interno di moduli facoltativi.

Il sistema di compilazione unisce le voci manifest di tutti i moduli al modulo di base. Se un modulo facoltativo contiene un componente esportato, quest'ultimo sarebbe accessibile anche prima dell'installazione del modulo e potrebbe causare un arresto anomalo a causa di codice mancante quando richiamato da un'altra app.

Questo non è un problema per i componenti interni, poiché vi accedono solo dall'app, quindi quest'ultima può verificare che il modulo sia installato prima di accedere al componente.

Se hai bisogno di un componente esportato e vuoi che i relativi contenuti siano inseriti in un modulo facoltativo, valuta l'implementazione di un pattern proxy. Puoi farlo aggiungendo un componente proxy esportato nella base; al momento dell'accesso, il componente proxy può verificare la presenza del modulo che contiene i contenuti. Se il modulo è presente, il componente proxy può avviare il componente interno dal modulo tramite un Intent, visualizzando l'intent dall'app del chiamante. Se il modulo non è presente, il componente può scaricare il modulo o restituire un messaggio di errore appropriato all'app del chiamante.

Accedi a codice e risorse dai moduli installati

Se abiliti SplitCompat per il tuo contesto applicazione di base e le attività nel modulo delle funzionalità, puoi utilizzare il codice e le risorse di un modulo della funzionalità come se facessero parte dell'APK di base, una volta installato il modulo facoltativo.

Codice di accesso da un modulo diverso

Accedere al codice di base da un modulo

Il codice all'interno del modulo di base può essere utilizzato direttamente da altri moduli. Non devi fare nulla di speciale; devi solo importare e utilizzare i corsi che ti servono.

Accedi al codice del modulo da un altro modulo

Un oggetto o una classe all'interno di un modulo non è accessibile direttamente in modo statico da un altro modulo, ma è possibile accedervi indirettamente tramite la riflessione.

Dovresti fare attenzione a quanto spesso accade, a causa dei costi legati alle prestazioni dovuti alla riflessione. Per i casi d'uso complessi, utilizza framework di inserimento delle dipendenze come Dagger 2 per garantire una singola chiamata di riflessione per durata dell'applicazione.

Per semplificare le interazioni con l'oggetto dopo la creazione dell'istanza, consigliamo di definire un'interfaccia nel modulo di base e la sua implementazione nel modulo della funzionalità. Ad esempio:

Kotlin

// In the base module
interface MyInterface {
  fun hello(): String
}

// In the feature module
object MyInterfaceImpl : MyInterface {
  override fun hello() = "Hello"
}

// In the base module, where we want to access the feature module code
val stringFromModule = (Class.forName("com.package.module.MyInterfaceImpl")
    .kotlin.objectInstance as MyInterface).hello();

Java

// In the base module
public interface MyInterface {
  String hello();
}

// In the feature module
public class MyInterfaceImpl implements MyInterface {
  @Override
  public String hello() {
    return "Hello";
  }
}

// In the base module, where we want to access the feature module code
String stringFromModule =
   ((MyInterface) Class.forName("com.package.module.MyInterfaceImpl").getConstructor().newInstance()).hello();

Accesso a risorse e asset da un modulo diverso

Una volta installato un modulo, puoi accedere alle risorse e agli asset all'interno del modulo nel modo standard, con due avvertenze:

  • Se si accede a una risorsa da un modulo diverso, quest'ultimo non avrà accesso all'identificatore della risorsa, anche se è possibile accedere alla risorsa per nome. Nota che il pacchetto da utilizzare per fare riferimento alla risorsa è il pacchetto del modulo in cui è definita la risorsa.
  • Se vuoi accedere ad asset o risorse presenti in un modulo appena installato da un altro modulo installato della tua app, devi farlo utilizzando il contesto dell'applicazione. Il contesto del componente che tenta di accedere alle risorse non verrà ancora aggiornato. In alternativa, puoi ricreare quel componente (ad esempio chiamando Activity.recreate()) o reinstallare SplitCompat al suo interno dopo l'installazione del modulo delle funzionalità.

Carica il codice nativo in un'app utilizzando la distribuzione on demand

Ti consigliamo di utilizzare ReLinker per caricare tutte le librerie native quando utilizzi la distribuzione on demand dei moduli delle funzionalità. ReLinker corregge un problema di caricamento delle librerie native dopo l'installazione di un modulo delle funzionalità. Puoi scoprire di più su ReLinker nei suggerimenti su JNI per Android.

Carica il codice nativo da un modulo facoltativo

Dopo aver installato una suddivisione, ti consigliamo di caricare il codice nativo tramite ReLinker. Per le app istantanee, devi utilizzare questo metodo speciale.

Se utilizzi System.loadLibrary() per caricare il codice nativo e la libreria nativa dipende da un'altra libreria nel modulo, devi prima caricare manualmente l'altra libreria. Se usi ReLinker, l'operazione equivalente è Relinker.recursively().loadLibrary().

Se utilizzi dlopen() nel codice nativo per caricare una libreria definita in un modulo facoltativo, non funzionerà con i relativi percorsi di libreria. La soluzione migliore consiste nel recuperare il percorso assoluto della libreria dal codice Java tramite ClassLoader.findLibrary(), per poi utilizzarlo nella chiamata dlopen(). Esegui questa operazione prima di inserire il codice nativo o utilizza una chiamata JNI dal tuo codice nativo a Java.

Accedi alle app istantanee Android installate

Dopo che un modulo dell'app istantanea Android ha generato report come INSTALLED, puoi accedere al relativo codice e alle relative risorse utilizzando un Contesto dell'app aggiornato. Un contesto creato dalla tua app prima di installare un modulo (ad esempio, già archiviato in una variabile) non include i contenuti del nuovo modulo. Ciò è possibile grazie a un contesto innovativo, che può essere ottenuto, ad esempio, utilizzando createPackageContext.

Kotlin

// Generate a new context as soon as a request for a new module
// reports as INSTALLED.
override fun onStateUpdate(state: SplitInstallSessionState ) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            ...
            SplitInstallSessionStatus.INSTALLED -> {
                val newContext = context.createPackageContext(context.packageName, 0)
                // If you use AssetManager to access your app’s raw asset files, you’ll need
                // to generate a new AssetManager instance from the updated context.
                val am = newContext.assets
            }
        }
    }
}

Java

// Generate a new context as soon as a request for a new module
// reports as INSTALLED.
@Override
public void onStateUpdate(SplitInstallSessionState state) {
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            ...
            case SplitInstallSessionStatus.INSTALLED:
                Context newContext = context.createPackageContext(context.getPackageName(), 0);
                // If you use AssetManager to access your app’s raw asset files, you’ll need
                // to generate a new AssetManager instance from the updated context.
                AssetManager am = newContext.getAssets();
        }
    }
}

App istantanee Android su Android 8.0 e versioni successive

Quando richiedi un modulo on demand per un'app istantanea Android su Android 8.0 (livello API 26) e versioni successive, dopo aver segnalato una richiesta di installazione come INSTALLED, devi aggiornare l'app con il contesto del nuovo modulo tramite una chiamata a SplitInstallHelper.updateAppInfo(Context context). In caso contrario, l'app non conosce ancora il codice e le risorse del modulo. Dopo aver aggiornato i metadati dell'app, devi caricare i contenuti del modulo durante l'evento del thread principale successivo richiamando un nuovo Handler, come mostrato di seguito:

Kotlin

override fun onStateUpdate(state: SplitInstallSessionState ) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            ...
            SplitInstallSessionStatus.INSTALLED -> {
                // You need to perform the following only for Android Instant Apps
                // running on Android 8.0 (API level 26) and higher.
                if (BuildCompat.isAtLeastO()) {
                    // Updates the app’s context with the code and resources of the
                    // installed module.
                    SplitInstallHelper.updateAppInfo(context)
                    Handler().post {
                        // Loads contents from the module using AssetManager
                        val am = context.assets
                        ...
                    }
                }
            }
        }
    }
}

Java

@Override
public void onStateUpdate(SplitInstallSessionState state) {
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            ...
            case SplitInstallSessionStatus.INSTALLED:
            // You need to perform the following only for Android Instant Apps
            // running on Android 8.0 (API level 26) and higher.
            if (BuildCompat.isAtLeastO()) {
                // Updates the app’s context with the code and resources of the
                // installed module.
                SplitInstallHelper.updateAppInfo(context);
                new Handler().post(new Runnable() {
                    @Override public void run() {
                        // Loads contents from the module using AssetManager
                        AssetManager am = context.getAssets();
                        ...
                    }
                });
            }
        }
    }
}

Carica le librerie C/C++

Se vuoi caricare le librerie C/C++ da un modulo che il dispositivo ha già scaricato in un'app istantanea, utilizza SplitInstallHelper.loadLibrary(Context context, String libName), come mostrato di seguito:

Kotlin

override fun onStateUpdate(state: SplitInstallSessionState) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            SplitInstallSessionStatus.INSTALLED -> {
                // Updates the app’s context as soon as a module is installed.
                val newContext = context.createPackageContext(context.packageName, 0)
                // To load C/C++ libraries from an installed module, use the following API
                // instead of System.load().
                SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”)
                ...
            }
        }
    }
}

Java

public void onStateUpdate(SplitInstallSessionState state) {
    if (state.sessionId() == mySessionId) {
        switch (state.status()) {
            case SplitInstallSessionStatus.INSTALLED:
                // Updates the app’s context as soon as a module is installed.
                Context newContext = context.createPackageContext(context.getPackageName(), 0);
                // To load C/C++ libraries from an installed module, use the following API
                // instead of System.load().
                SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”);
                ...
        }
    }
}

Limitazioni note

  • Non è possibile utilizzare Android WebView in un'attività che accede a risorse o asset da un modulo facoltativo. Ciò è dovuto a un'incompatibilità tra WebView e SplitCompat con livello API Android 28 e versioni precedenti.
  • Non puoi memorizzare nella cache gli oggetti Android ApplicationInfo, i relativi contenuti o oggetti che li contengono all'interno dell'app. Dovresti sempre recuperare questi oggetti come necessario dal contesto di un'app. Se questi oggetti vengono memorizzati nella cache, l'app potrebbe arrestarsi in modo anomalo durante l'installazione di un modulo delle funzionalità.

Gestisci moduli installati

Per verificare quali moduli delle funzionalità sono attualmente installati sul dispositivo, puoi chiamare SplitInstallManager.getInstalledModules(), che restituisce un Set<String> dei nomi dei moduli installati, come mostrato di seguito.

Kotlin

val installedModules: Set<String> = splitInstallManager.installedModules

Java

Set<String> installedModules = splitInstallManager.getInstalledModules();

Disinstallare moduli

Puoi richiedere al dispositivo di disinstallare i moduli richiamando SplitInstallManager.deferredUninstall(List<String> moduleNames), come mostrato di seguito.

Kotlin

// Specifies two feature modules for deferred uninstall.
splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))

Java

// Specifies two feature modules for deferred uninstall.
splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));

Le disinstallazioni dei moduli non avvengono immediatamente. In altre parole, il dispositivo le disinstalla in background secondo necessità per risparmiare spazio di archiviazione. Puoi confermare che il dispositivo abbia eliminato un modulo richiamando SplitInstallManager.getInstalledModules() e ispezionando il risultato, come descritto nella sezione precedente.

Scarica risorse linguistiche aggiuntive

Con gli app bundle, i dispositivi scaricano solo il codice e le risorse necessarie per eseguire la tua app. Pertanto, per le risorse relative alle lingue, il dispositivo di un utente scarica solo le risorse di lingua dell'app corrispondenti a una o più lingue attualmente selezionate nelle impostazioni del dispositivo.

Se vuoi che la tua app abbia accesso a risorse di lingua aggiuntive, ad esempio per implementare un selettore lingua in-app, puoi utilizzare la libreria di pubblicazione delle funzionalità di Google Play per scaricarle on demand. La procedura è simile a quella per il download di un modulo di funzionalità, come mostrato di seguito.

Kotlin

// Captures the user’s preferred language and persists it
// through the app’s SharedPreferences.
sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply()
...

// Creates a request to download and install additional language resources.
val request = SplitInstallRequest.newBuilder()
        // Uses the addLanguage() method to include French language resources in the request.
        // Note that country codes are ignored. That is, if your app
        // includes resources for “fr-FR” and “fr-CA”, resources for both
        // country codes are downloaded when requesting resources for "fr".
        .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
        .build()

// Submits the request to install the additional language resources.
splitInstallManager.startInstall(request)

Java

// Captures the user’s preferred language and persists it
// through the app’s SharedPreferences.
sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply();
...

// Creates a request to download and install additional language resources.
SplitInstallRequest request =
    SplitInstallRequest.newBuilder()
        // Uses the addLanguage() method to include French language resources in the request.
        // Note that country codes are ignored. That is, if your app
        // includes resources for “fr-FR” and “fr-CA”, resources for both
        // country codes are downloaded when requesting resources for "fr".
        .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
        .build();

// Submits the request to install the additional language resources.
splitInstallManager.startInstall(request);

La richiesta viene gestita come se fosse una richiesta di un modulo della funzionalità. Ciò significa che puoi monitorare lo stato della richiesta come faresti normalmente.

Se la tua app non richiede immediatamente le risorse di lingua aggiuntive, puoi posticipare l'installazione per quando l'app è in background, come mostrato di seguito.

Kotlin

splitInstallManager.deferredLanguageInstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))

Java

splitInstallManager.deferredLanguageInstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));

Accedi alle risorse linguistiche scaricate

Per ottenere l'accesso alle risorse di lingua scaricate, la tua app deve eseguire il metodo SplitCompat.installActivity() all'interno del metodo attachBaseContext() di ogni attività che richiede l'accesso a queste risorse, come mostrato di seguito.

Kotlin

override fun attachBaseContext(base: Context) {
  super.attachBaseContext(base)
  SplitCompat.installActivity(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
  super.attachBaseContext(base);
  SplitCompat.installActivity(this);
}

Per ogni attività per cui vuoi utilizzare risorse linguistiche scaricate dall'app, aggiorna il contesto di base e imposta una nuova impostazione internazionale tramite Configuration:

Kotlin

override fun attachBaseContext(base: Context) {
  val configuration = Configuration()
  configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
  val context = base.createConfigurationContext(configuration)
  super.attachBaseContext(context)
  SplitCompat.install(this)
}

Java

@Override
protected void attachBaseContext(Context base) {
  Configuration configuration = new Configuration();
  configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
  Context context = base.createConfigurationContext(configuration);
  super.attachBaseContext(context);
  SplitCompat.install(this);
}

Affinché queste modifiche abbiano effetto, devi ricreare l'attività una volta che la nuova lingua è installata e pronta per l'uso. Puoi usare il metodo Activity#recreate().

Kotlin

when (state.status()) {
  SplitInstallSessionStatus.INSTALLED -> {
      // Recreates the activity to load resources for the new language
      // preference.
      activity.recreate()
  }
  ...
}

Java

switch (state.status()) {
  case SplitInstallSessionStatus.INSTALLED:
      // Recreates the activity to load resources for the new language
      // preference.
      activity.recreate();
  ...
}

Disinstalla risorse di lingue aggiuntive

Analogamente ai moduli delle caratteristiche, puoi disinstallare risorse aggiuntive in qualsiasi momento. Prima di richiedere una disinstallazione, devi determinare quali lingue sono attualmente installate, come descritto di seguito.

Kotlin

val installedLanguages: Set<String> = splitInstallManager.installedLanguages

Java

Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();

Puoi quindi decidere quali lingue disinstallare utilizzando il metodo deferredLanguageUninstall(), come mostrato di seguito.

Kotlin

splitInstallManager.deferredLanguageUninstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))

Java

splitInstallManager.deferredLanguageUninstall(
    Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));

Testa le installazioni di moduli a livello locale

La libreria di Feature Delivery di Play ti consente di testare a livello locale la capacità della tua app di eseguire le seguenti operazioni, senza connetterti al Play Store:

In questa pagina viene descritto come eseguire il deployment degli APK suddivisi dell'app sul dispositivo di test, in modo che Play Feature Delivery utilizzi automaticamente gli APK per simulare la richiesta, il download e l'installazione di moduli dal Play Store.

Anche se non è necessario apportare modifiche alla logica dell'app, devi soddisfare i seguenti requisiti:

Creare un insieme di APK

Se non l'hai ancora fatto, sviluppa gli APK divisi per la tua app, procedendo nel seguente modo:

  1. Crea un app bundle per la tua app utilizzando uno dei seguenti metodi:
  2. Usa bundletool per generare un set di APK per tutte le configurazioni del dispositivo con il seguente comando:

    bundletool build-apks --local-testing
      --bundle my_app.aab
      --output my_app.apks
    

Il flag --local-testing include metadati nei file manifest degli APK che indicano alla libreria di pubblicazione delle caratteristiche di Google Play di utilizzare gli APK divisi locali per testare l'installazione dei moduli delle funzionalità, senza connettersi al Play Store.

Eseguire il deployment dell'app sul dispositivo

Dopo aver creato un insieme di APK utilizzando il flag --local-testing, utilizza bundletool per installare la versione di base dell'app e trasferire APK aggiuntivi nello spazio di archiviazione locale del tuo dispositivo. Puoi eseguire entrambe le azioni con il seguente comando:

bundletool install-apks --apks my_app.apks

Ora, quando avvii l'app e completi la procedura per scaricare e installare un modulo delle funzionalità, la libreria di pubblicazione delle funzionalità di Play utilizza gli APK che bundletoolè stato trasferito nello spazio di archiviazione locale del dispositivo.

Simula un errore di rete

Per simulare le installazioni di moduli dal Play Store, la libreria di pubblicazione delle caratteristiche di Google Play utilizza un'alternativa a SplitInstallManager, chiamata FakeSplitInstallManager, per richiedere il modulo. Quando utilizzi bundletool con il flag --local-testing per creare un insieme di APK e distribuirli sul dispositivo di test, sono inclusi i metadati che indicano alla libreria di distribuzione delle funzionalità di Play di cambiare automaticamente le chiamate API dell'app per richiamare FakeSplitInstallManager, anziché SplitInstallManager.

FakeSplitInstallManager include un flag booleano che puoi abilitare per simulare un errore di rete la prossima volta che la tua app richiede l'installazione di un modulo. Per accedere a FakeSplitInstallManager nei tuoi test, puoi ottenere un'istanza utilizzando FakeSplitInstallManagerFactory, come mostrato di seguito:

Kotlin

// Creates an instance of FakeSplitInstallManager with the app's context.
val fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context)
// Tells Play Feature Delivery Library to force the next module request to
// result in a network error.
fakeSplitInstallManager.setShouldNetworkError(true)

Java

// Creates an instance of FakeSplitInstallManager with the app's context.
FakeSplitInstallManager fakeSplitInstallManager =
    FakeSplitInstallManagerFactory.create(context);
// Tells Play Feature Delivery Library to force the next module request to
// result in a network error.
fakeSplitInstallManager.setShouldNetworkError(true);