Flutter, WebView - rebuild with custom HTML - flutter

I want to show some generated HTML in a WebView in my Flutter App.
The StatefulWidget which contains the WebView can change certain properties upon which the WebView would have to rebuild.
TL;DR: How to supply custom HTML without initialUrl?
Up to now I used the initialUrl propety of the WebView constructor to supply an URI with my HTML directly embedded:
WebView(
initialUrl: Uri.dataFromString(myHtml, mimeType: 'text/html').toString(),
)
Now I realized, I must rebuild the WebView with different values when some states get set. (Namely a dropdown above the WebView). As the name tells, this URI is just initial.
So my question is: How can I update the HTML in the WebView? Is there maybe some way to reset the internal state of the WebView?

I guess webview's api doesn't allow to do that, but you can use a workaround: just save the HTML to temp file and provide an URI to WebView using initialUrl. Here's the example:
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Uri uri;
Future<void> _showHtml(String html) async {
final tempDir = await getTemporaryDirectory();
final path = join(tempDir.path, 'page.html');
final tempFile = File(path);
tempFile.writeAsStringSync(html);
setState(() {
uri = Uri(scheme: 'file', path: path);
});
}
#override
void initState() {
super.initState();
_showHtml('<html>Test</html>');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: uri != null ? WebView(
initialUrl: uri.toString(),
) : Container()
),
);
}
}
You can also use onWebViewCreated callback to save webview's controller and use the controller later to load other using loadUrl method.

Related

Flutter scrape Google Shopping

I am trying to get a product price by searching for the product in Google Shopping with a given title and storeName.
I found this question on SO, which explains how you would do it with Python. How can something like this be done with Flutter?
Also like I said, is there any way to select the store?
I couldn't find anything on this. Any help is appreciated. Let me know if you need any more info!
I tried it like this:
Future<void> getGoogleShoppingResult() async {
const String requestUrl =
'https://www.google.com/search?q=minecraft+toys&tbm=shop';
final response = await http.get(Uri.parse(requestUrl));
dom.Document document = parser.parse(response.body);
final elements = document.querySelectorAll(
'div.sh-np__product-title.translate-content',
);
print(elements.first.innerHtml);
}
With this I tried to get the title of the first found product. But this never finds any product, even though I copied the selector from Google Shopping.
You should use these packages:
webview_flutter
http
html
And wait till JavaScript has been loaded.
This tutorial can help:
https://www.youtube.com/watch?v=EHk66k___EY
The code snippet:
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:html/dom.dart' as dom;
class WebViewPageExample extends StatefulWidget {
const WebViewPageExample({Key? key}) : super(key: key);
#override
State<WebViewPageExample> createState() => _WebViewPageExampleState();
}
class _WebViewPageExampleState extends State<WebViewPageExample> {
late WebViewController _controller;
#override
Widget build(BuildContext context) {
return WebView(
onWebViewCreated: _onWebViewCreated,
javascriptMode: JavascriptMode.unrestricted,
initialUrl: "https://www.google.com/search?q=minecraft+toys&tbm=shop",
onPageFinished: _onPageFinished,
);
}
void _onWebViewCreated(WebViewController controller) {
_controller = controller;
}
Future _onPageFinished(String url) async {
final html = await _controller.runJavascriptReturningResult(
"new XMLSerializer().serializeToString(document);");
final div = dom.Document.html(html)
.querySelectorAll('div.sh-np__product-title.translate-content');
log('Count: ${div.length}');
}
}

Post and get data using flutter webview

I'm having a problem with Flutter. More precisely, since it is not a language that I have a command of, I did something by looking at the videos. Of course, old videos etc. I've been in trouble.
First of all, I will write what I want to do and what I failed to achieve. I am pulling my website into application with webview. There is no problem here. Then I added onesignal. This also works flawlessly. But I want to get the id called playerid that onesignal defines for each device and post it to my php page. I tried many plugins for this, but I could not succeed. Then I sent it as a cookie, it still didn't work. I realized that I can send data as get in the latest webview link, but the fact that I can't pull the variable I created here also infuriated me. I'm adding the codes below and asking for help from an expert friend. If there is, you can suggest an easy way to POST and GET. Thanks everyone in advance.
In the code below, I can't get the variable that I defined as userid and printed in the link section. In the simplest way, if I do this, it can work for now.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:dio/dio.dart';
void main() async {
runApp(PnlbaseApp());
}
class PnlbaseApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PNLBASE APP',
home: PnlbaseAppPage(),
);
}
}
class PnlbaseAppPage extends StatefulWidget {
PnlbaseAppPage({Key? key}) : super(key: key);
#override
_PnlbaseAppPageState createState() => _PnlbaseAppPageState();
}
class _PnlbaseAppPageState extends State<PnlbaseAppPage> {
#override
void initState() {
super.initState();
OneSignal.shared.setLogLevel(OSLogLevel.verbose, OSLogLevel.none);
OneSignal.shared.setAppId("APP-ID");
OneSignal.shared.promptUserForPushNotificationPermission().then((accepted) {
print("Accepted permission: $accepted");
});
OneSignal.shared.getDeviceState().then((deviceState) {
print("OneSignal: device state: ${deviceState?.jsonRepresentation()}");
var userid;
userid = deviceState?.userId;
print(userid);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: true,
child: WebView(
initialUrl: "https://app.pnlbase.com/login?playerid",
javascriptMode: JavascriptMode.unrestricted,
),
),
);
}
}

i am trying to load dynamic url as intial url bt its not load in webview. if i put url into tem var and used temp as intial url then it will work

Here I am trying to load deep link in webview first enter the deep link in google and its redirect to the app and load deep link in webview. if I put static URL like var temp = "www.google.com" and then used temp var as initial URL in webview it will load the google in-app. but I tried to copy deep link var into string var and used temp var as initial URL in webview it will no load dynamic link in webview. even I converted deep link var into a string (typecast URI to string)
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:firebase_dynamic_links/firebase_dynamic_links.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(MaterialApp(
title: 'Dynamic Links Example',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => _MainScreen(),
},
));
}
class _MainScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MainScreenState();
}
class _MainScreenState extends State<_MainScreen> {
String temp;
// String temp = "www.google.com"; // this will work correct as intial url in webview
#override
void initState() {
initDynamicLinks();
super.initState();
}
Future initDynamicLinks() async {
// 1. Get the initial dynamic link if the app is opened with a dynamic link
final PendingDynamicLinkData data =
await FirebaseDynamicLinks.instance.getInitialLink();
// 2. handle link that has been retrieved
_handleDeepLink(data);
// 3. Register a link callback to fire if the app is opened up from the background
// using a dynamic link.
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
// 3a. handle link that has been retrieved
_handleDeepLink(dynamicLink);
}, onError: (OnLinkErrorException e) async {
print('Link Failed: ${e.message}');
});
}
#override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
appBar: AppBar(
title: const Text('Dynamic Links Example'),
),
body: Builder(builder: (BuildContext context) {
return Center(
child: WebView(
initialUrl: temp, // dynamic url copy from deep link var it will not load in web view
javascriptMode: JavascriptMode.unrestricted,
),
);
}),
),
);
}
void _handleDeepLink(PendingDynamicLinkData data) {
final Uri deepLink = data?.link;
if (deepLink != null) {
temp = deepLink.toString(); // here i had done type casting to uri to string
print('_handleDeepLink | deeplink: $deepLink');
}
}
}
To redirect the WebView dynamically, you will need to get the WebViewController variable after the WebView loaded. Then call .loadUrl(newUrl);
For example you create the _webControl variable outside the build function first:
late WebViewController _webControl;
#override
Widget build(BuildContext ctx) {
...
Then assign the _webControl inside the WebView after it created:
WebView(
initialUrl: firstTimeURL,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_webControl=webViewController;
webViewController.evaluateJavascript('''alert("Henlo from flutter")''');
},
),
Finnaly call .loadUrl(xxx) whenever you want (inside a material button,...). No need to setState:
_webControl.loadUrl(temp);

How to open a PDF file in a Flutter App and have a selectable view?

I want to implement a App in Flutter that allows the user to view PDF-files and select and copy the text thereinin so that I can proceed using the copied text from the Clipboard.
To be more precise I want want my Code to be somewhat like the following but with a package that allows to copy from the displayed PDF file.
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:pdf_viewer_plugin/pdf_viewer_plugin.dart';
import 'package:flutter/services.dart';
class PDFPage extends StatefulWidget {
final File file;
final Function onPressed;
const PDFPage(this.file,this.onPressed);
#override
_PDFPageState createState() => _PDFPageState();
}
class _PDFPageState extends State<PDFPage> {
#override
void initState() {
Clipboard.setData(ClipboardData(text: ''));
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PdfViewer(
filePath: widget.file.path,
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.beach_access),
onPressed: ()async{
ClipboardData data = await Clipboard.getData('text/plain');
widget.onPressed(data);
},
),
);
}
}
The package I am using here is
pdf_viewer_plugin: ^1.0.0+2
That seems not to work. It does display the PDF file but I can't select text or copy from it. I have also tried
flutter_full_pdf_viewer: ^1.0.6
advance_pdf_viewer: ^1.1.6
and some more I can't remind the name of.
Is there a package that allows me to do so, or a modest way to either modify or create such a package?
Thanks a lot.

Is it possible to load PDF File From Google Drive using flutter_plugin_pdf_viewer?

I had tried but it doesn't load pdf file. This is My Code
import 'package:flutter/material.dart';
import 'package:flutter_plugin_pdf_viewer/flutter_plugin_pdf_viewer.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _isLoading = true;
PDFDocument document;
#override
void initState() {
super.initState();
loadDocument();
}
loadDocument() async {
document = await PDFDocument.fromUrl('https://drive.google.com/drive/u/0/folders/1ei6916qmZ34LZECNf5e0DlvB7EJqxqz8');
setState(() => _isLoading = false);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('PDF FILE'),
),
body: Center(`enter code here`
child: _isLoading
? Center(child: CircularProgressIndicator())
: PDFViewer(document: document)),
),
);
}
}
It seems like the id in your link (https://drive.google.com/drive/u/0/folders/1ei6916qmZ34LZECNf5e0DlvB7EJqxqz8) is a folder id.
To get your link, open the file
in a new window and copy the Url into your code.
If the link doesn't work, try the following link format in which you insert the file Id from the Url you got previously.
https://drive.google.com/file/d/fileId/
For this you need to be autenticated user of Google.
And after successfully login
Use these api to ge the drive data:
https://www.googleapis.com/drive/v2/files
and also you need to pass the token over the header with Authorization key:
"Authorization" = "Bearer " + token
or simply you can create a public link of your file, than copy url and use it.