Flutter : Replace LaunchUrl with WebView - flutter

Within my flutter app, I am launching a payment gateway using the url_launcher plugin with opens the page in a browser. However I would rather have it open in a WebView plugin instead, within the app.
Do I need to use both? how can implement such.
Please assist
Url launcher
if (selectedPaymentMethod == 'Pay Now' &&
_formKey.currentState!.validate()) {
() async {
final ozowApiRes = await OzowApiProvider()
.createPaymentRequest(
'R${(cart.totalAmount + cart.serviceFee + value * cart.newCylinderPrice).toStringAsFixed(0)}',
userData?['username'],
userData?['phoneNumber'],
userData?['email'],
);
() async {
try {
await launchUrl(
Uri.parse(ozowApiRes.data),
);
} catch (ex) {
throw 'Could not launch $ozowApiRes';
}
}();
}();

To do this, you can use url_launcher or flutter_inappwebview. I will recommend you to use flutter_inappwebview if possible cause url_launcher 100% not guaranteed you to launch in inAppWebView and also flutter_inappwebview gives you the granular controll in a page.
(1) you can use url_launcher with mode LaunchMode.inAppWebView
await launchUrl(
Uri.parse("https://www.google.com/"),
mode: LaunchMode.inAppWebView,
);
(2) or you can use a stateless widget page with flutter_inappwebview and just pass the purchase url
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class InAppPurchasePage extends StatelessWidget {
const InAppPurchasePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Purchase Page"),
),
body: InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse(
"https://flutter.dev",
),
),
),
);
}
}

Related

The Enter/Return key is not being read on a flutter webview using the webview_flutter package

I'm using the Plaid Link Web View for a flutter project i'm working on. I have installed the latest Webview Flutter package. The web view has a text box to search for an institution (see Image 1.0).
Here's where i'm building the webview.
import 'package:ditch/settings.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class PlaidWebView extends StatefulWidget {
final String linkToken;
const PlaidWebView({
super.key,
required this.linkToken,
});
#override
State<PlaidWebView> createState() => _PlaidWebViewState();
}
class _PlaidWebViewState extends State<PlaidWebView> {
bool isAuthenticated = false;
late String publicToken;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
margin: const EdgeInsets.fromLTRB(15, 50, 15, 50),
child: WebView(
initialUrl:
'https://cdn.plaid.com/link/v2/stable/link.html?isWebview=true&token=${widget.linkToken}',
javascriptMode: JavascriptMode.unrestricted,
navigationDelegate: (request) {
if (request.url.contains('plaidlink://connected')) {
isAuthenticated = true;
return NavigationDecision.navigate;
} else if (request.url.contains('plaidlink://exit')) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const Settings()),
);
return NavigationDecision.prevent;
} else {
print(request);
return NavigationDecision.navigate;
}
},
),
),
);
}
}
The Web View registers key inputs and updates the search query succesfully, this is the HTTP redirect when I type let's say "First Platypus Bank"]
flutter: NavigationRequest(url: plaidlink://event?error_code=&error_message=&error_type=&event_name=SEARCH_INSTITUTION&exit_status=&institution_id=&institution_name=&institution_search_query=**first%20platypus%20bank**&...)
However, it does not register when I press the "Enter/Return" key on either a physical keyboard or on the I/O on the iOS simulator, or the keyboard on the phone when I run it from xcode directly on to my device. The results will not update unless I press the enter/return key.
Image 1.0
I have visited the same web view on my browser and the results don't update automatically either but it does update when I press enter on the keyboard.
When I run this to my physical device using flutter this is the console output on the text input (may be unrelated)
2022-11-28 07:49:42.430862-0500 Runner[7222:1919659] Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
I've scraped the web for some time and I don't see other with the same issue, anyone have any thoughts?
I resolved this issue by using the the Plaid Flutter plugin it does a really great job at natively integrating with both android and iOS and has a bunch of useful methods. Would highly advise you go this route.

'launch' is deprecated and shouldn't be used. Use launchUrl instead. - Flutter

Following all tutorials and articles online, everybody is using launch() function from the known url_launcher plugin to open links, so i used it in my application to open messenger, whatsApp, and directcalls as follows:
_directCall() {
launch('tel:00962785522213');
}
//Open WhatsApp
_launchWhatsapp() {
launch("https://wa.me/+962797809910");
}
//Open Messenger
_openMessenger() {
launch("http://m.me/amr.al.shugran");
}
but unfortunately the launch method is no longer used and i have to use launchUrl() so i would be thankful if anyone could tell us how to use this function at the same context am using launch().
You need to use
//Open Messenger
_openMessenger() {
launchUrl(Uri.parse("http://m.me/amr.al.shugran"));
}
Try it
Future _launchUrl(url) async {
if (!await launchUrl(Uri.parse(url))) {
throw 'Could not launch $url';
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: OutlinedButton(
onPressed: () async {
_launchUrl('www.google.com');
},
child: const Text('Open'),
),
);
}

How to write platform specific code for web in flutter?

In flutter, we use platform channels that allows us to call platform-specific APIs whether available in Kotlin or Java code on Android, or in Swift or Objective-C code on iOS.
How to achieve the same with web in flutter ? How can one use a npm package and write some javascript code and send the result to flutter? Is this even possible ? There is official docs for writing platform specific code for Android and iOS, but I couldn't find any docs for writing platform specific code for web.
Also, I tried using the js package. If this is the one that has to be used for this case, how to use it ?
This is what I do to display Hubspot chat on Flutter Web.
I have a folder for Hubspot with:
index.html
script.js
style.css
Then a Flutter Widget with webview_flutter_plus plugin:
class HubspotWebview extends StatefulWidget {
#override
_HubspotWebviewState createState() => _HubspotWebviewState();
}
class _HubspotWebviewState extends State<HubspotWebview> {
final _javascriptChannels = Set<JavascriptChannel>();
bool loading = true;
#override
void initState() {
super.initState();
_javascriptChannels.add(JavascriptChannel(
onMessageReceived: (JavascriptMessage message) {
debugPrint('message: ' + message.message);
_toggleLoading();
},
name: 'Loading'));
}
#override
Widget build(BuildContext context) {
final path = '${kIsWeb ? 'assets/' : ''}assets/hubspot_web_page/index.html';
final key = 'web_bot_key';
if (kIsWeb) {
ui.platformViewRegistry.registerViewFactory(
key,
(int viewId) => IFrameElement()
..width = '640'
..height = '360'
..src = path
..style.border = 'none'
..onLoadedData.listen((event) {
_toggleLoading();
}));
}
return Scaffold(
appBar: new AppBar(
backgroundColor: MyColors.blue_business,
title: MyText.subtitle(
getText('business_help_chat', backUpText: 'Help Chat'),
color: MyColors.white_rice,
)),
body: Stack(
children: [
kIsWeb
? HtmlElementView(viewType: key)
: WebViewPlus(
javascriptMode: JavascriptMode.unrestricted,
initialUrl: path,
javascriptChannels: _javascriptChannels,
),
if (loading)
Center(child: CircularProgressIndicator()),
],
),
);
}
void _toggleLoading() => setState(() => loading = !loading);
}
On Javascript file Loading.postMessage('') triggers toggleLoading() on Flutter:
function onConversationsAPIReady() {
window.hsConversationsSettings = {
inlineEmbedSelector: '#hubspot-conversations-inline-parent',
enableWidgetCookieBanner: true,
disableAttachment: true
};
window.history.pushState({}, 'bot', '?bot=true');
window.HubSpotConversations.widget.refresh({openToNewThread: true});
Loading.postMessage('');
}
if (window.HubSpotConversations) {
onConversationsAPIReady();
} else {
window.hsConversationsOnReady = [onConversationsAPIReady];
}

Trying to launch an external url via callback passed into a custom widget in Flutter

I have a small widget for a website button.
class WebsiteButton extends StatelessWidget {
final String url;
final Future<void> launchCallback;
WebsiteButton(this.url, this.launchCallback);
#override
Widget build(BuildContext context) {
if (url != null && url.isNotEmpty) {
return IconButton(
icon: Icon(FontAwesomeIcons.globe),
tooltip: url,
onPressed: () => launchCallback,
);
} else {
return IconButton(
icon: Icon(FontAwesomeIcons.globe),
onPressed: null,
);
}
}
}
To make it more reusable (e.g. in case I wanna set different logic of launching url in a webview instead of browser) I'm trying to pass the callback _launch into the widget like this:
Future<void> _launch(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false,
forceWebView: false,
);
} else {
throw 'Could not launch $url';
}
}
...
WebsiteButton(
profile.website,
_launch(profile.website)
),
It results in a strange behaviour: the url launches as soon as the page containing the widget is built, not as the IconButton is clicked as I expected. What am I missing?
(Flutter master v1.12.16-pre.35, url_launcher: 5.2.7)
It looks like the method that you are passing to the widget as a parameter is being called when you pass it. If you make the changes the other comment suggests, and also use an anonymous function that calls the _launch method with the url string as the parameter for the widget.
So, it would look like this:
WebsiteButton(
profile.website,
() => _launch(profile.website)
)
Or you could pass the url and the _launch method to the WebsiteButton, and then call _launch with the url inside WebsiteButton.

flutter download an Image from url

I'm trying to load image from server using networkimage() and I want to download the same once it is loaded.. can anyone suggest me some ideas.
CircleAvatar(
backgroundImage: NetworkImage(url),
maxRadius: 15.0,
);
Here I'm loading image from my server. I want to save to the image to particular path after the image is loaded.
I recently battled this, and decided to solve it without plugins. I hope it helps someone.
The below program downloads a picture from the web, stores it in the device's local path, and then displays it when run. (note, it does not work for flutter web because you don't have access to the local file storage on that platform. Instead you would have to save the image to a local database using a plugin like sqflite, or hive from pub.dev.) Here's the code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' show get;
import 'dart:io';
import 'package:path_provider/path_provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test Image',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Test Image'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
initState() {
_asyncMethod();
super.initState();
}
_asyncMethod() async {
//comment out the next two lines to prevent the device from getting
// the image from the web in order to prove that the picture is
// coming from the device instead of the web.
var url = "https://www.tottus.cl/static/img/productos/20104355_2.jpg"; // <-- 1
var response = await get(url); // <--2
var documentDirectory = await getApplicationDocumentsDirectory();
var firstPath = documentDirectory.path + "/images";
var filePathAndName = documentDirectory.path + '/images/pic.jpg';
//comment out the next three lines to prevent the image from being saved
//to the device to show that it's coming from the internet
await Directory(firstPath).create(recursive: true); // <-- 1
File file2 = new File(filePathAndName); // <-- 2
file2.writeAsBytesSync(response.bodyBytes); // <-- 3
setState(() {
imageData = filePathAndName;
dataLoaded = true;
});
}
String imageData;
bool dataLoaded = false;
#override
Widget build(BuildContext context) {
if (dataLoaded) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.file(File(imageData), width: 600.0, height: 290.0)
],
),
),
);
} else {
return CircularProgressIndicator(
backgroundColor: Colors.cyan,
strokeWidth: 5,
);
}
}
}
pubspec.yaml file:
http: ^0.12.1
path_provider: ^1.6.5
flutter version: 1.20.0-3.0.pre.112
dart version 2.9.0-19.0.dev
I recommend image_downloader.
For ios, image is saved in Photo Library.
For Android, image is saved in Environment.DIRECTORY_DOWNLOADS or specified location. By calling inExternalFilesDir(), specification of permission becomes unnecessary.
By callback(), you can get progress status.
The following is the simplest example. It will be saved.
await ImageDownloader.downloadImage(url);
I used image_downloader.
Use await ImageDownloader.downloadImage("url") of image_downloader package's method to download image using it's url.
Note : above method will return value as follows :-
imageId of the saved image if saving succeeded.
null if not been granted permission.
for this you have to ask for storage permission, just add following line into android manifest file :
uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
Otherwise it is a PlatformException.
I tried many solution, but this is simplest solution for my... Just try it
STEP - 1
Add this package in your pubspec.yaml file
dependencies:
image_downloader: ^0.20.1
STEP - 2
Add this in your dart file
import 'package:image_downloader/image_downloader.dart';
STEP - 3
Write this code on press download button
ColButton(
title: 'Download',
icon: Icons.file_download,
onTap: () async {
try {
showLoadingDialog(context);
// Saved with this method.
var imageId =
await ImageDownloader.downloadImage("https://raw.githubusercontent.com/wiki/ko2ic/image_downloader/images/bigsize.jpg");
if (imageId == null) {
return;
}
// Below is a method of obtaining saved image information.
var fileName = await ImageDownloader.findName(imageId);
var path = await ImageDownloader.findPath(imageId);
var size = await ImageDownloader.findByteSize(imageId);
var mimeType = await ImageDownloader.findMimeType(imageId);
Navigator.pop(context);
showToast('Image downloaded.');
} on PlatformException catch (error) {
print(error);
}
},
),
I use this plugin to save image in the phone using an URL
https://pub.dartlang.org/packages/image_picker_saver
For more advanced handling of Image/File downloads, you can consider the flutter_downloader package.
Some of the features that I like are :
Shows OS level download progress
can track all downloads
Has notification