Flutter uygulamanıza WebView ekleme

1. Giriş

Son Güncelleme: 2021-10-19

WebView Flutter eklentisi ile Android veya iOS Flutter uygulamanıza bir WebView widget'ı ekleyebilirsiniz. iOS'te WebView widget'ı WKWebView, Android'de ise WebView tarafından desteklenir. Eklenti, Flutter widget'larını web görünümünde oluşturabilir. Örneğin, web görünümünde bir açılır menü oluşturmak mümkündür.

Ne oluşturacaksınız?

Bu codelab'de, Flutter SDK'sını kullanarak WebView içeren bir mobil uygulamayı adım adım oluşturacaksınız. Uygulamanız şunları yapabilecek:

  • Web içeriğini WebView içinde görüntüleme
  • WebView üzerinde üst üste yerleştirilmiş Flutter widget'larını görüntüleme
  • Sayfa yükleme ilerleme durumu etkinliklerine tepki verme
  • WebView özelliğini WebViewController üzerinden kontrol etme
  • NavigationDelegate kullanarak web sitelerini engelleme
  • JavaScript ifadelerini değerlendirme
  • JavaScript'ten gelen geri çağırmaları JavascriptChannels ile işleme
  • Çerezleri ayarlama, kaldırma, ekleme veya gösterme
  • HTML içeren öğelerden, dosyalardan veya dizelerden HTML yükleme ve görüntüleme

Flutter.dev ana sayfasını gösteren yerleştirilmiş bir web görünümüyle Flutter uygulaması çalıştıran iPhone simülatörü

Flutter.dev ana sayfasını gösteren yerleştirilmiş bir web görünümüyle Flutter uygulamasının çalıştığı Android emülatörü

Öğrenecekleriniz

Bu codelab'de, webview_flutter eklentisini aşağıdakiler de dahil olmak üzere çeşitli şekillerde kullanmayı öğreneceksiniz:

  • webview_flutter eklentisini yapılandırma
  • Sayfa yükleme ilerleme etkinliklerini dinleme
  • Sayfa gezinmesini kontrol etme
  • WebView'ya geçmişinde ileri ve geri gitme komutu verme
  • Döndürülen sonuçları kullanma dahil olmak üzere JavaScript'i değerlendirme
  • JavaScript'ten Dart kodunu çağırmak için geri çağırmaları kaydetme
  • Çerezler nasıl yönetilir?
  • Öğelerden, dosyalardan veya HTML içeren dizeden HTML sayfalarını yükleme ve görüntüleme

İhtiyacınız olanlar

2. Flutter geliştirme ortamınızı kurma

Bu laboratuvarı tamamlamak için iki yazılıma ihtiyacınız var: Flutter SDK ve bir düzenleyici.

Codelab'i aşağıdaki cihazlardan herhangi birini kullanarak çalıştırabilirsiniz:

  • Bilgisayarınıza bağlı ve Geliştirici moduna ayarlanmış fiziksel bir Android veya iOS cihaz.
  • iOS simülatörü (Xcode araçlarının yüklenmesi gerekir).
  • Android Emulator (Android Studio'da kurulum gerektirir).

3. Başlarken

Flutter'ı kullanmaya başlama

Yeni bir Flutter projesi oluşturmanın çeşitli yolları vardır. Hem Android Studio hem de Visual Studio Code bu görev için araçlar sunar. Bağlantılı prosedürleri uygulayarak proje oluşturun veya aşağıdaki komutları kullanışlı bir komut satırı terminalinde çalıştırın.

$ flutter create --platforms=android,ios webview_in_flutter
Creating project webview_in_flutter...
Resolving dependencies in `webview_in_flutter`...
Downloading packages...
Got dependencies in `webview_in_flutter`.
Wrote 74 files.

All done!
You can find general documentation for Flutter at: https://docs.flutter.dev/
Detailed API documentation is available at: https://api.flutter.dev/
If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev

In order to run your application, type:

  $ cd webview_in_flutter
  $ flutter run

Your application code is in webview_in_flutter/lib/main.dart.

WebView Flutter eklentisini bağımlılık olarak ekleme

Flutter uygulamasına ek özellikler eklemek için en iyi yöntem Pub paketlerini kullanmaktır. Bu codelab'de projenize webview_flutter eklentisini ekleyeceksiniz. Terminalde aşağıdaki komutları çalıştırın.

$ cd webview_in_flutter
$ flutter pub add webview_flutter
Resolving dependencies...
Downloading packages...
  collection 1.18.0 (1.19.0 available)
  leak_tracker 10.0.5 (10.0.7 available)
  leak_tracker_flutter_testing 3.0.5 (3.0.7 available)
  material_color_utilities 0.11.1 (0.12.0 available)
+ plugin_platform_interface 2.1.8
  string_scanner 1.2.0 (1.3.0 available)
  test_api 0.7.2 (0.7.3 available)
+ webview_flutter 4.9.0
+ webview_flutter_android 3.16.7
+ webview_flutter_platform_interface 2.10.0
+ webview_flutter_wkwebview 3.15.0
Changed 5 dependencies!
6 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

pubspec.yaml dosyanızı incelerseniz artık bağımlılıklar bölümünde webview_flutter eklentisi için bir satır olduğunu görürsünüz.

Android minSDK'yı yapılandırma

Android'de webview_flutter eklentisini kullanmak için minSDK ayarını 20 olarak belirlemeniz gerekir. android/app/build.gradle dosyanızı aşağıdaki gibi değiştirin:

android/app/build.gradle

android {
    //...

    defaultConfig {
        applicationId = "com.example.webview_in_flutter"
        minSdk = 20                                         // Modify this line
        targetSdk = flutter.targetSdkVersion
        versionCode = flutterVersionCode.toInteger()
        versionName = flutterVersionName
    }

4. Flutter uygulamasına WebView widget'ı ekleme

Bu adımda, uygulamanıza bir WebView ekleyeceksiniz. WebView'lar, yerleşik olarak barındırılan görünümlerdir ve uygulama geliştirici olarak bu yerleşik görünümleri uygulamanızda nasıl barındıracağınız konusunda seçim yapabilirsiniz. Android'de, Android'in varsayılanı olan sanal ekranlar ve hibrit kompozisyon arasında seçim yapabilirsiniz. Ancak iOS her zaman karma oluşturmayı kullanır.

Sanal ekranlar ve karma bileşim arasındaki farkların ayrıntılı bir tartışması için Platform Views ile Flutter uygulamanızda yerel Android ve iOS görünümlerini barındırma hakkındaki dokümanları okuyun .

Ekrana bir WebView yerleştirme

lib/main.dart dosyasının içeriğini aşağıdakiyle değiştirin:

lib/main.dart

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

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const WebViewApp(),
    ),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({super.key});

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..loadRequest(
        Uri.parse('https://flutter.dev'),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
      ),
      body: WebViewWidget(
        controller: controller,
      ),
    );
  }
}

Bu kodu iOS veya Android'de çalıştırmak, cihazınızda WebView'ı tam alanlı bir tarayıcı penceresi olarak gösterir. Bu da tarayıcının cihazınızda herhangi bir kenarlık veya kenar boşluğu olmadan tam ekran olarak gösterildiği anlamına gelir. Kaydırdıkça sayfanın biraz tuhaf görünebilecek kısımlarını fark edeceksiniz. Bunun nedeni JavaScript'in devre dışı olması ve flutter.dev adresinin düzgün şekilde oluşturulması için JavaScript'in gerekli olmasıdır.

Uygulamayı çalıştırma

flutter.dev web sitesini görüntüleyen bir WebView'u görmek için Flutter uygulamasını iOS veya Android'de çalıştırın. Alternatif olarak, uygulamayı bir Android emülatöründe veya iOS simülatöründe çalıştırın. İlk WebView URL'sini kendi web sitenizle değiştirebilirsiniz.

$ flutter run

Uygun simülatör veya emülatörün çalıştığını ya da fiziksel bir cihazın bağlı olduğunu varsayarsak uygulamayı derleyip cihazınıza dağıttıktan sonra aşağıdakine benzer bir şey görmeniz gerekir:

Flutter.dev ana sayfasını gösteren yerleştirilmiş bir web görünümüyle Flutter uygulaması çalıştıran iPhone simülatörü

Flutter.dev ana sayfasını gösteren yerleştirilmiş bir web görünümüyle Flutter uygulamasının çalıştığı Android emülatörü

5. Sayfa yükleme etkinliklerini dinleme

WebView widget'ı, uygulamanızın dinleyebileceği çeşitli sayfa yükleme ilerleme durumu etkinlikleri sağlar. WebView sayfa yükleme döngüsü sırasında üç farklı sayfa yükleme etkinliği tetiklenir: onPageStarted, onProgress ve onPageFinished. Bu adımda bir sayfa yükleme göstergesi uygulayacaksınız. Ayrıca, bu işlem WebView içerik alanında Flutter içeriği oluşturabileceğinizi gösterir.

Uygulamanıza sayfa yükleme etkinlikleri ekleme

lib/src/web_view_stack.dart konumunda yeni bir kaynak dosyası oluşturun ve aşağıdaki içerikle doldurun:

lib/src/web_view_stack.dart

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

class WebViewStack extends StatefulWidget {
  const WebViewStack({super.key});

  @override
  State<WebViewStack> createState() => _WebViewStackState();
}

class _WebViewStackState extends State<WebViewStack> {
  var loadingPercentage = 0;
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..setNavigationDelegate(NavigationDelegate(
        onPageStarted: (url) {
          setState(() {
            loadingPercentage = 0;
          });
        },
        onProgress: (progress) {
          setState(() {
            loadingPercentage = progress;
          });
        },
        onPageFinished: (url) {
          setState(() {
            loadingPercentage = 100;
          });
        },
      ))
      ..loadRequest(
        Uri.parse('https://flutter.dev'),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        WebViewWidget(
          controller: controller,
        ),
        if (loadingPercentage < 100)
          LinearProgressIndicator(
            value: loadingPercentage / 100.0,
          ),
      ],
    );
  }
}

Bu kod, WebView widget'ını Stack ile sarmış ve sayfa yükleme yüzdesi %100'ün altında olduğunda WebView widget'ının üzerine koşullu olarak LinearProgressIndicator yerleştirmiştir. Bu durum, zaman içinde değişen program durumunu içerdiğinden bu durumu StatefulWidget ile ilişkili bir State sınıfında sakladınız.

Bu yeni WebViewStack widget'ını kullanmak için lib/main.dart öğenizi aşağıdaki şekilde değiştirin:

lib/main.dart

import 'package:flutter/material.dart';

import 'src/web_view_stack.dart';

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const WebViewApp(),
    ),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({super.key});

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
      ),
      body: const WebViewStack(),
    );
  }
}

Uygulamayı çalıştırdığınızda, ağ koşullarınıza ve tarayıcının, gittiğiniz sayfayı önbelleğe alıp almadığına bağlı olarak WebView içerik alanının üzerinde bir sayfa yükleme göstergesi görürsünüz.

6. WebViewController ile çalışma

WebView widget'ından WebViewController'a erişme

WebView widget'ı, WebViewController ile programatik kontrolü etkinleştirir. Bu denetleyici, WebView widget'ı oluşturulduktan sonra geri çağırma yoluyla kullanılabilir. Bu denetleyicinin kullanılabilirliğinin eşzamansız olması, onu Dart'ın eşzamansız Completer<T> sınıfı için uygun bir aday yapar.

lib/src/web_view_stack.dart uygulamasını şu şekilde güncelleyin:

lib/src/web_view_stack.dart

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

class WebViewStack extends StatefulWidget {
  const WebViewStack({required this.controller, super.key}); // MODIFY

  final WebViewController controller;                        // ADD

  @override
  State<WebViewStack> createState() => _WebViewStackState();
}

class _WebViewStackState extends State<WebViewStack> {
  var loadingPercentage = 0;
  // REMOVE the controller that was here

  @override
  void initState() {
    super.initState();
    // Modify from here...
    widget.controller.setNavigationDelegate(
      NavigationDelegate(
        onPageStarted: (url) {
          setState(() {
            loadingPercentage = 0;
          });
        },
        onProgress: (progress) {
          setState(() {
            loadingPercentage = progress;
          });
        },
        onPageFinished: (url) {
          setState(() {
            loadingPercentage = 100;
          });
        },
      ),
    );
    // ...to here.
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        WebViewWidget(
          controller: widget.controller,                     // MODIFY
        ),
        if (loadingPercentage < 100)
          LinearProgressIndicator(
            value: loadingPercentage / 100.0,
          ),
      ],
    );
  }
}

WebViewStack widget'ı artık çevreleyen widget'ta oluşturulan bir denetleyiciyi kullanıyor. Bu işlem, WebViewWidget için denetleyicinin uygulamanın diğer bölümleriyle paylaşılmasını sağlar.

Gezinme Kontrolleri Oluşturma

Çalışan bir WebView olması bir şeydir ancak sayfa geçmişinde ileri ve geri gidebilmek ve sayfayı yeniden yükleyebilmek faydalı bir dizi ekleme olacaktır. Neyse ki WebViewController ile bu işlevi uygulamanıza ekleyebilirsiniz.

lib/src/navigation_controls.dart konumunda yeni bir kaynak dosyası oluşturun ve aşağıdaki bilgilerle doldurun:

lib/src/navigation_controls.dart

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

class NavigationControls extends StatelessWidget {
  const NavigationControls({required this.controller, super.key});

  final WebViewController controller;

  @override
  Widget build(BuildContext context) {
    return Row(
      children: <Widget>[
        IconButton(
          icon: const Icon(Icons.arrow_back_ios),
          onPressed: () async {
            final messenger = ScaffoldMessenger.of(context);
            if (await controller.canGoBack()) {
              await controller.goBack();
            } else {
              messenger.showSnackBar(
                const SnackBar(content: Text('No back history item')),
              );
              return;
            }
          },
        ),
        IconButton(
          icon: const Icon(Icons.arrow_forward_ios),
          onPressed: () async {
            final messenger = ScaffoldMessenger.of(context);
            if (await controller.canGoForward()) {
              await controller.goForward();
            } else {
              messenger.showSnackBar(
                const SnackBar(content: Text('No forward history item')),
              );
              return;
            }
          },
        ),
        IconButton(
          icon: const Icon(Icons.replay),
          onPressed: () {
            controller.reload();
          },
        ),
      ],
    );
  }
}

Bu widget, kullanıcının bir dizi IconButton aracılığıyla WebView öğesini kontrol etmesini sağlamak için oluşturma sırasında kendisiyle paylaşılan WebViewController öğesini kullanır.

AppBar'a gezinme kontrolleri ekleme

Güncellenen WebViewStack ve yeni oluşturulan NavigationControls ile birlikte, artık tüm bunları güncellenmiş bir WebViewApp içinde bir araya getirmenin zamanı geldi. Paylaşılan WebViewController'yı burada oluştururuz. Bu uygulamadaki widget ağacının üst kısmına yakın bir yerde WebViewApp olduğundan bu seviyede oluşturmak mantıklıdır.

lib/main.dart dosyasını aşağıdaki gibi güncelleyin:

lib/main.dart

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';  // ADD

import 'src/navigation_controls.dart';                  // ADD
import 'src/web_view_stack.dart';

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const WebViewApp(),
    ),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({super.key});

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  // Add from here...
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..loadRequest(
        Uri.parse('https://flutter.dev'),
      );
  }
  // ...to here.

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
        // Add from here...
        actions: [
          NavigationControls(controller: controller),
        ],
        // ...to here.
      ),
      body: WebViewStack(controller: controller),       // MODIFY
    );
  }
}

Uygulamanın çalıştırılması, kontrollerin bulunduğu bir web sayfası göstermelidir:

Flutter.dev ana sayfasını gösteren yerleştirilmiş bir web görünümü içeren Flutter uygulamasının çalıştığı iPhone simülatörü. Önceki sayfa, sonraki sayfa ve sayfayı yeniden yükleme kontrolleri gösteriliyor.

Flutter.dev ana sayfasını önceki sayfa, sonraki sayfa ve sayfayı yeniden yükleme denetimleriyle gösteren yerleşik bir web görünümü içeren Flutter uygulamasının çalıştığı Android emülatörü

7. NavigationDelegate ile gezinmeyi takip etme

WebView, uygulamanıza NavigationDelegate, sağlar. Bu sayede uygulamanız, WebView widget'ının sayfa gezinmesini izleyip kontrol edebilir. Örneğin, bir kullanıcı bir bağlantıyı tıkladığında WebView, tarafından bir gezinme başlatıldığında NavigationDelegate çağrılır. NavigationDelegate geri çağırma işlevi, WebView öğesinin gezinmeye devam edip etmeyeceğini kontrol etmek için kullanılabilir.

Özel bir NavigationDelegate kaydetme

Bu adımda, NavigationDelegate geri çağırma işlevi kaydederek YouTube.com'a gitmeyi engellersiniz. Bu basit uygulamanın, çeşitli Flutter API doküman sayfalarında görünen satır içi YouTube içeriklerini de engellediğini unutmayın.

lib/src/web_view_stack.dart dosyasını aşağıdaki şekilde güncelleyin:

lib/src/web_view_stack.dart

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

class WebViewStack extends StatefulWidget {
  const WebViewStack({required this.controller, super.key});

  final WebViewController controller;

  @override
  State<WebViewStack> createState() => _WebViewStackState();
}

class _WebViewStackState extends State<WebViewStack> {
  var loadingPercentage = 0;

  @override
  void initState() {
    super.initState();
    widget.controller.setNavigationDelegate(
      NavigationDelegate(
        onPageStarted: (url) {
          setState(() {
            loadingPercentage = 0;
          });
        },
        onProgress: (progress) {
          setState(() {
            loadingPercentage = progress;
          });
        },
        onPageFinished: (url) {
          setState(() {
            loadingPercentage = 100;
          });
        },
        // Add from here...
        onNavigationRequest: (navigation) {
          final host = Uri.parse(navigation.url).host;
          if (host.contains('youtube.com')) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(
                  'Blocking navigation to $host',
                ),
              ),
            );
            return NavigationDecision.prevent;
          }
          return NavigationDecision.navigate;
        },
        // ...to here.
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        WebViewWidget(
          controller: widget.controller,
        ),
        if (loadingPercentage < 100)
          LinearProgressIndicator(
            value: loadingPercentage / 100.0,
          ),
      ],
    );
  }
}

Sonraki adımda, NavigationDelegate öğenizi WebViewController sınıfını kullanarak test etmenizi sağlayacak bir menü öğesi ekleyeceksiniz. Geri çağırma mantığını yalnızca YouTube.com'a tam sayfa gezinmeyi engelleyecek ve API belgelerindeki satır içi YouTube içeriğine izin verecek şekilde genişletmek okuyucunun sorumluluğundadır.

8. AppBar'a menü düğmesi ekleme

Sonraki birkaç adımda, JavaScript'i değerlendirmek, JavaScript kanallarını çağırmak ve çerezleri yönetmek için kullanılan AppBar widget'ında bir menü düğmesi oluşturacaksınız. Sonuç olarak, gerçekten de faydalı bir menü.

lib/src/menu.dart konumunda yeni bir kaynak dosyası oluşturun ve aşağıdaki bilgilerle doldurun:

lib/src/menu.dart

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

enum _MenuOptions {
  navigationDelegate,
}

class Menu extends StatelessWidget {
  const Menu({required this.controller, super.key});

  final WebViewController controller;

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<_MenuOptions>(
      onSelected: (value) async {
        switch (value) {
          case _MenuOptions.navigationDelegate:
            await controller.loadRequest(Uri.parse('https://youtube.com'));
        }
      },
      itemBuilder: (context) => [
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.navigationDelegate,
          child: Text('Navigate to YouTube'),
        ),
      ],
    );
  }
}

Kullanıcı YouTube'a git menü seçeneğini belirlediğinde WebViewController'nin loadRequest yöntemi yürütülür. Bu gezinme, önceki adımda oluşturduğunuz navigationDelegate geri çağırması tarafından engellenecek.

Menüyü WebViewApp ekranına eklemek için lib/main.dart öğesini aşağıdaki gibi değiştirin:

lib/main.dart

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

import 'src/menu.dart';                               // ADD
import 'src/navigation_controls.dart';
import 'src/web_view_stack.dart';

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(useMaterial3: true),
      home: const WebViewApp(),
    ),
  );
}

class WebViewApp extends StatefulWidget {
  const WebViewApp({super.key});

  @override
  State<WebViewApp> createState() => _WebViewAppState();
}

class _WebViewAppState extends State<WebViewApp> {
  late final WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..loadRequest(
        Uri.parse('https://flutter.dev'),
      );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter WebView'),
        actions: [
          NavigationControls(controller: controller),
          Menu(controller: controller),               // ADD
        ],
      ),
      body: WebViewStack(controller: controller),
    );
  }
}

Uygulamanızı çalıştırın ve YouTube'a git menü öğesine dokunun. Gezinme denetleyicisinin YouTube'a gitmeyi engellediğini bildiren bir SnackBar ile karşılaşırsınız.

Flutter.dev ana sayfasını gösteren yerleşik bir web görünümüyle Flutter uygulamasının çalıştığı Android emülatörü. Menü öğesinde &quot;YouTube&#39;a git&quot; seçeneği gösteriliyor.

Flutter.dev ana sayfasını gösteren yerleşik bir web görünümüyle Flutter uygulaması çalıştıran Android emülatörü ve &quot;m.youtube.com&#39;a gidiş engelleniyor&quot; yazan pop-up bildirimi

9. JavaScript'i değerlendirme

WebViewController, JavaScript ifadelerini geçerli sayfanın bağlamında değerlendirebilir. JavaScript'i değerlendirmenin iki farklı yolu vardır: Değer döndürmeyen JavaScript kodu için runJavaScript, değer döndüren JavaScript kodu için ise runJavaScriptReturningResult kullanın.

JavaScript'i etkinleştirmek için WebViewController özelliğini javaScriptMode özelliği JavascriptMode.unrestricted olarak ayarlanmış şekilde yapılandırmanız gerekir. Varsayılan olarak javascriptMode, JavascriptMode.disabled olarak ayarlanır.

_WebViewStackState sınıfını, javascriptMode ayarını aşağıdaki şekilde ekleyerek güncelleyin:

lib/src/web_view_stack.dart

class _WebViewStackState extends State<WebViewStack> {
  var loadingPercentage = 0;

  @override
  void initState() {
    super.initState();
    widget.controller
      ..setNavigationDelegate(              // Modify this line to use .. instead of .
        NavigationDelegate(
          onPageStarted: (url) {
            setState(() {
              loadingPercentage = 0;
            });
          },
          onProgress: (progress) {
            setState(() {
              loadingPercentage = progress;
            });
          },
          onPageFinished: (url) {
            setState(() {
              loadingPercentage = 100;
            });
          },
          onNavigationRequest: (navigation) {
            final host = Uri.parse(navigation.url).host;
            if (host.contains('youtube.com')) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text(
                    'Blocking navigation to $host',
                  ),
                ),
              );
              return NavigationDecision.prevent;
            }
            return NavigationDecision.navigate;
          },
        ),
      )
      ..setJavaScriptMode(JavaScriptMode.unrestricted);        // Add this line
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        WebViewWidget(
          controller: widget.controller,
        ),
        if (loadingPercentage < 100)
          LinearProgressIndicator(
            value: loadingPercentage / 100.0,
          ),
      ],
    );
  }
}

WebViewWidget artık JavaScript'i çalıştırabildiğinden menüye runJavaScriptReturningResult yöntemini kullanma seçeneği ekleyebilirsiniz.

Düzenleyicinizi veya klavyenizi kullanarak Menu sınıfını StatefulWidget'a dönüştürün. lib/src/menu.dart öğesini aşağıdakiyle eşleşecek şekilde değiştirin:

lib/src/menu.dart

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

enum _MenuOptions {
  navigationDelegate,
  userAgent,                                              // Add this line
}

class Menu extends StatefulWidget {                       // Convert to StatefulWidget
  const Menu({required this.controller, super.key});

  final WebViewController controller;

  @override                                               // Add from here
  State<Menu> createState() => _MenuState();
}

class _MenuState extends State<Menu> {                    // To here.
  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<_MenuOptions>(
      onSelected: (value) async {
        switch (value) {
          case _MenuOptions.navigationDelegate:           // Modify from here
            await widget.controller
                .loadRequest(Uri.parse('https://youtube.com'));
          case _MenuOptions.userAgent:
            final userAgent = await widget.controller
                .runJavaScriptReturningResult('navigator.userAgent');
            if (!context.mounted) return;
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text('$userAgent'),
            ));                                           // To here.
        }
      },
      itemBuilder: (context) => [
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.navigationDelegate,
          child: Text('Navigate to YouTube'),
        ),
        const PopupMenuItem<_MenuOptions>(                // Add from here
          value: _MenuOptions.userAgent,
          child: Text('Show user-agent'),
        ),                                                // To here.
      ],
    );
  }
}

"Kullanıcı aracısını göster" menü seçeneğine dokunduğunuzda, JavaScript ifadesini navigator.userAgent yürütmenin sonucu Snackbar içinde gösterilir. Uygulamayı çalıştırırken Flutter.dev sayfasının farklı göründüğünü fark edebilirsiniz. Bu, JavaScript etkinleştirilmiş olarak çalıştırmanın sonucudur.

Flutter.dev ana sayfasını gösteren yerleşik bir web görünümüyle Flutter uygulaması çalıştıran iPhone simülatörü. Menü öğelerinde &quot;YouTube&#39;a git&quot; veya &quot;Kullanıcı aracısını göster&quot; seçenekleri yer alıyor.

iPhone simülatöründe, Flutter.dev ana sayfasını gösteren yerleşik bir web görünümü içeren Flutter uygulaması çalıştırılıyor. Kullanıcı aracısı dizesini gösteren bir toast pop-up&#39;ı da mevcut.

10. JavaScript kanallarıyla çalışma

JavaScript kanalları, uygulamanızın WebViewWidget JavaScript bağlamında geri çağırma işleyicileri kaydetmesini sağlar. Bu işleyiciler, değerleri uygulamanın Dart koduna geri iletmek için çağrılabilir. Bu adımda, XMLHttpRequest sonucuyla çağrılacak bir SnackBar kanalı kaydedeceksiniz.

WebViewStack sınıfını aşağıdaki şekilde güncelleyin:

lib/src/web_view_stack.dart

class WebViewStack extends StatefulWidget {
  const WebViewStack({required this.controller, super.key});

  final WebViewController controller;

  @override
  State<WebViewStack> createState() => _WebViewStackState();
}

class _WebViewStackState extends State<WebViewStack> {
  var loadingPercentage = 0;

  @override
  void initState() {
    super.initState();
    widget.controller
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageStarted: (url) {
            setState(() {
              loadingPercentage = 0;
            });
          },
          onProgress: (progress) {
            setState(() {
              loadingPercentage = progress;
            });
          },
          onPageFinished: (url) {
            setState(() {
              loadingPercentage = 100;
            });
          },
          onNavigationRequest: (navigation) {
            final host = Uri.parse(navigation.url).host;
            if (host.contains('youtube.com')) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(
                  content: Text(
                    'Blocking navigation to $host',
                  ),
                ),
              );
              return NavigationDecision.prevent;
            }
            return NavigationDecision.navigate;
          },
        ),
      )
      // Modify from here...
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..addJavaScriptChannel(
        'SnackBar',
        onMessageReceived: (message) {
          ScaffoldMessenger.of(context)
              .showSnackBar(SnackBar(content: Text(message.message)));
        },
      );
      // ...to here.
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        WebViewWidget(
          controller: widget.controller,
        ),
        if (loadingPercentage < 100)
          LinearProgressIndicator(
            value: loadingPercentage / 100.0,
          ),
      ],
    );
  }
}

Set içindeki her JavaScript kanalı için JavaScript bağlamında, JavaScript kanalıyla aynı ada sahip bir pencere özelliği olarak bir kanal nesnesi kullanılabilir name. Bunu JavaScript bağlamından kullanmak, adlandırılmış JavascriptChannel öğesinin onMessageReceived geri çağırma işleyicisine iletilen bir mesajı göndermek için JavaScript Kanalı'nda postMessage işlevini çağırmayı içerir.

Daha önce eklediğiniz JavaScript kanalını kullanmak için JavaScript bağlamında XMLHttpRequest işlevini yürüten ve sonuçları SnackBar JavaScript kanalı aracılığıyla geri ileten başka bir menü öğesi ekleyin.

WebViewWidget artık JavaScript kanallarımız hakkında bilgi sahibi olduğuna göre, uygulamayı daha da genişletmek için bir örnek ekleyeceksiniz. Bunu yapmak için Menu sınıfına fazladan bir PopupMenuItem ekleyin ve ek işlevselliği uygulayın.

_MenuOptions numaralandırma değerini ekleyerek _MenuOptions öğesini ek menü seçeneğiyle güncelleyin ve Menu sınıfına aşağıdaki gibi bir uygulama ekleyin:javascriptChannel

lib/src/menu.dart

enum _MenuOptions {
  navigationDelegate,
  userAgent,
  javascriptChannel,                                      // Add this option
}

class Menu extends StatefulWidget {
  const Menu({required this.controller, super.key});

  final WebViewController controller;

  @override
  State<Menu> createState() => _MenuState();
}

class _MenuState extends State<Menu> {
  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<_MenuOptions>(
      onSelected: (value) async {
        switch (value) {
          case _MenuOptions.navigationDelegate:
            await widget.controller
                .loadRequest(Uri.parse('https://youtube.com'));
          case _MenuOptions.userAgent:
            final userAgent = await widget.controller
                .runJavaScriptReturningResult('navigator.userAgent');
            if (!context.mounted) return;
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text('$userAgent'),
            ));
          case _MenuOptions.javascriptChannel:            // Add from here
            await widget.controller.runJavaScript('''
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
  if (req.status == 200) {
    let response = JSON.parse(req.responseText);
    SnackBar.postMessage("IP Address: " + response.ip);
  } else {
    SnackBar.postMessage("Error: " + req.status);
  }
}
req.send();''');                                          // To here.
        }
      },
      itemBuilder: (context) => [
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.navigationDelegate,
          child: Text('Navigate to YouTube'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.userAgent,
          child: Text('Show user-agent'),
        ),
        const PopupMenuItem<_MenuOptions>(                // Add from here
          value: _MenuOptions.javascriptChannel,
          child: Text('Lookup IP Address'),
        ),                                                // To here.
      ],
    );
  }
}

Bu JavaScript, kullanıcı JavaScript Kanalı Örneği menü seçeneğini belirlediğinde yürütülür.

var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
  if (req.status == 200) {
    SnackBar.postMessage(req.responseText);
  } else {
    SnackBar.postMessage("Error: " + req.status);
  }
}
req.send();

Bu kod, genel IP adresi API'sine GET isteği göndererek cihazın IP adresini döndürür. Bu sonuç, SnackBar JavascriptChannel üzerinde postMessage çağrılarak SnackBar içinde gösterilir.

11. Çerezleri yönetme

Uygulamanız, CookieManager sınıfını kullanarak WebView içindeki çerezleri yönetebilir. Bu adımda, çerezlerin listesini gösterecek, çerez listesini temizleyecek, çerezleri silecek ve yeni çerezler ayarlayacaksınız. Çerez kullanım alanlarının her biri için _MenuOptions bölümüne aşağıdaki gibi girişler ekleyin:

lib/src/menu.dart

enum _MenuOptions {
  navigationDelegate,
  userAgent,
  javascriptChannel,
  // Add from here ...
  listCookies,
  clearCookies,
  addCookie,
  setCookie,
  removeCookie,
  // ... to here.
}

Bu adımdaki diğer değişiklikler, Menu sınıfının durumsuzdan durumluya dönüştürülmesi de dahil olmak üzere Menu sınıfına odaklanmıştır. Menu, CookieManager'nin sahibi olmalıdır ve durumsuz widget'larda değiştirilebilir durum kötü bir kombinasyondur. Bu nedenle bu değişiklik önemlidir.

CookieManager'ı aşağıdaki şekilde sonuçtaki State sınıfına ekleyin:

lib/src/menu.dart

class Menu extends StatefulWidget {
  const Menu({required this.controller, super.key});

  final WebViewController controller;

  @override
  State<Menu> createState() => _MenuState();
}

class _MenuState extends State<Menu> {
  final cookieManager = WebViewCookieManager();       // Add this line

  @override
  Widget build(BuildContext context) {
  // ...

_MenuState sınıfı, daha önce Menu sınıfına eklenen kodun yanı sıra yeni eklenen CookieManager sınıfını da içerir. Sonraki bölümlerde, _MenuState öğesine yardımcı işlevler ekleyeceksiniz. Bu işlevler de henüz eklenmemiş menü öğeleri tarafından çağrılacak.

Tüm çerezlerin listesini alma

Tüm çerezlerin listesini almak için JavaScript kullanacaksınız. Bunu yapmak için _MenuState sınıfının sonuna _onListCookies adlı bir yardımcı yöntem ekleyin. runJavaScriptReturningResult yöntemini kullandığınızda yardımcı yönteminiz JavaScript bağlamında document.cookie kodunu çalıştırarak tüm çerezlerin listesini döndürür.

_MenuState sınıfına aşağıdakileri ekleyin:

lib/src/menu.dart

Future<void> _onListCookies(WebViewController controller) async {
  final String cookies = await controller
      .runJavaScriptReturningResult('document.cookie') as String;
  if (!mounted) return;
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text(cookies.isNotEmpty ? cookies : 'There are no cookies.'),
    ),
  );
}

Tüm çerezleri temizleme

WebView'daki tüm çerezleri temizlemek için CookieManager sınıfının clearCookies yöntemini kullanın. Yöntem, Future<bool> döndürür. Bu değer, CookieManager çerezleri temizlediyse true, temizlenecek çerez yoksa false olarak çözümlenir.

_MenuState sınıfına aşağıdakileri ekleyin:

lib/src/menu.dart

Future<void> _onClearCookies() async {
  final hadCookies = await cookieManager.clearCookies();
  String message = 'There were cookies. Now, they are gone!';
  if (!hadCookies) {
    message = 'There were no cookies to clear.';
  }
  if (!mounted) return;
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(
      content: Text(message),
    ),
  );
}

Çerez eklemek için JavaScript çağrılabilir. Bir JavaScript belgesine çerez eklemek için kullanılan API, MDN'de ayrıntılı olarak belgelenmiştir.

_MenuState sınıfına aşağıdakileri ekleyin:

lib/src/menu.dart

Future<void> _onAddCookie(WebViewController controller) async {
  await controller.runJavaScript('''var date = new Date();
  date.setTime(date.getTime()+(30*24*60*60*1000));
  document.cookie = "FirstName=John; expires=" + date.toGMTString();''');
  if (!mounted) return;
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text('Custom cookie added.'),
    ),
  );
}

Çerezler, CookieManager kullanılarak da aşağıdaki gibi ayarlanabilir.

_MenuState sınıfına aşağıdakileri ekleyin:

lib/src/menu.dart

Future<void> _onSetCookie(WebViewController controller) async {
  await cookieManager.setCookie(
    const WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev'),
  );
  if (!mounted) return;
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text('Custom cookie is set.'),
    ),
  );
}

Bir çerezin kaldırılması, son kullanma tarihi geçmişte belirlenmiş bir çerezin eklenmesini içerir.

_MenuState sınıfına aşağıdakileri ekleyin:

lib/src/menu.dart

Future<void> _onRemoveCookie(WebViewController controller) async {
  await controller.runJavaScript(
      'document.cookie="FirstName=John; expires=Thu, 01 Jan 1970 00:00:00 UTC" ');
  if (!mounted) return;
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(
      content: Text('Custom cookie removed.'),
    ),
  );
}

CookieManager menü öğelerini ekleme

Geriye yalnızca menü seçeneklerini eklemek ve bunları az önce eklediğiniz yardımcı yöntemlere bağlamak kalır. _MenuState sınıfını aşağıdaki şekilde güncelleyin:

lib/src/menu.dart

class _MenuState extends State<Menu> {
  final cookieManager = WebViewCookieManager();

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<_MenuOptions>(
      onSelected: (value) async {
        switch (value) {
          case _MenuOptions.navigationDelegate:
            await widget.controller
                .loadRequest(Uri.parse('https://youtube.com'));
          case _MenuOptions.userAgent:
            final userAgent = await widget.controller
                .runJavaScriptReturningResult('navigator.userAgent');
            if (!context.mounted) return;
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text('$userAgent'),
            ));
          case _MenuOptions.javascriptChannel:
            await widget.controller.runJavaScript('''
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
  if (req.status == 200) {
    let response = JSON.parse(req.responseText);
    SnackBar.postMessage("IP Address: " + response.ip);
  } else {
    SnackBar.postMessage("Error: " + req.status);
  }
}
req.send();''');
          case _MenuOptions.clearCookies:                        // Add from here
            await _onClearCookies();
          case _MenuOptions.listCookies:
            await _onListCookies(widget.controller);
          case _MenuOptions.addCookie:
            await _onAddCookie(widget.controller);
          case _MenuOptions.setCookie:
            await _onSetCookie(widget.controller);
          case _MenuOptions.removeCookie:
            await _onRemoveCookie(widget.controller);            // To here.
        }
      },
      itemBuilder: (context) => [
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.navigationDelegate,
          child: Text('Navigate to YouTube'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.userAgent,
          child: Text('Show user-agent'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.javascriptChannel,
          child: Text('Lookup IP Address'),
        ),
        const PopupMenuItem<_MenuOptions>(                       // Add from here
          value: _MenuOptions.clearCookies,
          child: Text('Clear cookies'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.listCookies,
          child: Text('List cookies'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.addCookie,
          child: Text('Add cookie'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.setCookie,
          child: Text('Set cookie'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.removeCookie,
          child: Text('Remove cookie'),
        ),                                                       // To here.
      ],
    );
  }

CookieManager'ı kullanma

Uygulamaya yeni eklediğiniz tüm işlevleri kullanmak için aşağıdaki adımları deneyin:

  1. Liste çerezleri'ni seçin. Bu listede, flutter.dev tarafından ayarlanan Google Analytics çerezleri yer almalıdır.
  2. Çerezleri temizle'yi seçin. Çerezlerin gerçekten temizlendiği bildirilmelidir.
  3. Çerezleri temizle'yi tekrar seçin. Temizlenecek çerez bulunmadığı bildirilmelidir.
  4. Liste çerezleri'ni seçin. Çerez olmadığını bildirmelidir.
  5. Çerez ekle'yi seçin. Çerezin eklendiğini bildirmelidir.
  6. Çerez ayarla'yı seçin. Çerezin ayarlandığını bildirmelidir.
  7. Çerezleri listele'yi ve ardından son olarak Çerezi kaldır'ı seçin.

Flutter.dev ana sayfasını gösteren yerleşik bir web görünümüyle Flutter uygulamasının çalıştığı Android emülatörü. Bu ana sayfada YouTube&#39;a gitme, kullanıcı aracısını gösterme ve tarayıcının çerez kavanozuyla etkileşim kurma gibi menü seçeneklerinin listesi yer alıyor.

Tarayıcıda ayarlanan çerezleri gösteren bir toast iletişim kutusuyla Flutter.dev ana sayfasını gösteren yerleşik bir web görünümü içeren Flutter uygulamasının çalıştığı Android emülatörü

Flutter.dev ana sayfasını gösteren yerleşik bir web görünümüyle Flutter uygulamasının çalıştığı Android emülatörü ve &quot;Çerezler vardı. Artık yoklar!&quot;

Flutter.dev ana sayfasını gösteren yerleşik bir web görünümüyle Flutter uygulaması çalıştıran Android emülatöründe &quot;Özel çerez eklendi.&quot; yazan bir kısa mesaj iletişim kutusu gösteriliyor.

12. WebView'da Flutter öğelerini, dosyalarını ve HTML dizelerini yükleme

Uygulamanız, HTML dosyalarını farklı yöntemlerle yükleyip WebView'da gösterebilir. Bu adımda, pubspec.yaml dosyasında belirtilen bir Flutter öğesini, belirtilen yolda bulunan bir dosyayı ve bir HTML dizesi kullanarak bir sayfayı yükleyeceksiniz.

Belirli bir yolda bulunan bir dosyayı yüklemek istiyorsanız path_provider öğesini pubspec.yaml öğesine eklemeniz gerekir. Bu, dosya sisteminde sık kullanılan konumları bulmak için kullanılan bir Flutter eklentisidir.

Komut satırında aşağıdaki komutu çalıştırın:

$ flutter pub add path_provider

Öğeyi yüklemek için pubspec.yaml içinde öğenin yolunu belirtmemiz gerekir. pubspec.yaml bölümüne aşağıdaki satırları ekleyin:

pubspec.yaml

# The following section is specific to Flutter packages.
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true
  # Add from here
  assets:
    - assets/www/index.html
    - assets/www/styles/style.css
  # ... to here.

Öğeleri projenize eklemek için aşağıdaki adımları uygulayın:

  1. Projenizin kök klasöründe assets adlı yeni bir Dizin oluşturun.
  2. assets klasöründe www adlı yeni bir dizin oluşturun.
  3. www klasöründe styles adlı yeni bir dizin oluşturun.
  4. www klasöründe index.html adlı yeni bir Dosya oluşturun.
  5. styles klasöründe style.css adlı yeni bir Dosya oluşturun.

Aşağıdaki kodu kopyalayıp index.html dosyasına yapıştırın:

assets/www/index.html

<!DOCTYPE html>
<!-- Copyright 2013 The Flutter Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<html lang="en">
<head>
    <title>Load file or HTML string example</title>
    <link rel="stylesheet" href="styles/style.css" />
</head>
<body>

<h1>Local demo page</h1>
<p>
    This is an example page used to demonstrate how to load a local file or HTML
    string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
    webview</a> plugin.
</p>

</body>
</html>

style.css için HTML başlık stilini ayarlamak üzere aşağıdaki birkaç satırı kullanın:

assets/www/styles/style.css

h1 {
  color: blue;
}

Öğeler ayarlanıp kullanıma hazır hale geldiğine göre artık Flutter öğelerini, dosyalarını veya HTML dizelerini yüklemek ve görüntülemek için gereken yöntemleri uygulayabilirsiniz.

Flutter öğesini yükleme

Yeni oluşturduğunuz öğeyi yüklemek için tek yapmanız gereken WebViewController kullanarak loadFlutterAsset yöntemini çağırmak ve parametre olarak öğenin yolunu vermektir. Kodunuzun sonuna aşağıdaki yöntemi ekleyin:

lib/src/menu.dart

Future<void> _onLoadFlutterAssetExample(
    WebViewController controller, BuildContext context) async {
  await controller.loadFlutterAsset('assets/www/index.html');
}

Yerel dosyayı yükleme

Cihazınıza dosya yüklemek için loadFile yöntemini kullanacak bir yöntem ekleyebilirsiniz. Bunun için yine WebViewController yöntemini kullanın. Bu yöntem, dosyanın yolunu içeren bir String alır.

Öncelikle HTML kodunu içeren bir dosya oluşturmanız gerekir. Bunu, menu.dart dosyasındaki kodunuzun en üstüne, içe aktarma işlemlerinin hemen altına HTML kodunu String olarak ekleyerek yapabilirsiniz.

lib/src/menu.dart

import 'dart:io';                                   // Add this line,
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';  // And this one.
import 'package:webview_flutter/webview_flutter.dart';

// Add from here ...
const String kExamplePage = '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Load file or HTML string example</title>
</head>
<body>

<h1>Local demo page</h1>
<p>
 This is an example page used to demonstrate how to load a local file or HTML
 string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
 webview</a> plugin.
</p>

</body>
</html>
''';
// ... to here.

File oluşturmak ve HTML dizesini dosyaya yazmak için iki yöntem ekleyeceksiniz. _onLoadLocalFileExample, _prepareLocalFile() yöntemi tarafından döndürülen yolu Dize olarak sağlayarak dosyayı yükler. Kodunuza aşağıdaki yöntemleri ekleyin:

lib/src/menu.dart

Future<void> _onLoadLocalFileExample(
    WebViewController controller, BuildContext context) async {
  final String pathToIndex = await _prepareLocalFile();

  await controller.loadFile(pathToIndex);
}

static Future<String> _prepareLocalFile() async {
  final String tmpDir = (await getTemporaryDirectory()).path;
  final File indexFile = File('$tmpDir/www/index.html');

  await Directory('$tmpDir/www').create(recursive: true);
  await indexFile.writeAsString(kExamplePage);

  return indexFile.path;
}

HTML dizesini yükleme

Bir HTML dizesi sağlayarak sayfayı görüntülemek oldukça basittir. WebViewController, HTML dizesini bağımsız değişken olarak verebileceğiniz loadHtmlString adlı bir yönteme sahiptir. Daha sonra WebView, sağlanan HTML sayfasını gösterir. Kodunuza aşağıdaki yöntemi ekleyin:

lib/src/menu.dart

Future<void> _onLoadFlutterAssetExample(
    WebViewController controller, BuildContext context) async {
  await controller.loadFlutterAsset('assets/www/index.html');
}

Future<void> _onLoadLocalFileExample(
    WebViewController controller, BuildContext context) async {
  final String pathToIndex = await _prepareLocalFile();

  await controller.loadFile(pathToIndex);
}

static Future<String> _prepareLocalFile() async {
  final String tmpDir = (await getTemporaryDirectory()).path;
  final File indexFile = File('$tmpDir/www/index.html');

  await Directory('$tmpDir/www').create(recursive: true);
  await indexFile.writeAsString(kExamplePage);

  return indexFile.path;
}

// Add here ...
Future<void> _onLoadHtmlStringExample(
    WebViewController controller, BuildContext context) async {
  await controller.loadHtmlString(kExamplePage);
}
// ... to here.

Menü öğelerini ekleme

Öğeler ayarlanıp kullanıma hazır hale getirildikten ve tüm işlevlerin yer aldığı yöntemler oluşturulduktan sonra menü güncellenebilir. _MenuOptions enum'una aşağıdaki girişleri ekleyin:

lib/src/menu.dart

enum _MenuOptions {
  navigationDelegate,
  userAgent,
  javascriptChannel,
  listCookies,
  clearCookies,
  addCookie,
  setCookie,
  removeCookie,
  // Add from here ...
  loadFlutterAsset,
  loadLocalFile,
  loadHtmlString,
  // ... to here.
}

Numaralandırma güncellendiğine göre artık menü seçeneklerini ekleyebilir ve bunları az önce eklediğiniz yardımcı yöntemlere bağlayabilirsiniz. _MenuState sınıfını aşağıdaki şekilde güncelleyin:

lib/src/menu.dart

class _MenuState extends State<Menu> {
  final cookieManager = WebViewCookieManager();

  @override
  Widget build(BuildContext context) {
    return PopupMenuButton<_MenuOptions>(
      onSelected: (value) async {
        switch (value) {
          case _MenuOptions.navigationDelegate:
            await widget.controller
                .loadRequest(Uri.parse('https://youtube.com'));
          case _MenuOptions.userAgent:
            final userAgent = await widget.controller
                .runJavaScriptReturningResult('navigator.userAgent');
            if (!context.mounted) return;
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text('$userAgent'),
            ));
          case _MenuOptions.javascriptChannel:
            await widget.controller.runJavaScript('''
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
  if (req.status == 200) {
    let response = JSON.parse(req.responseText);
    SnackBar.postMessage("IP Address: " + response.ip);
  } else {
    SnackBar.postMessage("Error: " + req.status);
  }
}
req.send();''');
          case _MenuOptions.clearCookies:
            await _onClearCookies();
          case _MenuOptions.listCookies:
            await _onListCookies(widget.controller);
          case _MenuOptions.addCookie:
            await _onAddCookie(widget.controller);
          case _MenuOptions.setCookie:
            await _onSetCookie(widget.controller);
          case _MenuOptions.removeCookie:
            await _onRemoveCookie(widget.controller);
          case _MenuOptions.loadFlutterAsset:             // Add from here
            if (!mounted) return;
            await _onLoadFlutterAssetExample(widget.controller, context);
          case _MenuOptions.loadLocalFile:
            if (!mounted) return;
            await _onLoadLocalFileExample(widget.controller, context);
          case _MenuOptions.loadHtmlString:
            if (!mounted) return;
            await _onLoadHtmlStringExample(widget.controller, context);
                                                          // To here.
        }
      },
      itemBuilder: (context) => [
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.navigationDelegate,
          child: Text('Navigate to YouTube'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.userAgent,
          child: Text('Show user-agent'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.javascriptChannel,
          child: Text('Lookup IP Address'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.clearCookies,
          child: Text('Clear cookies'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.listCookies,
          child: Text('List cookies'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.addCookie,
          child: Text('Add cookie'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.setCookie,
          child: Text('Set cookie'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.removeCookie,
          child: Text('Remove cookie'),
        ),
        const PopupMenuItem<_MenuOptions>(                // Add from here
          value: _MenuOptions.loadFlutterAsset,
          child: Text('Load Flutter Asset'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.loadHtmlString,
          child: Text('Load HTML string'),
        ),
        const PopupMenuItem<_MenuOptions>(
          value: _MenuOptions.loadLocalFile,
          child: Text('Load local file'),
        ),                                                // To here.
      ],
    );
  }

Öğeleri, dosyayı ve HTML dizesini test etme

Yeni uyguladığınız kodun çalışıp çalışmadığını test etmek için kodu cihazınızda çalıştırabilir ve yeni eklenen menü öğelerinden birini tıklayabilirsiniz. _onLoadFlutterAssetExample etiketinin, HTML dosyasının başlığını mavi renge değiştirmek için eklediğimiz style.css etiketini nasıl kullandığına dikkat edin.

Android emülatöründe, &quot;Yerel demo sayfası&quot; etiketli ve başlığı mavi renkte olan bir sayfayı gösteren yerleşik web görünümü içeren bir Flutter uygulaması çalıştırılıyor.

Android emülatöründe, &quot;Local demo page&quot; (Yerel demo sayfası) etiketli bir sayfayı siyah başlıkla gösteren yerleşik bir web görünümü içeren Flutter uygulaması çalıştırılıyor.

13. İşlem tamamlandı

Tebrikler!!! Codelab'i tamamlamış olmanız gerekir. Bu codelab'in tamamlanmış kodunu codelab deposunda bulabilirsiniz.

Daha fazla bilgi edinmek için diğer Flutter codelab'lerini deneyin.