تقسيم رمز التنقّل إلى وحدات

توضّح هذه الصفحة كيفية تقسيم رمز التنقّل إلى وحدات. والهدف منه هو تكملة الإرشادات العامة لتقسيم التطبيق إلى وحدات.

نظرة عامة

إنّ تقسيم رمز التنقّل إلى وحدات هو عملية فصل مفاتيح التنقّل ذات الصلة والمحتوى الذي تمثّله إلى وحدات فردية. يوفر هذا فصلاً واضحًا للمسؤوليات ويتيح لك التنقل بين الميزات المختلفة في تطبيقك.

لتقسيم رمز التنقّل إلى وحدات، اتّبِع الخطوات التالية:

  • إنشاء وحدتَين فرعيتَين: api وimpl لكل ميزة في تطبيقك
  • وضع مفاتيح التنقّل لكل ميزة في وحدة api الخاصة بها
  • ضع entryProviders والمحتوى القابل للتنقّل لكل ميزة في وحدة impl المرتبطة بها
  • يجب توفير entryProviders لوحدات تطبيقك الرئيسية، إما مباشرةً أو باستخدام حقن التبعية

فصل الميزات إلى وحدات فرعية لواجهة برمجة التطبيقات والتنفيذ

لكل ميزة في تطبيقك، أنشئ وحدتَين فرعيتَين باسم api وimpl (اختصار لـ "implementation"). استخدِم الجدول التالي لتحديد مكان وضع رمز التنقّل.

اسم الوحدة

يحتوي على

api

مفاتيح التنقّل

impl

محتوى هذه الميزة، بما في ذلك تعريفات NavEntry وentryProvider. يُرجى الاطّلاع أيضًا على حلّ المفاتيح للمحتوى.

يتيح هذا الأسلوب لميزة معيّنة الانتقال إلى ميزة أخرى من خلال السماح لمحتواها، المضمَّن في وحدة impl، بالاعتماد على مفاتيح التنقّل لوحدة أخرى، المضمَّنة في وحدة api لتلك الوحدة.

مخطّط بياني لتبعية وحدة الميزات يوضّح كيف يمكن لوحدات `impl` أن تعتمد على وحدات `api`
الشكل 1. مخطّط بياني لتبعية وحدة الميزات يوضّح كيف يمكن أن تعتمد وحدات التنفيذ على وحدات واجهة برمجة التطبيقات

فصل إدخالات التنقّل باستخدام دوال الإضافات

في 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 المتعدد:

وحدة الميزات

بعد ذلك، في وحدة التطبيق الرئيسية، مثل MainActivity، يمكنك إدخال مجموعة أدوات المطابقة واستخدامها لمطابقة الطلبات الواردة:

وحدة التطبيق

لمزيد من المعلومات حول تحديد الروابط العميقة والتعامل معها، يُرجى الاطّلاع على إتاحة الروابط العميقة.

الموارد

للاطّلاع على عيّنات تعليمات برمجية توضّح كيفية تقسيم رمز Navigation 3 إلى وحدات، يُرجى مراجعة: