How to render a local HTML file with flutter dart webview - webview

I want to render a local HTML file stored in my phone memory in webview using flutter and dart.

I am using the webview_flutter plugin from the Flutter Team.
Steps
Add the dependency to pubspec.yaml:
dependencies:
webview_flutter: ^0.3.20+2
Put an html file in the assets folder (see this). I'll call it help.html.
Get the html string in code and add it to the 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());
}
}
Notes:
I needed to set the encoding to UTF-8 because I was getting a crash for non-ASCII characters.
In iOS you need to add the key io.flutter.embedded_views_preview as true in the Info.plist file. Check the docs for any update on this requirement.
See also
The Power of WebViews in Flutter

You can pass a data URI
Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
or you can launch a web server inside Flutter and pass an URL that points to the IP/port the server serves the file from.
See also the discussion in https://github.com/fluttercommunity/flutter_webview_plugin/issues/23
See https://flutter.io/docs/development/ui/assets-and-images#loading-text-assets about how to load a string from assets.
See https://flutter.io/docs/cookbook/persistence/reading-writing-files for how to read other files.

#Suragch, your code doesn't work as you posted it, it says localUrl was called on null.
_loadHtmlFromAssets needs to be called after assigning the controller :
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
_loadHtmlFromAssets();
}
Then it works fine :)

You may use Flutter InAppWebView Plugin. It will create a local server inside the app and it’ll run the HTML app there in the WebView. Start your server:
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();
}
}
And then point your localhost html index file in the WebView.
InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse('http://localhost:8080/assets/index.html')),
),
In many cases it doesn't work for many people because they forget to add all the folders as the assets in the pubspec.yaml file. For example, you need to specify all the folders and index file like below:
assets:
- assets/index.html
- assets/css/
- assets/images/
- assets/js/
- assets/others/
You can see this tutorial for further details.

I have the same problem; this is how I solved it.
Add webview_flutter to your project dependencies:
webview_flutter: 0.3.14+1
Create a WebViewController inside your screen/stateful widget
WebViewController _controller;
Implement the WebView and assign a value to the _controller using the onWebViewCreated property. Load the HTML file.
WebView(
initialUrl: '',
onWebViewCreated: (WebViewController webViewController) async {
_controller = webViewController;
await loadHtmlFromAssets('legal/privacy_policy.html', _controller);
},
)
Implement the function to load the file from the asset folder
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());
}

You can use my plugin flutter_inappwebview, which has a lot of events, methods, and options compared to other plugins!
To load an html file from your assets folder, you need to declare it in the pubspec.yaml file before use it (see more here).
Example of a pubspec.yaml file:
...
# 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
...
After that, you can simply use the initialFile parameter of the InAppWebView widget to load index.html into the 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) {
},
),
),
),
]))
);
}
}

unzip the apk package,I found the reason: path is wrong;
For Android:
"assets/test.html" == "file:///android_asset/flutter_assets/assets/test.html"
so,just like this:
WebView(
initialUrl: "file:///android_asset/flutter_assets/assets/test.html",
javascriptMode: JavascriptMode.unrestricted,
)
you can load "assets/test.html".

The asset_webview plugin is specifically designed for this. Fewer features than other plugins, but simple to use.

Use flutter_widget_from_html_core---->
link -> https://pub.dev/packages/flutter_widget_from_html_core
dependencies:
flutter_widget_from_html_core: ^0.5.1+4
Code like this
HtmlWidget(
"""
<html lang="en">
<body>hello world</body>
</html>
""",
),

Finally found a proper way
String webview_content = '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Load file or HTML string example</title>
</head>
<body>
<h1>Local demo page</h1>
<p>
This is an example page used to demonstrate how to load a local file
or
HTML
string using the <a
href="https://pub.dev/packages/webview_flutter">Flutter
webview</a> plugin.
</p>
</body>
</html>
''';
final Completer<WebViewController> _controller =
Completer<WebViewController>();
Future<void> _loadHtmlString(
Completer<WebViewController> controller, BuildContext context) async {
WebViewController _controller = await controller.future;
await _controller.loadHtmlString(webview_content);
return WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated:
(WebViewController webViewController) async {
_controller.complete(webViewController);
_loadHtmlString(_controller, context);
},
),

I follow #Suragch answer and find that local image path in the html file cannot be loaded. So I tried a few ways and found that replacing the method loadUrl() with loadFlutterAsset() actually do the job (the code is also more simple).
class UserGuidePage extends StatefulWidget {
final UserGuideArguments arguments;
const UserGuidePage({required this.arguments, Key? key}) : super(key: key);
#override
State<UserGuidePage> createState() => _UserGuidePageState();
}
class _UserGuidePageState extends State<UserGuidePage> {
late WebViewController _controller;
#override
Widget build(BuildContext context) {
return WebView(
initialUrl: 'about:blank',
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
_loadHtmlFromAssets();
},
);
}
void _loadHtmlFromAssets() {
_controller.loadFlutterAsset('assets/index.html');
}
}

You can get the page html and use it to load the page with code below that is an example
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),
);
}
}

Here is much more cleaner code of above code
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),
);
}
}
In this code you can see also how to use javascript dom manipulation and selection and interaction with web page.

Related

flutter provider: notifyListeners(); is not working after changing variable still showing null on printing

the problem is when i try to log in the user user name should show up instead of null the signName variable should hold the username from firebase cloud when i try to the user its showing the correct username from firebase db but when i try to print the value if variable like uid or signName or bool values like loggedin they show the initial value pls help
this is my class that extend change ChangeNotifier
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:indiaghumo/utils.dart';
class FirebaseAuthMethod extends ChangeNotifier {
String? uid;
String? signName;
String? guest;
bool loggedin = false;
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _firetore = FirebaseFirestore.instance;
// String res = "Failed to login";
// FirebaseAuthMethod(this._auth);
Stream<User?> get authstate => FirebaseAuth.instance.authStateChanges();
User get user => _auth.currentUser!;
Future<void> signUpWithEmail(
{required String email,
required String password,
required String username,
required BuildContext context}) async {
try {
UserCredential cred = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
uid = cred.user!.uid;
loggedin = true;
// print(_auth.currentUser!.email);
try {
_firetore.collection("users").doc(cred.user!.uid).set({
"username": username,
"uid": cred.user!.uid,
"email": email,
});
getdata(uid!);
// notifyListeners();
} on FirebaseException catch (e) {
showSnackbar(context, e.message.toString());
}
// await sendEmailVerificaton(context);
} on FirebaseAuthException catch (e) {
showSnackbar(context, e.message.toString());
}
notifyListeners();
}
// Future<void> sendEmailVerificaton(BuildContext context) async {
// try {
// _auth.currentUser!.sendEmailVerification();
// } on FirebaseAuthException catch (e) {
// showSnackbar(context, e.message.toString());
// }
// }
loginWithEmail(
{required String email,
required String password,
required BuildContext context}) async {
try {
UserCredential cred = await _auth.signInWithEmailAndPassword(
email: email, password: password);
uid = cred.user!.uid;
loggedin = true;
getdata(uid!);
// notifyListeners();
// if (!_auth.currentUser!.emailVerified) {
// sendEmailVerificaton(context);
// }
} on FirebaseAuthException catch (e) {
showSnackbar(context, e.message.toString());
}
notifyListeners();
}
Future<void> logOut(BuildContext context) async {
try {
await _auth.signOut();
loggedin = false;
signName = "guest";
} on FirebaseAuthException catch (e) {
showSnackbar(context, e.message.toString());
}
notifyListeners();
}
Future<void> forgetPassword(
{required BuildContext context, required String email}) async {
try {
await _auth.sendPasswordResetEmail(email: email);
} on FirebaseAuthException catch (e) {
showSnackbar(context, e.message.toString());
}
}
getdata(String uID) async {
String? i = await _firetore
.collection("users")
.doc(uID.toString())
.get()
.then((snapshot) {
guest = snapshot.get("username");
signName = guest;
// print(signName);
});
// print(signName);
print(uID);
notifyListeners();
return i;
}
test(String str) {
signName = str;
notifyListeners();
}
}
this is my button where i called my variable from changenotifier class
IconButton(
icon: const Icon(
Icons.notifications_rounded,
color: Colors.white,
),
onPressed: () {
print(context.read<FirebaseAuthMethod>().loggedin);
},
),
the output is : I/flutter (14797): false
even after successful login the value of bool didnt changed
below is my main file
import 'package:flutter/material.dart';
import 'package:indiaghumo/screens/Signup.dart';
import 'package:indiaghumo/screens/forgetpassword.dart';
import 'package:indiaghumo/screens/homescreen.dart';
import 'package:indiaghumo/screens/locationPage.dart';
import 'package:indiaghumo/screens/login.dart';
import 'package:indiaghumo/services/firebase_auth.dart';
import 'package:indiaghumo/services/locationAndCity.dart';
import 'package:provider/provider.dart';
import 'firebase_options.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => FirebaseAuthMethod(),
),
ChangeNotifierProvider(
create: (_) => LocationAndPlace(),
),
],
child: MaterialApp(
home: LocationPage(),
),
);
}
}

Lost connection to device. Exited (sigterm) - Flutter Crash

My Flutter app is crashing on loading
It operates a FutureBuilder and I believe this to be where the issue comes from.
My app makes an API Call and returns the data to a map marker.
When i have the FutureBuilder return a list view it works fine.
However, when i change it to return a Stack containing my Map SDK and the buttons to call the API it crashes on start up.
Relevant code is below, thank you!
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Future<Stations> stations;
BuildContext _context;
MapMarkerExample _mapMarkerExample;
#override
void initState() {
stations = API_Call().fetchStations();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Example 1'),
),
body: Container(
child: FutureBuilder<Stations>(
future: stations,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text("Error");
}
if (snapshot.connectionState == ConnectionState.done) {
return
Stack(
children: [
HereMap(onMapCreated: _onMapCreated),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
button('Stations Near Me', _anchoredMapMarkersButtonClicked),
button('Clear', _clearButtonClicked),
],
),
],
),
],
);
}
return Text("Loading");
}
)
)
);
}
api_call.dart
class API_Call {
Future<Stations> fetchStations() async {
var client = http.Client();
final response = await client.get(
'https://transit.hereapi.com/v8/stations?in=x,-x&return=transport&apiKey=API_KEY');
if (response.statusCode == 200) {
return Stations.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load stations');
}
}
}
api_manager.dart
typedef ShowDialogFunction = void Function(String title, String message);
class MapMarkerExample{
void showAnchoredMapMarkers() {
print('step5');
GeoCoordinates geoCoordinates = _callGeoCoordinates();
// use the coords .. to add a marker
_addCircleMapMarker(geoCoordinates, 0);
_addPOIMapMarker(geoCoordinates, 1);
print('step6');
}
GeoCoordinates _callGeoCoordinates() {
print('step7');
var stations;
Future<Stations> fetchStations() async {
stations = await API_Call().fetchStations();
for (Station stations in stations) {
GeoCoordinates geoCoordinates = GeoCoordinates (stations.place.location.lat, stations.place.location.lng);
// use the coords .. to add a marker
_addCircleMapMarker(geoCoordinates, 0);
_addPOIMapMarker(geoCoordinates, 1);
}
}
}
HereMapController _hereMapController;
List<MapMarker> _mapMarkerList = [];
MapImage _poiMapImage;
MapImage _circleMapImage;
ShowDialogFunction _showDialog;
List<MapMarker3D> _mapMarker3DList = [];
MapMarkerExample(ShowDialogFunction showDialogCallback, HereMapController hereMapController) {
_showDialog = showDialogCallback;
_hereMapController = hereMapController;
double distanceToEarthInMeters = 8000;
_hereMapController.camera.lookAtPointWithDistance(
GeoCoordinates(x, -x), distanceToEarthInMeters);
// Setting a tap handler to pick markers from map.
_setTapGestureHandler();
_showDialog("Note", "Tap markers for more.");
}
void clearMap() {
for (var mapMarker in _mapMarkerList) {
_hereMapController.mapScene.removeMapMarker(mapMarker);
}
_mapMarkerList.clear();
for (var mapMarker3D in _mapMarker3DList) {
_hereMapController.mapScene.removeMapMarker3d(mapMarker3D);
}
_mapMarker3DList.clear();
}
Future<void> _addPOIMapMarker(GeoCoordinates geoCoordinates, int drawOrder) async {
// Reuse existing MapImage for new map markers.
if (_poiMapImage == null) {
Uint8List imagePixelData = await _loadFileAsUint8List('assets/poi.png');
_poiMapImage = MapImage.withPixelDataAndImageFormat(imagePixelData, ImageFormat.png);
}
Anchor2D anchor2D = Anchor2D.withHorizontalAndVertical(0.5, 1);
MapMarker mapMarker = MapMarker.withAnchor(geoCoordinates, _poiMapImage, anchor2D);
mapMarker.drawOrder = drawOrder;
Metadata metadata = new Metadata();
metadata.setString("key_poi", "Next Departures");
mapMarker.metadata = metadata;
_hereMapController.mapScene.addMapMarker(mapMarker);
_mapMarkerList.add(mapMarker);
}
Future<void> _addCircleMapMarker(GeoCoordinates geoCoordinates, int drawOrder) async {
// Reuse existing MapImage for new map markers.
if (_circleMapImage == null) {
Uint8List imagePixelData = await _loadFileAsUint8List('assets/circle.png');
_circleMapImage = MapImage.withPixelDataAndImageFormat(imagePixelData, ImageFormat.png);
}
MapMarker mapMarker = MapMarker(geoCoordinates, _circleMapImage);
mapMarker.drawOrder = drawOrder;
_hereMapController.mapScene.addMapMarker(mapMarker);
_mapMarkerList.add(mapMarker);
}
Future<Uint8List> _loadFileAsUint8List(String assetPathToFile) async {
// The path refers to the assets directory as specified in pubspec.yaml.
ByteData fileData = await rootBundle.load(assetPathToFile);
return Uint8List.view(fileData.buffer);
}
void _setTapGestureHandler() {
_hereMapController.gestures.tapListener = TapListener.fromLambdas(lambda_onTap: (Point2D touchPoint) {
_pickMapMarker(touchPoint);
});
}
void _pickMapMarker(Point2D touchPoint) {
double radiusInPixel = 2;
_hereMapController.pickMapItems(touchPoint, radiusInPixel, (pickMapItemsResult) {
// Note that 3D map markers can't be picked yet. Only marker, polgon and polyline map items are pickable.
List<MapMarker> mapMarkerList = pickMapItemsResult.markers;
if (mapMarkerList.length == 0) {
print("No map markers found.");
return;
}
});
}
}
In api_manager.dart, this looks very suspicous, and you aren't returning anything from this function, it could also explain the error saying future not complete
Future<Stations> fetchStations() async {
stations = await API_Call().fetchStations();
for (Station stations in stations) {
GeoCoordinates geoCoordinates = GeoCoordinates (stations.place.location.lat, stations.place.location.lng);
// use the coords .. to add a marker
_addPOIMapMarker(geoCoordinates, 1);
}
// GeoCoordinates geoCoordinates = stations.coordinates;
// _addPOIMapMarker(geoCoordinates, 1);
}
}
You have to return a Stations object from it, try after your for loop something like return stations;, it could fix your problem, if the error changes, it's also a good start.
Also change your line in future builder to this:
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData)
And for the meantime, remove this _setTapGestureHandler(). The crash is most likely caused by some memory leak, and from the code posted, it could be explained by listeners.

Flutter: Asking Location permission pauses all app execution, how to let it run asynchronously

When my app requests location permission the entire app stops until the dialog is complete (e.g. if the permission dialog pops up during a page transition the transition will freeze mid transition until the dialog is resolved).
Literally it causes execution to pause.
Using: flutter_riverpod, location.
The offending code:
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/all.dart';
import 'package:location/location.dart';
class MapApiBloc extends StateNotifier<MapApiState> {
// Instantiating a location service
static Location _location = Location();
// This will subscribe to the user's location
StreamSubscription<LocationData> _streamSubscription;
// Permissions stuff
bool _serviceEnabled;
PermissionStatus _permissionGranted;
// Initial (empty) state
static const MapApiState _initialState = MapApiState(userLocation: null);
MapApiBloc() : super(_initialState) {
init();
}
// This runs when you initialize the class
init() async {
// Checks if user toggled on location service
_serviceEnabled = await _location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await _location.requestService();
if (!_serviceEnabled) {
return;
}
}
// Asks for permission
_permissionGranted = await _location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await _location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return;
}
}
// Starts the subscription
_streamSubscription = _location.onLocationChanged.listen((event) {
state = MapApiState(userLocation: event);
});
}
#override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
}
class MapApiState {
final LocationData userLocation;
const MapApiState({#required this.userLocation});
}
final mapApiProvider = StateNotifierProvider<MapApiBloc>((ref) {
return MapApiBloc();
});
UI Code:
class ViewNearbyMapPage extends StatefulWidget {
#override
_ViewNearbyMapPageState createState() => _ViewNearbyMapPageState();
}
class _ViewNearbyMapPageState extends State<ViewNearbyMapPage> {
Completer<GoogleMapController> _controller = Completer();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Search Sellers")),
body: Consumer(
builder: (context, watch, child) {
var location = watch(mapApiProvider.state);
if (location.userLocation?.latitude == null) {
return Center(child: CircularProgressIndicator());
}
CameraPosition _myPosition = CameraPosition(
target: LatLng(location.userLocation.latitude,
location.userLocation.longitude),
zoom: 14.4746,
);
return GoogleMap(
initialCameraPosition: _myPosition,
onMapCreated: (controller) {
_controller.complete(controller);
},
);
},
),
);
}
}

How to clear data in bloc?

As is it right now, when a user tries to click login, the button changes to a progress bar. The trouble i'm having is that I'm not able to get the progress bar turned back into a button using streams.
I'm kinda copying a tutorial I found online and I'm trying to modify it to fit what I need so I'm not 100% understanding bloc yet.
This is the tutorial I'm kinda following
https://medium.com/flutterpub/when-firebase-meets-bloc-pattern-fb5c405597e0
This is the login button
Widget loginButton() {
return StreamBuilder(
stream: _bloc.signInStatus,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData || snapshot.hasError) {
return button();
} else {
return LinearProgressIndicator();
}
});
}
Widget button() {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: MaterialButton(
minWidth: 200.0,
height: 42.0,
child: Text(
StringConstant.submit,
style: TextStyle(color: Colors.white),
),
color: ThemeSettings.RaisedButton,
onPressed: () {
if (_bloc.validateFields()) {
authenticateUser();
} else {
showAlertDialog(context, "Verification Failed",
"The Email / Number you entered couldn't be found or your password was incorrect. Please try again.");
}),
);
}
void authenticateUser() {
_bloc.showProgressBar(true);
_bloc.authenticateUser().then((value) {
//Username and password ARE correct
if (value) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => EventsList(_bloc.emailAddress)));
} else {
print("this one");
showAlertDialog(context, "Verification Failed",
"The Email / Number you entered couldn't be found or your password was incorrect. Please try again.");
// I believe I need to clear what is inside of snapshot here?
}
});
}
and inside of my login_bloc.dart here is what I think is important to know?
class LoginBloc {
final _repository = Repository();
final _email = BehaviorSubject<String>();
final _password = BehaviorSubject<String>();
final _firstName = BehaviorSubject<String>();
final _phoneNumber = BehaviorSubject<int>();
final _profilePicture = BehaviorSubject<String>();
final _isSignedIn = BehaviorSubject<bool>();
Observable<String> get email => _email.stream.transform(_validateEmail);
Observable<String> get password =>
_password.stream.transform(_validatePassword);
Observable<bool> get signInStatus => _isSignedIn.stream;
String get emailAddress => _email.value;
// Change data
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
Function(bool) get showProgressBar => _isSignedIn.sink.add;
final _validateEmail =
StreamTransformer<String, String>.fromHandlers(handleData: (email, sink) {
if (email.contains('#')) {
sink.add(email);
} else {
sink.addError(StringConstant.emailValidateMessage);
}
});
final _validatePassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
if (password.length >= 6) {
sink.add(password);
} else {
sink.addError(StringConstant.passwordValidateMessage);
}
});
Future<bool> authenticateUser() {
return _repository.authenticateUser(_email.value, _password.value);
}
Future<AuthenticatedStatus> doesUserExist() {
return _repository.doesUserExist(_email.value);
}
Future<void> addUserToDatabase() {
return _repository.addUserToDatabase(_email.value, _password.value,
_firstName.value, _phoneNumber.value, _profilePicture.value);
}
bool validateFields() {
if (_email.value != null &&
_email.value.isNotEmpty &&
_password.value != null &&
_password.value.isNotEmpty &&
_email.value.contains('#') &&
_password.value.length >= 6) {
return true;
} else {
return false;
}
}
void dispose() async {
await _email.drain();
_email.close();
await _password.drain();
_password.close();
await _firstName.drain();
_firstName.close();
await _phoneNumber.drain();
_phoneNumber.close();
await _profilePicture.drain();
_profilePicture.close();
await _isSignedIn.drain();
_isSignedIn.close();
}
I have yet to try the sample provided in the blog post, but going through the snippets, it looks like a simple _bloc.showProgressBar(false); should do the trick. Have you tried doing so?

Flutter get logged user data to other screen view

I have API.dart like this to authenticating a user, log in and log out
class Api {
static FirebaseAuth _auth = FirebaseAuth.instance;
static GoogleSignIn _googleSignIn = GoogleSignIn();
FirebaseUser firebaseUser;
Api(FirebaseUser user) {
this.firebaseUser = user;
}
static Future<FBApi> signInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final FirebaseUser user = await _auth.signInWithGoogle(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
assert(user.email != null);
assert(user.displayName != null);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
// print('photoURL api ' + user.photoUrl);
return Api(user);
}
static Future<void> signOut() async {
await _auth.signOut().then((_) {
print("***** log out...what the hell?");
_googleSignIn.signOut();
});
}
}
I've have a cloud function to create new user to database cloud firestore.
And in view account settings, I want to update user information like displayName, photoUrl into firestore. How I get current user in my account setting view.
class Settings extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(
'ACCOUNT',
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: new SettingsScreen(),
);
}
}
class SettingsScreen extends StatefulWidget {
#override
State createState() => new SettingsScreenState();
}
class SettingsScreenState extends State<SettingsScreen> {
TextEditingController controllerNickname;
SharedPreferences prefs;
String id;
String nickName;
String photoUrl;
bool isLoading = false;
File avatarImageFile;
final FocusNode focusNodeNickname = new FocusNode();
#override
void initState() {
super.initState();
readLocal();
}
void readLocal() async {
prefs = await SharedPreferences.getInstance();
id = prefs.getString('id') ?? '';
nickName = prefs.getString('nickName') ?? '';
photoUrl = prefs.getString('photoUrl') ?? '';
controllerNickname = new TextEditingController(text: nickName);
// Force refresh input
setState(() {});
}
Future getImage() async {
File image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
avatarImageFile = image;
isLoading = true;
});
}
uploadFile();
}
Future uploadFile() async {
String fileName = id;
StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(avatarImageFile);
StorageTaskSnapshot storageTaskSnapshot;
uploadTask.onComplete.then((value) {
if (value.error == null) {
storageTaskSnapshot = value;
storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
photoUrl = downloadUrl;
Firestore.instance
.collection('users')
.document(id)
.updateData({'displayName': nickName, 'photoUrl': photoUrl}).then((data) async {
await prefs.setString('photoUrl', photoUrl);
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: "Upload success");
}).catchError((err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}, onError: (err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: 'This file is not an image');
});
} else {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: 'This file is not an image');
}
}, onError: (err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}
void handleUpdateData() {
focusNodeNickname.unfocus();
setState(() {
isLoading = true;
});
Firestore.instance
.collection('users')
.document(id)
.updateData({'displayName': nickName, 'photoUrl': photoUrl}).then((data) async {
await prefs.setString('nickname', nickName);
await prefs.setString('photoUrl', photoUrl);
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: "Update success");
}).catchError((err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}
#override
Widget build(BuildContext context) {
...
You can do something like this FirebaseAuth.instance.currentUser()
This returns the current user if any. Otherwise it returns null

Resources