Open oexza opened 6 years ago
not possible yet, but a hack would be to create a server with dart:io
in the app on localhost
, like here, https://medium.com/@segaud.kevin/facebook-oauth-login-flow-with-flutter-9adb717c9f2e
new WebviewScaffold(
url: new Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
worked for me as well
Loading data URIs seems quite limiting. I found it difficult to load other data on click
Any plans to support
https://developer.android.com/reference/android/webkit/WebView.html#loadDataWithBaseURL(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
and the other similar methods?
yes I planned to do it,
I can't find time to work on the plugin at the moment and I also need to find an equivalent on iOS which is not my domain of expertise :/
I guess this is the equivalent function on iOS
https://developer.apple.com/documentation/uikit/uiwebview/1617941-loaddata?language=objc
I understand. I haven't done native mobile development and not the time to dive into it right now, therefore depend on plugins of others ;-) I guess I'll figure out some workaround. Thanks a lot for your work on the plugin ๐
To create a server easily you have an example in the readme of this repo
Hello guys,
new Uri.dataFromString('<html><body><h1>hello world</h1></body></html>', mimeType: 'text/html').toString();
this example also worked for me. But I have another question how can I render a whole .html file in flutter? Fot example insted using this string <html><body><h1>hello world</h1></body></html>
just load the whole file new Uri.dataFromString('assets/test.html', mimeType: 'text/html').toString();
@zoechi Your approach works!
new WebviewScaffold(
url: new Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
Although it doesn't load any images from img=src from the network. Any ideas how to force load them?
@AppleEducate Images work for me
I added parameters: { 'charset': 'utf-8' }
, don't remember why or if it is related
(or pass encoding
like shown in https://github.com/dart-flitter/flutter_webview_plugin/issues/68#issuecomment-384696379)
Thanks!
@lejard-h , how to load images/data that are stored locally when launching a webview scaffold that as above?
@MaskyS see the link in the 2nd comment
@zoechi I think I'm probably missing something, but that link leads to android documentation? I checked the flutter_webview_plugin documentation and code but there seem to be no implementation of loadData() or loadDataWithBaseUrl() Could you help me understand with an example or clarification?
@MaskyS the 2nd comment, not my 2nd comment https://github.com/dart-flitter/flutter_webview_plugin/issues/23#issuecomment-354431595
@zoechi I had a look at that article; I tried it out and couldn't serve multiple files (I have html1.html, html2.html, etc along with their data folders.). Is it possible? am I missing something?
@MaskyS just because it doesn't demonstrate how you can serve multiple files, doesn't mean it's not possible. Just serve different files based on the URL
Thank you will try that.
I would suggest on the iOS side to use Swift and not Objective C. Most new projects in iOS are written in Swift. Just my thoughts.
Any news on this? I tried with creating a path and simple html file like this:
project
|
+--assets/index.html
|
+--lib
|
...
and referencing it in the pubspec.yaml under assets. I can see it in the build, so the file is there. But how do I call it correctly in the dart method? Tried all possibilities I could think of but none worked. Is this supposed to work already? Additionally I saw there is an option "withLocalUrl". Does this do anything already?
@Chris1234567899 see the medium article linked in the 2nd comment or my comment just below the 2nd one.
You can also use golang as your web server running locally. This is essentially a plugin that exposes itself to the flutter dart code over a http based RPC.
I am honestly not sure of the workflow needed here for this Facebook workflow though . But I just wanted to add this comment in case it helps anyone
@gedw99 serving HTTP from Dart is quite easy though. All you need is shipped with Flutter already (dart:io
)
true.. I just wanted to rock the boat.. No i am just saying it can be useful if you need to also package a ton of other logic and database stuff.
On Fri, 15 Jun 2018 at 18:11 Gรผnter Zรถchbauer notifications@github.com wrote:
@gedw99 https://github.com/gedw99 serving HTTP from Dart is quite easy though. All you need is shipped with Flutter already (dart:io)
โ You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dart-flitter/flutter_webview_plugin/issues/23#issuecomment-397669312, or mute the thread https://github.com/notifications/unsubscribe-auth/ATuCwlb42QUW85c_91raX5HG_hf_LKeoks5t89ycgaJpZM4RO-SO .
@zoechi your solution worked for me, but i am trying to get the webview a rectangle as to the documentation
final flutterWebviewPlugin = new FlutterWebviewPlugin();
flutterWebviewPlugin.launch(url,
fullScreen: false,
rect: new Rect.fromLTWH(
0.0,
0.0,
MediaQuery.of(context).size.width,
300.0));
But it's not working - just a white screen on my device. Any ideas?
@mdanics sorry, no idea. Haven't tried that yet myself. It seems unrelated to this issue and perhaps better to create a new issue.
You can now do this on android, using my fork.
Example-
(place test.html at android/app/src/main/assets
)
WebviewScaffold(
url: 'file:///android_asset/test.html',
allowFileURLs: true,
),
Flutter doesn't give the path to it's assets, so this won't work with flutter's assets, only android's.
pull request - #122
So I think I can actually make this work by using this feature of flutter.
I have tried it out for flutter_pdf_viewer and it works great. So might issue a pull request if I get some time.
got error java.lang.ClassCastException: android.webkit.WebView cannot be cast to com.flutter_webview_plugin.ObservableWebView for the following code
new WebviewScaffold(
url: new Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
I/flutter (23463): [response]
I/flutter (23463): -------------------------------------------------------->
I/flutter (23463): [data]={code: 1, msg: ่ทๅๆๅ, time: 1536571706, data: {id: 15, contentlist_id: 4, title: ๅปบ็ซ็พไธไบบๅบๅ ๆฐๆฎๅบๅๅฅๅบท็ฎก็็ณป็ป๏ผโๅ็พโๅทฅ็จๅฉๅๅฅๅบทไธญๅฝ, desc: ๅฅๅบทๅทฅ็จ, image: http://ym.51xixi.me/uploads/20180831/d38192d4b4956f939aeacb85dbfaf1f2.jpg, weigh: 12, auth: admin, recommend: 0, top: 0, index: 0, on: 0, content: <p style="margin-top:12.8pt;text-align:justify;text-justify:inter-ideograph;
I/flutter (23463): line-height:18.0pt;mso-pagination:widow-orphan"><span lang="EN-US" style="font-family: Arial, sans-serif; color: rgb(51, 51, 51); background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"> 7</span><span style="font-family: ๅฎไฝ; color: rgb(51, 51, 51); background-image: initial; background-position: initial; background-size: initial; background
I/flutter (23463): โโโก EXCEPTION CAUGHT BY WIDGETS LIBRARY โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
I/flutter (23463): The following ArgumentError was thrown building Builder(dirty):
I/flutter (23463): Invalid argument(s): String contains invalid characters.
I/flutter (23463):
I/flutter (23463): When the exception was thrown, this was the stack:
I/flutter (23463): #0 _UnicodeSubsetEncoder.convert (dart:convert/ascii.dart:95:9)
I/flutter (23463): #1 AsciiCodec.encode (dart:convert/ascii.dart:45:46)
I/flutter (23463): #2 new UriData.fromString (dart:core/uri.dart:3214:44)
I/flutter (23463): #3 new Uri.dataFromString (dart:core/uri.dart:304:24)
I/flutter (23463): #4 DetailPageState._body (file:///Users/maokangren/workspace/flutter_template/lib/detail/Detail.dart:101:142)
I/flutter (23463): #5 DetailPageState.build.<anonymous closure> (file:///Users/maokangren/workspace/flutter_template/lib/detail/Detail.dart:49:20)
I/flutter (23463): #6 Builder.build (package:flutter/src/widgets/basic.dart:5590:41)
I/flutter (23463): #7 StatelessElement.build (package:flutter/src/widgets/framework.dart:3741:28)
I/flutter (23463): #8 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3688:15)
I/flutter (23463): #9 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #10 StatelessElement.update (package:flutter/src/widgets/framework.dart:3748:5)
I/flutter (23463): #11 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #12 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #13 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #14 ProxyElement.update (package:flutter/src/widgets/framework.dart:3957:5)
I/flutter (23463): #15 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #16 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #17 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #18 ProxyElement.update (package:flutter/src/widgets/framework.dart:3957:5)
I/flutter (23463): #19 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #20 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4531:32)
I/flutter (23463): #21 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4921:17)
I/flutter (23463): #22 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #23 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #24 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #25 StatefulElement.update (package:flutter/src/widgets/framework.dart:3845:5)
I/flutter (23463): #26 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #27 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #28 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #29 ProxyElement.update (package:flutter/src/widgets/framework.dart:3957:5)
I/flutter (23463): #30 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #31 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #32 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #33 StatefulElement.update (package:flutter/src/widgets/framework.dart:3845:5)
I/flutter (23463): #34 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #35 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4813:14)
I/flutter (23463): #36 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #37 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #38 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #39 StatelessElement.update (package:flutter/src/widgets/framework.dart:3748:5)
I/flutter (23463): #40 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #41 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4813:14)
I/flutter (23463): #42 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #43 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #44 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #45 StatefulElement.update (package:flutter/src/widgets/framework.dart:3845:5)
I/flutter (23463): #46 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #47 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #48 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #49 StatefulElement.update (package:flutter/src/widgets/framework.dart:3845:5)
I/flutter (23463): #50 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #51 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #52 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #53 ProxyElement.update (package:flutter/src/widgets/framework.dart:3957:5)
I/flutter (23463): #54 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #55 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #56 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #57 ProxyElement.update (package:flutter/src/widgets/framework.dart:3957:5)
I/flutter (23463): #58 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #59 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #60 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #61 StatefulElement.update (package:flutter/src/widgets/framework.dart:3845:5)
I/flutter (23463): #62 Element.updateChild (package:flutter/src/widgets/framework.dart:2729:15)
I/flutter (23463): #63 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:16)
I/flutter (23463): #64 Element.rebuild (package:flutter/src/widgets/framework.dart:3541:5)
I/flutter (23463): #65 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2273:33)
I/flutter (23463): #66 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:653:20)
I/flutter (23463): #67 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:208:5)
I/flutter (23463): #68 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter (23463): #69 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter (23463): #70 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
I/flutter (23463): #71 _invoke (dart:ui/hooks.dart:128:13)
I/flutter (23463): #72 _drawFrame (dart:ui/hooks.dart:117:3)
Was working on this, it would be great if you guys tested it out. https://github.com/flutter/plugins/pull/1137
@MaskyS: In my case, I was able to eliminate the error Invalid argumnent(s): String contains invalid characters
by removing the following character: โ
(aprostrophe). Afterwards I was able to load a HTML-string into a WebView in Flutter...
Having issue to display html string to normal string in flutter.. i was try all libs but not working suggest me new thank you......
NSString* key = [_registrar lookupKeyForAsset:@"assets/xxx.html"];
NSURL* nsUrl = [[NSBundle mainBundle] URLForResource:key withExtension:nil];
[self.webview loadFileURL:nsUrl allowingReadAccessToURL:[NSURL URLWithString:@"file:///"]];
can solve this problem, but you should modify open source code for your url schema rule. (get _registrar
from plugin entrance )
Hi, I want to load the local Html file which is placed in my assets folder as "assets/file/privacy.html" this would be the path and I am using the same plugin and replacing the url as "assets/privacy.html" but still i am not able to view the html file content. Its showing the error as could not found the file. Please suggest some solution.
@neelu004: I saw that you use a subfolder (i.e. "assets/file/...") for your html file. The Flutter-webview plugin is very tedious if it comes to folder/subfolder/ locations. Try: 1. eliminate the subfolder and place it directly into "assets/privacy.html" instead. Or 2. make sure you also provide the subfolder in your URL when calling the webview. Also, if you have references to other html files or folders from within your html-file that the webview calls (normally index.html with references to other files and folders ... or in your case privacy.html), make sure you use a webserver together with the webview-plugin.
Here is what works in my case:
(Again: This server is only needed in the case you have references to files and folders from your root html you are trying to show in your webview). If you only show one single html-file (without references), then you don't need this Jaguar server...
But if you do have a webpage with references to other files and folders (all in your assets), then your webview-URL must be called with localhost
such as: http://localhost:8080/fullPathName
as can be seen below...
The webserver I set up at the very beginning (inside main())...
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// import 'dart:async';
import 'package:jaguar/jaguar.dart';
import 'package:jaguar_flutter_asset/jaguar_flutter_asset.dart';
void main() async {
final server = Jaguar();
server.addRoute(serveFlutterAssets());
await server.serve(logRequests: false);
// await server.serve(logRequests: true);
// server.log.onRecord.listen((r) => print(r));
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]).then((_) {
runApp(MyApp());
});
}
If you want to navigate to your webview from somewhere:
await navigateToWebView(context, 'file/privacy.html');
The navigation:
Future<String> navigateToWebView(
BuildContext context, String pathName) async {
return await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WebViewExample(pathName)));
}
And here the webview implementation with the localhost-URL call:
(small detail: the comments are an alternative if you don't want the snackbar)
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:webview_flutter/webview_flutter.dart';
// import 'package:flutter/services.dart';
class WebViewExample extends StatelessWidget {
final String pathName;
WebViewExample(this.pathName);
final Completer<WebViewController> _controller =
Completer<WebViewController>();
@override
Widget build(BuildContext context) {
final String serverURL = 'http://localhost:8080/' + this.pathName;
final double screenWidth = MediaQuery.of(context).size.shortestSide;
final double screenHeight = MediaQuery.of(context).size.longestSide;
return Scaffold(
appBar: MyAppBar(
title: Text(
'My Title',
style: TextStyle(
fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.w500),
),
),
// body: FutureBuilder<String>(
// future: loadAsset(),
// builder: (context, snapshot) {
// if (snapshot.hasData) {
// return WebView(
// initialUrl:
// Uri.dataFromString(snapshot.data, mimeType: 'text/html')
// .toString(),
// javascriptMode: JavascriptMode.unrestricted,
// onWebViewCreated: (WebViewController webViewController) {
// _controller.complete(webViewController);
// },
// javascriptChannels: <JavascriptChannel>[
// _toasterJavascriptChannel(context),
// ].toSet(),
// );
// } else if (snapshot.hasError) {
// return Text("${snapshot.error}");
// }
// return CircularProgressIndicator();
// },
// ),
// We're using a Builder here so we have a context that is below the Scaffold
// to allow calling Scaffold.of(context) so we can show a snackbar.
body: Builder(builder: (BuildContext context) {
return Container(
color: Color.fromRGBO(
0x3c, 0x3c, 0x3c, 1), // color for bottom part of iOS safe-area
child: SafeArea(
child: Stack(
fit: StackFit.expand,
alignment: AlignmentDirectional.topStart,
children: <Widget>[
Positioned(
left: 0.0,
top: 0.0,
width: screenWidth,
height: screenHeight,
child: Container(
child: WebView(
initialUrl: serverURL,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
javascriptChannels: <JavascriptChannel>[
_toasterJavascriptChannel(context),
].toSet(),
),
),
),
],
),
),
);
}),
floatingActionButton: favoriteButton(),
);
}
// Future<String> loadAsset() async {
// return await rootBundle.loadString('assets/web1/index.html');
// }
JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toaster',
onMessageReceived: (JavascriptMessage message) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(message.message)),
);
});
}
Widget favoriteButton() {
return FutureBuilder<WebViewController>(
future: _controller.future,
builder: (BuildContext context,
AsyncSnapshot<WebViewController> controller) {
if (controller.hasData) {
return FloatingActionButton(
onPressed: () async {
final String url = await controller.data.currentUrl();
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Favorited $url')),
);
},
child: const Icon(Icons.favorite),
);
}
return Container();
});
}
}
enum MenuOptions {
showUserAgent,
toast,
}
class SampleMenu extends StatelessWidget {
SampleMenu(this.controller);
final Future<WebViewController> controller;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: controller,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> controller) {
return PopupMenuButton<MenuOptions>(
onSelected: (MenuOptions value) {
switch (value) {
case MenuOptions.showUserAgent:
_onShowUserAgent(controller.data, context);
break;
case MenuOptions.toast:
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('You selected: $value'),
),
);
break;
}
},
itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[
PopupMenuItem<MenuOptions>(
value: MenuOptions.showUserAgent,
child: const Text('Show user agent'),
enabled: controller.hasData,
),
const PopupMenuItem<MenuOptions>(
value: MenuOptions.toast,
child: Text('Make a toast'),
),
],
);
},
);
}
void _onShowUserAgent(
WebViewController controller, BuildContext context) async {
// Send a message with the user agent string to the Toaster JavaScript channel we registered
// with the WebView.
controller.evaluateJavascript(
'Toaster.postMessage("User Agent: " + navigator.userAgent);');
}
}
class NavigationControls extends StatelessWidget {
const NavigationControls(this._webViewControllerFuture)
: assert(_webViewControllerFuture != null);
final Future<WebViewController> _webViewControllerFuture;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
final bool webViewReady =
snapshot.connectionState == ConnectionState.done;
final WebViewController controller = snapshot.data;
return Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: !webViewReady
? null
: () async {
if (await controller.canGoBack()) {
controller.goBack();
} else {
Scaffold.of(context).showSnackBar(
const SnackBar(content: Text("No back history item")),
);
return;
}
},
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: !webViewReady
? null
: () async {
if (await controller.canGoForward()) {
controller.goForward();
} else {
Scaffold.of(context).showSnackBar(
const SnackBar(
content: Text("No forward history item")),
);
return;
}
},
),
IconButton(
icon: const Icon(Icons.replay),
onPressed: !webViewReady
? null
: () {
controller.reload();
},
),
],
);
},
);
}
}
class MyAppBar extends PreferredSize {
MyAppBar({Key key, Widget title})
: super(
key: key,
preferredSize: Size.fromHeight(app_bar_height), // set AppBar height
child: AppBar(
elevation: 0.0, // represents shaddow of AppBar
brightness: Brightness
.dark, // makes statusbar shine in dark AppBar environment
backgroundColor:
Color.fromRGBO(0x3c, 0x3c, 0x3c, 1), // sets AppBar color
title: title, // sets AppBar title
// maybe other AppBar properties
),
);
}
You should change the pluginโs origin code, because the plugin didnโt use the correct API, you canโt load local html by LoadRequest but LoadFile API, have a try~
ๅ่ชๆ็iPhone
------------------ Original ------------------ From: neelu004 notifications@github.com Date: Thu,Apr 18,2019 8:39 PM To: fluttercommunity/flutter_webview_plugin flutter_webview_plugin@noreply.github.com Cc: vvlong 741668847@qq.com, Comment comment@noreply.github.com Subject: Re: [fluttercommunity/flutter_webview_plugin] How to display custom html instead of URL (#23)
Hi, I want to load the local Html file which is placed in my assets folder as "assets/file/privacy.html" this would be the path and I am using the same plugin and replacing the url as "assets/privacy.html" but still i am not able to view the html file content. Its showing the error as could not found the file. Please suggest some solution.
โ You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.
@neelu004: I saw that you use a subfolder (i.e. "assets/file/...") for your html file. The Flutter-webview plugin is very tedious if it comes to folder/subfolder/ locations. Try: 1. eliminate the subfolder and place it directly into "assets/privacy.html" instead. Or 2. make sure you also provide the subfolder in your URL when calling the webview. Also, if you have references to other html files or folders from within your html-file that the webview calls (normally index.html with references to other files and folders ... or in your case privacy.html), make sure you use a webserver together with the webview-plugin.
Here is what works in my case:
(Again: This server is only needed in the case you have references to files and folders from your root html you are trying to show in your webview). If you only show one single html-file (without references), then you don't need this Jaguar server...
But if you do have a webpage with references to other files and folders (all in your assets), then your webview-URL must be called with
localhost
such as:http://localhost:8080/fullPathName
as can be seen below...The webserver I set up at the very beginning (inside main())...
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // import 'dart:async'; import 'package:jaguar/jaguar.dart'; import 'package:jaguar_flutter_asset/jaguar_flutter_asset.dart'; void main() async { final server = Jaguar(); server.addRoute(serveFlutterAssets()); await server.serve(logRequests: false); // await server.serve(logRequests: true); // server.log.onRecord.listen((r) => print(r)); SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]).then((_) { runApp(MyApp()); }); }
If you want to navigate to your webview from somewhere:
await navigateToWebView(context, 'file/privacy.html');
The navigation:
Future<String> navigateToWebView( BuildContext context, String pathName) async { return await Navigator.push( context, MaterialPageRoute( builder: (context) => WebViewExample(pathName))); }
And here the webview implementation with the localhost-URL call:
(small detail: the comments are an alternative if you don't want the snackbar)
import 'package:flutter/material.dart'; import 'dart:async'; import 'package:webview_flutter/webview_flutter.dart'; // import 'package:flutter/services.dart'; class WebViewExample extends StatelessWidget { final String pathName; WebViewExample(this.pathName); final Completer<WebViewController> _controller = Completer<WebViewController>(); @override Widget build(BuildContext context) { final String serverURL = 'http://localhost:8080/' + this.pathName; final double screenWidth = MediaQuery.of(context).size.shortestSide; final double screenHeight = MediaQuery.of(context).size.longestSide; return Scaffold( appBar: MyAppBar( title: Text( 'My Title', style: TextStyle( fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.w500), ), ), // body: FutureBuilder<String>( // future: loadAsset(), // builder: (context, snapshot) { // if (snapshot.hasData) { // return WebView( // initialUrl: // Uri.dataFromString(snapshot.data, mimeType: 'text/html') // .toString(), // javascriptMode: JavascriptMode.unrestricted, // onWebViewCreated: (WebViewController webViewController) { // _controller.complete(webViewController); // }, // javascriptChannels: <JavascriptChannel>[ // _toasterJavascriptChannel(context), // ].toSet(), // ); // } else if (snapshot.hasError) { // return Text("${snapshot.error}"); // } // return CircularProgressIndicator(); // }, // ), // We're using a Builder here so we have a context that is below the Scaffold // to allow calling Scaffold.of(context) so we can show a snackbar. body: Builder(builder: (BuildContext context) { return Container( color: Color.fromRGBO( 0x3c, 0x3c, 0x3c, 1), // color for bottom part of iOS safe-area child: SafeArea( child: Stack( fit: StackFit.expand, alignment: AlignmentDirectional.topStart, children: <Widget>[ Positioned( left: 0.0, top: 0.0, width: screenWidth, height: screenHeight, child: Container( child: WebView( initialUrl: serverURL, javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { _controller.complete(webViewController); }, javascriptChannels: <JavascriptChannel>[ _toasterJavascriptChannel(context), ].toSet(), ), ), ), ], ), ), ); }), floatingActionButton: favoriteButton(), ); } // Future<String> loadAsset() async { // return await rootBundle.loadString('assets/web1/index.html'); // } JavascriptChannel _toasterJavascriptChannel(BuildContext context) { return JavascriptChannel( name: 'Toaster', onMessageReceived: (JavascriptMessage message) { Scaffold.of(context).showSnackBar( SnackBar(content: Text(message.message)), ); }); } Widget favoriteButton() { return FutureBuilder<WebViewController>( future: _controller.future, builder: (BuildContext context, AsyncSnapshot<WebViewController> controller) { if (controller.hasData) { return FloatingActionButton( onPressed: () async { final String url = await controller.data.currentUrl(); Scaffold.of(context).showSnackBar( SnackBar(content: Text('Favorited $url')), ); }, child: const Icon(Icons.favorite), ); } return Container(); }); } } enum MenuOptions { showUserAgent, toast, } class SampleMenu extends StatelessWidget { SampleMenu(this.controller); final Future<WebViewController> controller; @override Widget build(BuildContext context) { return FutureBuilder<WebViewController>( future: controller, builder: (BuildContext context, AsyncSnapshot<WebViewController> controller) { return PopupMenuButton<MenuOptions>( onSelected: (MenuOptions value) { switch (value) { case MenuOptions.showUserAgent: _onShowUserAgent(controller.data, context); break; case MenuOptions.toast: Scaffold.of(context).showSnackBar( SnackBar( content: Text('You selected: $value'), ), ); break; } }, itemBuilder: (BuildContext context) => <PopupMenuItem<MenuOptions>>[ PopupMenuItem<MenuOptions>( value: MenuOptions.showUserAgent, child: const Text('Show user agent'), enabled: controller.hasData, ), const PopupMenuItem<MenuOptions>( value: MenuOptions.toast, child: Text('Make a toast'), ), ], ); }, ); } void _onShowUserAgent( WebViewController controller, BuildContext context) async { // Send a message with the user agent string to the Toaster JavaScript channel we registered // with the WebView. controller.evaluateJavascript( 'Toaster.postMessage("User Agent: " + navigator.userAgent);'); } } class NavigationControls extends StatelessWidget { const NavigationControls(this._webViewControllerFuture) : assert(_webViewControllerFuture != null); final Future<WebViewController> _webViewControllerFuture; @override Widget build(BuildContext context) { return FutureBuilder<WebViewController>( future: _webViewControllerFuture, builder: (BuildContext context, AsyncSnapshot<WebViewController> snapshot) { final bool webViewReady = snapshot.connectionState == ConnectionState.done; final WebViewController controller = snapshot.data; return Row( children: <Widget>[ IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: !webViewReady ? null : () async { if (await controller.canGoBack()) { controller.goBack(); } else { Scaffold.of(context).showSnackBar( const SnackBar(content: Text("No back history item")), ); return; } }, ), IconButton( icon: const Icon(Icons.arrow_forward_ios), onPressed: !webViewReady ? null : () async { if (await controller.canGoForward()) { controller.goForward(); } else { Scaffold.of(context).showSnackBar( const SnackBar( content: Text("No forward history item")), ); return; } }, ), IconButton( icon: const Icon(Icons.replay), onPressed: !webViewReady ? null : () { controller.reload(); }, ), ], ); }, ); } } class MyAppBar extends PreferredSize { MyAppBar({Key key, Widget title}) : super( key: key, preferredSize: Size.fromHeight(app_bar_height), // set AppBar height child: AppBar( elevation: 0.0, // represents shaddow of AppBar brightness: Brightness .dark, // makes statusbar shine in dark AppBar environment backgroundColor: Color.fromRGBO(0x3c, 0x3c, 0x3c, 1), // sets AppBar color title: title, // sets AppBar title // maybe other AppBar properties ), ); }
You can provide the complete example of localhost. Jaguar. thank.
got error java.lang.ClassCastException: android.webkit.WebView cannot be cast to com.flutter_webview_plugin.ObservableWebView for the following code
new WebviewScaffold( url: new Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
How to render image using HTML to create Flutter-iOS-App?
new WebviewScaffold( url: new Uri.dataFromString('<html><body>hello world</body></html>', mimeType: 'text/html').toString()
worked for me as well
I seem to be having trouble when the html is too large (maybe). It seems to only work half the time on iOS
How to load custom font(ex: Baamini) in webviewScaffold..?
I want to display some custom html string instead of loading from a url. Is this possible today?