I currently have a widget that I use to open a specific webpage using the LaunchUrl feature from the URL_Launcher package.
Throughout my app there are several instances where I'd like to open a webpage using this exact method, but I suppose it's not very efficient to copy-paste the widget I created for this over and over again, and simply replacing the URL.
This is the widget I have written, which is working. But this one is opening a specific URL.
Future<void> openHCReservationPortal(String url) async {
final url = Uri.parse('');
if (!await launchUrl(url, mode: LaunchMode.platformDefault)) {
throw Exception('Kon $url niet openen');
}
}
I'd like to have the url be a parameter, so I can reuse the widget.
I have tried to create a statefull widget with a required parameter but got all sorts of errors, so I must be missing something or doing something wrong.
This is what I wrote:
class OpenWebPageWidget extends StatefulWidget {
final String url;
const OpenWebPageWidget({super.key, required this.url});
@override
State<OpenWebPageWidget> createState() => _OpenWebPageWidgetState();
}
class _OpenWebPageWidgetState extends State<OpenWebPageWidget> {
@override
Widget build(BuildContext context) {
Future<void> openWebPageWidget(String url) async {
final url = Uri.parse(url);
if (!await launchUrl(url, mode: LaunchMode.platformDefault)) {
throw Exception('Kon $url niet openen');
}
}
}
}
Flutter is complaining that:
- The body might complete normally, causing 'null' to be returned, but the return type, 'Widget', is a potentially non-nullable type. Try adding either a return or a throw statement at the end.
- The declaration 'openWebPageWidget' isn't referenced.
I currently have a widget that I use to open a specific webpage using the LaunchUrl feature from the URL_Launcher package.
Throughout my app there are several instances where I'd like to open a webpage using this exact method, but I suppose it's not very efficient to copy-paste the widget I created for this over and over again, and simply replacing the URL.
This is the widget I have written, which is working. But this one is opening a specific URL.
Future<void> openHCReservationPortal(String url) async {
final url = Uri.parse('https://portal.mijnhandicart.nl/site/login');
if (!await launchUrl(url, mode: LaunchMode.platformDefault)) {
throw Exception('Kon $url niet openen');
}
}
I'd like to have the url be a parameter, so I can reuse the widget.
I have tried to create a statefull widget with a required parameter but got all sorts of errors, so I must be missing something or doing something wrong.
This is what I wrote:
class OpenWebPageWidget extends StatefulWidget {
final String url;
const OpenWebPageWidget({super.key, required this.url});
@override
State<OpenWebPageWidget> createState() => _OpenWebPageWidgetState();
}
class _OpenWebPageWidgetState extends State<OpenWebPageWidget> {
@override
Widget build(BuildContext context) {
Future<void> openWebPageWidget(String url) async {
final url = Uri.parse(url);
if (!await launchUrl(url, mode: LaunchMode.platformDefault)) {
throw Exception('Kon $url niet openen');
}
}
}
}
Flutter is complaining that:
- The body might complete normally, causing 'null' to be returned, but the return type, 'Widget', is a potentially non-nullable type. Try adding either a return or a throw statement at the end.
- The declaration 'openWebPageWidget' isn't referenced.
- To launch a URL a reusable method may be a better option. You method only needs slight modification. Please check out my answer below. – rusty Commented Feb 16 at 2:26
3 Answers
Reset to default 3You can easily pass the URL as a string to the simple function as below:
Future<void> launchMyURL(String url) async {
if (url.isEmpty) {
throw 'Given URL is empty';
}
final Uri uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
throw 'Could not launch $url';
}
}
Then you can call the function to launch the URL from anywhere you like, e.g. from an elevated button:
ElevatedButton(
onPressed: () async {
try {
await launchMyURL("https://www.google/");
} catch (e) {
print("#### Caught exception: ${e.toString()}");
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
textStyle: const TextStyle(fontSize: 16.0),
),
child: const Text(
"Click to launch URL",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.normal,
fontSize: 16.0,
),
),
),
Currently in your code, your build
method has a Widget
return type, but you are not returning any widget from the method, and only calling a function of Future<void>
type, so the warning.
And, your method openHCReservationPortal
can be slightly modified to achieve what you need. Here is the modified version:
Future<void> openHCReservationPortal(String url) async {
final urlLaunch = Uri.parse('https://portal.mijnhandicart.nl/site/login');
if (!await launchUrl(urlLaunch, mode: LaunchMode.platformDefault)) {
throw Exception('Kon $url niet openen');
}
}
You can modify your method with the above changes and also include the check with canLaunchUrl
instead of directly calling launchUrl
.
The errors you're encountering stem from two primary issues in your OpenWebPageWidget implementation:
Non-Exhaustive Return in build
Method: In Dart, every code path in a function with a non-nullable return type must return a value. Your build
method currently lacks a return statement.
try this :
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class OpenWebPageWidget extends StatelessWidget {
final String url;
const OpenWebPageWidget({Key? key, required this.url}) : super(key: key);
Future<void> _openWebPage() async {
final uri = Uri.parse(url);
if (!await launchUrl(uri, mode: LaunchMode.platformDefault)) {
throw Exception('Could not open $url');
}
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _openWebPage,
child: const Text('Open Web Page'),
);
}
}
and use it like this:
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('URL Launcher Example'),
),
body: Center(
child: OpenWebPageWidget(url: 'https://example'),
),
);
}
}
The code you have Provided is not a Widget
it is a Function of type Future<void>
Future<void> openHCReservationPortal(String url) async {
final url = Uri.parse('https://portal.mijnhandicart.nl/site/login');
if (!await launchUrl(url, mode: LaunchMode.platformDefault)) {
throw Exception('Kon $url niet openen');
}
}
The body might complete normally, causing 'null' to be returned, but the return type, 'Widget', is a potentially non-nullable type. Try adding either a return or a throw statement at the end.
This error is because the build
method return type is a Widget
but you did not return anything and it is need a return value of a Widget
too , So try to return a Widget like a Scaffold or whatever you want to return then you can use your method when an event happened like click on a button or any change in the UI or you can call it on another method
Example
class OpenWebPageWidget extends StatelessWidget {
const OpenWebPageWidget({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: MaterialButton(
onPressed: () {
LaunchURL.openWebPageWidget(
url: "https://portal.mijnhandicart.nl/site/login");
},
color: Colors.cyan,
),
),
);
}
}
Function: It's better to create it inside the class
class LaunchURL {
static Future<void> openWebPageWidget({
required String url,
}) async {
final Uri uri = Uri.parse(url);
if (!await canLaunchUrl(uri)) {
log("Error while luanch URL");
return;
}
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
}