الانتقال إلى Navigation 3

يمثّل Navigation 3 تغييرًا أساسيًا في طريقة تعامل Jetpack Compose مع حالة التنقّل، ويقدّم مزايا معمارية كبيرة مقارنةً بـ Navigation 2.

تعرَّف على التغييرات المعمارية والخطوات المطلوبة لنقل تطبيق Wear Compose من Navigation 2 إلى Navigation 3.

المزايا الرئيسية في Navigation 3

  • التحكّم المباشر في قائمة التتبّع السابقة: إنّ NavBackStack هي في الأساس مجرّد قائمة قابلة للتعديل من عناصر NavKey، تمثّل سجلّ الشاشات التي زارها المستخدم. يمكنك التحكّم فيها تمامًا كما تفعل مع أي Kotlin MutableList (add, removeLast, clear). يمكنك تعديل القائمة مباشرةً لتنفيذ إجراءات التنقّل، مثل إضافة مفتاح للانتقال إلى الأمام أو إزالة مفتاح للرجوع إلى الخلف.
  • التصميم المستند إلى Compose أولاً: يتم تصميم قائمة التتبّع السابقة كحالة قابلة للمراقبة عادية يتطابق تعديل سجلّ التنقّل تمامًا مع تعديل أي حالة أخرى في Compose، ما يؤدي تلقائيًا إلى إعادة الإنشاء لعرض الشاشة الحالية.
  • النوع الآمن تلقائيًا: يتم التخلّص تمامًا من المسارات المستندة إلى السلاسل. يستخدم التنقّل كائنات بيانات وفئات بيانات قابلة للنشر على نحو متسلسِل.
  • العروض المفصولة (استراتيجيات المشهد): يتم فصل طبقة انتقال واجهة المستخدم (NavDisplay وSwipeDismissableSceneStrategy) تمامًا عن تتبُّع الحالة (NavBackStack)، ما يتيح دمجًا أبسط لعمليات انتقال التنقّل المضمّنة في Wear OS.

خطوات نقل البيانات

‫1. تعديل الطلبات المرتبطة

أزِل الاعتمادية القديمة androidx.wear.compose:compose-navigation وأضِف الاعتماديات الجديدة المنقسمة في Navigation 3، بالإضافة إلى دعم النشر على نحو متسلسِل في Kotlin.

الإزالة:

implementation("androidx.wear.compose:compose-navigation:...")

الإضافة:

implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...")      // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin

‫2. تعديل الوجهات لتنفيذ NavKey

في Navigation 2، ربما استخدمت سلاسل أو كائنات عامة للتوجيه. في Navigation 3، عليك تنفيذ واجهة العلامة NavKey وتصنيف كل كائن شاشة باستخدام @Serializable.

لماذا هذا الإجراء مطلوب؟ لكي يمكن حفظ الأنشطة السابقة واستعادتها عند إيقاف العملية نهائيًا، يعتمد navigation3-runtime الأساسي على kotlinx-serialization لنشر الحالة على نحو متسلسِل.

قبل (Navigation 2 - المسارات العامة الآمنة من حيث النوع):

sealed class Nav2Screen {
    data object Landing : Nav2Screen()
    data object List : Nav2Screen()
}

بعد (Navigation 3 - NavKey + قابل للنشر على نحو متسلسِل):

@Serializable
sealed interface MigrationScreen : NavKey {
    @Serializable
    data object Landing : MigrationScreen

    @Serializable
    data object List : MigrationScreen
}

‫3. استبدال منطق التوجيه (NavController بـ NavBackStack)

استبدِل NavController بـ NavBackStack تم إعداده باستخدام rememberNavBackStack. عليك أيضًا إنشاء مثيل SwipeDismissableSceneStrategy خصيصًا لنظام التشغيل Wear OS.

قبل (Navigation 2):

val navController = rememberSwipeDismissableNavController()

بعد (Navigation 3):

val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey)
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

‫4. استبدال NavHost بـ NavDisplay وDSL entryProvider

يتم استبدال الحاوية NavHost وDSL المنشئ الداخلي composable("route") { ... } بـ NavDisplay وDSL entryProvider { entry<Key> { ... } }.

قبل (Navigation 2):

SwipeDismissableNavHost(navController = navController, startDestination = "menu") {
    composable("menu") {
        GreetingScreen(
            onShowList = { navController.navigate("list") }
        )
    }
    composable("list") {
        ListScreen()
    }
}

بعد (Navigation 3):

NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        entry<MigrationScreen.Landing> {
            GreetingScreen(
                onShowList = { backStack.add(MigrationScreen.List) }
            )
        }
        entry<MigrationScreen.List> {
            ListScreen()
        }
    }
)