توضّح هذه الصفحة كيفية تقسيم رمز التنقّل إلى وحدات. والهدف منه هو تكملة الإرشادات العامة لتقسيم التطبيق إلى وحدات.
نظرة عامة
إنّ تقسيم رمز التنقّل إلى وحدات هو عملية فصل مفاتيح التنقّل ذات الصلة والمحتوى الذي تمثّله إلى وحدات فردية. يوفر هذا فصلاً واضحًا للمسؤوليات ويتيح لك التنقل بين الميزات المختلفة في تطبيقك.
لتقسيم رمز التنقّل إلى وحدات، اتّبِع الخطوات التالية:
- إنشاء وحدتَين فرعيتَين:
apiوimplلكل ميزة في تطبيقك - وضع مفاتيح التنقّل لكل ميزة في وحدة
apiالخاصة بها - ضع
entryProvidersوالمحتوى القابل للتنقّل لكل ميزة في وحدةimplالمرتبطة بها - يجب توفير
entryProvidersلوحدات تطبيقك الرئيسية، إما مباشرةً أو باستخدام حقن التبعية
فصل الميزات إلى وحدات فرعية لواجهة برمجة التطبيقات والتنفيذ
لكل ميزة في تطبيقك، أنشئ وحدتَين فرعيتَين باسم api وimpl (اختصار لـ "implementation"). استخدِم الجدول التالي لتحديد مكان وضع رمز التنقّل.
اسم الوحدة |
يحتوي على |
|
|
|
محتوى هذه الميزة، بما في ذلك تعريفات |
يتيح هذا الأسلوب لميزة معيّنة الانتقال إلى ميزة أخرى من خلال السماح لمحتواها،
المضمَّن في وحدة impl، بالاعتماد على مفاتيح التنقّل لوحدة أخرى،
المضمَّنة في وحدة api لتلك الوحدة.
فصل إدخالات التنقّل باستخدام دوال الإضافات
في Navigation 3، يتم تحديد المحتوى القابل للتنقّل باستخدام إدخالات التنقّل. للفصل بين هذه الإدخالات في وحدات منفصلة، يمكنك إنشاء دوال إضافية على EntryProviderScope ونقلها إلى وحدة impl لهذه الميزة.
وتُعرف هذه باسم أدوات إنشاء الإدخالات.
يوضّح مثال الرمز البرمجي التالي أداة إنشاء إدخالات تنشئ إدخالَي تنقّل.
// import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey fun EntryProviderScope<NavKey>.featureAEntryBuilder() { entry<KeyA> { ContentRed("Screen A") { // Content for screen A } } entry<KeyA2> { ContentGreen("Screen A2") { // Content for screen A2 } } }
يمكنك استدعاء هذه الدالة باستخدام entryProvider DSL عند تحديد
entryProvider في وحدة التطبيق الرئيسية.
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
استخدام حقن التبعية لإضافة إدخالات إلى التطبيق الرئيسي
في مثال الرمز البرمجي السابق، يتم استدعاء كل أداة إنشاء إدخالات مباشرةً من خلال
التطبيق الرئيسي باستخدام لغة entryProvider DSL. إذا كان تطبيقك يحتوي على الكثير من الشاشات أو
وحدات الميزات، قد لا يتناسب هذا النمط مع حجم التطبيق.
لحلّ هذه المشكلة، يجب أن تساهم كل وحدة ميزات في إضافة أدوات إنشاء الإدخالات إلى نشاط التطبيق باستخدام حقن التبعية.
على سبيل المثال، يستخدم الرمز البرمجي التالي عمليات الربط المتعددة في Dagger،
وتحديدًا @IntoSet، لإدخال أدوات إنشاء الإدخالات في Set يملكه
MainActivity. يتم بعد ذلك استدعاء هذه الدوال بشكل متكرر داخل entryProvider،
ما يلغي الحاجة إلى استدعاء العديد من دوال إنشاء الإدخالات بشكل صريح.
وحدة الميزات
// import dagger.Module // import dagger.Provides // import dagger.hilt.InstallIn // import dagger.hilt.android.components.ActivityRetainedComponent // import dagger.multibindings.IntoSet @Module @InstallIn(ActivityRetainedComponent::class) object FeatureAModule { @IntoSet @Provides fun provideFeatureAEntryBuilder() : EntryProviderScope<NavKey>.() -> Unit = { featureAEntryBuilder() } }
وحدة التطبيق
// import android.os.Bundle // import androidx.activity.ComponentActivity // import androidx.activity.compose.setContent // import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey // import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay // import javax.inject.Inject class MainActivity : ComponentActivity() { @Inject lateinit var entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<NavKey>.() -> Unit> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NavDisplay( entryProvider = entryProvider { entryBuilders.forEach { builder -> this.builder() } }, // ... ) } } }
إذا كانت إدخالات التنقّل بحاجة إلى التنقّل، على سبيل المثال، إذا كانت تحتوي على عناصر في واجهة المستخدم تنقل إلى شاشات جديدة، يمكنك إدخال عنصر قادر على تعديل حالة التنقّل في التطبيق في كل دالة إنشاء.
تقسيم أدوات مطابقة الروابط لصفحات معيّنة إلى وحدات
إذا كان تطبيقك يتيح استخدام الروابط العميقة وكان مقسّمًا إلى وحدات، يجب أن تحدّد كل وحدة ميزات مثيلات DeepLinkMatcher للوجهات التي تملكها.
لتجميع كل أدوات المطابقة من جميع أنحاء تطبيقك، يمكنك استخدام
عمليات الربط المتعددة لحقن التبعية. على سبيل المثال، يمكن لكل وحدة ميزات
أن تساهم بمطابقاتها في ربط Dagger @IntoSet المتعدد:
وحدة الميزات
@Module @InstallIn(ActivityRetainedComponent::class) object FeatureADeepLinkModule { @IntoSet @Provides fun provideUserMatcher(): DeepLinkMatcher<*, *> { return UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) } }
بعد ذلك، في وحدة التطبيق الرئيسية، مثل MainActivity، يمكنك إدخال مجموعة أدوات المطابقة واستخدامها لمطابقة الطلبات الواردة:
وحدة التطبيق
@AndroidEntryPoint class MainActivityWithDI : ComponentActivity() { @Inject lateinit var deepLinkMatchers: Set<@JvmSuppressWildcards DeepLinkMatcher<*, *>> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val request = DeepLinkRequest(intent = intent) val matchResult = deepLinkMatchers .mapNotNull { it.match(request) } .maxOrNull() val backStack = when (matchResult) { null -> listOf(HomeKey) is BackStackMatchResult<*, *> -> { @Suppress("UNCHECKED_CAST") matchResult.backStack as List<NavKey> } else -> listOf(matchResult.key) } } }
لمزيد من المعلومات حول تحديد الروابط العميقة والتعامل معها، يُرجى الاطّلاع على إتاحة الروابط العميقة.
الموارد
للاطّلاع على عيّنات تعليمات برمجية توضّح كيفية تقسيم رمز Navigation 3 إلى وحدات، يُرجى مراجعة:
- The Navigation 3 architecture code recipes
- رحلة تعلُّم التقسيم إلى وحدات من تطبيق Now in Android
- Androidify