Mobile Development

Flutter Web & Desktop Development

TOKEN

Tutorial komprehensif Flutter untuk Web, Windows, macOS, Linux — responsive layout, platform channels, plugin, deployment

📋 Daftar Isi
  1. Flutter Multi-Platform
  2. Responsive Layout
  3. Adaptive Widgets
  4. Platform Channels
  5. Plugin Development
  6. Fitur Khusus Web
  7. Fitur Khusus Desktop
  8. Deployment
  9. Quiz Pemahaman

1. Flutter untuk Multi-Platform

Flutter bukan hanya framework mobile — Flutter mendukung pengembangan untuk Web, Windows, macOS, dan Linux dari satu basis kode. Dengan single codebase, Anda membangun aplikasi untuk enam platform.

Sejak Flutter 3.x, dukungan web dan desktop sudah stable dan siap produksi.

Arsitektur Flutter Multi-Platform
📱
Mobile
Android & iOS
Skia / Impeller
🌐
Web
HTML / CanvasKit
WebAssembly
🖥️
Desktop
Win, macOS, Linux
Native rendering

1.1 Inisialisasi Proyek

Bash — Membuat Proyek Flutter
# Buat proyek Flutter baru
flutter create my_multiplatform_app
cd my_multiplatform_app

# Cek platform yang tersedia
flutter devices

# Jalankan di web
flutter run -d chrome

# Jalankan di Windows
flutter run -d windows

# Enable platform
flutter config --enable-web
flutter config --enable-windows-desktop
flutter config --enable-macos-desktop
flutter config --enable-linux-desktop

1.2 Struktur Proyek

Struktur Folder
my_multiplatform_app/
├── lib/
│   └── main.dart               # Kode utama (shared)
├── android/                     # Konfigurasi Android
├── ios/                         # Konfigurasi iOS
├── web/                         # Konfigurasi Web
│   ├── index.html
│   ├── manifest.json
│   └── favicon.png
├── windows/                     # Konfigurasi Windows
│   ├── CMakeLists.txt
│   └── runner/
├── macos/                       # Konfigurasi macOS
├── linux/                       # Konfigurasi Linux
├── test/                        # Unit & widget tests
└── pubspec.yaml
💡 Deteksi Platform

Gunakan kIsWeb dari package:flutter/foundation.dart untuk mendeteksi web. Untuk desktop, gunakan Platform.isWindows, Platform.isMacOS, atau Platform.isLinux dari dart:io.

2. Responsive Layout

Aplikasi multi-platform harus mendukung berbagai ukuran layar. Flutter menyediakan LayoutBuilder, MediaQuery, dan Flexible/Expanded.

Dart — Responsive Layout
import 'package:flutter/material.dart';

class ResponsiveLayout extends StatelessWidget {
  final Widget mobile;
  final Widget tablet;
  final Widget desktop;

  const ResponsiveLayout({
    super.key,
    required this.mobile,
    required this.tablet,
    required this.desktop,
  });

  static bool isMobile(BuildContext context) =>
      MediaQuery.of(context).size.width < 600;

  static bool isDesktop(BuildContext context) =>
      MediaQuery.of(context).size.width >= 1200;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth >= 1200) return desktop;
        if (constraints.maxWidth >= 600) return tablet;
        return mobile;
      },
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Dashboard')),
      body: ResponsiveLayout(
        mobile: ListView(children: [
          _stat('Users', '1,234'), _stat('Revenue', 'Rp 50jt'),
        ]),
        tablet: Row(children: [
          Expanded(child: _stat('Users', '1,234')),
          Expanded(child: _stat('Revenue', 'Rp 50jt')),
        ]),
        desktop: Row(children: [
          Expanded(child: _stat('Users', '1,234')),
          Expanded(child: _stat('Revenue', 'Rp 50jt')),
          Expanded(child: _stat('Orders', '892')),
        ]),
      ),
    );
  }

  Widget _stat(String title, String value) {
    return Card(child: Padding(
      padding: const EdgeInsets.all(20),
      child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
        Text(title, style: const TextStyle(color: Colors.grey)),
        Text(value, style: const TextStyle(fontSize: 28, fontWeight: FontWeight.bold)),
      ]),
    ));
  }
}

2.1 Breakpoints Standar

UkuranBreakpointTarget
Compact< 600dpMobile phone
Medium600–839dpTablet portrait
Expanded840–1199dpTablet landscape
Large1200–1599dpDesktop
Extra Large≥ 1600dpUltrawide

3. Adaptive Widgets

Flutter menyediakan widget adaptive yang menyesuaikan tampilan berdasarkan platform.

Dart — Adaptive Widgets
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class AdaptiveScaffold extends StatelessWidget {
  final String title;
  final Widget body;

  const AdaptiveScaffold({super.key, required this.title, required this.body});

  @override
  Widget build(BuildContext context) {
    final isWide = MediaQuery.of(context).size.width > 800;

    if (!kIsWeb && Platform.isIOS) {
      return CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(middle: Text(title)),
        child: body,
      );
    }
    if (isWide) {
      return Scaffold(body: Row(children: [
        NavigationRail(
          selectedIndex: 0,
          destinations: const [
            NavigationRailDestination(icon: Icon(Icons.dashboard), label: Text('Home')),
            NavigationRailDestination(icon: Icon(Icons.settings), label: Text('Settings')),
          ],
          onDestinationSelected: (i) {},
        ),
        const VerticalDivider(width: 1),
        Expanded(child: body),
      ]));
    }
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: body,
      bottomNavigationBar: NavigationBar(
        selectedIndex: 0,
        destinations: const [
          NavigationDestination(icon: Icon(Icons.dashboard), label: 'Home'),
          NavigationDestination(icon: Icon(Icons.settings), label: 'Settings'),
        ],
      ),
    );
  }
}
⚠️ Hindari dart:io di Web

Import dart:io tidak tersedia di Flutter Web. Selalu gunakan kIsWeb check sebelum menggunakan API dari dart:io.

4. Platform Channels

Platform Channels memungkinkan Flutter berkomunikasi dengan native code (Java/Kotlin, Swift/ObjC, C++).

4.1 MethodChannel

Dart — MethodChannel
import 'package:flutter/services.dart';

class NativeBridge {
  static const _channel = MethodChannel('com.myapp/native');

  static Future getDeviceName() async {
    try {
      final name = await _channel.invokeMethod('getDeviceName');
      return name ?? 'Unknown';
    } on PlatformException catch (e) {
      return 'Error: \${e.message}';
    }
  }

  static Future sendNotification(String title, String body) async {
    await _channel.invokeMethod('showNotification', {
      'title': title, 'body': body,
    });
  }
}
Kotlin — Android Side
class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.myapp/native"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
            .setMethodCallHandler { call, result ->
                when (call.method) {
                    "getDeviceName" -> result.success(android.os.Build.MODEL)
                    "showNotification" -> {
                        result.success(null)
                    }
                    else -> result.notImplemented()
                }
            }
    }
}

4.2 EventChannel (Streaming)

Dart — EventChannel
class BatteryMonitor {
  static const _ch = EventChannel('com.myapp/battery');
  static Stream get stream =>
      _ch.receiveBroadcastStream().map((v) => v as int);
}

// Usage
StreamBuilder(
  stream: BatteryMonitor.stream,
  builder: (ctx, snap) =>
    Text('Battery: \${snap.data ?? 0}%'),
)

5. Plugin Development

Flutter plugin menggabungkan kode Dart dengan implementasi native untuk mengakses fitur platform.

Bash — Membuat Plugin
# Buat plugin dengan template
flutter create --template=plugin \
  --platforms=android,ios,web,windows,macos,linux \
  my_custom_plugin

# Struktur yang dihasilkan:
# my_custom_plugin/
# ├── lib/                    # Dart public API
# ├── android/src/main/kotlin # Kotlin implementation
# ├── ios/Classes/            # Swift implementation
# ├── windows/                # C++ implementation
# ├── example/                # Example app
# └── pubspec.yaml
Dart — Platform Interface
import 'package:plugin_platform_interface/plugin_platform_interface.dart';

abstract class MyPluginPlatform extends PlatformInterface {
  MyPluginPlatform() : super(token: _token);
  static final Object _token = Object();
  static MyPluginPlatform _instance = MethodChannelMyPlugin();

  static MyPluginPlatform get instance => _instance;
  static set instance(MyPluginPlatform i) {
    PlatformInterface.verifyToken(i, _token);
    _instance = i;
  }

  Future getPlatformVersion() {
    throw UnimplementedError();
  }
}

6. Fitur Khusus Web

6.1 Web Renderers

RendererKarakteristikKapan Digunakan
HTMLHTML/CSS/JS, ringanAplikasi teks-heavy
CanvasKitSkia/Wasm, pixel-perfectGrafik kompleks
AutoOtomatisKebanyakan kasus
Bash — Web Build
flutter build web --web-renderer html
flutter build web --web-renderer canvaskit
flutter build web --wasm

6.2 URL Strategy & JS Interop

Dart — URL & JS Interop
// URL Strategy - hilangkan '#' dari URL
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void main() {
  usePathUrlStrategy();
  runApp(const MyApp());
}

// JS Interop
import 'dart:js_interop';
@JS('window.navigator.userAgent')
external String get userAgent;

7. Fitur Khusus Desktop

Dart — Window Manager
import 'package:window_manager/window_manager.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await windowManager.ensureInitialized();
  const opts = WindowOptions(
    size: Size(1280, 800),
    minimumSize: Size(800, 600),
    center: true,
    title: 'My App',
    titleBarStyle: TitleBarStyle.hidden,
  );
  await windowManager.waitUntilReadyToShow(opts, () async {
    await windowManager.show();
    await windowManager.focus();
  });
  runApp(const MyApp());
}
Dart — File Picker
import 'package:file_picker/file_picker.dart';

Future pickFile() async {
  FilePickerResult? result = await FilePicker.platform.pickFiles(
    type: FileType.custom,
    allowedExtensions: ['pdf', 'doc', 'jpg', 'png'],
    allowMultiple: true,
  );
  if (result != null) {
    for (var file in result.files) {
      print('File: \${file.name}, Size: \${file.size}');
    }
  }
}

8. Deployment

Bash — Web Deployment
# Build untuk production
flutter build web --release --web-renderer canvaskit

# Deploy ke Firebase Hosting
firebase deploy --only hosting

# Deploy ke Nginx
sudo cp -r build/web/* /var/www/html/
Bash — Desktop Build
# Build Windows
flutter build windows --release
# Output: build/windows/x64/runner/Release/

# Build macOS
flutter build macos --release

# Build Linux
flutter build linux --release

# Packaging MSIX (Windows)
flutter pub run msix:create
YAML — GitHub Actions Multi-Platform
name: Build All Platforms
on:
  push:
    tags: ['v*']
jobs:
  build-web:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - run: flutter build web --release
  build-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - run: flutter build windows --release
  build-macos:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v4
      - uses: subosito/flutter-action@v2
      - run: flutter build macos --release
💡 Flutter Flavor

Gunakan Flutter Flavor untuk membuat konfigurasi build berbeda (dev, staging, production) dengan environment berbeda per target.

Quiz Pemahaman

Pertanyaan 1: Apa fungsi kIsWeb di Flutter?

a) Mengecek koneksi internet
b) Mengecek apakah platform adalah web
c) Menginisialisasi web renderer
d) Mengecek versi browser

Pertanyaan 2: Renderer apa yang menggunakan Skia/Wasm?

a) HTML Renderer
b) CanvasKit
c) Auto Renderer
d) WebGL Renderer

Pertanyaan 3: Channel apa untuk komunikasi request-response?

a) MethodChannel
b) EventChannel
c) BasicMessageChannel
d) BinaryCodec

Pertanyaan 4: Package untuk custom window management?

a) desktop_window
b) bitsdojo_window
c) window_manager
d) flutter_window

Pertanyaan 5: Apa yang dilakukan usePathUrlStrategy()?

a) Mengenkripsi URL
b) Menghilangkan '#' dari URL
c) Mengatur base URL
d) Mengatur redirect URL
← SebelumnyaKembali ke Beranda Selanjutnya →Lihat Kategori
🔍 Zoom
100%
🎨 Tema