La libreria Dynamic Navigator estende le funzionalità Componente Navigazione Jetpack per lavorare con le destinazioni definiti in moduli delle funzionalità. Questa libreria fornisce inoltre un'installazione immediata di funzionalità on demand durante la navigazione verso queste destinazioni.
Configura
Per supportare i moduli delle funzionalità, usa le seguenti dipendenze nel file build.gradle
del modulo dell'app:
Groovy
dependencies { def nav_version = "2.8.4" api "androidx.navigation:navigation-fragment-ktx:$nav_version" api "androidx.navigation:navigation-ui-ktx:$nav_version" api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.4" api("androidx.navigation:navigation-fragment-ktx:$nav_version") api("androidx.navigation:navigation-ui-ktx:$nav_version") api("androidx.navigation:navigation-dynamic-features-fragment:$nav_version") }
Tieni presente che le altre dipendenze di navigazione devono utilizzare le configurazioni dell'API. in modo che siano disponibili per i moduli delle funzionalità.
Utilizzo di base
Per supportare i moduli delle funzionalità, modifica prima tutte le istanze di
NavHostFragment
nella tua app per
androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment
:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
app:navGraph="@navigation/nav_graph"
... />
Poi, aggiungi un attributo app:moduleName
a qualsiasi elemento <activity>
, <fragment>
o
<navigation>
destinazioni nei moduli com.android.dynamic-feature
grafici di navigazione associati a DynamicNavHostFragment
.
Questo attributo indica alla libreria Dynamic Navigator che la destinazione
appartiene a un modulo di caratteristiche con il nome da te specificato.
<fragment
app:moduleName="myDynamicFeature"
android:id="@+id/featureFragment"
android:name="com.google.android.samples.feature.FeatureFragment"
... />
Quando passi a una di queste destinazioni, la libreria Dynamic Navigator verifica innanzitutto se il modulo delle funzionalità è installato. Se l'elemento è già presente, l'app raggiunge la destinazione come previsto. Se il modulo non è presente, la tua app mostra un frammento di avanzamento intermedio durante l'installazione del modulo. L'implementazione predefinita il frammento di avanzamento mostra un'interfaccia utente di base con una barra di avanzamento e gestisce qualsiasi errori di installazione.
Per personalizzare questa UI o per gestire manualmente l'installazione avanza dalla schermata della tua app, controlla Personalizza il frammento di avanzamento e Monitora le sezioni dello stato della richiesta in questo argomento.
Le destinazioni che non specificano app:moduleName
continuano a funzionare senza
cambia e si comportano come se la tua app utilizzasse un normale NavHostFragment
.
Personalizza il frammento di avanzamento
Puoi ignorare l'implementazione del frammento di avanzamento per ogni grafico di navigazione
impostando l'attributo app:progressDestination
sull'ID della destinazione
da utilizzare per gestire l'avanzamento dell'installazione. I tuoi progressi personalizzati
destinazione deve essere una
Fragment
che deriva da
AbstractProgressFragment
.
Devi eseguire l'override dei metodi astratti per le notifiche sull'installazione
avanzamento, errori e altri eventi. Puoi quindi mostrare l'avanzamento dell'installazione in un
che preferisci.
L'implementazione predefinita
DefaultProgressFragment
utilizza questa API per mostrare lo stato di avanzamento dell'installazione.
Monitora lo stato della richiesta
La libreria Dynamic Navigator ti consente di implementare un flusso UX simile uno in Best practice per l'esperienza utente per la distribuzione on demand, in cui un utente rimane nel contesto di una schermata precedente in attesa per completare l'installazione. Ciò significa che non devi mostrare una parte intermedia UI o frammento di avanzamento.
In questo scenario, sei responsabile monitorare e gestire tutti gli stati di installazione, le modifiche di avanzamento, gli errori così via.
Per avviare questo flusso di navigazione non bloccante, passa un
DynamicExtras
che contiene un oggetto
DynamicInstallMonitor
a
NavController.navigate()
,
come mostrato nell'esempio seguente:
Kotlin
val navController = ... val installMonitor = DynamicInstallMonitor() navController.navigate( destinationId, null, null, DynamicExtras(installMonitor) )
Java
NavController navController = ... DynamicInstallMonitor installMonitor = new DynamicInstallMonitor(); navController.navigate( destinationId, null, null, new DynamicExtras(installMonitor); )
Subito dopo aver chiamato navigate()
, devi controllare il valore di
installMonitor.isInstallRequired
per vedere se il tentativo di navigazione ha generato risultati
in un'installazione di un modulo delle funzionalità.
- Se il valore è
false
, ti stai dirigendo verso una destinazione normale e non non devi fare altro. Se il valore è
true
, dovresti iniziare a osservare l'oggettoLiveData
che ora si trova ininstallMonitor.status
. Questo oggettoLiveData
emetteSplitInstallSessionState
aggiornamenti dalla libreria Play Core. Questi aggiornamenti contengono l'installazione eventi di avanzamento che puoi usare per aggiornare la UI. Ricorda di gestire tutte le pertinenti come descritto Guida di base di Play, tra cui richiesta di conferma dell'utente se necessario.Kotlin
val navController = ... val installMonitor = DynamicInstallMonitor() navController.navigate( destinationId, null, null, DynamicExtras(installMonitor) ) if (installMonitor.isInstallRequired) { installMonitor.status.observe(this, object : Observer<SplitInstallSessionState> { override fun onChanged(sessionState: SplitInstallSessionState) { when (sessionState.status()) { SplitInstallSessionStatus.INSTALLED -> { // Call navigate again here or after user taps again in the UI: // navController.navigate(destinationId, destinationArgs, null, null) } SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> { SplitInstallManager.startConfirmationDialogForResult(...) } // Handle all remaining states: SplitInstallSessionStatus.FAILED -> {} SplitInstallSessionStatus.CANCELED -> {} } if (sessionState.hasTerminalStatus()) { installMonitor.status.removeObserver(this); } } }); }
Java
NavController navController = ... DynamicInstallMonitor installMonitor = new DynamicInstallMonitor(); navController.navigate( destinationId, null, null, new DynamicExtras(installMonitor); ) if (installMonitor.isInstallRequired()) { installMonitor.getStatus().observe(this, new Observer<SplitInstallSessionState>() { @Override public void onChanged(SplitInstallSessionState sessionState) { switch (sessionState.status()) { case SplitInstallSessionStatus.INSTALLED: // Call navigate again here or after user taps again in the UI: // navController.navigate(mDestinationId, mDestinationArgs, null, null); break; case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION: SplitInstallManager.startConfirmationDialogForResult(...) break; // Handle all remaining states: case SplitInstallSessionStatus.FAILED: break; case SplitInstallSessionStatus.CANCELED: break; } if (sessionState.hasTerminalStatus()) { installMonitor.getStatus().removeObserver(this); } } }); }
Al termine dell'installazione, l'oggetto LiveData
emette un
Stato SplitInstallSessionStatus.INSTALLED
. Devi quindi chiamare
NavController.navigate()
di nuovo. Poiché il modulo è ora installato, la chiamata
ora va a buon fine e l'app raggiunge la destinazione come previsto.
Dopo aver raggiunto lo stato di terminale, ad esempio al termine dell'installazione o quando
installazione non riuscita. Devi rimuovere il tuo osservatore LiveData
per evitare memoria
di fughe di notizie. Puoi verificare se lo stato rappresenta uno stato terminale utilizzando
SplitInstallSessionStatus.hasTerminalStatus()
.
Vedi AbstractProgressFragment
per un'implementazione di esempio di questo osservatore.
Grafici inclusi
La libreria Dynamic Navigator supporta l'inclusione di grafici definiti in moduli delle funzionalità. Per includere un grafico definito in un elemento procedi nel seguente modo:
Usa
<include-dynamic/>
anziché<include/>
, come mostrato di seguito esempio:<include-dynamic android:id="@+id/includedGraph" app:moduleName="includedgraphfeature" app:graphResName="included_feature_nav" app:graphPackage="com.google.android.samples.dynamic_navigator.included_graph_feature" />
All'interno di
<include-dynamic ... />
, devi specificare i seguenti attributi:app:graphResName
: il nome del file di risorse del grafico di navigazione. La deriva dal nome del file del grafico. Ad esempio, se il grafico ères/navigation/nav_graph.xml
, il nome della risorsa ènav_graph
.android:id
: l'ID destinazione del grafico. La libreria Dynamic Navigator ignora tutti i valoriandroid:id
che si trovano nell'elemento principale della incluso nel grafico.app:moduleName
: il nome del pacchetto del modulo.
Utilizza il graphicPackage corretto
È importante che i valori app:graphPackage
siano corretti per la navigazione
non sarà in grado di includere il valore navGraph
specificato dalla caratteristica
di questo modulo.
Il nome pacchetto di un modulo di funzionalità dinamiche viene creato aggiungendo il tag
del modulo al applicationId
del modulo dell'app di base. Quindi se
Il modulo per l'app di base ha un valore applicationId
di com.example.dynamicfeatureapp
e
il modulo di funzionalità dinamiche è denominato DynamicFeatureModule
, quindi il pacchetto
il nome del modulo dinamico sarà
com.example.dynamicfeatureapp.DynamicFeatureModule
. Il nome del pacchetto è
sensibile alle maiuscole.
In caso di dubbi, è possibile confermare il nome pacchetto del modulo delle funzionalità
controllando il valore AndroidManifest.xml
generato. Dopo aver realizzato il progetto,
per <DynamicFeatureModule>/build/intermediates/merged_manifest/debug/AndroidManifest.xml
,
che dovrebbe avere un aspetto simile al seguente:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution" featureSplit="DynamicFeatureModule" package="com.example.dynamicfeatureapp" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> <dist:module dist:instant="false" dist:title="@string/title_dynamicfeaturemodule" > <dist:delivery> <dist:install-time /> </dist:delivery> <dist:fusing dist:include="true" /> </dist:module> <application /> </manifest>
Il valore featureSplit
deve corrispondere al nome del modulo di funzionalità dinamiche e il pacchetto corrisponderà al valore applicationId
del modulo dell'app di base. app:graphPackage
è la combinazione di questi elementi: com.example.dynamicfeatureapp.DynamicFeatureModule
.
Passaggio a un grafico di navigazione dinamico di inclusione
È possibile accedere solo al startDestination
di un
Grafico di navigazione include-dynamic
. Il modulo dinamico è responsabile
un proprio grafico di navigazione e l'app di base non ne è al corrente.
Il meccanismo include-dinamico consente al modulo dell'app di base di includere un
grafico di navigazione nidificato
definito nel modulo dinamico. Questo grafico di navigazione nidificato si comporta
come qualsiasi grafico di navigazione nidificato. Il grafico di navigazione principale (ovvero l'URL
del grafico nidificato) può solo definire il grafico di navigazione nidificato come se
e non ai relativi figli. Di conseguenza, startDestination
viene utilizzato quando
il grafico include- dynamicnavigation è la destinazione.
Limitazioni
- I grafici inclusi dinamicamente non supportano attualmente i link diretti.
- Grafici nidificati caricati dinamicamente (ossia un elemento
<navigation>
con unapp:moduleName
) al momento non supportano i link diretti.