All Posts
[Bagian 1] Flutter Deep Linking — Android App Links: Menyiapkan Routing Aplikasi dengan Go Router

[Bagian 1] Flutter Deep Linking — Android App Links: Menyiapkan Routing Aplikasi dengan Go Router

Langkah pertama implementasi Deep Linking di Flutter — menyiapkan routing aplikasi dengan Go Router, termasuk nested routes dan pengiriman data antar halaman.

Published

September 13, 2024

Category

Flutter

Read time

7 min

Flutter Deep Link Android Go Router Mobile

Halo Devs! Semoga masih semangat ya! Artikel ini adalah langkah awal untuk memulai mengimplementasikan Deep linking (Android App Links) pada aplikasi Android menggunakan framework Flutter. Jika belum paham mengenai Deep linking, silakan baca artikel pembukanya dulu ya :)

Seri ini akan dibagi menjadi beberapa artikel mengingat kita harus menyiapkan beberapa hal sebelum benar-benar bisa mengimplementasikan Deep linking pada aplikasi Android kita:

Untuk development, disarankan menggunakan Android Studio atau Microsoft Visual Studio Code dengan Flutter dan Dart extension yang sudah terinstall.

Pastikan sudah install plugin (Android Studio) atau ekstensi (Microsoft Visual Studio Code) Flutter & Dart

Starter code project tersedia di: https://github.com/rafiadipramana/flutter_deep_link_android

Struktur folder dari starter code

Implementasi pada artikel ini dibagi menjadi 5 TODO:


TODO 1: Menambahkan MaterialApp.router

import 'package:flutter/material.dart';

void main() {
  runApp(
    const FlutterDeepLinks(),
  );
}

class FlutterDeepLinks extends StatelessWidget {
  const FlutterDeepLinks({super.key});

  @override
  Widget build(BuildContext context) {
    // TODO 1: Add MaterialApp.router
    // TODO 3: Add our AppRouter.routerConfig as the router property
    return MaterialApp.router();
  }
}

TODO 2: Membuat GoRouter Instance dengan Routes

import 'package:go_router/go_router.dart';

import 'detail_page.dart';
import 'home_page.dart';

class AppRouter {
  /// Add go_router as our dependency using this command in the terminal:
  /// 'flutter pub add go_router'
  /// Add the following import statement to the top of the file
  /// import 'package:go_router/go_router.dart';

  // TODO 2: Create a static instance of GoRouter and define some routes
  static GoRouter routerConfig = GoRouter(
    initialLocation: '/',
    routes: <GoRoute>[
      GoRoute(
        path: '/',
        name: 'home',
        builder: (context, state) {
          return const HomePage();
        },
        routes: <GoRoute>[
          GoRoute(
            path: 'detail/:username',
            name: 'detail',
            builder: (context, state) {
              return DetailPage(
                passedData: {
                  'pathParameters': state.pathParameters,
                  'queryParameters': state.uri.queryParameters,
                  'extra': state.extra,
                },
              );
            },
          ),
        ],
      ),
    ],
  );
}

Nested Routes

Rute bersarang memastikan pengguna tidak dikeluarkan dari aplikasi ketika menekan tombol back pada device jika sebelumnya mengakses Deep linking.

/// Other rest of the code

GoRoute(
  path: '/',
  name: 'home',
  builder: (context, state) {
    return const HomePage();
  },
  routes: <GoRoute>[
    /// Back action from detail page will be redirect to parent route (home)
    GoRoute(
      path: 'detail/:username',
      name: 'detail',

/// Other rest of the code

Meneruskan Data dari URL

Meneruskan data yang didapatkan dari path parameters, query parameters, dan extra (jika ada). Mekanisme ini sangat penting agar halaman yang kita tuju menggunakan Deep linking bisa mengekstrak informasi dari link/URL.

Informasi yang diekstrak dari link atau URL

/// Other rest of the code

GoRoute(
  /// :username as path parameter key
  path: 'detail/:username',
  name: 'detail',
  builder: (context, state) {
    return DetailPage(
      passedData: {
        /// Parse the path parameters (if any)
        'pathParameters': state.pathParameters,
        /// Parse the query parameters (if any)
        'queryParameters': state.uri.queryParameters,
        /// Parse the extra parameters (if any)
        'extra': state.extra,
      },
    );
  },
),

/// Other rest of the code

TODO 3: Menambahkan routerConfig ke MaterialApp.router

import 'package:flutter/material.dart';
import 'app_router.dart';

void main() {
  runApp(
    const FlutterDeepLinks(),
  );
}

class FlutterDeepLinks extends StatelessWidget {
  const FlutterDeepLinks({super.key});

  @override
  Widget build(BuildContext context) {
    // TODO 1: Add MaterialApp.router
    // TODO 3: Add our AppRouter.routerConfig as the router property
    return MaterialApp.router(
      /// Add the routerConfig property
      routerConfig: AppRouter.appRouter,
    );
  }
}

Sekarang, seharusnya kita sudah bisa mencoba menjalankan aplikasi kita. Sesuai konfigurasi rute yang kita telah definisikan sebelumnya pada properti initialLocation, maka rute pertama aplikasi adalah pada path '/' yaitu di HomePage().

Tampilan HomePage() dari file home_page.dart


TODO 4: Navigasi ke Detail Page dengan Data

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home Page'),
      ),
      body: SizedBox(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Welcome to the Home Page :)'),
            ElevatedButton(
              onPressed: () {
                // TODO 4: Navigate to the details page and pass some data
                /// Use context.pushNamed to navigate to the details page
                context.pushNamed(
                  /// Use named route "detail" to pass some data
                  "detail",
                  /// Pass the path parameters
                  pathParameters: {
                    "username": "rafiadipramana",
                  },
                  /// Pass the query parameters
                  queryParameters: {
                    "lang": "id"
                  },
                  /// Pass the extra data
                  extra: {
                    "extra": "This is coming from HomePage()",
                  },
                );
              },
              child: const Text('Go to Details Page'),
            ),
          ],
        ),
      ),
    );
  }
}

Penggunaan context.pushNamed merupakan mekanisme navigasi yang disediakan Go Router untuk melakukan push (mendorong/menumpuk) halaman baru di atas halaman sebelumnya — di kasus ini adalah menumpuk halaman detail di atas halaman home.

Mekanisme tumpukan halaman di aplikasi

context.pushNamed dipilih daripada context.push, karena kita dapat menggunakan properti seperti pathParameters, queryParameters, dan extra. Properti-properti tersebut akan dimanfaatkan untuk mengirimkan data ke halaman detail.


TODO 5: Menampilkan Data di Detail Page

import 'package:flutter/material.dart';

class DetailPage extends StatelessWidget {
  /// The data passed from the home page, make it nullable
  final Map<String, dynamic>? passedData;

  const DetailPage({
    super.key,

    /// Initialize the passedData parameter as not required
    this.passedData,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Detail Page'),
      ),
      body: SizedBox(
        width: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('Hi, You are on the Detail Page :)'),
            // TODO 5: If passedData is not null, display it
            Text(
              /// Using ternary operator to check if passedData is not null
              passedData != null ? passedData.toString() : 'No data passed',
              textAlign: TextAlign.center,
            ),
          ],
        ),
      ),
    );
  }
}

Penggunaan ternary operator untuk mengecek apakah ada data yang diterima di halaman detail. Jika ada data yang diterima (!= null) = true, maka menampilkan data tersebut. Sebaliknya, jika tidak ada data yang diterima (!= null) = false, maka akan menampilkan teks 'No data passed'.

/// Other rest of the code

// TODO 5: If passedData is not null, display it
Text(
  /// Using ternary operator to check if passedData is not null
  passedData != null ? passedData.toString() : 'No data passed',
  textAlign: TextAlign.center,
),

/// Other rest of the code

Hasil Akhir

Demo aplikasi dengan navigasi dan data passing


Sekarang kita sudah satu langkah lebih dekat untuk bisa mengimplementasikan fitur Deep linking pada aplikasi kita! Silakan ikuti bagian demi bagian dari seri ini ya, terima kasih banyak sudah membaca sampai akhir!

Jika kamu tertarik, merasa kesulitan, atau hanya sekedar ingin terhubung. Boleh banget follow & kontak saya di akun berikut :)