Membangun navigasi kompleks di aplikasi mobile: stack, tab, dan drawer di Android/iOS/RN/Flutter, plus deep linking untuk membuka layar spesifik dari notifikasi atau URL — sambil menyusun navigasi multi-layer Fitku

Aplikasi Fitku sekarang punya data dan penyimpanan — tapi bagaimana pengguna berpindah antar layar dengan benar? Di episode 12 ini kita membangun navigasi: stack, tab, drawer, lalu deep linking — kemampuan membuka layar tertentu dari notifikasi atau URL. Navigasi yang buruk membuat pengguna tersesat; navigasi yang baik terasa alami tanpa disadari.
Mengapa deep linking penting? Karena ini jembatan antara aplikasi dan dunia luar: notifikasi "workout kamu dimulai" harus bisa langsung membuka layar workout yang tepat, bukan membuka ulang beranda.
Layar ditumpuk: beranda → detail → edit. Tombol back mem-pop tumpukan. Ini pola paling umum:
Home ─▶ WorkoutDetail ─▶ EditWorkout
▲
└───────── back ───────┘Layar utama dalam tab: Beranda, Workout, Progres, Profil. Sudah kita terapkan di episode 3 (Android) dengan NavigationBar.
Menu geser dari sisi layar — cocok untuk aksi jarang dipakai (Pengaturan, Bantuan, Logout).
Kombinasi ketiganya wajar dalam satu aplikasi: tab sebagai kerangka utama, stack di dalam tiap tab, drawer untuk menu tambahan.
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(onOpenWorkout = { id ->
navController.navigate("workout/$id")
}) }
composable(
route = "workout/{workoutId}",
arguments = listOf(navArgument("workoutId") { type = NavType.StringType })
) { WorkoutDetailScreen() }
}NavigationStack {
List(workouts) { workout in
NavigationLink("\(workout.name)") {
WorkoutDetailView(workout: workout)
}
}
.navigationTitle("Workout")
}// app/_layout.tsx
import { Stack } from "expo-router";
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: "Beranda" }} />
<Stack.Screen name="workout/[id]" options={{ title: "Detail Workout" }} />
</Stack>
);
}Expo Router (2026) berbasis file — setiap file di folder app/ adalah route. Deep linking langsung terdukung otomatis.
final router = GoRouter(
initialLocation: '/home',
routes: [
GoRoute(
path: '/home',
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: '/workout/:id',
builder: (context, state) => WorkoutDetailScreen(
workoutId: state.pathParameters['id']!),
),
],
);go_router juga mendukung redirect, guard, dan nested navigation.
Deep linking membuka layar spesifik saat aplikasi dibuka dari URL (custom scheme atau https) atau notifikasi.
<activity android:name=".WorkoutDetailActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="fitku" android:host="workout" />
</intent-filter>
</activity>Deklarasikan scheme di Info.plist, atau pakai Universal Links (https) untuk link yang terverifikasi. SwiftUI menerimanya via onOpenURL:
.onOpenURL { url in
// fitku://workout/42
if url.scheme == "fitku", let id = url.host == "workout" ? pathComponent(url) : nil {
navigateTo(workoutId: id)
}
}Note
Deep linking sering menjadi titik crash yang tidak disadari: pengguna membuka link lama, route sudah berubah, lalu aplikasi blank. Selalu siapkan fallback (redirect ke beranda) dan uji semua link yang pernah diedarkan.
Pola umum: aplikasi di background menerima notifikasi → user tap → aplikasi harus tahu "buka layar X". Solusinya: notifikasi membawa payload route, dan navigator memprosesnya setelah aplikasi siap.
Notifikasi (payload: workout/42)
│ tap
▼
Aplikasi dibuka / di-foreground
│
▼
Parser payload → navController.navigate("workout/42")
│
▼
Layar Detail Workout 42 tampilPayload notifikasi di episode 14 akan memakai pola ini — penting disiapkan sejak sekarang.
Tip
Bungkus semua rute dalam satu konstanta atau objek (misal AppRoutes.WORKOUT_DETAIL). Saat struktur navigasi berubah, kalian hanya mengubah satu tempat — deep link, notifikasi, dan kode internal tetap konsisten.
workout/{id} dengan id invalid → crash. Validasi sebelum render.navigate berulang saat user memencet tombol cepat → tumpukan menumpuk. Gunakan popUpTo/launchMode.Pada episode 12 ini, kalian telah membangun jalur pengguna:
Di episode 13 selanjutnya kita mengamankan aplikasi: Security Mobile — secure storage (Keychain/Keystore), certificate pinning, dan obfuscation untuk mengeraskan Fitku. Sampai jumpa!