Router — pola arsitektur yang memusatkan logika navigasi antar layar aplikasi. Router menentukan ke mana dan bagaimana berpindah saat suatu peristiwa terjadi. Di iOS, Router mengabstraksi UINavigationController dan segue, di Android — FragmentManager dan NavController dari Jetpack Navigation. Router dapat berfungsi sebagai pola mandiri atau sebagai komponen Coordinator (Router-per-Coordinator) dan VIPER (Router-per-module). Selengkapnya — di Android Navigation Component Guide.
Poin utama
Router — pola yang mengenkapsulasi logika perpindahan antar layar. Ide utama: ViewController (atau Presenter/ViewModel) tidak memanggil langsung navigationController.pushViewController, melainkan memberi tahu Router tentang niat berpindah. Router memutuskan ViewController mana yang akan dibuat dan bagaimana menampilkannya. Router bisa sederhana (kumpulan metode navigasi) atau kompleks (dengan routing berdasarkan skema URL, deep link, dan notifikasi push).
Tiga pendekatan Router — Router sebagai layanan (Navigator-singleton global), Router sebagai komponen modul (pendekatan VIPER), Router sebagai protokol (abstraksi untuk Coordinator). Router global — kesederhanaan (satu instance per aplikasi) — populer di proyek kecil. Router modular — setiap fitur memiliki Router sendiri — standar VIPER dan Clean Architecture. Router protokol — digunakan di Coordinator: RouterProtocol dengan metode push/present/pop/dismiss.
| Pendekatan | Struktur | Kapan digunakan |
|---|---|---|
| Navigator global | Singleton dengan metode perpindahan | Proyek kecil, prototipe |
| Router modular | Router di dalam setiap modul | VIPER, Clean Architecture |
| Router protokol | Protocol + implementasi untuk Coordinator | MVVM-C, Coordinator pattern |
Sejarah pola — Router muncul di framework web (URL Router — Rails Routes, Express.js) dan diadaptasi untuk pengembangan mobile. Di iOS, Router menjadi populer seiring pertumbuhan VIPER (2015-2017). Di Android, Router — bagian dari Jetpack Navigation (2018), solusi standar Google untuk navigasi. Saat ini Router merupakan bagian tak terpisahkan dari setiap arsitektur modular aplikasi mobile.
iOS Router — protokol dengan metode untuk berbagai jenis navigasi. Implementasi dasar membungkus UINavigationController. Router dapat mengelola presentasi modal (present/dismiss), push/pop di tumpukan navigasi, showDetail untuk Split View Controller dan presentasi layar penuh (iOS 13+). Router tidak membuat ViewController — ia menerima instance jadi dan menampilkannya. Pembuatan ViewController dilakukan oleh pabrik (Assembly, wadah DI) atau Coordinator.
// RouterProtocol untuk 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)
}
// Implementasi Router melalui 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 — pembuatan modul dengan Router
protocol ProfileModuleFactory {
func makeProfileView() -> UIViewController
}
Router di VIPER — setiap modul VIPER memiliki Router sendiri yang tahu layar mana yang akan dibuka dari modul saat ini. Router membuat ViewController modul berikutnya melalui pabrik dan mentransfer kendali. Router di VIPER — satu-satunya komponen yang berisi import UIKit (selain View). Ini menyederhanakan pengujian Presenter dan Interactor: mereka tidak bergantung pada UIKit.
Jetpack Navigation Component — router standar untuk Android, direkomendasikan oleh Google sejak 2018. Navigasi didefinisikan dalam grafik XML (nav_graph.xml): simpul (fragments, activities, destinations) dan tepi (actions). NavController mengelola transisi: memanggil FragmentManager.replace/add dan mengelola tumpukan balik (back stack). Navigation Component mendukung deep link, argumen, animasi transisi, dan Safe Args untuk transmisi data yang aman tipe.
// nav_graph.xml — grafik navigasi
<!-- @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 — navigasi melalui 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 — argumen aman tipe
class HomeFragmentArgs : NavArgs {
val userId: Int get() = arguments?.getInt("userId") ?: 0
}
// NavigationUI — integrasi dengan 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 link di Android Navigation — Navigation Component mendukung deep link eksplisit (PendingIntent + NavDeepLinkBuilder) dan implisit (melalui intent-filter di manifes). Deep link dapat mengarah ke simpul mana pun di nav_graph. Pemrosesan notifikasi push: Notification membuat PendingIntent dengan NavDeepLinkBuilder yang memulihkan tumpukan balik dan membuka layar yang diinginkan. Navigation Component secara otomatis menangani tombol Up/Back dan mengembalikan pengguna ke layar sebelumnya.
URL Routing — routing berdasarkan skema URL, deep link, dan universal link. Aplikasi mendaftarkan skema (myapp://profile/42) atau universal link (https://example.com/profile/42). Router mem-parse URL, mengekstrak parameter (userId=42) dan membuka layar yang sesuai. URL Routing memungkinkan pembukaan aplikasi dari luar: melalui tautan situs web, email, notifikasi push, kode QR. iOS menggunakan NSUserActivity + universal link, Android — intent-filter + deep link.
// URL Router — parsing deep link dan navigasi
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 — pemetaan URL ke rute
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 dalam praktik — aplikasi harus memproses deep link dalam tiga keadaan: belum dimulai (memulai dengan deep link), di latar belakang (pemulihan dari latar belakang), aktif (onNewIntent/SceneDelegate). URL Router harus memulihkan tumpukan balik dengan benar: saat deep link ke layar profil, pengguna harus dapat menekan Back dan kembali ke layar sebelumnya. iOS dan Android menangani tumpukan balik secara berbeda — Router harus mempertimbangkan karakteristik platform.
Router vs Coordinator — Router menjawab pertanyaan "bagaimana menampilkan layar?" (push/present), Coordinator — "layar mana yang akan ditampilkan?" (flow mana yang akan dijalankan). Router — alat navigasi, Coordinator — pengatur flow. Router digunakan oleh Coordinator. Di VIPER, Router menjalankan kedua fungsi: memutuskan ke mana pergi dan bagaimana menampilkan. Di MVVM-C, Router — protokol terpisah yang digunakan oleh Coordinator. Pola-pola ini tidak saling mengecualikan, melainkan saling melengkapi.
| Karakteristik | Router | Coordinator | Navigator |
|---|---|---|---|
| Fokus | Mekanika navigasi | Flow navigasi | Akses global |
| Tingkat | UI-framework (push/present) | Logika bisnis (flow) | Infrastruktur |
| Pembuatan layar | Menerima VC jadi | Membuat VC melalui pabrik | Membuat VC |
| Siklus hidup | Satu per navigasi | childCoordinators | Singleton |
Router vs Navigator — Navigator — nama lama Router di komunitas iOS. Dalam implementasi awal, Navigator adalah kelas Singleton dengan metode perpindahan. Navigator — Router-singleton global. Navigator lebih sederhana, tetapi menciptakan ketergantungan tersembunyi. Router berbasis protokol — lebih mudah diuji dan lebih modular. Navigator cocok untuk proyek tanpa arsitektur ketat, Router — untuk Clean Architecture dan VIPER.
Pertanyaan yang sering diajukan
Router — abstraksi di atas UINavigationController (push/present/pop). Coordinator — lapisan di atas Router yang mengelola flow (layar mana yang akan ditampilkan berikutnya). Router bertanggung jawab atas mekanika, Coordinator — atas logika navigasi. Coordinator menggunakan Router untuk melakukan transisi. Di VIPER, Router menggabungkan kedua fungsi, di MVVM-C — dipisahkan.
Tidak. Untuk aplikasi dengan 3-5 layar, pemanggilan langsung navigationController.pushViewController adalah solusi normal. Router menjadi berguna pada 10+ layar, deep link, notifikasi push, dan arsitektur modular. Router menyederhanakan pengujian navigasi dan memungkinkan pemrosesan terpusat transisi dari sumber mana pun (tombol, deep link, push).
URL Router — ekstensi Router yang mem-parse deep link dan universal link. URL Router menentukan kecocokan antara URL dan layar aplikasi. Misalnya, route myapp://profile/42 → ProfileViewController(userId: 42). URL Router memusatkan pemrosesan deep link dari berbagai sumber: notifikasi push, kode QR, tautan email, tautan universal.
Ya. Router dapat berfungsi secara mandiri — sebagai Navigator global atau sebagai komponen modul VIPER. Router tanpa Coordinator — hanya enkapsulasi UINavigationController di belakang protokol. Coordinator tanpa Router — lebih sulit (ViewController sendiri memanggil push/present), tetapi mungkin. Praktik terbaik — Router + Coordinator bersama-sama.
Secara fungsional — ya, keduanya memusatkan navigasi. Implementasi berbeda: iOS Router — protokol + kelas di sekitar UINavigationController; Android — Jetpack Navigation Component dengan grafik XML dan NavController. Android Router tertanam dalam framework (Navigation Component), iOS Router — implementasi eksternal. Android Router mendukung Safe Args, iOS Router — tidak (perlu generics atau Codable).
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga