Biblioteka Dynamic Navigator rozszerza możliwości komponentu Jetpack Nawigacja, aby umożliwić działanie z miejscami docelowymi zdefiniowanymi w modułach funkcji. Ta biblioteka umożliwia też bezproblemową instalację modułów funkcji na żądanie podczas przechodzenia do tych miejsc.
Skonfiguruj
Aby obsługiwać moduły funkcji, użyj tych zależności w pliku build.gradle
modułu aplikacji:
Odlotowy
dependencies { def nav_version = "2.7.7" 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.7.7" 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") }
Pamiętaj, że pozostałe zależności Nawigacji powinny korzystać z konfiguracji interfejsu API, aby były dostępne dla modułów funkcji.
Podstawowe użycie
Aby obsługiwać moduły funkcji, najpierw zmień wszystkie wystąpienia NavHostFragment
w aplikacji na 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"
... />
Następnie dodaj atrybut app:moduleName
do dowolnych miejsc docelowych <activity>
, <fragment>
lub <navigation>
na wykresach nawigacyjnych modułu com.android.dynamic-feature
, które są powiązane z elementem DynamicNavHostFragment
.
Ten atrybut informuje bibliotekę Dynamic Navigator, że miejsce docelowe należy do modułu funkcji o określonej przez Ciebie nazwie.
<fragment
app:moduleName="myDynamicFeature"
android:id="@+id/featureFragment"
android:name="com.google.android.samples.feature.FeatureFragment"
... />
Gdy dotrzesz do jednego z tych miejsc docelowych, biblioteka Dynamic Navigator najpierw sprawdza, czy moduł funkcji jest zainstalowany. Jeśli moduł funkcji jest już dostępny, aplikacja przejdzie do miejsca docelowego zgodnie z oczekiwaniami. Jeśli go nie ma, podczas instalowania modułu będzie się wyświetlał pośredni fragment postępu. Domyślna implementacja fragmentu postępu wyświetla podstawowy interfejs z paskiem postępu i obsługuje wszelkie błędy instalacji.
![2 ekrany wczytywania, które przy pierwszym przejściu do modułu funkcji wyświetlają pasek postępu.](https://developer.android.com/static/images/guide/navigation/dfm-nav-loading.png?authuser=6&hl=pl)
Aby dostosować ten interfejs lub ręcznie obsługiwać postęp instalacji z poziomu ekranu własnej aplikacji, przeczytaj sekcje Dostosowywanie fragmentu postępu i Monitorowanie stanu żądania w tym temacie.
Strony docelowe, które nie mają zdefiniowanego atrybutu app:moduleName
, nadal będą działać bez zmian i zachować się tak, jakby aplikacja używała zwykłego interfejsu NavHostFragment
.
Dostosuj fragment postępu
Aby zastąpić implementację fragmentu postępu w przypadku każdego wykresu nawigacyjnego, ustaw atrybut app:progressDestination
na identyfikator miejsca docelowego, którego chcesz używać do obsługi postępu instalacji. Niestandardowe miejsce docelowe postępu powinno mieć postać Fragment
i pochodzi z parametru AbstractProgressFragment
.
Musisz zastąpić metody abstrakcyjne w przypadku powiadomień o postępie instalacji, błędach i innych zdarzeniach. Postęp instalacji możesz pokazać
w wybranym interfejsie.
Klasa DefaultProgressFragment
implementacji domyślnej używa tego interfejsu API do wyświetlania postępu instalacji.
Monitorowanie stanu żądania
Biblioteka Dynamic Navigator umożliwia wdrożenie przepływu UX podobnego do opisanego w sprawdzonych metodach dotyczących UX na żądanie. Polega on na tym, że przed zakończeniem instalacji użytkownik pozostaje w kontekście poprzedniego ekranu. Oznacza to, że nie musisz w ogóle wyświetlać pośredniego interfejsu ani fragmentu postępu.
![ekran z dolnym paskiem nawigacyjnym z ikoną wskazującą, że trwa pobieranie modułu funkcji](https://developer.android.com/static/images/guide/navigation/nav-dfm-ui.png?authuser=6&hl=pl)
W takim przypadku odpowiadasz za monitorowanie i obsługę wszystkich stanów instalacji, zmian postępu, błędów itp.
Aby zainicjować ten nieblokujący proces nawigacji, przekaż obiekt DynamicExtras
zawierający obiekt DynamicInstallMonitor
do NavController.navigate()
, jak pokazano w tym przykładzie:
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); )
Bezpośrednio po wywołaniu metody navigate()
sprawdź wartość installMonitor.isInstallRequired
, aby zobaczyć, czy próba nawigacji spowodowała instalację modułu funkcji.
- Jeśli wartość to
false
, przejdziesz do normalnego miejsca docelowego i nie musisz nic więcej robić. Jeśli wartość to
true
, zacznij obserwować obiektLiveData
, który jest teraz w lokalizacjiinstallMonitor.status
. Ten obiektLiveData
emituje aktualizacjeSplitInstallSessionState
z biblioteki Play Core. Te aktualizacje zawierają zdarzenia postępu instalacji, które można wykorzystać do aktualizacji interfejsu użytkownika. Pamiętaj o obsłudze wszystkich istotnych stanów zgodnie z opisem w przewodniku po Google Play Core, w tym także z prośbą o potwierdzenie przez użytkownika, jeśli to konieczne.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); } } }); }
Po zakończeniu instalacji obiekt LiveData
wyda stan SplitInstallSessionStatus.INSTALLED
. Następnie należy ponownie zadzwonić pod numer NavController.navigate()
. Moduł został zainstalowany, więc wywołanie się uda, a aplikacja przejdzie do miejsca docelowego zgodnie z oczekiwaniami.
Po osiągnięciu stanu terminala, na przykład po zakończeniu instalacji lub niepowodzeniu instalacji, usuń obserwatora LiveData
, aby uniknąć wycieku pamięci. Aby sprawdzić, czy stan wskazuje na stan terminala, użyj funkcji SplitInstallSessionStatus.hasTerminalStatus()
.
Przykład implementacji obserwatora znajdziesz w sekcji AbstractProgressFragment
.
Dołączone wykresy
Biblioteka dynamicznej nawigacji obsługuje dołączanie wykresów zdefiniowanych w modułach funkcji. Aby uwzględnić wykres zdefiniowany w module funkcji, wykonaj te czynności:
Użyj właściwości
<include-dynamic/>
zamiast<include/>
, jak pokazano w tym przykładzie:<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" />
W elemencie
<include-dynamic ... />
musisz określić te atrybuty:app:graphResName
: nazwa pliku zasobów wykresu nawigacyjnego. Nazwa pochodzi z nazwy pliku wykresu. Jeśli na przykład wykres przedstawia obszarres/navigation/nav_graph.xml
, nazwa zasobu tonav_graph
.android:id
– identyfikator miejsca docelowego wykresu. Biblioteka Dynamic Navigator ignoruje wszystkie wartościandroid:id
, które znajdują się w elemencie głównym dołączonego wykresu.app:moduleName
: nazwa pakietu modułu.
Użyj właściwego wykresu Package
Ważne jest, aby app:graphPackage
był poprawny, ponieważ w przeciwnym razie komponent Nawigacja nie będzie mógł uwzględnić określonego navGraph
z modułu funkcji.
Nazwa pakietu modułu funkcji dynamicznych tworzy się przez dołączenie nazwy modułu do elementu applicationId
podstawowego modułu aplikacji. Jeśli więc moduł aplikacji podstawowej ma applicationId
o wartości com.example.dynamicfeatureapp
, a moduł funkcji dynamicznych o nazwie DynamicFeatureModule
, nazwa pakietu modułu dynamicznego będzie wyglądać tak: com.example.dynamicfeatureapp.DynamicFeatureModule
. Wielkość liter w nazwie pakietu jest rozróżniana.
Jeśli masz wątpliwości, możesz potwierdzić nazwę pakietu modułu funkcji, sprawdzając wygenerowany AndroidManifest.xml
. Po utworzeniu projektu przejdź do usługi <DynamicFeatureModule>/build/intermediates/merged_manifest/debug/AndroidManifest.xml
, która powinna wyglądać mniej więcej tak:
<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>
Wartość featureSplit
powinna być zgodna z nazwą modułu funkcji dynamicznych, a pakiet będzie zgodny z parametrem applicationId
podstawowego modułu aplikacji. app:graphPackage
to kombinacja tych elementów: com.example.dynamicfeatureapp.DynamicFeatureModule
.
Przechodzenie do dynamicznego wykresu nawigacyjnego
Możesz przejść tylko do obszaru startDestination
na wykresie nawigacyjnym include-dynamic
. Moduł dynamiczny odpowiada za własny wykres nawigacyjny, o którym aplikacja podstawowa nie wie.
Mechanizm uwzględniania-dynamiczny umożliwia dołączenie do podstawowego modułu aplikacji zagnieżdżonego wykresu nawigacyjnego zdefiniowanego w module dynamicznym. Ten zagnieżdżony wykres nawigacyjny działa jak każdy zagnieżdżony wykres nawigacyjny. Główny wykres nawigacyjny (tj. element nadrzędny zagnieżdżonego wykresu) może wskazywać tylko zagnieżdżony wykres nawigacyjny jako miejsce docelowe, a nie jego elementy podrzędne. Dlatego element startDestination
jest używany, gdy miejscem docelowym jest wykres nawigacji dynamicznej.
Ograniczenia
- Wykresy dynamiczne nie obsługują obecnie precyzyjnych linków.
- Dynamicznie wczytywane wykresy zagnieżdżone (czyli element
<navigation>
z elementemapp:moduleName
) nie obsługują obecnie precyzyjnych linków.