تعمل مكتبة Dynamic Navigator على توسيع نطاق وظائف مكوِّن التنقّل في Jetpack للعمل مع الوجهات التي يتم تحديدها في وحدات الميزات: توفّر هذه المكتبة أيضًا إمكانية تثبيت الميزات المتوفرة عند الطلب بسهولة. الوحدات عند الانتقال إلى هذه الوجهات.
ضبط إعدادات الجهاز
لدعم وحدات الميزات، استخدِم الاعتماديات التالية في ملف build.gradle
الخاص بوحدة تطبيقك:
Groovy
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") }
لاحظ أن اعتماديات التنقّل الأخرى يجب أن تستخدم عمليات ضبط واجهة برمجة التطبيقات. لكي تكون متاحة لوحدات الميزات لديك.
الاستخدام الأساسي
لدعم وحدات الميزات، غيِّر أولاً جميع مثيلات
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
.
تخبر هذه السمة مكتبة Dynamic Navigator بأن الوجهة
إلى وحدة ميزة بالاسم الذي تحدده.
<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
تستخدم هذه الفئة واجهة برمجة التطبيقات هذه لعرض مستوى تقدُّم عملية التثبيت.
مراقبة حالة الطلب
تتيح لك مكتبة Dynamic Navigator تنفيذ تدفق تجربة مستخدم مشابه واحد من كل أفضل ممارسات تجربة المستخدم للتسليم عند الطلب يظل فيها المستخدم في سياق شاشة سابقة أثناء انتظار التثبيت لإنهاء العمل. وهذا يعني أنك لست بحاجة إلى عرض رمز متوسط واجهة المستخدم أو جزء التقدم على الإطلاق.
في هذا السيناريو، أنت مسئول عن مراقبة والتعامل مع جميع حالات التثبيت وتغييرات التقدم والأخطاء وهكذا.
لبدء عملية التنقل التي لا تؤدي إلى الحظر، عليك اجتياز
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 من بينها طلب تأكيد من المستخدم إذا لزم الأمر.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
: اسم حزمة الوحدة
استخدام حزم الرسوم البيانية الصحيحة
من المهم الحصول على 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
تكون الوحدة الديناميكية المسئولة عن
الرسم البياني للتنقل والتطبيق الأساسي ليس لديه معرفة بذلك.
تتيح آلية التضمين الديناميكية لوحدة التطبيق الأساسية أن تتضمّن
رسم بياني مضمَّن للتنقّل
المحدد داخل الوحدة الديناميكية. يتصرف الرسم البياني للتنقل المتداخل هذا
مثل أي رسم بياني للتنقل متداخل. الرسم البياني للتنقل الجذري (أي الصفحة الرئيسية
من الرسم البياني المتداخل) يمكنه فقط تحديد الرسم البياني للتنقل المتداخل نفسه
الوجهة وليس عناصرها الثانوية. وبالتالي، يتم استخدام startDestination
عند
الرسم البياني لتضمين التنقل الديناميكي هي الوجهة.
القيود
- لا تتوافق الرسوم البيانية المضمّنة ديناميكيًا حاليًا مع الروابط لصفحات في التطبيق.
- الرسوم البيانية المدمجة التي يتم تحميلها ديناميكيًا (أي عنصر
<navigation>
معapp:moduleName
) لا تتوافق حاليًا مع الروابط لصفحات في التطبيق.