הספרייה Dynamic Navigator מרחיב את הפונקציונליות של רכיב הניווט של Jetpack לעבודה עם יעדים שמוגדרות מודולים של תכונות. הספרייה הזו גם מספקת התקנה חלקה של תכונה על פי דרישה מודולים כשמנווטים ליעדים האלה.
הגדרה
כדי לתמוך במודולים של תכונות, צריך להשתמש ביחסי התלות הבאים בקובץ build.gradle
של מודול האפליקציה:
מגניב
dependencies { def nav_version = "2.8.0" 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.0" 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") }
שים לב שיחסי התלות האחרים של הניווט צריכים להשתמש בהגדרות API כדי שיהיו זמינים למודולים של התכונות.
שימוש בסיסי
כדי לתמוך במודולים של תכונות, קודם צריך לשנות את כל המופעים של
NavHostFragment
באפליקציה שלך כדי
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"
... />
בשלב הבא, צריך להוסיף את המאפיין app:moduleName
לכל <activity>
, <fragment>
או
<navigation>
יעדים במודול com.android.dynamic-feature
תרשימי ניווט שמשויכים ל-DynamicNavHostFragment
.
מאפיין זה מציין לספריית הניווט הדינמי שהיעד
שייכת למודול תכונה עם השם שציינתם.
<fragment
app:moduleName="myDynamicFeature"
android:id="@+id/featureFragment"
android:name="com.google.android.samples.feature.FeatureFragment"
... />
כשמנווטים לאחד מהיעדים האלה, הספרייה Dynamic Navigator בודק קודם אם מודול התכונות מותקן. אם התכונה המודול כבר קיים, האפליקציה מנווטת ליעד כמצופה. אם המודול לא נמצא, האפליקציה שלך מציגה מקטע של התקדמות ביניים היעד כשהוא מתקין את המודול. הטמעת ברירת המחדל של קטע התקדמות מציג ממשק משתמש בסיסי עם סרגל התקדמות ומטפל בכל במהלך ההתקנה.
כדי להתאים אישית את ממשק המשתמש הזה, או לטפל בהתקנה באופן ידני את ההתקדמות מתוך מסך האפליקציה שלכם, להתאים אישית את מקטע ההתקדמות וגם מעקב אחרי הקטעים של מצב הבקשה בנושא הזה.
יעדים שלא צוין בהם app:moduleName
ימשיכו לפעול בלי
משתנה ומתנהג כאילו האפליקציה משתמשת ב-NavHostFragment
רגיל.
התאמה אישית של מקטע ההתקדמות
אפשר לשנות את ההטמעה של מקטע ההתקדמות בכל תרשים ניווט
באמצעות הגדרת המאפיין app:progressDestination
כמזהה של היעד
שבהן רוצים להשתמש לטיפול בהתקדמות ההתקנה. ההתקדמות בהתאמה אישית
היעד צריך להיות
Fragment
שנגזרת
AbstractProgressFragment
כדי לקבל התראות על התקנה צריך לשנות את השיטות המופשטות
התקדמות, שגיאות ואירועים אחרים. לאחר מכן תוכלו להציג את התקדמות ההתקנה
ממשק משתמש לבחירתך.
תבניות ברירת המחדל להטמעה
DefaultProgressFragment
class משתמש ב-API הזה כדי להציג את התקדמות ההתקנה.
מעקב אחרי מצב הבקשה
הספרייה Dynamic Navigator מאפשרת להטמיע תהליך UX שדומה אחד ב שיטות מומלצות לשיפור חוויית המשתמש למסירה על פי דרישה, שבו המשתמש נשאר בהקשר של מסך קודם בזמן שהוא ממתין עד לסיום ההתקנה. כלומר, אין צורך להציג לחצן ביניים ממשק משתמש או מקטע התקדמות.
במקרה כזה, באחריותכם מעקב אחר כל מצבי ההתקנה, שינויים בהתקדמות, שגיאות וטיפול בהן וכן הלאה.
כדי להתחיל תהליך ניווט ללא חסימה, מעבירים
DynamicExtras
שמכיל
DynamicInstallMonitor
אל
NavController.navigate()
,
כפי שאפשר לראות בדוגמה הבאה:
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); )
מיד לאחר השיחה אל navigate()
, יש לבדוק את הערך של
installMonitor.isInstallRequired
כדי לבדוק אם ניסיון הניווט הוביל
בהתקנה של מודול תכונה.
- אם הערך הוא
false
, הניווט שלך ליעד רגיל ולא מתבצע תצטרכו לעשות משהו נוסף. אם הערך הוא
true
, צריך להתחיל לצפות באובייקטLiveData
נמצא עכשיו ב-installMonitor.status
. אובייקטLiveData
זה פולטSplitInstallSessionState
עדכונים מספריית Play Core. העדכונים האלה כוללים התקנה אירועי התקדמות שאפשר להשתמש בהם כדי לעדכן את ממשק המשתמש. חשוב לזכור לטפל בהכול הרלוונטיים, כפי שמתואר Play Core guide כולל בקשת אישור משתמש במידת הצורך.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); } } }); }
בסיום ההתקנה, האובייקט LiveData
פולט
סטטוס SplitInstallSessionStatus.INSTALLED
. לאחר מכן צריך להתקשר
NavController.navigate()
שוב. מכיוון שהמודול מותקן עכשיו, הקריאה
עכשיו הפעולה מצליחה, והאפליקציה מנווטת ליעד כמצופה.
אחרי שמגיעים למצב מסוף, למשל כשההתקנה מסתיימת או מתי
ההתקנה נכשלה, עליך להסיר את הצופה ב-LiveData
כדי להימנע מהזיכרון
דליפות. אפשר לבדוק אם הסטטוס מייצג מצב של מסוף באמצעות
SplitInstallSessionStatus.hasTerminalStatus()
ראו AbstractProgressFragment
ליישום דוגמה של הצופה הזה.
תרשימים כלולים
ספריית Dynamic Navigator תומכת ולכלול גרפים שמוגדרים של הפיצ'רים האלה. לכלול גרף שמוגדר בתכונה מבצעים את הפעולות הבאות:
עליך להשתמש ב-
<include-dynamic/>
במקום ב-<include/>
, כפי שמוצג בהמשך דוגמה:<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" />
בתוך
<include-dynamic ... />
, צריך לציין את המאפיינים הבאים:app:graphResName
: שם קובץ המשאבים של תרשים הניווט. נגזר משם הקובץ של התרשים. לדוגמה, אם הגרףres/navigation/nav_graph.xml
, שם המשאב הואnav_graph
.android:id
- מזהה היעד בתרשים. ספריית Dynamic Navigator מתעלמת מכל ערכיandroid:id
שנמצאים ברכיב השורש של גרפי.app:moduleName
: שם החבילה של המודול.
צריך להשתמש ב-ChartPackage הנכון
חשוב לוודא שה-app:graphPackage
נכון בתור הניווט
הרכיב לא יוכל לכלול את navGraph
שצוין מהתכונה
אחר, אחרת.
שם החבילה של מודול תכונה דינמית נבנה על ידי הוספת התג
שם המודול אל applicationId
של מודול האפליקציה הבסיסית. כך שאם
מודול האפליקציה הבסיסי מכיל applicationId
של com.example.dynamicfeatureapp
ו
המודול של התכונה הדינמית נקרא DynamicFeatureModule
, ואז החבילה
של המודול הדינמי יהיה
com.example.dynamicfeatureapp.DynamicFeatureModule
שם החבילה הוא
תלוי אותיות רישיות.
אם יש לכם ספק, תוכלו לאשר את שם החבילה של מודול התכונה
באמצעות בדיקה של AndroidManifest.xml
שנוצר. אחרי בניית הפרויקט,
אל <DynamicFeatureModule>/build/intermediates/merged_manifest/debug/AndroidManifest.xml
,
שאמורה להיראות בערך כך:
<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>
הערך featureSplit
צריך להתאים לשם של המודול של התכונה הדינמית, והחבילה תתאים ל-applicationId
של מודול האפליקציה הבסיסי. app:graphPackage
הוא השילוב של: com.example.dynamicfeatureapp.DynamicFeatureModule
.
ניווט לתרשים ניווט דינמי-הכללה
אפשר רק לנווט אל startDestination
של
תרשים ניווט של include-dynamic
. המודול הדינמי אחראי
את תרשים הניווט עצמו, והאפליקציה הבסיסית לא יודעת על זה.
המנגנון הכללה-דינמית מאפשר למודול הבסיסי של האפליקציה לכלול
תרשים ניווט מוטמע
שמוגדר במודול הדינמי. תרשים הניווט המקונן הזה מתנהג
כמו כל תרשים ניווט מקונן. תרשים הניווט ברמה הבסיסית (root) (כלומר ההורה
של הגרף המקונן) יכול להגדיר רק את תרשים הניווט הפנימי
ולא הצאצאים שלו. לכן, נעשה שימוש ב-startDestination
כאשר
תרשים הניווט הדינמי-הכללה הוא היעד.
מגבלות
- תרשימים שנכללים באופן דינמי לא תומכים כרגע בקישורי עומק.
- גרפים מקוננים שנטענים באופן דינמי (כלומר, רכיב
<navigation>
עםapp:moduleName
) לא תומכים כרגע בקישורי עומק.