Router — βασικές αρχές του προτύπου δρομολόγησης σε iOS και Android

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-02-19 Χρόνος ανάγνωσης: 9 λεπ

Router (δρομολογητής) — αρχιτεκτονικό πρότυπο που συγκεντρώνει τη λογική πλοήγησης μεταξύ των οθονών της εφαρμογής. Το Router καθορίζει πού και πώς να μεταβεί όταν συμβεί ένα συμβάν. Στο iOS, το Router αφαιρεί το UINavigationController και το segue, στο Android — το FragmentManager και το NavController από το Jetpack Navigation. Το Router μπορεί να λειτουργήσει ως ανεξάρτητο πρότυπο ή ως συστατικό Coordinator (Router-per-Coordinator) και VIPER (Router-per-module). Περισσότερα — στο Android Navigation Component Guide.

Κύρια σημεία

  • Router — πρότυπο δρομολόγησης που συγκεντρώνει την πλοήγηση μεταξύ οθονών
  • Δύο επίπεδα — Το Router μπορεί να είναι συστατικό Coordinator ή ανεξάρτητο πρότυπο
  • iOS Router — αφαίρεση πάνω από το UINavigationController με μεθόδους push/present/pop
  • Android Router — Jetpack Navigation Component με NavController και deep links
  • URL Routing — δρομολόγηση βάσει σχημάτων URL (deeplink, universal link)

Τι είναι το Router: ουσία του προτύπου δρομολόγησης

Router — πρότυπο που ενσωματώνει τη λογική μετάβασης μεταξύ οθονών. Βασική ιδέα: ο ViewController (ή Presenter/ViewModel) δεν καλεί απευθείας το navigationController.pushViewController, αλλά ενημερώνει το Router για την πρόθεση πλοήγησης. Το Router αποφασίζει ποιο ViewController να δημιουργήσει και πώς να το εμφανίσει. Το Router μπορεί να είναι απλό (συλλογή μεθόδων πλοήγησης) ή σύνθετο (με δρομολόγηση βάσει σχημάτων URL, deep links και push ειδοποιήσεων).

Τρεις προσεγγίσεις στο Router — Router ως υπηρεσία (καθολικό Navigator-singleton), Router ως συστατικό ενότητας (προσέγγιση VIPER), Router ως πρωτόκολλο (αφαίρεση για Coordinator). Καθολικό Router — απλότητα (μία παρουσία ανά εφαρμογή) — δημοφιλές σε μικρά έργα. Αρθρωτό Router — κάθε λειτουργία έχει το δικό της Router — πρότυπο VIPER και Clean Architecture. Πρωτοκολλικό Router — χρησιμοποιείται στο Coordinator: RouterProtocol με μεθόδους push/present/pop/dismiss.

ΠροσέγγισηΔομήΠότε να χρησιμοποιηθεί
Καθολικό NavigatorSingleton με μεθόδους μετάβασηςΜικρά έργα, πρωτότυπα
Αρθρωτό RouterRouter εντός κάθε ενότηταςVIPER, Clean Architecture
Πρωτοκολλικό RouterProtocol + υλοποίηση για CoordinatorMVVM-C, Coordinator pattern

Ιστορία του προτύπου — Το Router εμφανίστηκε σε web frameworks (URL Router — Rails Routes, Express.js) και προσαρμόστηκε για κινητή ανάπτυξη. Στο iOS, το Router έγινε δημοφιλές με την άνοδο του VIPER (2015-2017). Στο Android, το Router — μέρος του Jetpack Navigation (2018), της τυπικής λύσης της Google για πλοήγηση. Τώρα το Router είναι αναπόσπαστο μέρος κάθε αρθρωτής αρχιτεκτονικής εφαρμογών κινητών.

Router στο iOS: υλοποίηση σε Swift

iOS Router — πρωτόκολλο με μεθόδους για διαφορετικούς τύπους πλοήγησης. Η βασική υλοποίηση περιβάλλει το UINavigationController. Το Router μπορεί να διαχειριστεί modal παρουσιάσεις (present/dismiss), push/pop στη στοίβα πλοήγησης, showDetail για Split View Controller και παρουσιάσεις πλήρους οθόνης (iOS 13+). Το Router δεν δημιουργεί ViewController — λαμβάνει μια έτοιμη παρουσία και την εμφανίζει. Η δημιουργία ViewController γίνεται από εργοστάσιο (Assembly, DI-container) ή Coordinator.

swift
// RouterProtocol για iOS
protocol RouterProtocol {
    func push(_ viewController: UIViewController, animated: Bool)
    func pop(animated: Bool)
    func popToRoot(animated: Bool)
    func present(_ viewController: UIViewController, animated: Bool)
    func dismiss(animated: Bool)
    func setViewControllers(_: [UIViewController], animated: Bool)
}

// Υλοποίηση Router μέσω UINavigationController
class NavigationRouter: RouterProtocol {
    private let navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func push(_ vc: UIViewController, animated: Bool) {
        if navigationController.presentedViewController {
            navigationController.dismiss(animated: false)
        }
        navigationController.pushViewController(vc, animated: animated)
    }

    func pop(animated: Bool) {
        navigationController.popViewController(animated: animated)
    }

    func popToRoot(animated: Bool) {
        navigationController.popToRootViewController(animated: animated)
    }

    func present(_ vc: UIViewController, animated: Bool) {
        navigationController.present(vc, animated: animated)
    }

    func dismiss(animated: Bool) {
        navigationController.dismiss(animated: animated)
    }

    func setViewControllers(_ vcs: [UIViewController], animated: Bool) {
        navigationController.setViewControllers(vcs, animated: animated)
    }
}

// Assembly — δημιουργία ενότητας με Router
protocol ProfileModuleFactory {
    func makeProfileView() -> UIViewController
}

Router στο VIPER — κάθε ενότητα VIPER έχει το δικό της Router που γνωρίζει ποιες οθόνες να ανοίξει από την τρέχουσα ενότητα. Το Router δημιουργεί το ViewController της επόμενης ενότητας μέσω εργοστασίου και μεταφέρει τον έλεγχο. Router στο VIPER — το μόνο συστατικό που περιέχει import UIKit (εκτός από το View). Αυτό απλοποιεί τη δοκιμή Presenter και Interactor: δεν εξαρτώνται από το UIKit.

Router στο Android: Jetpack Navigation Component

Jetpack Navigation Component — τυπικός router για Android, προτεινόμενος από την Google από το 2018. Η πλοήγηση ορίζεται σε ένα γράφημα XML (nav_graph.xml): κόμβοι (fragments, activities, destinations) και ακμές (actions). Το NavController διαχειρίζεται τις μεταβάσεις: καλεί FragmentManager.replace/add και διαχειρίζεται τη στοίβα επιστροφής (back stack). Το Navigation Component υποστηρίζει deep links, ορίσματα, κινούμενα σχέδια μετάβασης και Safe Args για ασφαλή μεταφορά δεδομένων τύπων.

kotlin
// nav_graph.xml — γράφημα πλοήγησης
<!-- @xml/nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/loginFragment">

    <fragment android:id="@+id/loginFragment"
        android:name=".ui.login.LoginFragment">
        <action android:id="@+id/to_home"
            app:destination="@id/homeFragment" />
    </fragment>

    <fragment android:id="@+id/homeFragment"
        android:name=".ui.home.HomeFragment">
        <argument android:name="userId"
            android:defaultValue="0"
            app:argType="integer" />
        <deepLink app:uri="myapp://home/{userId}" />
    </fragment>
</navigation>

// Kotlin — πλοήγηση μέσω NavController
class LoginFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.loginButton.setOnClickListener {
            val action = LoginFragmentDirections.toHome(userId = 42)
            findNavController().navigate(action)
        }
    }
}

// Safe Args — ασφαλή ορίσματα τύπων
class HomeFragmentArgs : NavArgs {
    val userId: Int get() = arguments?.getInt("userId") ?: 0
}

// NavigationUI — ενσωμάτωση με Toolbar, BottomNav, Drawer
class MainActivity : AppCompatActivity() {
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val navHost = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHost.navController
        NavigationUI.setupActionBarWithNavController(this, navController)
    }
}

Deep links στο Android Navigation — Το Navigation Component υποστηρίζει ρητά deep links (PendingIntent + NavDeepLinkBuilder) και άρρητα (μέσω intent-filter στο manifest). Το deep link μπορεί να οδηγήσει σε οποιονδήποτε κόμβο του nav_graph. Επεξεργασία push ειδοποιήσεων: η Notification δημιουργεί ένα PendingIntent με NavDeepLinkBuilder που επαναφέρει τη στοίβα επιστροφής και ανοίγει την επιθυμητή οθόνη. Το Navigation Component διαχειρίζεται αυτόματα τα κουμπιά Up/Back και επιστρέφει τον χρήστη στην προηγούμενη οθόνη.

URL Routing: δρομολόγηση Deeplink και Universal Link

URL Routing — δρομολόγηση βάσει σχημάτων URL, deep links και universal links. Η εφαρμογή καταχωρεί ένα σχήμα (myapp://profile/42) ή ένα universal link (https://example.com/profile/42). Το Router αναλύει το URL, εξάγει παραμέτρους (userId=42) και ανοίγει την αντίστοιχη οθόνη. Το URL Routing επιτρέπει το άνοιγμα της εφαρμογής από έξω: μέσω συνδέσμου από ιστότοπο, email, push ειδοποίησης, κωδικού QR. Το iOS χρησιμοποιεί NSUserActivity + universal link, το Android — intent-filter + deep link.

swift
// URL Router — ανάλυση deep link και πλοήγηση
protocol URLRoute {
    var pattern: String { get }
    func navigate(parameters: [String: String], router: RouterProtocol)
}

struct ProfileRoute: URLRoute {
    let pattern = "myapp://profile/{userId}"

    func navigate(parameters: [String: String], router: RouterProtocol) {
        guard let userId = parameters["userId"] else { return }
        let profileVC = ProfileViewController(userId: userId)
        router.push(profileVC, animated: true)
    }
}

// URL Router — αντιστοίχιση URL με διαδρομές
class URLRouter {
    private var routes: [URLRoute] = []

    func handle(_ url: URL, router: RouterProtocol) {
        for route in routes {
            if let params = matchPattern(route.pattern, url: url) {
                route.navigate(parameters: params, router: router)
                return
            }
        }
    }
}

Deep link routing στην πράξη — η εφαρμογή πρέπει να επεξεργαστεί το deep link σε τρεις καταστάσεις: δεν έχει ξεκινήσει (εκκίνηση με deep link), στο παρασκήνιο (επαναφορά από παρασκήνιο), ενεργή (onNewIntent/SceneDelegate). Το URL Router πρέπει να επαναφέρει σωστά τη στοίβα επιστροφής: σε deep link στην οθόνη προφίλ, ο χρήστης πρέπει να μπορεί να πατήσει Back και να επιστρέψει στην προηγούμενη οθόνη. Το iOS και το Android διαχειρίζονται διαφορετικά τη στοίβα επιστροφής — το Router πρέπει να λαμβάνει υπόψη τα χαρακτηριστικά πλατφόρμας.

Σύγκριση Router με Coordinator και Navigator

Router vs Coordinator — Το Router απαντά στην ερώτηση "πώς να εμφανίσουμε την οθόνη;" (push/present), το Coordinator — "ποια οθόνη να εμφανίσουμε;" (ποιο flow να ξεκινήσουμε). Router — εργαλείο πλοήγησης, Coordinator — διοργανωτής flow. Το Router χρησιμοποιείται από τον Coordinator. Στο VIPER, το Router εκτελεί και τις δύο λειτουργίες: αποφασίζει πού να πάει και πώς να εμφανίσει. Στο MVVM-C, το Router — ξεχωριστό πρωτόκολλο που χρησιμοποιείται από τον Coordinator. Τα πρότυπα δεν αλληλοαποκλείονται, αλλά αλληλοσυμπληρώνονται.

ΧαρακτηριστικόRouterCoordinatorNavigator
ΕστίασηΜηχανική πλοήγησηςFlow πλοήγησηςΚαθολική πρόσβαση
ΕπίπεδοUI-framework (push/present)Επιχειρηματική λογική (flow)Υποδομή
Δημιουργία οθονώνΛαμβάνει έτοιμο VCΔημιουργεί VC μέσω εργοστασίουΔημιουργεί VC
Κύκλος ζωήςΈνα ανά πλοήγησηchildCoordinatorsSingleton

Router vs Navigator — Navigator — παλιά ονομασία του Router στην κοινότητα iOS. Σε πρώιμες υλοποιήσεις, το Navigator ήταν μια κλάση Singleton με μεθόδους μετάβασης. Navigator — ένα καθολικό Router-singleton. Το Navigator είναι απλούστερο, αλλά δημιουργεί κρυφές εξαρτήσεις. Το Router σε πρωτόκολλα — πιο δοκιμάσιμο και αρθρωτό. Το Navigator είναι κατάλληλο για έργα χωρίς αυστηρή αρχιτεκτονική, το Router — για Clean Architecture και VIPER.

Συχνές ερωτήσεις

Ποια είναι η διαφορά μεταξύ Router και Coordinator;

Router — αφαίρεση πάνω από UINavigationController (push/present/pop). Coordinator — στρώμα πάνω από το Router που διαχειρίζεται το flow (ποια οθόνη θα εμφανιστεί επόμενη). Το Router είναι υπεύθυνο για τη μηχανική, ο Coordinator — για τη λογική πλοήγησης. Ο Coordinator χρησιμοποιεί το Router για την εκτέλεση μεταβάσεων. Στο VIPER, το Router συνδυάζει και τις δύο λειτουργίες, στο MVVM-C — είναι διαχωρισμένες.

Είναι υποχρεωτική η χρήση Router σε εφαρμογή κινητού;

Όχι. Για εφαρμογές με 3-5 οθόνες, οι άμεσες κλήσεις navigationController.pushViewController είναι μια φυσιολογική λύση. Το Router γίνεται χρήσιμο σε 10+ οθόνες, deep links, push ειδοποιήσεις και αρθρωτή αρχιτεκτονική. Το Router απλοποιεί τη δοκιμή πλοήγησης και επιτρέπει την κεντρική επεξεργασία μεταβάσεων από οποιαδήποτε πηγή (κουμπί, deep link, push).

Πώς σχετίζεται το Router με τα Deep Links;

URL Router — επέκταση του Router που αναλύει deep links και universal links. Το URL Router καθορίζει την αντιστοιχία μεταξύ URL και οθόνης εφαρμογής. Για παράδειγμα, route myapp://profile/42 → ProfileViewController(userId: 42). Το URL Router συγκεντρώνει την επεξεργασία deep links από διαφορετικές πηγές: push ειδοποιήσεις, κωδικοί QR, σύνδεσμοι email, καθολικοί σύνδεσμοι.

Μπορεί να χρησιμοποιηθεί το Router χωρίς Coordinator;

Ναι. Το Router μπορεί να λειτουργήσει ανεξάρτητα — ως καθολικό Navigator ή ως συστατικό ενότητας VIPER. Router χωρίς Coordinator — απλώς ενσωμάτωση του UINavigationController πίσω από ένα πρωτόκολλο. Coordinator χωρίς Router — πιο δύσκολο (ο ViewController καλεί ο ίδιος push/present), αλλά δυνατό. Βέλτιστη πρακτική — Router + Coordinator μαζί.

Το Router στο Android είναι το ίδιο με το iOS Router;

Λειτουργικά — ναι, και τα δύο συγκεντρώνουν την πλοήγηση. Η υλοποίηση διαφέρει: iOS Router — πρωτόκολλο + κλάση γύρω από το UINavigationController; Android — Jetpack Navigation Component με γράφημα XML και NavController. Το Android Router είναι ενσωματωμένο στο framework (Navigation Component), το iOS Router — εξωτερική υλοποίηση. Το Android Router υποστηρίζει Safe Args, το iOS Router — όχι (χρειάζονται generics ή Codable).

Συμπέρασμα

  • Router — πρότυπο δρομολόγησης που ενσωματώνει τη λογική μεταβάσεων μεταξύ οθονών
  • iOS Router — πρωτόκολλο με μεθόδους push/present/pop γύρω από UINavigationController
  • Android Router — Jetpack Navigation Component με XML nav_graph και NavController
  • URL Routing — δρομολόγηση μέσω deep links και καθολικών συνδέσμων
  • Router vs Coordinator — Router υπεύθυνο για μηχανική, Coordinator για flow πλοήγησης
  • Εφαρμογή — αρθρωτή αρχιτεκτονική, deep links, δοκιμή πλοήγησης

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης