Flutter之InAppWebView 官方例子转发

丁雅懿
2023-12-01

资料

官方文档

源码

pubspec.yaml

name: flutter_project
description: A new Flutter project.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
  sdk: '>=2.12.0 <3.0.0'
dependencies:
  dio: ^4.0.4
  cupertino_icons: ^1.0.2
  flutter_downloader: ^1.5.2
  path_provider: ^2.0.0-nullsafety
  flutter_inappwebview: ^5.3.2
  permission_handler: ^5.1.0+2
  url_launcher: ^6.0.0-nullsafety.4
  flutter:
    sdk: flutter
dev_dependencies:
  flutter_test:
    sdk: flutter
flutter:
  uses-material-design: true

安卓下设置

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.VIDEO_CAPTURE" />
<uses-permission android:name="android.permission.AUDIO_CAPTURE" />

<provider
    android:name="com.pichillilorenzo.flutter_inappwebview.InAppWebViewFileProvider"
    android:authorities="${applicationId}.flutter_inappwebview.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
        
</provider>

        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />

IOS

<key>NSMicrophoneUsageDescription</key>
<string>Flutter requires acess to microphone.</string>

<key>NSCameraUsageDescription</key>
<string>Flutter requires acess to camera.</string>

const.dart

class Const {
  static const String Route = "/";
  static const String InAppBrowser = "/InAppBrowser";
  static const String ChromeSafariBrowser = "/ChromeSafariBrowser";
  static const String HeadlessInAppWebView = "/HeadlessInAppWebView";
}

main.dart

import 'dart:io';

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

import 'chrome_safari_browser_example.sceen.dart';
import 'const.dart';
import 'headless_in_app_webview.screen.dart';
import 'in_app_broser_example.screen.dart';
import 'in_app_webview_example.screen.dart';

Future main() async {
// 初始化Messenger
  WidgetsFlutterBinding.ensureInitialized();
  //await Permission.camera.request();
  //await Permission.microphone.request();
  //await Permission.storage.request();

  if (Platform.isAndroid) {
  	// Debuging WebViews
    await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);

    var swAvailable = await AndroidWebViewFeature.isFeatureSupported(
        AndroidWebViewFeature.SERVICE_WORKER_BASIC_USAGE);
    var swInterceptAvailable = await AndroidWebViewFeature.isFeatureSupported(
        AndroidWebViewFeature.SERVICE_WORKER_SHOULD_INTERCEPT_REQUEST);

    if (swAvailable && swInterceptAvailable) {
      AndroidServiceWorkerController serviceWorkerController =
          AndroidServiceWorkerController.instance();

      serviceWorkerController.serviceWorkerClient = AndroidServiceWorkerClient(
        shouldInterceptRequest: (request) async {
          print(request);
          return null;
        },
      );
    }
  }

  runApp(MyApp());
}

Drawer myDrawer({required BuildContext context}) {
  return Drawer(
    child: ListView(
      children: [
        DrawerHeader(
          child: Text('flutter_inappbrowser example'),
          decoration: BoxDecoration(color: Colors.blue),
        ),
        ListTile(
          title: Text('InAppBrowser'),
          onTap: () {
            Navigator.pushReplacementNamed(context, Const.InAppBrowser);
          },
        ),
        ListTile(
          title: Text('ChromeSafariBrowser'),
          onTap: () {
            Navigator.pushReplacementNamed(context, Const.ChromeSafariBrowser);
          },
        ),
        ListTile(
          title: Text('InAppWebView'),
          onTap: () {
            Navigator.pushReplacementNamed(context, Const.Route);
          },
        ),
        ListTile(
          title: Text('HeadlessInAppWebView'),
          onTap: () {
            Navigator.pushReplacementNamed(context, Const.HeadlessInAppWebView);
          },
        ),
      ],
    ),
  );
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: Const.Route,
      routes: {
        Const.Route: (context) => InAppWebViewExampleScreen(),
        Const.InAppBrowser: (context) => InAppBrowserExampleScreen(),
        Const.ChromeSafariBrowser: (context) =>
            ChromeSafariBrowserExampleScreen(),
        Const.HeadlessInAppWebView: (context) =>
            HeadlessInAppWebViewExampleScreen(),
      },
    );
  }
}

in_app_webview_example.screen.dart

import 'dart:collection';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';

import 'main.dart';

class InAppWebViewExampleScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _InAppWebViewExampleScreenState();
}

class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
  final GlobalKey webViewKey = GlobalKey();

  InAppWebViewController? webViewController;
  InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
    crossPlatform: InAppWebViewOptions(
      useShouldOverrideUrlLoading: true, // 是否需要跳转
      mediaPlaybackRequiresUserGesture: false, // 设置为true,方式H5的音频自动播放
    ),
    android: AndroidInAppWebViewOptions(
      useHybridComposition: true,
    ),
    ios: IOSInAppWebViewOptions(
      allowsInlineMediaPlayback: true,
    ),
  );

  late PullToRefreshController pullToRefreshController;
  late ContextMenu contextMenu;
  String url = "";
  double progress = 0;
  final urlController = TextEditingController();

  @override
  void initState() {
    super.initState();
    contextMenu = ContextMenu(
        menuItems: [
          ContextMenuItem(
              androidId: 1,
              iosId: "1",
              title: 'Special',
              action: () async {
                print("Menu item Special clicked!");
                print(await webViewController?.getSelectedText());
                await webViewController?.clearFocus();
              }),
        ],
        options: ContextMenuOptions(
          hideDefaultSystemContextMenuItems: false,
        ),
        onCreateContextMenu: (hitTestResult) async {
          print('onCreateContextMenu');
          print(hitTestResult.extra);
          print(await webViewController?.getSelectedText());
        },
        onHideContextMenu: () {
          print('onHideContextMenu');
        },
        onContextMenuActionItemClicked: (contextMenuItemClicked) async {
          var id = (Platform.isAndroid)
              ? contextMenuItemClicked.androidId
              : contextMenuItemClicked.iosId;
          print('onContextMenuActionItemClicked: ' +
              id.toString() +
              " " +
              contextMenuItemClicked.title);
        });

    pullToRefreshController = PullToRefreshController(
        options: PullToRefreshOptions(color: Colors.blue),
        onRefresh: () async {
          if (Platform.isAndroid) {
            webViewController?.reload();
          } else if (Platform.isIOS) {
            webViewController?.loadUrl(
              urlRequest: URLRequest(url: await webViewController?.getUrl()),
            );
          }
        });
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("InAppWebView")),
      drawer: myDrawer(context: context),
      body: SafeArea(
        child: Column(
          children: [
            TextField(
              decoration: InputDecoration(prefixIcon: Icon(Icons.search)),
              controller: urlController,
              keyboardType: TextInputType.url,
              onSubmitted: (value) {
                var url = Uri.parse(value);
                if (url.scheme.isEmpty) {
                  url = Uri.parse("https://www.google.com/serch?q=" + value);
                }
                webViewController?.loadUrl(urlRequest: URLRequest(url: url));
              },
            ),
            Expanded(
              child: Stack(
                children: [
                  InAppWebView(
                    key: webViewKey,
                    //contextMenu: contextMenu,
                    initialUrlRequest: URLRequest(
                        url: Uri.parse("https://github.com/flutter")),
                    //initialFile: "assets/index.html",
                    initialUserScripts: UnmodifiableListView<UserScript>([]),
                    initialOptions: options,
                    pullToRefreshController: pullToRefreshController,
                    onWebViewCreated: (controller) {
                      webViewController = controller;
                    },
                    onLoadStart: (controller, url) {
                      setState(() {
                        this.url = url.toString();
                        urlController.text = this.url;
                      });
                    },
                    androidOnPermissionRequest:
                        (controller, origin, resources) async {
                      return PermissionRequestResponse(
                          resources: resources,
                          action: PermissionRequestResponseAction.GRANT);
                    },
                    shouldOverrideUrlLoading:
                        (controller, navigationAction) async {
                      var uri = navigationAction.request.url;
                      if (![
                        "http",
                        "https",
                        "file",
                        "chrome",
                        "data",
                        "javascript",
                        "about"
                      ].contains(uri?.scheme ?? "")) {
                        if (await canLaunch(url)) {
                          await launch(url);
                          return NavigationActionPolicy.CANCEL;
                        }
                      }
                      return NavigationActionPolicy.ALLOW;
                    },
                    onLoadStop: (controller, url) async {
                      pullToRefreshController.endRefreshing();
                      setState(() {
                        this.url = url.toString();
                        urlController.text = this.url;
                      });
                    },
                    onLoadError: (controller, url, code, message) {
                      pullToRefreshController.endRefreshing();
                    },
                    onProgressChanged: (controller, progress) {
                      if (progress == 100) {
                        pullToRefreshController.endRefreshing();
                      }
                      setState(() {
                        this.progress = progress / 100;
                        urlController.text = this.url;
                      });
                    },
                    onUpdateVisitedHistory: (controller, url, androidIsReload) {
                      setState() {
                        this.url = url.toString();
                        urlController.text = this.url;
                      }
                    },
                    onConsoleMessage: (controller, consoleMessage) {
                      print(consoleMessage);
                    },
                  ),
                  progress < 1.0
                      ? LinearProgressIndicator(value: progress)
                      : Container(),
                ],
              ),
            ),
            ButtonBar(
              alignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    webViewController?.goBack();
                  },
                  child: Icon(Icons.arrow_back),
                ),
                ElevatedButton(
                  onPressed: () {
                    webViewController?.goForward();
                  },
                  child: Icon(Icons.arrow_forward),
                ),
                ElevatedButton(
                  onPressed: () {
                    webViewController?.reload();
                  },
                  child: Icon(Icons.refresh),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

in_app_broser_example.screen.dart

import 'dart:collection';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

import 'main.dart';

class MyInAppBrowser extends InAppBrowser {
  MyInAppBrowser({
    int? windowId,
    UnmodifiableListView<UserScript>? initialUserScripts,
  }) : super(windowId: windowId, initialUserScripts: initialUserScripts);

  @override
  void onBrowserCreated() {
    super.onBrowserCreated();
    print("Browser Created!");
  }

  @override
  void onLoadStart(Uri? url) {
    super.onLoadStart(url);
    print("Started $url");
  }

  @override
  void onLoadStop(Uri? url) {
    super.onLoadStop(url);
    pullToRefreshController?.endRefreshing();
    print("Stopped $url");
  }

  @override
  void onLoadError(Uri? url, int code, String message) {
    super.onLoadError(url, code, message);
    pullToRefreshController?.endRefreshing();
    print("Can't load $url.. Error:$message");
  }

  @override
  void onProgressChanged(int progress) {
    super.onProgressChanged(progress);
    if (progress == 100) {
      pullToRefreshController?.endRefreshing();
    }
    print("Progress: $progress");
  }

  @override
  void onExit() {
    super.onExit();
    print("Browser closed!");
  }

  @override
  Future<NavigationActionPolicy?>? shouldOverrideUrlLoading(
      NavigationAction navigationAction) {
    print("Override ${navigationAction.request.url}");
    return super.shouldOverrideUrlLoading(navigationAction);
  }

  @override
  void onLoadResource(LoadedResource resource) {
    super.onLoadResource(resource);
    print("Started at: " +
        resource.startTime.toString() +
        "ms ----> duration: " +
        resource.duration.toString() +
        "ms " +
        (resource.url ?? '').toString());
  }

  @override
  void onConsoleMessage(ConsoleMessage consoleMessage) {
    super.onConsoleMessage(consoleMessage);
    print("""
    console output:
      message : ${consoleMessage.message}
      messageLevel: ${consoleMessage.messageLevel.toValue()}
    """);
  }
}

class InAppBrowserExampleScreen extends StatefulWidget {
  final MyInAppBrowser browser = new MyInAppBrowser();

  @override
  State<StatefulWidget> createState() => _InAppBrowserExampleScreenState();
}

class _InAppBrowserExampleScreenState extends State<InAppBrowserExampleScreen> {
  late PullToRefreshController pullToRefreshController;

  @override
  void initState() {
    super.initState();
    pullToRefreshController = PullToRefreshController(
      options: PullToRefreshOptions(
        color: Colors.black,
      ),
      onRefresh: () async {
        if (Platform.isAndroid) {
          widget.browser.webViewController.reload();
        } else if (Platform.isIOS) {
          widget.browser.webViewController.loadUrl(
            urlRequest: URLRequest(
              url: await widget.browser.webViewController.getUrl(),
            ),
          );
        }
      },
    );
    widget.browser.pullToRefreshController = pullToRefreshController;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('InAppBrowser')),
      drawer: myDrawer(context: context),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () async {
                await widget.browser.openUrlRequest(
                  urlRequest: URLRequest(url: Uri.parse("https://flutter.dev")),
                  options: InAppBrowserClassOptions(
                    inAppWebViewGroupOptions: InAppWebViewGroupOptions(
                      crossPlatform: InAppWebViewOptions(
                        useShouldOverrideUrlLoading: true,
                        useOnLoadResource: true,
                      ),
                    ),
                  ),
                );
              },
              child: Text("Open In-App Browser"),
            ),
            Container(height: 40),
            ElevatedButton(
              onPressed: () async {
                await InAppBrowser.openWithSystemBrowser(
                    url: Uri.parse("https://flutter.dev/"));
              },
              child: Text('Open System Broser'),
            ),
          ],
        ),
      ),
    );
  }
}

headless_in_app_webview.screen.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

import 'main.dart';

class HeadlessInAppWebViewExampleScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HeadlessInAppWebViewExampleScreenState();
  }
}

class _HeadlessInAppWebViewExampleScreenState
    extends State<HeadlessInAppWebViewExampleScreen> {

  HeadlessInAppWebView? headlessWebView;
  String url = "";

  @override
  void initState() {
    super.initState();
    headlessWebView = HeadlessInAppWebView(
        initialUrlRequest: URLRequest(
          url: Uri.parse("https://flutter.dev"),
        ),
        initialOptions: InAppWebViewGroupOptions(
          crossPlatform: InAppWebViewOptions(),
        ),
        onWebViewCreated: (controller) {
          print('HeadlessInAppWebView created!');
        },
        onConsoleMessage: (controller, consoleMessage) {
          print('CONSOLE MESSAGE: ' + consoleMessage.message);
        },
        onLoadStart: (controller, url) async {
          print("onLoadStart $url");
          setState(() {
            this.url = url.toString();
          });
        },
        onLoadStop: (controller, url) async {
          print("onLoadStop $url");
          setState(() {
            this.url = url.toString();
          });
        },
        onUpdateVisitedHistory: (controller, url, androidIsReload) {
          print("onUpdateVisitedHistory $url");
          setState(() {
            this.url = url.toString();
          });
        }
    );
  }

  @override
  void dispose() {
    super.dispose();
    headlessWebView?.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: AppBar(title: Text("HeadlessInAppWebView"))),
      drawer: myDrawer(context: context),
      body: SafeArea(
        child: Column(
          children: [
            Container(
              padding: EdgeInsets.all(20.0),
              child: Text(
                  "CURRENT URL\n${(url.length > 50) ? url.substring(0, 50) +
                      "..." : url}"
              ),
            ),
            Center(
              child: ElevatedButton(
                onPressed: () async {
                  await headlessWebView?.dispose();
                  await headlessWebView?.run();
                },
                child: Text("Run HeadlessInAppWebView"),
              ),
            ),
            Center(
              child: ElevatedButton(
                onPressed: () async {
                  try {
                    await headlessWebView?.webViewController.evaluateJavascript(
                      source: """console.log('Here is the message!');""",
                    );
                  } on MissingPluginException {
                    print(
                        "HeadlessInAppWebView is not running. Click on \"Run HeadlessInAppWebView\"!");
                  }
                },
                child: Text("Send console.log message"),
              ),
            ),
            Center(
              child: ElevatedButton(
                onPressed: (){
                  headlessWebView?.dispose();
                },
                child: Text("Dispose HeadlessInAppWebView"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

chrome_safari_browser_example.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';

import 'main.dart';

class MyChromeSafariBrowser extends ChromeSafariBrowser {
  @override
  void onOpened() {
    super.onOpened();
    print("ChromeSafari browser opened");
  }

  @override
  void onCompletedInitialLoad() {
    super.onCompletedInitialLoad();
    print("ChromeSafari browser initial load completed");
  }

  @override
  void onClosed() {
    super.onClosed();
    print("ChromeSafari browser closed");
  }
}

class ChromeSafariBrowserExampleScreen extends StatefulWidget {
  final ChromeSafariBrowser browser = MyChromeSafariBrowser();

  @override
  State<StatefulWidget> createState() =>
      _ChromeSafariBrowserExampleScreenState();
}

class _ChromeSafariBrowserExampleScreenState
    extends State<ChromeSafariBrowserExampleScreen> {
  @override
  void initState() {
    widget.browser.addMenuItem(
      ChromeSafariBrowserMenuItem(
        id: 1,
        label: 'Custom item menu 1 clicked!',
        action: (url, title) {
          print('Custom item menu 1 clicked!');
          print(url);
          print(title);
        },
      ),
    );
    widget.browser.addMenuItem(ChromeSafariBrowserMenuItem(
      id: 2,
      label: 'Cusstom item menu 2 clicked!',
      action: (url, title) {
        print('Custom item menu 2');
        print(url);
        print(title);
      },
    ));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('ChromeSafariBrowser')),
      drawer: myDrawer(context: context),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            await widget.browser.open(
              url: Uri.parse("https://flutter.dev/"),
              options: ChromeSafariBrowserClassOptions(
                android: AndroidChromeCustomTabsOptions(
                  addDefaultShareMenuItem: false,
                  keepAliveEnabled: true,
                ),
                ios: IOSSafariOptions(
                    dismissButtonStyle: IOSSafariDismissButtonStyle.CLOSE,
                    presentationStyle:
                        IOSUIModalPresentationStyle.OVER_FULL_SCREEN),
              ),
            );
          },
          child: Text("Open Chrome Safari Browser"),
        ),
      ),
    );
  }
}

 类似资料: