在 Flutter 中使用 Webview

Dro*_*dOS 6 android webview ios cordova flutter

我在 Android 上有一个非常复杂的 Cordova 应用程序,我已经开发了一年多的时间。该应用程序使用一种自定义方式,即由我编写的 Cordova 插件。AI 考虑将应用程序移植到 iOS 我正在考虑切换到 Flutter 以便只维护一个代码库 - 如果整个插件将不得不为 iOS 重写。

使用干净的 HTML5 + ES6 + CSS3,它运行得非常好,我认为没有理由把它全部扔掉,重新作为一个纯 Flutter 应用程序重新开始。输入 Web 视图。我计划在颤动的 WebView 中使用我当前的所有 Cordova Webview 代码 - 基本上是整个 Cordova 项目 www 文件夹。这一切的关键是能够在 WebView 和 Flutter 之间有效地进行双向通信。为此,我编写了一个小型骨架项目。该main.dart项目的文件如下所示

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

void main() => runApp(Webby());

class Webby extends StatelessWidget 
{
 @override Widget build(BuildContext context) 
 {
  return MaterialApp
  (
   title: 'Flutter Demo',
   theme: ThemeData(primarySwatch: Colors.blue,),
   home: Feuille(),
  );
 }
}

class Feuille extends StatefulWidget
{
 Feuille({Key key}):super(key: key);
 @override  _FeuilleState createState() => _FeuilleState();
}

class _FeuilleState extends State<Feuille>
{
 WebViewController wVC; 
 @override Widget build(BuildContext context) 
 {
  SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);  
  return Scaffold
  (
   body:SafeArea
   (
    child:Column
    (
     children:<Widget>
     [
      Expanded
      (
       child:Container
       (
        margin:const EdgeInsets.all(0.0),
        child:WebView
        (
         debuggingEnabled:true, 
         initialUrl:'',
         javascriptMode:JavascriptMode.unrestricted,
         onWebViewCreated:registerController,
         javascriptChannels:Set.from
         ([JavascriptChannel(name:'JSBridge',onMessageReceived:handleMessage)]),
        ),),)])));
 }

 Future<void> handleMessage(JavascriptMessage message) async
 {
  print(message.message);
  wVC.evaluateJavascript("addNums(10,21)");
 }

 void registerController (WebViewController controller) async
 {
  wVC = controller;
  String html = await rootBundle.loadString('assets/index.html');
  wVC.loadUrl(Uri.dataFromString(html,mimeType:'text/html',
  encoding:Encoding.getByName('utf-8')).toString());
 }
}
Run Code Online (Sandbox Code Playgroud)

加载到此 webview 中的本地 HTML 如下所示

<!DOCTYPE html>
<html>
 <head>
  <meta name='viewport'
   content='user-scalable=no, initial-scale=1, maximum-scale=1, 
   minimum-scale=1, width=device-width, height=device-height' />
   <meta charset='utf-8' />
 </head>  
 <body>
  <p>The result is <span id="spnResult">Not Available Yet</span></p> 
 </body>
 <script>
   window.addEventListener("load",flutterReady);

   function flutterReady()
   {
    alert("Sending message");
    setTimeout(function(){JSBridge.postMessage("This is London calling");},5000);
   } 

   function addNums(n1,n2)
   {
    document.getElementById("spnResult").innerText = n1 + n2;
   }
  </script>
</html>
Run Code Online (Sandbox Code Playgroud)

最后pubspec.yaml项目的文件如下

name: webby
description: Webby Project

version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

dependencies:
 flutter:
  sdk: flutter

 cupertino_icons: ^0.1.2
 path_provider: ^1.4.0
 permission_handler: ^3.3.0
 connectivity: ^0.4.5+6
 webview_flutter: ^0.3.19+9

dev_dependencies:
 flutter_test:
 sdk: flutter


flutter:
 uses-material-design: true
assets:
  - assets/
Run Code Online (Sandbox Code Playgroud)

现在我的问题

  • 我正在使用这个骨架项目来测试我是否可以双向通信:从 Webview 托管的 JS 到 Flutter,从 Flutter 返回到 Webview 托管的 JS。这有效 - 非常好。然而,我在这里做了一些非常盲目的事情——这是我使用 Flutter 的第二天——需要澄清

  • 我已经使用 HTML5 中的 window.load 事件来了解我何时开始与 Flutter 通信。这是我对 Cordova.docReady 事件的替代。假设发生此事件时 Flutter 将“准备好”,WebViewController 将可用等是否合理?

  • 在我努力让 WebView 占据整个设备屏幕的过程中,我最终使用的Scaffold...SafeAera...Expanded...很简单,因为我遇到了它被用来显示全屏图像并且它对我有用。但是,我不清楚这是做事的最佳方式/正确方式

  • 我注意到pubspec.yaml指定使用 Material Design 和这里创建的“小部件”是一个MaterialApp. 鉴于我的整个 UI 是通过 WebView 中的 HTML5 + CSS3 + ES6 创建和管理的,没有一种更简单的方法来创建可能带来一些性能/内存占用优势的小部件

  • 我遇到过这样的评论,即 WebView 很慢,在 iOS 上不能很好地呈现等等。根据我的经验,发表此类评论的人通常倾向于依赖“框架”,这会给系统带来不必要的负担。干净的 HTML + ES6 仅依赖于 HTML5 DOM 作为其“框架”性能对我来说从来都不是问题。Flutter WebView(最终是操作系统提供的 WebView)表现不佳是否有任何已知原因?

  • 最后:一旦我确定了这一点,我就需要开始实施地理定位、Wifi 网络监视、加速度计监控、websocket 驱动的 I/O、本地文件存储、SQLite 数据库存储等。Fluter 提供的 API 是否适合这些任务 -他们是否充分了解操作系统,才能真正为 Android 和 iOS 生成应用程序?

我将非常感谢任何能够在这里提供一些提示和指示的人。


我不确定我会在这里得到回应。但是,对于遇到此线程并试图复制我迄今为止所做的任何人的人来说,这是一个脚注。

很简单——这行不通。使用Uri.dataFromString(...将允许您显示带有嵌入样式和 JS 的静态 HTML 文档。它将无法访问存储在 Flutterassets文件夹内其他文件/文件夹中的样式表和脚本。为此,您需要运行本地 HTTP 服务器。虽然您可以尝试自己旋转,但不值得这样做。考虑使用优秀的、有据可查的 flutter_inappwebview插件。

Oma*_*att 1

据我了解,您似乎只想在 Flutter 上使用 WebView 显示网页。如果您需要访问 WebView 上的地理定位支持,webview_flutter 仍然存在此问题。作为解决方法,您可能需要考虑同时使用flutter_inappwebview 。至于在 Flutter 上处理 WebView 回调,这里有一个有趣的指南,您可以将其作为开始。