如何使用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: Encoding.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 文件?例如:<script type="text/javascript" src="froala_editor.pkgd.min.js"></script>
我在加载 .js 文件时遇到问题
@ArnoldParge 我看到您正在尝试加载 Froala;我正要尝试同样的事情。你能让这个工作吗?
PDF 怎么样?您将如何加载 PDF?
@GoodSp33d,你可能想为此使用一个包。我自己没做过。【参考方案3】:
@Suragch,您的代码在您发布时不起作用,它说localUrl
在null
上被调用。
分配控制器后需要调用_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文件的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter Web 中从 JS 调用 Dart 方法
如何在 Flutter 的 webview 中隐藏页眉和页脚。?