Flutter uygulamanıza WebView ekleme

1. Giriş

Son Güncelleme: 19.10.2021

WebView Flutter eklentisi ile Android veya iOS Flutter uygulamanıza WebView widget'ı ekleyebilirsiniz. iOS'te WebView widget'ı WKWebView, Android'de ise WebView widget'ı WebView ile desteklenir. Eklenti, web görünümü üzerinden Flutter widget'larını oluşturabilir. Dolayısıyla, örneğin web görünümü üzerinde bir açılır menü oluşturulabilir.

Neler oluşturacaksınız?

Bu codelab'de, Flutter SDK'sını kullanarak bir WebView'u öne çıkaran, adım adım mobil uygulama geliştireceksiniz. Uygulamanız şunları yapabilecek:

  • Web içeriğini WebView uygulamasında göster
  • Flutter widget'larını WebView öğesinin üzerine yığılmış olarak görüntüle
  • Sayfa yükleme ilerleme etkinliklerine tepki verme
  • WebView öğesini WebViewController aracılığıyla kontrol edin
  • NavigationDelegate özelliğini kullanan web sitelerini engelleyin
  • JavaScript ifadelerini değerlendirme
  • JavaScript'ten gelen geri çağırmaları JavascriptChannels ile ele alın
  • Çerezleri ayarlama, kaldırma, ekleme veya gösterme
  • Öğelerden, dosyalardan veya HTML içeren dizelerden HTML yükleyin ve görüntüleyin

Yerleşik web görünümüyle Flutter.dev ana sayfasını gösteren bir Flutter uygulaması çalıştıran iPhone simülatörünün ekran görüntüsü

Yerleşik web görünümüyle Flutter.dev ana sayfasını gösteren bir Flutter uygulaması çalıştıran Android emülatörünün ekran görüntüsü

Neler öğreneceksiniz?

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

  • webview_flutter eklentisi nasıl yapılandırılır?
  • Sayfa yükleme ilerleme etkinliklerini dinleme
  • Sayfada gezinmeyi kontrol etme
  • WebView öğesinin geçmişinde geri ve ileri gitmesi için nasıl komut verilir?
  • Döndürülen sonuçların kullanımı da dahil olmak üzere JavaScript'i değerlendirme
  • JavaScript'ten Dart kodu çağırmak için geri çağırmalar kaydetme
  • Çerezler nasıl yönetilir?
  • Öğelerden veya dosyalardan ya da HTML içeren dizeden HTML sayfaları yükleme ve görüntüleme

Gerekenler

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

Bu laboratuvarı tamamlamak için iki yazılıma ihtiyacınız vardır: Flutter SDK'sı ve düzenleyici.

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

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 gerekli araçları sağlar. Proje oluşturmak için bağlantılı prosedürleri izleyin veya kullanışlı bir komut satırı terminalinde aşağıdaki komutları yürütü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.

Bağımlılık olarak WebView Flutter eklentisi ekleme

Pub paketlerini kullanarak Flutter uygulamasına yeni özellikler eklemek kolaydı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... 
  leak_tracker 10.0.4 (10.0.5 available)
  leak_tracker_flutter_testing 3.0.3 (3.0.5 available)
  material_color_utilities 0.8.0 (0.11.1 available)
  meta 1.12.0 (1.14.0 available)
+ plugin_platform_interface 2.1.8
  test_api 0.7.0 (0.7.1 available)
+ webview_flutter 4.7.0
+ webview_flutter_android 3.16.0
+ webview_flutter_platform_interface 2.10.0
+ webview_flutter_wkwebview 3.13.0
Changed 5 dependencies!
5 packages have newer versions incompatible with dependency constraints.
Try `flutter pub outdated` for more information.

pubspec.yaml dosyanızı incelerseniz webview_flutter eklentisinin bağımlılıklar bölümünde bir satır olduğunu görürsünüz.

Android minSDK'yı yapılandırma

webview_flutter eklentisini Android'de kullanmak için minSDK özelliğini 20 olarak ayarlamanız 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. Web Görünümleri, barındırılan yerel görünümlerdir ve uygulama geliştirici olarak bu yerel görünümleri uygulamanızda nasıl barındıracağınızı seçebilirsiniz. Android'de, Android'in varsayılan ayarı olan Sanal Ekran ile Karma ekran arasından seçim yapabilirsiniz. Ancak iOS her zaman Karma bileşim kullanır.

Sanal Ekranlar ve Karma beste arasındaki farklılıkların ayrıntılı bir açıklaması için lütfen Platform Görünümleri ile Flutter uygulamanızda yerel Android ve iOS görünümleri barındırma hakkındaki dokümanları okuyun.

Ekrana web görünümü yerleştirme

lib/main.dart içeriğini şununla 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 uygulama iOS veya Android'de çalıştırıldığında, Web Görünümü, cihazınızda tam çerçeveli bir tarayıcı penceresi olarak gösterilir. Bu pencere, tarayıcının cihazınızda herhangi bir kenarlık veya kenar boşluğu olmadan tam ekranda gösterildiği anlamına gelir. Kaydırırken sayfanın biraz tuhaf görünebileceğini fark edeceksiniz. Bunun nedeni JavaScript'in şu anda devre dışı olması ve flutter.dev'in düzgün şekilde oluşturulması için JavaScript'in gerekli olmasıdır.

Uygulamayı çalıştırma

iOS veya Android'de Flutter uygulamasını çalıştırarak flutter.dev web sitesini görüntüleyen bir web görünümü elde edin. Alternatif olarak uygulamayı bir Android emülatöründe veya iOS simülatöründe çalıştırabilirsiniz. Başlangıçtaki WebView URL'sini, örneğin kendi web sitenizle değiştirebilirsiniz.

$ flutter run

Uygulamayı derleyip cihazınıza dağıttıktan sonra aşağıdakine benzer bir simülatör veya emülatörün çalıştığını ya da fiziksel bir cihazınızın olduğunu varsayarsak aşağıdakine benzer bir sonuç görürsünüz:

Yerleşik web görünümüyle Flutter.dev ana sayfasını gösteren bir Flutter uygulaması çalıştıran iPhone simülatörünün ekran görüntüsü

Yerleşik web görünümüyle Flutter.dev ana sayfasını gösteren bir Flutter uygulaması çalıştıran Android emülatörünün ekran görüntüsü

5. Sayfa yükleme etkinlikleri dinleniyor

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 tetiklenen üç farklı sayfa yükleme etkinliği vardır: onPageStarted, onProgress ve onPageFinished. Bu adımda bir sayfa yükleme göstergesi uygulayacaksınız. Bu sayede, WebView içerik alanı üzerinde Flutter içeriği oluşturabileceğiniz de gösterilir.

Uygulamanıza sayfa yükleme etkinlikleri ekleme

lib/src/web_view_stack.dart adresinde yeni bir kaynak dosya oluşturun ve dosyayı 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ı bir Stack içine sarmış ve sayfa yükleme yüzdesi %100'den az olduğunda WebView öğesini koşullu olarak bir LinearProgressIndicator ile yerleştirmiştir. Zaman içinde değişen program durumu da söz konusu olduğundan bu durumu StatefulWidget ile ilişkili bir State sınıfında depoladınız.

Bu yeni WebViewStack widget'ından yararlanmak için lib/main.dart'ınızı aşağıdaki gibi 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 ziyaret ettiğ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 kumanda, WebView widget'ının oluşturulmasından sonra, geri çağırma yoluyla kullanıma sunulur. Kullanılabilirliğinin eşzamansız olması, bu denetleyiciyi Dart'ın eşzamansız Completer<T> sınıfı için başlıca aday haline getirir.

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 etrafındaki widget'ta oluşturulan bir kumandayı kullanıyor. Bu işlem, WebViewWidget için kumandanın uygulamanın diğer bölümleriyle kolayca paylaşılmasını sağlar.

Gezinme Denetimleri Oluşturma

Çalışan bir WebView'ye sahip olmak önemlidir, ancak sayfa geçmişinde geri ve ileri gidip sayfayı yeniden yükleyebilmek de faydalı bir ekleme grubu olacaktır. Neyse ki WebViewController ile bu işlevi uygulamanıza ekleyebilirsiniz.

lib/src/navigation_controls.dart adresinde yeni bir kaynak dosya oluşturun ve aşağıdakini girin:

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 WebView öğesini bir dizi IconButton aracılığıyla kontrol edebilmesi için, oluşturma sırasında kendisiyle paylaşılan WebViewController kullanır.

AppBar'a gezinme denetimleri ekleme

Güncellenmiş WebViewStack ve yeni geliştirilen NavigationControls ile artık her şeyi güncellenmiş bir WebViewApp dosyasında bir araya getirmenin zamanı geldi. Paylaşılan WebViewController öğesini burada oluştururuz. Bu uygulamadaki Widget ağacının üst kısmına yakın bir yerde WebViewApp yer aldığından, widget'ı bu düzeyde oluşturmak mantıklıdır.

lib/main.dart dosyasını şu şekilde 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
    );
  }
}

Uygulamayı çalıştırdığınızda kontrollerin bulunduğu bir web sayfası gösterilir:

Önceki sayfa, sonraki sayfa ve sayfa yeniden yükleme denetimlerinin yer aldığı Flutter.dev ana sayfasını gösteren yerleşik web görünümüyle Flutter uygulamasını çalıştıran iPhone simülatörünün ekran görüntüsü

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörün ekran görüntüsünde önceki sayfa, sonraki sayfa ve sayfa yeniden yükleme denetimlerinin yer aldığı Flutter.dev ana sayfası gösteriliyor.

7. Gezinme Temsilcisi ile navigasyonu takip etme

WebView, uygulamanıza WebView widget'ının sayfada gezinmesini izleme ve kontrol etme olanağı tanıyan bir NavigationDelegate, sağlar. Gezinme WebView, tarafından başlatıldığında (ör. kullanıcı bir bağlantıyı tıkladığında) NavigationDelegate çağrılır. NavigationDelegate geri çağırması, WebView öğesinin gezinmeye devam edip etmeyeceğini kontrol etmek için kullanılabilir.

Özel NavigationDelegate kaydetme

Bu adımda, YouTube.com'a gitmeyi engellemek için bir NavigationDelegate geri çağırması kaydedeceksiniz. Bu basit uygulamanın, çeşitli Flutter API belge sayfalarında görünen satır içi YouTube içeriğini de engellediğini unutmayın.

lib/src/web_view_stack.dart öğesini ş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});

  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, WebViewController sınıfını kullanarak NavigationDelegate cihazınızı test etmenize olanak tanıyan bir menü öğesi ekleyeceksiniz. Okuyucu için geri çağırma mantığının kapsamını genişleterek, YouTube.com'da yalnızca tam sayfada gezinmeyi engellemek ve API dokümanlarında satır içi YouTube içeriğine izin vermeye devam etmek için bırakıldı.

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

Sonraki birkaç adımda, AppBar widget'ında JavaScript'i değerlendirmek, JavaScript kanallarını çağırmak ve çerezleri yönetmek için kullanılacak bir menü düğmesi oluşturacaksınız. Tam anlamıyla yararlı bir menü.

lib/src/menu.dart adresinde yeni bir kaynak dosya oluşturun ve aşağıdakini girin:

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 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 adlı kullanıcının 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ıp YouTube'a Git menü öğesine dokunun. Gezinme denetleyicisinin YouTube'a gitmeyi engellediğini bildiren bir SnackBar ile karşılaşacaksınız.

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörünün ekran görüntüsünde Flutter.dev ana sayfasında, &quot;YouTube&#39;a Git&quot; seçeneğinin yer aldığı bir menü öğesi yer alıyor.

Yerleşik web görünümü içeren Flutter uygulamasını çalıştıran Android emülatörünün ekran görüntüsünde &quot;m.youtube.com&#39;da gezinmeyi engelleme&quot; mesajının yer aldığı Flutter.dev ana sayfası

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çinse runJavaScriptReturningResult kullanın.

JavaScript'i etkinleştirmek için WebViewController öğesini, javaScriptMode özelliği JavascriptMode.unrestricted olacak şekilde yapılandırmanız gerekir. javascriptMode, varsayılan olarak JavascriptMode.disabled değerine ayarlıdır.

javascriptMode ayarını aşağıdaki şekilde ekleyerek _WebViewStackState sınıfını 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,
          ),
      ],
    );
  }
}

Artık WebViewWidget JavaScript yürütebildiğine göre runJavaScriptReturningResult yöntemini kullanmak için menüye bir seçenek ekleyebilirsiniz.

Düzenleyicinizi veya bazı klavye işlemlerini kullanarak Menü sınıfını StatefulWidget'a dönüştürün. lib/src/menu.dart öğesini aşağıdakilerle 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"e dokunduğunuzda seçeneğinde, navigator.userAgent JavaScript ifadesinin çalıştırılmasının sonucu bir Snackbar içinde gösterilir. Uygulamayı çalıştırırken Flutter.dev sayfasının farklı göründüğünü fark edebilirsiniz. Bu, JavaScript'in etkin olduğu çalıştırmanın bir sonucudur.

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran iPhone simülatörünün ekran görüntüsü ve Flutter.dev ana sayfasında, &quot;YouTube&#39;a Git&quot; seçeneklerinin yer aldığı menü öğelerinin yer aldığı bir ekran görüntüsü veya &quot;Kullanıcı aracısını göster&quot;

Yerleşik web görünümü içeren Flutter uygulamasını çalıştıran iPhone simülatörünün ekran görüntüsü, Flutter.dev ana sayfasını ve kullanıcı aracısı dizesini içeren durum mesajı pop-up&#39;ının yer aldığı ekran görüntüsü.

10. JavaScript Kanallarıyla Çalışma

JavaScript Kanalları, uygulamanızın değerleri uygulamanın Dart koduna geri aktarmak için çağrılabilecek WebViewWidget JavaScript bağlamında geri çağırma işleyicileri kaydetmesine olanak tanır. 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 bir JavaScript Kanalı için kanal nesnesi, JavaScript bağlamında name JavaScript Kanalı ile aynı ada sahip bir pencere özelliği olarak sunulur. Bunun JavaScript bağlamından kullanılması, JavascriptChannel adlı kullanıcının onMessageReceived geri çağırma işleyicisine iletilecek bir mesajı göndermek için JavaScript Kanalında postMessage çağrısı yapmayı içerir.

Yukarıda eklenen JavaScript Kanalından yararlanmak için, JavaScript bağlamında bir XMLHttpRequest yürüten ve sonuçları SnackBar JavaScript Kanalını kullanarak geri veren başka bir menü öğesi ekleyin.

WebViewWidget, JavaScript Kanallarımızı artık bildiğine 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 ekstra işlevi dahil edin.

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

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, bir 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 bir 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 bir çerez listesi gösterir, çerez listesini temizler, çerezleri siler ve yeni çerezler ayarlarsınız. Çerez kullanım alanlarının her biri için _MenuOptions öğesine 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ımda yapılan değişikliklerin geri kalanı, Menu sınıfının durum bilgisizden durum bilgiliye dönüştürülmesi de dahil olmak üzere Menu sınıfına odaklanmıştır. Menu öğesinin, CookieManager öğesinin sahibi olması gerektiğinden bu değişiklik önemlidir ve durum bilgisiz widget'larda değişebilir durum kötü bir kombinasyondur.

CookieManager'ı elde edilen State sınıfına aşağıdaki gibi 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ı, yeni eklenen CookieManager ile birlikte daha önce Menu sınıfına eklenen kodu içerir. Sonraki bölüm dizilerinde, _MenuState öğesine yardımcı işlevler ekleyeceksiniz. Bu işlevler de henüz eklenmemiş menü öğeleri tarafından çağrılacaktır.

Tüm çerezlerin listesini alma

Tüm çerezlerin listesini almak için JavaScript kullanacaksınız. Bunu sağlamak için _MenuState sınıfının sonuna _onListCookies adlı bir yardımcı yöntem ekleyin. Yardımcı yönteminiz, runJavaScriptReturningResult yöntemini kullanarak JavaScript bağlamında document.cookie öğesini yürüterek tüm çerezlerin listesini döndürür.

_MenuState sınıfına şunu 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

Web Görünümü'ndeki tüm çerezleri temizlemek için CookieManager sınıfının clearCookies yöntemini kullanın. Yöntem, CookieManager çerezleri temizlediyse true, temizlenecek çerez yoksa false olarak çözümlenen bir Future<bool> döndürür.

_MenuState sınıfına şunu 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, JavaScript'in çağrılmasıyla yapılabilir. JavaScript dokümanına Çerez eklemek için kullanılan API, MDN üzerinde ayrıntılı olarak belgelenmiştir.

_MenuState sınıfına şunu 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, aşağıdaki gibi CookieManager kullanılarak da ayarlanabilir.

_MenuState sınıfına şunu 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.'),
    ),
  );
}

Çerez kaldırma işlemi, son kullanma tarihi geçmiş bir tarihe ayarlanmış bir çerez eklemeyi kapsar.

_MenuState sınıfına şunu 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 sadece menü seçeneklerini ekleyip, eklediğiniz yardımcı yöntemlere aktarmak yeterli olacaktı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'ı uygulama

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

  1. Liste çerezleri'ni seçin. flutter.dev tarafından ayarlanan Google Analytics çerezleri listelenmelidir.
  2. Çerezleri temizle'yi seçin. Çerezlerin gerçekten temizlendiğini bildirmelidir.
  3. Tekrar Çerezleri temizle'yi seçin. Temizlenecek çerez olmadığı bildirilir.
  4. Liste çerezleri'ni seçin. Hiç çerez olmadığını bildirmelidir.
  5. Çerez ekle'yi seçin. Çerezi eklenmiş olarak bildirmelidir.
  6. Çerez ayarla'yı seçin. Çerezi ayarlandığı şekilde bildirmelidir.
  7. Liste çerezleri'ni seçin ve ardından son gelişme olarak Çerezi kaldır'ı seçin.

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörünün ekran görüntüsünde Flutter.dev ana sayfası ve YouTube&#39;a gitme, kullanıcı aracısını gösterme ve tarayıcının çerez kutusuyla etkileşimde bulunma gibi menü seçeneklerinin yer aldığı bir liste gösteriliyor.

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörünün ekran görüntüsünde Flutter.dev ana sayfası ile birlikte tarayıcıdaki çerezleri gösteren bir pop-up pop-up&#39;ı gösteriliyor

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörünün ekran görüntüsü ve Flutter.dev ana sayfası, yanında &quot;Çerezler vardı. Artık görünmüyorlar.&quot;

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörünün ekran görüntüsü. Üzerinde &quot;Özel çerez eklendi&quot; yazan bir pop-up pop-up mesajıyla Flutter.dev ana sayfası gösteriliyor.

12. Web Görünümü'nde Flutter öğelerini, dosyaları ve HTML dizelerini yükleme

Uygulamanız, HTML dosyalarını farklı yöntemler kullanarak yükleyebilir ve Web Görünümü'nde görüntüleyebilir. Bu adımda pubspec.yaml dosyasında belirtilen bir Flutter öğesini yükleyecek, belirtilen yolda bulunan bir dosyayı yükleyecek ve HTML Dizesi kullanarak bir sayfa yükleyeceksiniz.

Belirli bir yolda bulunan bir dosyayı yüklemek istiyorsanız pubspec.yaml öğesine path_provider eklemeniz gerekir. Bu, dosya sisteminde yaygın olarak 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 öğenin yolunu pubspec.yaml içinde belirtmemiz gerekir. pubspec.yaml içine 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 adıyla yeni bir Dizin oluşturun.
  2. assets klasöründe www adında yeni bir Dizin oluşturun.
  3. www klasöründe styles adında yeni bir Dizin oluşturun.
  4. www klasöründe index.html adında yeni bir Dosya oluşturun.
  5. styles klasöründe style.css adında 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 ayarlandığına ve kullanıma hazır olduğuna göre artık Flutter öğelerini, dosyaları 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 tüm yapmanız gereken WebViewController kullanarak loadFlutterAsset yöntemini çağırmak ve öğenin yolunu parametre olarak 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 dosya yükle

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

Öncelikle HTML kodunu içeren bir dosya oluşturmanız gerekir. Bunu, içe aktarma işlemlerinin hemen altındaki menu.dart dosyasında kodunuzun üst kısmına bir Dize olarak HTML kodunu 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.

Bir File oluşturmak ve HTML Dizesini dosyaya yazmak için iki yöntem eklersiniz. _onLoadLocalFileExample, yolu _prepareLocalFile() yöntemi tarafından döndürülen bir Dize şeklinde sağlayarak dosyayı yükler. Aşağıdaki yöntemleri kodunuza 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 Dizesi yükleme

Bir sayfayı HTML dizesi sağlayarak görüntülemek oldukça basit bir işlemdir. WebViewController, HTML Dizesini bağımsız değişken olarak verebileceğiniz loadHtmlString adlı bir yönteme sahiptir. Bunun ardından WebView, sağlanan HTML sayfasını gösterir. Aşağıdaki yöntemi kodunuza 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 getirildiğine ve tüm işlevleri içeren yöntemler yapıldığına göre artık menü güncellenebilir. _MenuOptions sıralamasına şu 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.
}

Sıralama güncellendiğine göre menü seçeneklerini ekleyebilir ve 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

Kodun az önce uyguladığınız kodu çalışıp çalışmadığını test etmek için kodu cihazınızda çalıştırıp yeni eklenen menü öğelerinden birini tıklayabilirsiniz. _onLoadFlutterAssetExample öğesinin, HTML dosyasının üstbilgisini mavi renge dönüştürmek için eklediğimiz style.css parametresini nasıl kullandığına dikkat edin.

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörün ekran görüntüsünde &quot;Yerel demo sayfası&quot; etiketli bir sayfa gösteriliyor başlığı mavi

Yerleşik web görünümüyle Flutter uygulamasını çalıştıran Android emülatörün ekran görüntüsünde &quot;Yerel demo sayfası&quot; etiketli bir sayfa gösteriliyor başlık siyah renkte

13. Hepsi bu kadar.

Tebrikler!!! Codelab'i tamamladınız. Bu codelab için tamamlanmış kodu codelab deposunda bulabilirsiniz.

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