如何使用flutter dart webview渲染本地HTML文件

Posted

技术标签:

【中文标题】如何使用flutter dart webview渲染本地HTML文件【英文标题】:How to render a local HTML file with flutter dart webview 【发布时间】:2019-05-18 18:28:19 【问题描述】:

我想使用 Flutter 和 dart 在 webview 中渲染存储在我手机内存中的本地 html 文件。

【问题讨论】:

你可以使用这个***.com/a/64875729/7760245 【参考方案1】:

您可以传递数据 URI

Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()

或者你可以在 Flutter 中启动一个 Web 服务器,并传递一个指向服务器提供文件的 IP/端口的 URL。

另见https://github.com/fluttercommunity/flutter_webview_plugin/issues/23中的讨论

请参阅https://flutter.io/docs/development/ui/assets-and-images#loading-text-assets,了解如何从资产中加载字符串。

查看https://flutter.io/docs/cookbook/persistence/reading-writing-files了解如何读取其他文件。

【讨论】:

encoding: E​​ncoding.getByName('utf-8') 也很有用【参考方案2】:

我正在使用 Flutter 团队的 webview_flutter 插件。

步骤

    将依赖添加到pubspec.yaml

    dependencies:
      webview_flutter: ^0.3.20+2
    

    将 html 文件放入 assets 文件夹(请参阅 this)。我就叫它help.html

    获取代码中的html字符串并将其添加到webview中。

    import 'dart:convert';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:webview_flutter/webview_flutter.dart';
    
    
    class HelpScreen extends StatefulWidget 
      @override
      HelpScreenState createState() 
        return HelpScreenState();
      
    
    
    class HelpScreenState extends State<HelpScreen> 
      WebViewController _controller;
    
      @override
      Widget build(BuildContext context) 
        return Scaffold(
          appBar: AppBar(title: Text('Help')),
          body: WebView(
            initialUrl: 'about:blank',
            onWebViewCreated: (WebViewController webViewController) 
              _controller = webViewController;
              _loadHtmlFromAssets();
            ,
          ),
        );
      
    
      _loadHtmlFromAssets() async 
        String fileText = await rootBundle.loadString('assets/help.html');
        _controller.loadUrl( Uri.dataFromString(
            fileText,
            mimeType: 'text/html',
            encoding: Encoding.getByName('utf-8')
        ).toString());
      
    
    

注意事项:

我需要将编码设置为 UTF-8,因为我遇到了非 ASCII 字符的崩溃。 在 ios 中,您需要在 Info.plist 文件中将密钥 io.flutter.embedded_views_preview 添加为 true。查看docs 了解有关此要求的任何更新。

另见

The Power of WebViews in Flutter

【讨论】:

@Suragch 如何在 webview 中从 html 访问本地 js 文件?例如:&lt;script type="text/javascript" src="froala_editor.pkgd.min.js"&gt;&lt;/script&gt; 我在加载 .js 文件时遇到问题 @ArnoldParge 我看到您正在尝试加载 Froala;我正要尝试同样的事情。你能让这个工作吗? PDF 怎么样?您将如何加载 PDF? @GoodSp33d,你可能想为此使用一个包。我自己没做过。【参考方案3】:

@Suragch,您的代码在您发布时不起作用,它说localUrlnull 上被调用。 分配控制器后需要调用_loadHtmlFromAssets

onWebViewCreated: (WebViewController webViewController) 
  _controller = webViewController;
  _loadHtmlFromAssets();

然后它工作正常:)

【讨论】:

谢谢@Garbor,我相信它现在已经修复了。【参考方案4】:

解压apk包,找到原因:路径错误;

对于安卓:

"assets/test.html" == "file:///android_asset/flutter_assets/assets/test.html"

所以,就像这样:

WebView(
    initialUrl: "file:///android_asset/flutter_assets/assets/test.html",
    javascriptMode: JavascriptMode.unrestricted,
  )

你可以加载“assets/test.html”。

【讨论】:

多平台 Flutter 的错误解决方案 安卓专用,对我有用 在 android 上工作正常,但在 ios 上?【参考方案5】:

我也有同样的问题;我就是这样解决的。

    将 webview_flutter 添加到您的项目依赖项中:

    webview_flutter: 0.3.14+1

    在您的屏幕/有状态小部件中创建一个 WebViewController

    WebViewController _controller;

    实现 WebView 并使用 onWebViewCreated 属性为 _controller 分配一个值。加载 HTML 文件。

    WebView(
        initialUrl: '',
        onWebViewCreated: (WebViewController webViewController) async 
          _controller = webViewController;
          await loadHtmlFromAssets('legal/privacy_policy.html', _controller);
        ,
      )
    实现从资产文件夹加载文件的功能
    Future<void> loadHtmlFromAssets(String filename, controller) async 
        String fileText = await rootBundle.loadString(filename);
        controller.loadUrl(Uri.dataFromString(fileText, mimeType: 'text/html', encoding: Encoding.getByName('utf-8')).toString());
    

【讨论】:

谢谢,但它似乎停在这一行 String fileText = await rootBundle.loadString(filename); @68060 你在 pubspec.yaml 中声明了你的资产【参考方案6】:

你可以使用我的插件flutter_inappwebview,与其他插件相比,它有很多事件、方法和选项!

要从资产文件夹加载 html 文件,您需要在使用前在 pubspec.yaml 文件中声明它(查看更多 here)。

pubspec.yaml 文件示例:

...

# The following section is specific to Flutter.
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

  assets:
    - assets/index.html

...

之后,您可以简单地使用InAppWebView 小部件的initialFile 参数将index.html 加载到WebView 中:

import 'dart:async';

import 'package:flutter/material.dart';

import 'package:flutter_inappwebview/flutter_inappwebview.dart';

Future main() async 
  runApp(new MyApp());


class MyApp extends StatefulWidget 
  @override
  _MyAppState createState() => new _MyAppState();


class _MyAppState extends State<MyApp> 

  @override
  void initState() 
    super.initState();
  

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

  @override
  Widget build(BuildContext context) 
    return MaterialApp(
        home: InAppWebViewPage()
    );
  


class InAppWebViewPage extends StatefulWidget 
  @override
  _InAppWebViewPageState createState() => new _InAppWebViewPageState();


class _InAppWebViewPageState extends State<InAppWebViewPage> 
  InAppWebViewController webView;

  @override
  Widget build(BuildContext context) 
    return Scaffold(
        appBar: AppBar(
            title: Text("InAppWebView")
        ),
        body: Container(
            child: Column(children: <Widget>[
              Expanded(
                child: Container(
                  child: InAppWebView(
                    initialFile: "assets/index.html",
                    initialHeaders: ,
                    initialOptions: InAppWebViewWidgetOptions(
                      inAppWebViewOptions: InAppWebViewOptions(
                        debuggingEnabled: true,
                      ),
                    ),
                    onWebViewCreated: (InAppWebViewController controller) 
                      webView = controller;
                    ,
                    onLoadStart: (InAppWebViewController controller, String url) 

                    ,
                    onLoadStop: (InAppWebViewController controller, String url) 

                    ,
                  ),
                ),
              ),
            ]))
    );
  

【讨论】:

它是否适用于大 (3-5Mb) html 字符串(通过 loadData)?它是否支持这些页面内的内部href链接(Title1)?【参考方案7】:

您可以使用Flutter InAppWebView Plugin。它将在应用程序内创建一个本地服务器,并在 WebView 中运行 HTML 应用程序。启动你的服务器:

InAppLocalhostServer localhostServer = new InAppLocalhostServer();

Future main() async 
  WidgetsFlutterBinding.ensureInitialized();
  await localhostServer.start();
  runApp(new MyApp());


//... ...

class _MyHomePageState extends State < MyHomePage > 

//... ...

  @override
  void dispose() 
    localhostServer.close();
    super.dispose();
  

然后在 WebView 中指向你的 localhost html 索引文件。

InAppWebView(
  initialUrlRequest: URLRequest(
          url: Uri.parse('http://localhost:8080/assets/index.html')),
),

在许多情况下,它对许多人不起作用,因为他们忘记将所有文件夹添加为 pubspec.yaml 文件中的资产。例如,您需要指定所有文件夹和索引文件,如下所示:

  assets:
    - assets/index.html
    - assets/css/
    - assets/images/
    - assets/js/
    - assets/others/

您可以查看this tutorial了解更多详情。

【讨论】:

【参考方案8】:

使用flutter_widget_from_html_core---->

dependencies:
  flutter_widget_from_html_core: ^0.5.1+4
    

这样的代码

HtmlWidget(
     """
               <html lang="en">
                <body>hello world</body>
               </html>
          """,
    ),

【讨论】:

在我看来这没有答案,因为他提到他想渲染一个本地文件。这个答案中没有任何内容。【参考方案9】:

asset_webview 插件是专门为此设计的。功能比其他插件少,但使用简单。

【讨论】:

【参考方案10】:

您可以获取页面 html 并使用它来加载页面,下面的代码是一个示例

    import 'dart:convert';

import 'package:aws_bot/Utils/Const.dart';
import 'package:aws_bot/Utils/User.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:html/parser.dart';

class signIn extends StatefulWidget 
  const signIn(Key? key) : super(key: key);

  @override
  _signInState createState() => _signInState();


class _signInState extends State<signIn> 
  String userEmail = "";
  String userPassword = "";
  final flutterWebviewPlugin = new FlutterWebviewPlugin();
  bool evalJsOnce = false;
  String _currentUrl = "";

  User _user = User();
  bool _loading = true;
  double progress = 0.0;

  @override
  void initState() 
    super.initState();
    // Future.delayed(Duration(microseconds: 3), () async 
    //   Map info = await _user.getEmailPassword();
    //   _user.userEmail = info['email'];
    //   _user.userPassword = info['password'];
    //   setState(() );
    // );
  

  @override
  Widget build(BuildContext context) 
    flutterWebviewPlugin.onProgressChanged.listen((double progress) 
      print("progress changed = $progress");
      if (progress == 1.0) 
        //https://portal.aws.amazon.com/billing/signup
        flutterWebviewPlugin.onUrlChanged.listen((String url) 
          _currentUrl = url;
          print("url changed = $url");
          if (url.contains('https://portal.aws.amazon.com/billing/signup')) 
            print("signup");
            flutterWebviewPlugin.evalJavascript(''
                'document.querySelector("#CredentialCollection").addEventListener("submit", function(e) window.Mchannel.postMessage(JSON.stringify("email": document.querySelector("#awsui-input-0").value, "password": document.querySelector("#awsui-input-1").value, "confirmPass": document.querySelector("#awsui-input-2").value, "accountName": document.querySelector("#awsui-input-3").value)););');
           else 
            flutterWebviewPlugin.evalJavascript(''
                'let pageHtml = document.documentElement.innerHTML;'
                'window.Emailchannel.postMessage(pageHtml);'
                'if (pageHtml.includes("Root user email address")) '
                'document.querySelector("#next_button").addEventListener("click", function(e) window.Emailchannel.postMessage(JSON.stringify("email": document.querySelector("#resolving_input").value)););'
                '');
          
          //  else if (url.contains(
          //     'https://signin.aws.amazon.com/signin?redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3Ffromtb%3Dtrue%26hashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-1_2b2a9061808657b8&client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&forceMobileApp=0&code_challenge=-HEkj8kWzXDv2qBLcBQX2GYULvcP2gsHr0p0X_fJJcU&code_challenge_method=SHA-256')) 
          //   flutterWebviewPlugin.evalJavascript(''
          //       'document.querySelector("#next_button").addEventListener("click", function(e) e.preventDefault(); window.Emailchannel.postMessage(JSON.stringify("email": document.querySelector("#resolving_input").value)););;');
          //  else if (url.contains(
          //     "https://signin.aws.amazon.com/signin?redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3Ffromtb%3Dtrue%26hashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-1_c885b81ed0514ab4&client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&forceMobileApp=0&code_challenge=_Tqr3pEXTDAqOYjWp0ehE6ToYYSN7OLeyJWBx5HTPVM&code_challenge_method=SHA-256")) 
          //   print("enter pass");
          //   // flutterWebviewPlugin.evalJavascript(''
          //   //     'document.querySelector("#signin_button").addEventListener("click", function(e) e.preventDefault(); window.Passwordchannel.postMessage(JSON.stringify("password": document.querySelector("#password").value)););;');
          //  else if (url.contains("https://console.aws.amazon.com/")) 
          //   // flutterWebviewPlugin.launch(_consts.successDirectUrl +
          //   //     "email=$_user.userEmail&password=$_user.userPassword");
          // 
        );
      
    );

    flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged state) 
      print("state changed = $state");
    );

    return Scaffold(
      appBar: AppBar(
        title: Text(
          'AWS Sign In',
          style: TextStyle(color: Colors.black),
        ),
        backgroundColor: Colors.yellow[600],
      ),
      floatingActionButton: _backButton(context),
      body: Column(
        children: [
          (progress != 1.0)
              ? LinearProgressIndicator(
                  // minHeight: 10.0,
                  value: progress,
                  backgroundColor: Colors.redAccent,
                  valueColor: AlwaysStoppedAnimation<Color>(Colors.black))
              : Container(),
          Container(
              color: Colors.yellow[600],
              width: double.infinity,
              padding: EdgeInsets.all(8.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    "Email Address of you AWS : $consts.user.userEmail",
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  SizedBox(
                    height: 4.0,
                  ),
                  Text(
                    "IAM user name : $consts.user.accountName",
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  SizedBox(
                    height: 4.0,
                  ),
                  Text(
                    "Password : $consts.user.userPassword != "null" && consts.user.userPassword != "" ? consts.user.userPassword.replaceAll(consts.user.userPassword, "******") : """,
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ],
              )),
          Expanded(child: _buildSignInPage()),
        ],
      ),
    );
  

  _buildSignInPage() 
    String _url = "https://console.aws.amazon.com/iam/home#/users";
    return InAppWebView(
      initialUrlRequest: URLRequest(url: Uri.parse(_url)),
      // javascriptChannels: Set.from([
      //   JavascriptChannel(
      //       name: 'Emailchannel',
      //       onMessageReceived: (JavascriptMessage message) 
      //         //This is where you receive message from
      //         //javascript code and handle in Flutter/Dart
      //         //like here, the message is just being printed
      //         //in Run/LogCat window of android studio
      //         print("console message = $message.message");
      //         setState(() 
      //           _user.userEmail =
      //               jsonDecode(message.message)['email'].toString();
      //         );
      //       ),
      //   JavascriptChannel(
      //       name: 'Passwordchannel',
      //       onMessageReceived: (JavascriptMessage message) 
      //         //This is where you receive message from
      //         //javascript code and handle in Flutter/Dart
      //         //like here, the message is just being printed
      //         //in Run/LogCat window of android studio
      //         print("console message = $jsonDecode(message.message)");
      //         setState(() 
      //           _user.userEmail =
      //               jsonDecode(message.message)['password'].toString();
      //         );
      //       )
      // ]),
      // withJavascript: true,
      onConsoleMessage: (controller, consoleMessage) async 
        print("console message = $consoleMessage.message");
        print(consoleMessage.messageLevel.toString());
        // LOG ERROR => message levels
        if (consoleMessage.messageLevel.toString() != "ERROR" &&
            consoleMessage.messageLevel.toString() != "WARNING") 
          Map message = jsonDecode(consoleMessage.message);
          if (message.containsKey("email")) 
            consts.user.userEmail = message['email'].toString();
            await consts.user.storeSignUpInfo(email: consts.user.userEmail);
           else if (message.containsKey("password")) 
            consts.user.userPassword = message['password'].toString();
            await consts.user
                .storeSignUpInfo(password: consts.user.userPassword);
           else if (message.containsKey("delete")) 
            Future.delayed(Duration.zero, () async 
              await consts.user.clearStorage();
              consts.user.userEmail = "";
              consts.user.userPassword = "";
            );
           else if (message.containsKey("sEmail")) 
            consts.user.userEmail = message['sEmail'].toString();
            await consts.user.storeSignUpInfo(email: consts.user.userEmail);
           else if (message.containsKey("sPassword")) 
            consts.user.userPassword = message["sPassword"].toString();
            await consts.user
                .storeSignUpInfo(password: consts.user.userPassword);
           else if (message.containsKey("sAccountName")) 
            consts.user.accountName = message["sAccountName"].toString();
            await consts.user
                .storeSignUpInfo(accountName: consts.user.accountName);
           else if (message.containsKey("sFullName")) 
            consts.user.fullName = message["sFullName"].toString();
            await consts.user.storeSignUpInfo(fullName: consts.user.fullName);
           else if (message.containsKey("sPhone")) 
            consts.user.phoneNumber = message["sPhone"].toString();
            await consts.user
                .storeSignUpInfo(phoneNumber: consts.user.phoneNumber);
           else if (message.containsKey("sRegion")) 
            consts.user.region = message["sRegion"].toString();
            await consts.user.storeSignUpInfo(region: consts.user.region);
           else if (message.containsKey("sAddress")) 
            consts.user.address = message["sAddress"].toString();
            await consts.user.storeSignUpInfo(address: consts.user.address);
           else if (message.containsKey("sCity")) 
            consts.user.city = message["sCity"].toString();
            await consts.user.storeSignUpInfo(city: consts.user.city);
           else if (message.containsKey("sState")) 
            consts.user.state = message["sState"].toString();
            await consts.user.storeSignUpInfo(state: consts.user.state);
           else if (message.containsKey("sPostal")) 
            consts.user.postalCode = message["sPostal"].toString();
            await consts.user
                .storeSignUpInfo(postalCode: consts.user.postalCode);
           else if (message.containsKey("sOrganize")) 
            consts.user.oraganization = message["sOrganize"].toString();
            await consts.user
                .storeSignUpInfo(organization: consts.user.oraganization);
          

          setState(() 
            if (consts.user.userPassword != "" &&
                !message.containsKey("delete")) 
              /*Future.delayed(Duration.zero, () async 
                await consts.user.storeEmailAndPassword(
                    consts.user.userEmail, consts.user.userPassword);
                // controller.loadUrl(
                //     urlRequest: URLRequest(
                //         url: Uri.parse(_consts.successDirectUrl +
                //             "email=$_user.userEmail&password=$_user.userPassword")));
              );*/
            
          );
        
      ,
      onWindowFocus: (controller) async 
        var currentUrl = await controller.getUrl();
        final html = await controller.getHtml();
        var document = parse(html);
        if (currentUrl != _currentUrl) 
          Future.delayed(Duration.zero, () async 
            var htmlCode = await controller.getHtml();
            var document = parse(htmlCode);
            var currentUrl = await controller.getUrl();
            print("currentUrl = $currentUrl");
            if (document.body!.innerHtml.contains("username@example.com")) 
              print("get email");
              await consts.user.clearStorage();

              // get entered email address
              getUserEmail(controller, document.body!.innerHtml);
             else if (document.body!.innerHtml.contains("Root user sign in")) 
              print("get pass");
              // get entered password
              getUserPassword(controller, document.body!.innerHtml);
             else if (currentUrl
                .toString()
                .contains("https://portal.aws.amazon.com/billing/signup")) 
              if (document.body!.innerHtml.contains("AWS account name")) 
                print("sign up");
                // get signUp email
                getSignUpEmail(controller);
                // get signUp password
                getSignUpPassword(controller);
                // get signUp account name
                getSignUpAccountName(controller);
               else if (document.body!.innerHtml
                  .contains("Contact Information")) 
                // get full name
                getSignUpFullname(controller);
                // get phone number
                getSignUpPhoneNumber(controller);
                // get region
                getSignUpRegion(controller);
                // get address
                getSignUpAddress(controller);
                // get city
                getSignUpCity(controller);
                // get state
                getSignUpState(controller);
                // get postal code
                getSignUpPostalCode(controller);
                // get organization
                getSignUpOrganization(controller);
              
            
          );
        
        _currentUrl = currentUrl.toString();
        //controller.goBack();
      ,
      onProgressChanged:
          (InAppWebViewController controller, int progress) async 
        setState(() 
          this.progress = progress / 100;
          print("progress = $this.progress");
        );
        if (progress == 100) 
          var currentUrl = await controller.getUrl();

          Future.delayed(Duration(microseconds: 3), () async 
            var htmlCode = await controller.getHtml();
            var document = parse(htmlCode);

            print("currentUrl progress = $currentUrl.toString()");
            //print("html = $document.body!.innerHtml");
            if (document.body!.innerHtml
                .contains("Email address of your AWS account")) 
              print("get email");
              await consts.user.clearStorage();
              consts.user.userEmail = "";
              consts.user.userPassword = "";
              controller.evaluateJavascript(source: """
                   document.querySelector("#new_account_container").style.display = "none";
            """);
              setState(() );

              // get entered email address
              getUserEmail(controller, document.body!.innerHtml);
             else if (document.body!.innerHtml.contains("Root user sign in")) 
              print("get pass");
              // get entered password
              getUserPassword(controller, document.body!.innerHtml);
             else if (currentUrl
                .toString()
                .contains("https://portal.aws.amazon.com/billing/signup#/")) 
              if (document.body!.innerHtml.contains("AWS account name")) 
                print("sign up progress");
                // get signUp email
                getSignUpEmail(controller);
                // get signUp password
                getSignUpPassword(controller);
                // get signUp account name
                getSignUpAccountName(controller);
               else if (document.body!.innerHtml
                  .contains("Contact Information")) 
                // get full name
                getSignUpFullname(controller);
                // get phone number
                getSignUpPhoneNumber(controller);
                // get region
                getSignUpRegion(controller);
                // get address
                getSignUpAddress(controller);
                // get city
                getSignUpCity(controller);
                // get state
                getSignUpState(controller);
                // get postal code
                getSignUpPostalCode(controller);
                // get organization
                getSignUpOrganization(controller);
              
            
            if (currentUrl.toString() ==
                    "https://console.aws.amazon.com/iam/home#/users" ||
                currentUrl.toString() ==
                    "https://console.aws.amazon.com/iam/home?#/users") 
              print("delete credentials");
              // delete user data if loged out
              deleteCredentials(controller);
            
          );
        
      ,
    );
  

  // get user amil
  getUserEmail(InAppWebViewController controller, String html) 
    controller.addJavaScriptHandler(
        handlerName: 'EmailGetter',
        callback: (args) 
          // print arguments coming from the JavaScript side!
          print("email args = $args");
          // return data to the JavaScript side!
          return args;
        );
    controller.evaluateJavascript(source: """
            document.querySelector("#next_button").addEventListener("click", function(ee) 
            window.console.log(JSON.stringify("email": document.querySelector("#resolving_input").value)););
            """);
  

  // getting password
  getUserPassword(InAppWebViewController controller, String html) 
    controller.evaluateJavascript(source: """
            document.querySelector("#signin_button").addEventListener("click", function(ee) 
            window.console.log(JSON.stringify("password": document.querySelector("#password").value)););
            """);
  

  // getting SignUp Email address
  getSignUpEmail(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#CredentialCollection").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sEmail": document.querySelector("input[name='email']").value)););
            """);
  

  // getting SignUp password
  getSignUpPassword(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#CredentialCollection").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sPassword": document.querySelector("input[name='password']").value)););
            """);
  

  // getting SignUp account name
  getSignUpAccountName(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#CredentialCollection").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sAccountName": document.querySelector("input[name='accountName']").value)););
            """);
  

  // getting SignUp fullName
  getSignUpFullname(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sFullName": document.querySelector("input[name='address.fullName']").value)););
            """);
  

  // getting SignUp phone number
  getSignUpPhoneNumber(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sPhone": document.querySelector("input[name='address.phoneNumber']").value)););
            """);
  

  // getting SignUp region
  getSignUpRegion(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sRegion": document.querySelectorAll(".awsui-select-trigger-label")[1].innerText)););
            """);
  

  // getting SignUp address
  getSignUpAddress(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sAddress": document.querySelectorAll("input[name='address.addressLine1']").value)););
            """);
  

  // getting SignUp city
  getSignUpCity(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sCity": document.querySelectorAll("input[name='address.city']").value)););
            """);
  

  // getting SignUp state
  getSignUpState(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sState": document.querySelectorAll("input[name='address.state']").value)););
            """);
  

  // getting SignUp postal code
  getSignUpPostalCode(controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sPostal": document.querySelectorAll("input[name='address.postalCode']").value)););
            """);
  

  // getting SignUp organization
  getSignUpOrganization(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sOrganize": document.querySelectorAll("input[name='address.company']").value)););
            """);
  

  // deleting user credentials
  deleteCredentials(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#aws-console-logout").addEventListener("click", function(ee) 
            window.console.log(JSON.stringify("delete": "delete")););
            """);
  

  _backButton(BuildContext context) 
    return ElevatedButton(
      onPressed: () 
        Navigator.pop(context);
      ,
      child: Icon(Icons.arrow_back),
    );
  

【讨论】:

您应该删除 cmets 并可能将您的代码拆分为更多逻辑块【参考方案11】:

这是上面代码的更简洁的代码

import 'dart:convert';

import 'package:aws_bot/Utils/Const.dart';
import 'package:aws_bot/Utils/User.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:html/parser.dart';

class signIn extends StatefulWidget 
  const signIn(Key? key) : super(key: key);

  @override
  _signInState createState() => _signInState();


class _signInState extends State<signIn> 
  String userEmail = "";
  String userPassword = "";
  final flutterWebviewPlugin = new FlutterWebviewPlugin();
  bool evalJsOnce = false;
  String _currentUrl = "";

  User _user = User();
  bool _loading = true;
  double progress = 0.0;

  @override
  void initState() 
    super.initState();
    
  

  @override
  Widget build(BuildContext context) 
    flutterWebviewPlugin.onProgressChanged.listen((double progress) 
      print("progress changed = $progress");
      if (progress == 1.0) 
        //https://portal.aws.amazon.com/billing/signup
        flutterWebviewPlugin.onUrlChanged.listen((String url) 
          _currentUrl = url;
          print("url changed = $url");
          if (url.contains('https://portal.aws.amazon.com/billing/signup')) 
            print("signup");
            flutterWebviewPlugin.evalJavascript(''
                'document.querySelector("#CredentialCollection").addEventListener("submit", function(e) window.Mchannel.postMessage(JSON.stringify("email": document.querySelector("#awsui-input-0").value, "password": document.querySelector("#awsui-input-1").value, "confirmPass": document.querySelector("#awsui-input-2").value, "accountName": document.querySelector("#awsui-input-3").value)););');
           else 
            flutterWebviewPlugin.evalJavascript(''
                'let pageHtml = document.documentElement.innerHTML;'
                'window.Emailchannel.postMessage(pageHtml);'
                'if (pageHtml.includes("Root user email address")) '
                'document.querySelector("#next_button").addEventListener("click", function(e) window.Emailchannel.postMessage(JSON.stringify("email": document.querySelector("#resolving_input").value)););'
                '');
          
          redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3Ffromtb%3Dtrue%26hashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-1_2b2a9061808657b8&client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&forceMobileApp=0&code_challenge=-HEkj8kWzXDv2qBLcBQX2GYULvcP2gsHr0p0X_fJJcU&code_challenge_method=SHA-256'))   'document.querySelector("#next_button").addEventListener("click", function(e) e.preventDefault(); window.Emailchannel.postMessage(JSON.stringify("email": document.querySelector("#resolving_input").value)););;');redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3Ffromtb%3Dtrue%26hashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-1_c885b81ed0514ab4&client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&forceMobileApp=0&code_challenge=_Tqr3pEXTDAqOYjWp0ehE6ToYYSN7OLeyJWBx5HTPVM&code_challenge_method=SHA-256"))    'document.querySelector("#signin_button").addEventListener("click", function(e) e.preventDefault(); window.Passwordchannel.postMessage(JSON.stringify("password": document.querySelector("#password").value)););;');
        );
      
    );

    flutterWebviewPlugin.onStateChanged.listen((WebViewStateChanged state) 
      print("state changed = $state");
    );

    return Scaffold(
      appBar: AppBar(
        title: Text(
          'AWS Sign In',
          style: TextStyle(color: Colors.black),
        ),
        backgroundColor: Colors.yellow[600],
      ),
      floatingActionButton: _backButton(context),
      body: Column(
        children: [
          (progress != 1.0)
              ? LinearProgressIndicator(
                  // minHeight: 10.0,
                  value: progress,
                  backgroundColor: Colors.redAccent,
                  valueColor: AlwaysStoppedAnimation<Color>(Colors.black))
              : Container(),
          Container(
              color: Colors.yellow[600],
              width: double.infinity,
              padding: EdgeInsets.all(8.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    "Email Address of you AWS : $consts.user.userEmail",
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  SizedBox(
                    height: 4.0,
                  ),
                  Text(
                    "IAM user name : $consts.user.accountName",
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  SizedBox(
                    height: 4.0,
                  ),
                  Text(
                    "Password : $consts.user.userPassword != "null" && consts.user.userPassword != "" ? consts.user.userPassword.replaceAll(consts.user.userPassword, "******") : """,
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ],
              )),
          Expanded(child: _buildSignInPage()),
        ],
      ),
    );
  

  _buildSignInPage() 
    String _url = "https://console.aws.amazon.com/iam/home#/users";
    return InAppWebView(
      initialUrlRequest: URLRequest(url: Uri.parse(_url)),
      onConsoleMessage: (controller, consoleMessage) async 
        print("console message = $consoleMessage.message");
        print(consoleMessage.messageLevel.toString());
        // LOG ERROR => message levels
        if (consoleMessage.messageLevel.toString() != "ERROR" &&
            consoleMessage.messageLevel.toString() != "WARNING") 
          Map message = jsonDecode(consoleMessage.message);
          if (message.containsKey("email")) 
            consts.user.userEmail = message['email'].toString();
            await consts.user.storeSignUpInfo(email: consts.user.userEmail);
           else if (message.containsKey("password")) 
            consts.user.userPassword = message['password'].toString();
            await consts.user
                .storeSignUpInfo(password: consts.user.userPassword);
           else if (message.containsKey("delete")) 
            Future.delayed(Duration.zero, () async 
              await consts.user.clearStorage();
              consts.user.userEmail = "";
              consts.user.userPassword = "";
            );
           else if (message.containsKey("sEmail")) 
            consts.user.userEmail = message['sEmail'].toString();
            await consts.user.storeSignUpInfo(email: consts.user.userEmail);
           else if (message.containsKey("sPassword")) 
            consts.user.userPassword = message["sPassword"].toString();
            await consts.user
                .storeSignUpInfo(password: consts.user.userPassword);
           else if (message.containsKey("sAccountName")) 
            consts.user.accountName = message["sAccountName"].toString();
            await consts.user
                .storeSignUpInfo(accountName: consts.user.accountName);
           else if (message.containsKey("sFullName")) 
            consts.user.fullName = message["sFullName"].toString();
            await consts.user.storeSignUpInfo(fullName: consts.user.fullName);
           else if (message.containsKey("sPhone")) 
            consts.user.phoneNumber = message["sPhone"].toString();
            await consts.user
                .storeSignUpInfo(phoneNumber: consts.user.phoneNumber);
           else if (message.containsKey("sRegion")) 
            consts.user.region = message["sRegion"].toString();
            await consts.user.storeSignUpInfo(region: consts.user.region);
           else if (message.containsKey("sAddress")) 
            consts.user.address = message["sAddress"].toString();
            await consts.user.storeSignUpInfo(address: consts.user.address);
           else if (message.containsKey("sCity")) 
            consts.user.city = message["sCity"].toString();
            await consts.user.storeSignUpInfo(city: consts.user.city);
           else if (message.containsKey("sState")) 
            consts.user.state = message["sState"].toString();
            await consts.user.storeSignUpInfo(state: consts.user.state);
           else if (message.containsKey("sPostal")) 
            consts.user.postalCode = message["sPostal"].toString();
            await consts.user
                .storeSignUpInfo(postalCode: consts.user.postalCode);
           else if (message.containsKey("sOrganize")) 
            consts.user.oraganization = message["sOrganize"].toString();
            await consts.user
                .storeSignUpInfo(organization: consts.user.oraganization);
          

          setState(() 
            if (consts.user.userPassword != "" &&
                !message.containsKey("delete")) 
            
          );
        
      ,
      onWindowFocus: (controller) async 
        var currentUrl = await controller.getUrl();
        final html = await controller.getHtml();
        var document = parse(html);
        if (currentUrl != _currentUrl) 
          Future.delayed(Duration.zero, () async 
            var htmlCode = await controller.getHtml();
            var document = parse(htmlCode);
            var currentUrl = await controller.getUrl();
            print("currentUrl = $currentUrl");
            if (document.body!.innerHtml.contains("username@example.com")) 
              print("get email");
              await consts.user.clearStorage();

              // get entered email address
              getUserEmail(controller, document.body!.innerHtml);
             else if (document.body!.innerHtml.contains("Root user sign in")) 
              print("get pass");
              // get entered password
              getUserPassword(controller, document.body!.innerHtml);
             else if (currentUrl
                .toString()
                .contains("https://portal.aws.amazon.com/billing/signup")) 
              if (document.body!.innerHtml.contains("AWS account name")) 
                print("sign up");
                // get signUp email
                getSignUpEmail(controller);
                // get signUp password
                getSignUpPassword(controller);
                // get signUp account name
                getSignUpAccountName(controller);
               else if (document.body!.innerHtml
                  .contains("Contact Information")) 
                // get full name
                getSignUpFullname(controller);
                // get phone number
                getSignUpPhoneNumber(controller);
                // get region
                getSignUpRegion(controller);
                // get address
                getSignUpAddress(controller);
                // get city
                getSignUpCity(controller);
                // get state
                getSignUpState(controller);
                // get postal code
                getSignUpPostalCode(controller);
                // get organization
                getSignUpOrganization(controller);
              
            
          );
        
        _currentUrl = currentUrl.toString();
        //controller.goBack();
      ,
      onProgressChanged:
          (InAppWebViewController controller, int progress) async 
        setState(() 
          this.progress = progress / 100;
          print("progress = $this.progress");
        );
        if (progress == 100) 
          var currentUrl = await controller.getUrl();

          Future.delayed(Duration(microseconds: 3), () async 
            var htmlCode = await controller.getHtml();
            var document = parse(htmlCode);

            print("currentUrl progress = $currentUrl.toString()");
            //print("html = $document.body!.innerHtml");
            if (document.body!.innerHtml
                .contains("Email address of your AWS account")) 
              print("get email");
              await consts.user.clearStorage();
              consts.user.userEmail = "";
              consts.user.userPassword = "";
              controller.evaluateJavascript(source: """
                   document.querySelector("#new_account_container").style.display = "none";
            """);
              setState(() );

              // get entered email address
              getUserEmail(controller, document.body!.innerHtml);
             else if (document.body!.innerHtml.contains("Root user sign in")) 
              print("get pass");
              // get entered password
              getUserPassword(controller, document.body!.innerHtml);
             else if (currentUrl
                .toString()
                .contains("https://portal.aws.amazon.com/billing/signup#/")) 
              if (document.body!.innerHtml.contains("AWS account name")) 
                print("sign up progress");
                // get signUp email
                getSignUpEmail(controller);
                // get signUp password
                getSignUpPassword(controller);
                // get signUp account name
                getSignUpAccountName(controller);
               else if (document.body!.innerHtml
                  .contains("Contact Information")) 
                // get full name
                getSignUpFullname(controller);
                // get phone number
                getSignUpPhoneNumber(controller);
                // get region
                getSignUpRegion(controller);
                // get address
                getSignUpAddress(controller);
                // get city
                getSignUpCity(controller);
                // get state
                getSignUpState(controller);
                // get postal code
                getSignUpPostalCode(controller);
                // get organization
                getSignUpOrganization(controller);
              
            
            if (currentUrl.toString() ==
                    "https://console.aws.amazon.com/iam/home#/users" ||
                currentUrl.toString() ==
                    "https://console.aws.amazon.com/iam/home?#/users") 
              print("delete credentials");
              // delete user data if loged out
              deleteCredentials(controller);
            
          );
        
      ,
    );
  

  // get user amil
  getUserEmail(InAppWebViewController controller, String html) 
    controller.addJavaScriptHandler(
        handlerName: 'EmailGetter',
        callback: (args) 
          // print arguments coming from the JavaScript side!
          print("email args = $args");
          // return data to the JavaScript side!
          return args;
        );
    controller.evaluateJavascript(source: """
            document.querySelector("#next_button").addEventListener("click", function(ee) 
            window.console.log(JSON.stringify("email": document.querySelector("#resolving_input").value)););
            """);
  

  // getting password
  getUserPassword(InAppWebViewController controller, String html) 
    controller.evaluateJavascript(source: """
            document.querySelector("#signin_button").addEventListener("click", function(ee) 
            window.console.log(JSON.stringify("password": document.querySelector("#password").value)););
            """);
  

  // getting SignUp Email address
  getSignUpEmail(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#CredentialCollection").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sEmail": document.querySelector("input[name='email']").value)););
            """);
  

  // getting SignUp password
  getSignUpPassword(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#CredentialCollection").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sPassword": document.querySelector("input[name='password']").value)););
            """);
  

  // getting SignUp account name
  getSignUpAccountName(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#CredentialCollection").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sAccountName": document.querySelector("input[name='accountName']").value)););
            """);
  

  // getting SignUp fullName
  getSignUpFullname(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sFullName": document.querySelector("input[name='address.fullName']").value)););
            """);
  

  // getting SignUp phone number
  getSignUpPhoneNumber(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sPhone": document.querySelector("input[name='address.phoneNumber']").value)););
            """);
  

  // getting SignUp region
  getSignUpRegion(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sRegion": document.querySelectorAll(".awsui-select-trigger-label")[1].innerText)););
            """);
  

  // getting SignUp address
  getSignUpAddress(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sAddress": document.querySelectorAll("input[name='address.addressLine1']").value)););
            """);
  

  // getting SignUp city
  getSignUpCity(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sCity": document.querySelectorAll("input[name='address.city']").value)););
            """);
  

  // getting SignUp state
  getSignUpState(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sState": document.querySelectorAll("input[name='address.state']").value)););
            """);
  

  // getting SignUp postal code
  getSignUpPostalCode(controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sPostal": document.querySelectorAll("input[name='address.postalCode']").value)););
            """);
  

  // getting SignUp organization
  getSignUpOrganization(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#ContactInformation").addEventListener("submit", function(ee) 
            window.console.log(JSON.stringify("sOrganize": document.querySelectorAll("input[name='address.company']").value)););
            """);
  

  // deleting user credentials
  deleteCredentials(InAppWebViewController controller) 
    controller.evaluateJavascript(source: """
            document.querySelector("#aws-console-logout").addEventListener("click", function(ee) 
            window.console.log(JSON.stringify("delete": "delete")););
            """);
  

  _backButton(BuildContext context) 
    return ElevatedButton(
      onPressed: () 
        Navigator.pop(context);
      ,
      child: Icon(Icons.arrow_back),
    );
  

在此代码中,您还可以看到如何使用 javascript dom 操作和选择以及与网页的交互。

【讨论】:

以上是关于如何使用flutter dart webview渲染本地HTML文件的主要内容,如果未能解决你的问题,请参考以下文章

如何允许 webview 中的 mailto 方案颤动

在 Flutter Web 中从 JS 调用 Dart 方法

如何在 Flutter 的 webview 中隐藏页眉和页脚。?

打开 Flutter Webview 链接到浏览器

Flutter Webview - 如何在页面上添加更多链接或元素?

仅在 Flutter Web 上重定向