WebView JavaScript Bridge untuk Navigasi

Menggunakan JavaScript Bridge untuk navigasi WebView

Panduan WebView JavaScript Bridge untuk Navigasi

Tutorial sederhana untuk membuat tombol dan link di halaman web (WebView) yang dapat menavigasi ke menu lain di aplikasi Hexaflate.


Apa itu JavaScript Bridge?

JavaScript Bridge memungkinkan halaman web di dalam aplikasi berkomunikasi dengan aplikasi native Flutter. Dengan fitur ini, Anda bisa:

  • Navigasi ke menu lain (menuId)
  • Buka screen tertentu (route)
  • Buka WebView baru (nested webview)
  • Buka submenu (bottom sheet atau full screen)
  • Print struk/receipt (print)
  • Buka URL eksternal (browser)
  • Reload halaman atau kembali

Daftar Action yang Tersedia

ActionFungsiURL Scheme
menuIdNavigasi ke menu berdasarkan ID✅ Didukung
navigateNavigasi ke Flutter route✅ Didukung
webviewBuka WebView baru✅ Didukung
submenuTampilkan submenu❌ Via JS Bridge saja
printTampilkan print preview dengan data custom❌ Via JS Bridge saja
externalBuka URL di browser eksternal✅ Didukung
reloadRefresh WebView✅ Didukung
backKembali/tutup WebView✅ Didukung

Bonus: URL Scheme Method

Selain JavaScript Bridge, ada dua cara alternatif menggunakan URL:

1. Eksternal Browser: ?newbrowser=ok

  • Tambahkan ?newbrowser=ok di URL untuk otomatis buka di browser eksternal
  • Tidak perlu JavaScript! Contoh: <a href="https://google.com?newbrowser=ok">Google</a>
  • Detail lengkap di bagian Buka URL di Browser Eksternal

2. Navigasi Aplikasi: hexaflate://

  • Gunakan custom scheme hexaflate:// untuk navigasi internal tanpa JavaScript Bridge
  • Format: hexaflate://<action>[/<route>]?<query_params>
  • Tidak perlu JavaScript! Cukup link atau redirect biasa
  • Contoh: <a href="hexaflate://navigate/history">Riwayat</a>
  • Detail lengkap di bagian Alternatif: URL Scheme Bridge

Cara Menggunakan JavaScript Bridge

Template Dasar

Semua action menggunakan format yang sama:

window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
  action: 'nama_action',
  // parameter lainnya...
}));

1. Navigasi ke Menu Berdasarkan ID (menuId)

Prioritas Tertinggi - Sama seperti banner dan menu icon!

Cara Mendapatkan Menu ID

  1. Buka Admin PanelLayout AplikasiCanvas
  2. Pilih screen yang memiliki menu
  3. Klik widget Grup Menu
  4. Klik Buka Editor Menu
  5. Copy ID dari menu yang ingin dituju

Contoh HTML + JavaScript

Via JavaScript Bridge:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Navigasi ke Menu</title>
</head>
<body>
    <h1>Pilih Menu</h1>
    
    <button onclick="goToMenu('pulsa-menu-001')">Beli Pulsa</button>
    <button onclick="goToMenu('data-menu-002')">Beli Paket Data</button>
    <button onclick="goToMenu('listrik-menu-003')">Bayar Listrik</button>

    <script>
        function goToMenu(menuId) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'menuId',
                menuId: menuId
            }));
        }
    </script>
</body>
</html>

Via URL Scheme (tanpa JavaScript):

<a href="hexaflate://menuId?menuId=pulsa-menu-001">Beli Pulsa</a>
<a href="hexaflate://menuId?menuId=data-menu-002">Paket Data</a>

2. Navigasi ke Flutter Route (navigate)

Buka screen tertentu di aplikasi (seperti /product, /history, /profile).

Contoh HTML + JavaScript

Via JavaScript Bridge:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Navigasi Route</title>
</head>
<body>
    <h1>Navigasi Cepat</h1>
    
    <button onclick="navigateToRoute('/product')">Beli Produk</button>
    <button onclick="navigateToRoute('/history')">Lihat Riwayat</button>
    <button onclick="navigateToRoute('/mutasi')">Mutasi Saldo</button>
    <button onclick="navigateToRoute('/profile')">Profil</button>
    <button onclick="navigateToRoute('/settings')">Pengaturan</button>
    <button onclick="navigateToProductWithOperator()">Beli Pulsa Indosat</button>

    <script>
        function navigateToRoute(route) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'navigate',
                route: route
            }));
        }
        
        function navigateToProductWithOperator() {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'navigate',
                route: '/product',
                args: {
                    operators: ['INDOSAT'],
                    hintText: 'Masukkan nomor Indosat',
                    screenTitle: 'Pulsa Indosat'
                }
            }));
        }
    </script>
</body>
</html>

Via URL Scheme (tanpa JavaScript):

<!-- Navigasi sederhana tanpa args -->
<a href="hexaflate://navigate/history">Riwayat Transaksi</a>
<a href="hexaflate://navigate/profile">Profil Saya</a>

<!-- Navigasi dengan args via query parameters -->
<a href="hexaflate://navigate/product?screenTitle=Pulsa%20Indosat&hintText=Masukkan%20nomor&operators=INDOSAT">
  Beli Pulsa Indosat
</a>

Catatan: Query parameters diterjemahkan sebagai key-value string di args. Parameter yang membutuhkan array (seperti operators) hanya bisa menerima satu nilai via URL. Gunakan JavaScript Bridge jika perlu multiple values.

Route yang Tersedia

Main Screens:

  • /history - Riwayat transaksi
  • /mutasi - Mutasi saldo
  • /profile atau /profile_screen - Profil pengguna
  • /settings atau /settings_screen - Pengaturan aplikasi
  • /product - Pencarian produk (mendukung arguments)
  • /downline_list - Daftar downline
  • /all_senders_screen - Daftar semua pengirim
  • /jaringan - Informasi jaringan/network
  • /pusat_bantuan - Pusat bantuan
  • /tentang_aplikasi atau /about - Tentang aplikasi
  • /menu_deposit - Menu deposit
  • /balance_transfer - Transfer saldo
  • /poin_exchange - Tukar poin
  • /chat - Chat customer service
  • /piutang - Piutang/hutang
  • /bookkeeping - Pembukuan
  • /register_downline - Daftar downline baru

Route Arguments yang Sering Dipakai

Untuk Route /product

{
    operators: ['TELKOMSEL', 'INDOSAT'],  // Filter operator
    hintText: 'Masukkan nomor HP',        // Hint input
    alphanumeric: false,                   // Input alfanumerik?
    screenTitle: 'Beli Pulsa'              // Judul screen
}

Untuk Route /webview

{
    url: 'https://example.com',            // URL yang dibuka
    title: 'Judul WebView'                 // Judul screen
}

3. Buka WebView Baru (webview)

Buka halaman web lain di dalam aplikasi (nested webview).

Contoh HTML + JavaScript

Via JavaScript Bridge:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Buka WebView</title>
</head>
<body>
    <h1>Link Eksternal</h1>
    
    <button onclick="openWebView('https://example.com/promo', 'Promo Spesial')">Lihat Promo</button>
    <button onclick="openWebView('https://example.com/terms', 'Syarat & Ketentuan')">S&K</button>

    <script>
        function openWebView(url, title) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'webview',
                url: url,
                title: title
            }));
        }
    </script>
</body>
</html>

Via URL Scheme (tanpa JavaScript):

<a href="hexaflate://webview?url=https://example.com/promo&title=Promo%20Spesial">
  Lihat Promo
</a>
<a href="hexaflate://webview?url=https://example.com/help&title=Bantuan">
  Bantuan
</a>

Catatan: Parameter headers tidak bisa dikirim via URL scheme karena formatnya JSON. Gunakan JavaScript Bridge jika perlu custom headers.


4. Tampilkan Submenu (submenu)

Tampilkan daftar menu dalam bottom sheet atau full screen.

Contoh HTML + JavaScript

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Submenu</title>
</head>
<body>
    <h1>Menu Layanan</h1>
    
    <button onclick="showBottomSheetSubmenu()">Pilih Operator (Bottom Sheet)</button>
    <button onclick="showFullScreenSubmenu()">Pilih Operator (Full Screen)</button>

    <script>
        function showBottomSheetSubmenu() {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'submenu',
                submenu: {
                    submenuTitle: 'Pilih Operator',
                    submenuStyle: 'bottomSheet',
                    submenuLayout: 'grid',
                    items: [
                        {
                            title: 'Telkomsel',
                            iconUrl: 'https://example.com/icon-telkomsel.png',
                            menuId: 'pulsa-telkomsel-001'
                        },
                        {
                            title: 'Indosat',
                            iconUrl: 'https://example.com/icon-indosat.png',
                            menuId: 'pulsa-indosat-002'
                        }
                    ]
                }
            }));
        }
        
        function showFullScreenSubmenu() {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'submenu',
                submenu: {
                    submenuTitle: 'Pilih Operator',
                    submenuStyle: 'fullScreen',
                    submenuLayout: 'grid',
                    items: [
                        {
                            title: 'Telkomsel',
                            iconUrl: 'https://example.com/icon-telkomsel.png',
                            route: '/product',
                            routeArgs: {
                                operators: ['TELKOMSEL'],
                                screenTitle: 'Pulsa Telkomsel'
                            }
                        }
                    ]
                }
            }));
        }
    </script>
</body>
</html>

5. Tampilkan Print Preview (print)

Tampilkan preview cetak struk/receipt dengan data custom dari WebView.

Struktur Data Print

{
    action: 'print',
    printData: {
        // Data Utama (Required)
        id: 'TRX001',
        kode_produk: 'PLN20',
        tujuan: '081234567890',
        harga: 20000,
        status: 20,
        
        // Data Opsional
        tgl_status: '2026-06-24 10:30:00',
        jasa_outlet: 2000,
        sn: 'SN123456789',
        
        // Custom fields (akan muncul di struk)
        token: '1234-5678-9012',
        nama_pelanggan: 'John Doe'
    }
}

Contoh HTML + JavaScript

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Print Receipt</title>
</head>
<body>
    <h1>Detail Transaksi</h1>
    
    <h2>Transaksi #TRX001</h2>
    <p>Produk: Token PLN 20K</p>
    <p>No. Meter: 12345678901</p>
    <p>Token: 1234-5678-9012-3456</p>
    <p>Total: Rp 20.000</p>
    <p>Status: Berhasil</p>
    
    <button onclick="printReceipt()">Cetak Struk</button>

    <script>
        function printReceipt() {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'print',
                printData: {
                    id: 'TRX001',
                    kode_produk: 'PLN20',
                    tujuan: '12345678901',
                    harga: 20000,
                    status: 20,
                    tgl_status: '2026-06-24 10:30:00',
                    sn: '1234-5678-9012-3456',
                    nama_pelanggan: 'John Doe',
                    daya: '900 VA'
                }
            }));
        }
    </script>
</body>
</html>

6. Buka URL di Browser Eksternal (external)

Buka URL di browser default sistem (Chrome, Safari, dll).

Cara 1: Menggunakan JavaScript Bridge

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Link Eksternal</title>
</head>
<body>
    <h1>Link Eksternal</h1>
    
    <button onclick="openExternal('https://www.google.com')">Buka Google</button>
    <button onclick="openExternal('https://www.youtube.com')">Buka YouTube</button>

    <script>
        function openExternal(url) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'external',
                url: url
            }));
        }
    </script>
</body>
</html>

Via URL Scheme:

<a href="hexaflate://external?url=https://www.google.com">Buka Google</a>
<a href="hexaflate://external?url=https://www.youtube.com">Buka YouTube</a>

Cara 2: Menggunakan URL Parameter ?newbrowser=ok

Cara ini lebih sederhana karena tidak perlu JavaScript! Cukup tambahkan ?newbrowser=ok di URL.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Link Eksternal</title>
</head>
<body>
    <h1>Link Eksternal (Tanpa JavaScript)</h1>
    
    <a href="https://www.google.com?newbrowser=ok">Buka Google</a><br>
    <a href="https://www.youtube.com?newbrowser=ok">Buka YouTube</a><br>
    <a href="https://wa.me/6281234567890?newbrowser=ok">WhatsApp CS</a><br>
    
    <!-- Jika URL sudah punya query parameter, gunakan & -->
    <a href="https://example.com/page?id=123&newbrowser=ok">Link dengan Parameter Lain</a>
</body>
</html>

7. Reload & Back (reload, back)

Fungsi utilitas untuk refresh halaman atau kembali.

Contoh HTML + JavaScript

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Utilitas</title>
</head>
<body>
    <h1>Utilitas WebView</h1>
    
    <button onclick="reloadPage()">Refresh Halaman</button>
    <button onclick="goBack()">Kembali</button>

    <script>
        function reloadPage() {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'reload'
            }));
        }
        
        function goBack() {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'back'
            }));
        }
    </script>
</body>
</html>

Via URL Scheme (tanpa JavaScript):

<a href="hexaflate://reload">Refresh Halaman</a>
<a href="hexaflate://back">Kembali</a>

Contoh Lengkap: Halaman Dashboard

Halaman lengkap dengan berbagai jenis navigasi.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard Layanan</title>
</head>
<body>
    <h1>Dashboard Layanan</h1>
    <p>Pilih layanan yang Anda butuhkan</p>
    
    <h2>Menu Utama</h2>
    <button onclick="goToMenu('pulsa-menu-001')">Beli Pulsa</button>
    <button onclick="goToMenu('data-menu-002')">Paket Data</button>
    <button onclick="goToMenu('listrik-menu-003')">Token Listrik</button>
    
    <h2>Navigasi Cepat</h2>
    <button onclick="navigateToRoute('/history')">Riwayat Transaksi</button>
    <button onclick="navigateToRoute('/mutasi')">Mutasi Saldo</button>
    <button onclick="navigateToRoute('/profile')">Profil Saya</button>
    <button onclick="navigateToRoute('/settings')">Pengaturan</button>
    <button onclick="navigateToRoute('/chat')">Chat CS</button>
    
    <h2>Informasi</h2>
    <button onclick="openWebView('https://example.com/promo', 'Promo')">Lihat Promo</button>
    <button onclick="openWebView('https://example.com/help', 'Bantuan')">Bantuan</button>
    
    <h2>Link Eksternal</h2>
    <button onclick="openExternal('https://wa.me/6281234567890')">Hubungi CS via WhatsApp</button>

    <script>
        function goToMenu(menuId) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'menuId',
                menuId: menuId
            }));
        }
        
        function navigateToRoute(route) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'navigate',
                route: route
            }));
        }
        
        function openWebView(url, title) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'webview',
                url: url,
                title: title
            }));
        }
        
        function openExternal(url) {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: 'external',
                url: url
            }));
        }
    </script>
</body>
</html>

Alternatif: Halaman Sama dengan URL Scheme

Navigasi yang sama bisa dilakukan tanpa JavaScript sama sekali menggunakan tag <a>:

<h2>Menu Utama (URL Scheme)</h2>
<a href="hexaflate://menuId?menuId=pulsa-menu-001">Beli Pulsa</a><br>
<a href="hexaflate://menuId?menuId=data-menu-002">Paket Data</a><br>
<a href="hexaflate://menuId?menuId=listrik-menu-003">Token Listrik</a><br>

<h2>Navigasi Cepat (URL Scheme)</h2>
<a href="hexaflate://navigate/history">Riwayat Transaksi</a><br>
<a href="hexaflate://navigate/profile">Profil Saya</a><br>
<a href="hexaflate://navigate/product?screenTitle=Pulsa">Beli Produk</a><br>

<h2>Informasi (URL Scheme)</h2>
<a href="hexaflate://webview?url=https://example.com/promo&title=Promo">Lihat Promo</a><br>
<a href="hexaflate://webview?url=https://example.com/help&title=Bantuan">Bantuan</a><br>

<h2>Link Eksternal (URL Scheme)</h2>
<a href="hexaflate://external?url=https://wa.me/6281234567890">Hubungi CS via WhatsApp</a><br>
<a href="hexaflate://back">Kembali</a>

Referensi Lengkap Parameter

menuId Action

{
    action: 'menuId',
    menuId: 'string'       // Required: ID menu dari admin panel
}

URL Scheme: hexaflate://menuId?menuId=<id>

navigate Action

{
    action: 'navigate',
    route: 'string',       // Required: Route Flutter (contoh: '/product')
    args: {}               // Optional: Arguments untuk route
}

URL Scheme: hexaflate://navigate/<route>?<key>=<value>&...

webview Action

{
    action: 'webview',
    url: 'string',         // Required: URL yang akan dibuka
    title: 'string'        // Optional: Judul WebView
}

URL Scheme: hexaflate://webview?url=<url>&title=<title>

submenu Action

{
    action: 'submenu',
    submenu: {
        submenuTitle: 'string',      // Required: Judul submenu
        submenuStyle: 'string',      // 'bottomSheet' atau 'fullScreen'
        submenuLayout: 'string',     // 'grid' atau 'list'
        items: [                     // Required: Array menu items
            {
                title: 'string',     // Required
                iconUrl: 'string',   // Optional
                menuId: 'string'     // Option 1: Reference menu lain
            }
        ]
    }
}

print Action

{
    action: 'print',
    printData: {
        id: 'string',               // Required
        kode_produk: 'string',      // Required
        tujuan: 'string',           // Required
        harga: number,              // Required (integer)
        status: number,             // Required (20 = success)
        tgl_status: 'string',       // Optional
        jasa_outlet: number,        // Optional (integer)
        sn: 'string'                // Optional (akan di-highlight)
    }
}

external Action

{
    action: 'external',
    url: 'string'          // Required: URL yang dibuka di browser
}

URL Scheme: hexaflate://external?url=<url>

reload Action

{
    action: 'reload'       // Tidak perlu parameter tambahan
}

URL Scheme: hexaflate://reload

back Action

{
    action: 'back'         // Tidak perlu parameter tambahan
}

URL Scheme: hexaflate://back


Tips Penggunaan

  1. Gunakan menuId untuk Fleksibilitas

    // Rekomendasi
    goToMenu('pulsa-telkomsel-001');
    
    // Kurang fleksibel
    navigateToRoute('/product', { operators: ['TELKOMSEL'] });
    
  2. Gunakan URL Scheme untuk Navigasi Sederhana Untuk navigasi tanpa argumen kompleks, URL scheme lebih praktis:

    <!-- Rekomendasi untuk navigasi sederhana -->
    <a href="hexaflate://navigate/history">Riwayat</a>
    <a href="hexaflate://menuId?menuId=pulsa-menu-001">Pulsa</a>
    <a href="hexaflate://back">Kembali</a>
    
    <!-- Gunakan JavaScript Bridge untuk data kompleks -->
    <button onclick="navigateToProductWithOperator()">Pulsa Indosat</button>
    
  3. URL Parameter ?newbrowser=ok untuk Link Eksternal

    <!-- Rekomendasi untuk link eksternal statis -->
    <a href="https://wa.me/6281234567890?newbrowser=ok">Chat WhatsApp</a>
    
    <!-- Overkill -->
    <button onclick="openExternal('https://wa.me/6281234567890')">Chat</button>
    
  4. Encode Nilai Query Parameter Jika nilai parameter mengandung spasi atau karakter khusus, gunakan URL encoding:

    <!-- Benar -->
    <a href="hexaflate://navigate/product?screenTitle=Pulsa%20Indosat">Pulsa</a>
    
    <!-- Salah (spasi tidak di-encode) -->
    <a href="hexaflate://navigate/product?screenTitle=Pulsa Indosat">Pulsa</a>
    
  5. Tambahkan Error Handling

    function safeNavigate(action, params) {
        try {
            window.flutter_inappwebview.callHandler('AppBridge', JSON.stringify({
                action: action,
                ...params
            }));
        } catch (error) {
            console.error('Navigation error:', error);
            alert('Gagal melakukan navigasi. Silakan coba lagi.');
        }
    }
    

Troubleshooting

URL Scheme Tidak Bekerja

Masalah: Saat klik link hexaflate://..., tidak terjadi apa-apa (halaman tidak merespon).

Solusi:

  • Pastikan aplikasi menggunakan versi terbaru yang mendukung URL scheme bridge
  • Coba gunakan JavaScript Bridge sebagai alternatif
  • Periksa console browser untuk error:
    console.log('Navigating via URL scheme...');
    window.location.href = 'hexaflate://navigate/history';
    

JavaScript Bridge Tidak Bekerja

Masalah:

Uncaught ReferenceError: flutter_inappwebview is not defined

Solusi: Tambahkan delay untuk memastikan bridge siap:

setTimeout(function() {
    window.flutter_inappwebview.callHandler('AppBridge', ...);
}, 100);

Menu ID Tidak Ditemukan

Solusi:

  • Periksa Menu ID di Admin Panel
  • Pastikan menu sudah di-publish
  • Gunakan console.log untuk debug:
console.log('Navigating to menu:', menuId);

Kesimpulan

Hexaflate WebView menyediakan dua metode untuk navigasi dari halaman web:

MetodeKelebihanCocok Untuk
JavaScript BridgeMendukung data kompleks (array, nested object), error handlingNavigasi dengan argumen dinamis, submenu, print
URL Scheme (hexaflate://)Sederhana, tanpa JavaScript, bisa pakai tag <a> biasaNavigasi sederhana, link statis, tombol back/reload

Action yang Tersedia

  • menuId - Reference menu lain
  • navigate - Navigate ke route
  • webview - Buka WebView baru
  • submenu - Tampilkan submenu (via JS Bridge saja)
  • print - Print preview custom data (via JS Bridge saja)
  • external - Buka browser eksternal
  • reload - Refresh halaman
  • back - Kembali/tutup