Flutter URL Launcher for HTML content is not working - flutter

I am developing an app using Flutter. Now I need to render the HTML content in my application that includes anchor links. But there is a problem with the links in the HTML content, it is not opening the links in the browser when it is clicked.
This is my code.
Container(
color: Colors.white,
padding: EdgeInsets.only(top: 10, right: 10, bottom: 10, left: 10),
child: Html(
data: htmlContent,
onLinkTap: (link) {
launch(link);
},
))
When I click on it, it is not working.
I imported this library at the top.
import 'package:url_launcher/url_launcher.dart';
What is wrong with my code and how can I fix it?

Html(
data: dataHTML,
onLinkTap: (url, _, __, ___) async {
if (await canLaunch(url!)) {
await launch(
url,
);
}
},
);
In recent versions, flutter_html, when using this event, requests more parameters that fulfill a specific task which is detailed in the documentation, but if the intention is only to launch the Urls, they can do it this way, do not forget to add the <queries> in the AndroidManifest if your app uses API 30 or higher that you specify in using url_launcher

Opening links in HTML works for me like this:
Html(
data: 'This is some link',
onLinkTap: (url) async {
if (await canLaunch(url)) {
await launch(
url,
);
} else {
throw 'Could not launch $url';
}
},
)
Note that I first await the canLaunch method before using launch to open my link.
What was your link? Would you provide us an example? Thanks!

onLinkTap: (url) async {
if (await canLaunch(url)) {
await launch(
url,
);
} else {
throw 'Could not launch $url';
}
},
Also don't forgot to add this in your Manifest file
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>

Related

How to connect Phantom wallet to a Flutter app using deep links?

I'm making a flutter mobile app where I want to connect the user to the Phantom wallet using the connect deep link and then set the redirect_link as a Firebase dynamic link for the app, however I am not getting a response from the Phantom wallet as a query parameters. Any help will be highly appreciated! Thanks.
Install uni_links and url_luncher pakage
add this intent to androidManifest
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with https://YOUR_HOST -->
<data
android:scheme="https"
android:host="[YOUR_HOST]" />
</intent-filter>
then create queryParameter like
Map<String, dynamic> queryParameters = {
"dapp_encryption_public_key":
base58.encode(Uint8List.fromList(keypair.publicKey)),
"cluster": "devnet",
"app_url": "https://google.com",
"redirect_link":
"app://flutterdapp?handleQuery=onConnect}",
};
then lunchUrl
final url =Uri(
scheme: "https",
host: "phantom.app",
path: "/ul/v1/onConnect",
queryParameters: queryParameters,
);
launchUrl(
url,
mode: LaunchMode.externalNonBrowserApplication,
);
and recive data from phantom like
StreamSubscription _sub;
Future<void> initUniLinks() async {
// ... check initialLink
// Attach a listener to the stream
_sub = linkStream.listen((String? link) {
// Parse the link and warn the user, if it is not correct
}, onError: (err) {
// Handle exception by warning the user their action did not succeed
});
// NOTE: Don't forget to call _sub.cancel() in dispose()
}
// ...
hope help you

Can't send an email through url_launcher

I try to send an email whenever a user clicks on an individual's email address. However, I ran into an error. I am testing through the Android emulator. Doesn't it work since there is no mail app on the emulator?
This is the error I get:
PlatformException (PlatformException(ACTIVITY_NOT_FOUND, No Activity found to handle intent { mailto:example#gmail.com?subject=Default%20subject&body=Default%20body }, null, null))
Here is the code:
sendEmail(String email) async {
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
final Uri emailLaunchUri = Uri(
scheme: 'mailto',
path: '$email',
query: encodeQueryParameters(<String, String>{
'subject': 'Default subject',
'body': 'Default body',
}));
await launch(emailLaunchUri.toString());
}
I call it like this:
onTap: () {
setState(() {
sendEmail('example#gmail.com');
});
},
I have configured Android and IOS.
For API >=30, you need to add in AndroidManifest.xml.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
You can find more info from Configuration section.
dependencies:
flutter_email_sender: ^5.0.2
Example:
final Email email = Email(
body: 'Email body',
subject: 'Email subject',
recipients: ['example#example.com'],
cc: ['cc#example.com'],
bcc: ['bcc#example.com'],
attachmentPaths: ['/path/to/attachment.zip'],
isHTML: false,
);
await FlutterEmailSender.send(email);
Setup:
With Android 11, package visibility is introduced that alters the ability to query installed applications and packages on a user’s device. To enable your application to get visibility into the packages you will need to add a list of queries into your AndroidManifest.xml.
<manifest package="com.mycompany.myapp">
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
</manifest>
I use below function for handling email try using it, for sending email through android/ ios using flutter and launch function
launchMail(String toMailId, String subject, String body) async {
final Uri _emailLaunchUri = Uri(
scheme: 'mailto', path: toMailId, query: "subject=$subject&body=$body");
String a = _emailLaunchUri
.toString()
.replaceAll("+", "%20")
.replaceAll("%2520", "%20");
if (await canLaunch(a)) {
await launch(a);
} else {
throw 'Could not launch $a';
}
}

I/UrlLauncher(17669): component name for (url) is null

Why does it throw an error and give me the link is empty even though the link exists?
And when I use launch (url) alone, the link opens without any problems
String StateUrl = 'View App' ;
var url = 'https://www.youtube.com/watch?v=-k0IXjCHObw' ;
body: Column(
children: [
Text(StateUrl),
Center(
child: ElevatedButton.icon(
onPressed: () async{
try {
await canLaunch(url) ?
await launch(url):
throw 'Error';
} catch(e){
setState(() {
StateUrl = e.toString() ;
});
}
},
icon: const Icon(FontAwesomeIcons.link),
label: const Text('View Url')
),
),
],
),
Performing hot reload
D/EGL_emulation(17669): app_time_stats: avg=17852.65ms min=658.78ms
max=35046.52ms count=2 I/UrlLauncher(17669): component name for
https://www.youtube.com/watch?v=-k0IXjCHObw is null
D/EGL_emulation(17669): app_time_stats: avg=8279.72ms min=8279.72ms
max=8279.72ms count=1
You have to add <queries> elements to you AndroidManifest.xml file.
more info
try using
await launch(url);
instead of
if (await canLaunch(url)) { print("launching $url"); await launch(url); } else { throw 'Could not launch maps'; }
it seems theres a problem with canLaunch(url) function
With link can handle via other app like youtube, spreadsheets, document...
from android 11 (API 30) and above you must add this permission to AndroidManifest.xml
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
please refer:
https://developer.android.com/training/package-visibility/declaring
don't use canLaunch with videos URL just use try/catch
If you come here looking for why your email link (mailto:email#example.com) doesn't work, then try this out.
Don't call canLaunch for mailto links - use it only for http and https!
Since I have both http(s) and mailto links in my app, I use the try-catch block.
Here is the full function:
class UrlHandler {
/// Attempts to open the given [url] in in-app browser. Returns `true` after successful opening, `false` otherwise.
static Future<bool> open(String url) async {
try {
await launch(
url,
enableJavaScript: true,
);
return true;
} catch (e) {
log(e.toString());
return false;
}
}
}
You can use this code, it works for me. Check it out:
_launchURL() async {
const url = 'https://en.wikipedia.org/wiki/Body_mass_index';
if (await launch(url)) {
await canLaunch(url);
} else {
throw 'Could not launch $url';
}
}
and use this _launchURL() function in onPressed();
Try is like this:
try {
if(await canLaunch(url)) await launch(url):
} catch(e){
setState(() {
StateUrl = e.toString() ;
});
throw e;}
},
maybe a little late, but i also had the same problem. The solution was so set an intent in the android manifest file. If this is done, the canLaunch() call will not fail, cause you allow the android system to query this url.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="youtube.com" />
</intent>
</queries>
For comparison, the url launcher now prints following text to the console:
I/UrlLauncher( 2628): component name for <your youtube link> is {com.google.android.youtube/com.google.android.youtube.UrlActivity}
Further if you set the launchMode to LaunchMode.externalApplication the youtube app will launch, if installed.
Hope this helps.
Also Google updates his PolicyBytes and I think using
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
or
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
might lead to app rejects, if you can not explain in detail why you need to use those permissions.
Regards Max.
The url_launcher requires a Uri object to be passed instead of a string. Add a Uri.parse
String StateUrl = 'View App' ;
var url = 'https://www.youtube.com/watch?v=-k0IXjCHObw' ;
body: Column(
children: [
Text(StateUrl),
Center(
child: ElevatedButton.icon(
onPressed: () async{
try {
Uri uri = Uri.parse(url);
await canLaunch(uri) ?
await launch(uri):
throw 'Error';
} catch(e){
setState(() {
StateUrl = e.toString() ;
});
}
},
icon: const Icon(FontAwesomeIcons.link),
label: const Text('View Url')
),
),
],
),
for me the solution is
to copy and paste
<!-- Provide required visibility configuration for API level 30 and above -->
<queries>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<!-- If your app checks for call support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
</queries>
from official packages docs
but the problem is that the package removed the next lines from code snippet
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
so add them first to the
I just used this and it worked...(nb:Dec 2022)
if (!await launchUrl(url)) {
throw 'Could not launch $url';
}
Try using await launch(url); instead of
if (await canLaunch(url)) {
print("launching $url");
await launch(url);
}
else {
throw 'Could not launch maps';
}
It seems theres a problem with canLaunch(url) function
Thank you for this Solution :)

flutter + firebase passwordless email login - dynamic link data returns null

I am trying to implement passwordless email login on my app.
After the link has been clicked on, the app returns from the background but the dynamic link is null.
This is how I send the mail (with the right values for my app of course):
user.sendSignInWithEmailLink(
email: _email,
androidInstallIfNotAvailable: true,
iOSBundleID: "com.company.appname",
androidMinimumVersion: "16",
androidPackageName: "com.company.appname",
url: "https://appname.page.link/email",
handleCodeInApp: true);
I also added the intent as follows:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="appname.page.link" android:scheme="http"/>
<data android:host="appname.page.link" android:scheme="https"/>
</intent-filter>
Tried different variations with the intent, and non helped, including writing the firebase
project url as the host like: project-name.firebaseapp.com
The data still comes back empty.
Any thoughts? am I missing something?
I've updated the firebase_dynamic_links package to the latest version (0.5.0+9),
while using the configuration below and it starts working.
Sending sign-in link configuration:
firebaseAuth.sendSignInWithEmailLink(
email: email,
url: "https://mydemoapp.page.link/email",
androidInstallIfNotAvailable: true,
androidMinimumVersion: '21',
androidPackageName: 'com.example.mydemoapp'
handleCodeInApp: true,
iOSBundleID: 'com.example.mydemoapp');
AndroidManifest.xml intent-filter configuration:
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<data android:host="mydemoapp.page.link" android:scheme="https"/>
<data android:host="mydemoapp.page.link" android:scheme="http"/>
</intent-filter>
Getting a dynamic link in Flutter.
The example comes form from https://pub.dev/packages/firebase_dynamic_links
If your app did not open from a dynamic link, getInitialLink() will return null. That's the reason why you have to FirebaseDynamicLinks.instance.onLink implemented in case the app is already opened.
void main() {
runApp(MaterialApp(
title: 'Dynamic Links Example',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => MyHomeWidget(), // Default home route
'/helloworld': (BuildContext context) => MyHelloWorldWidget(),
},
));
}
class MyHomeWidgetState extends State<MyHomeWidget> {
.
.
.
#override
void initState() {
super.initState();
this.initDynamicLinks();
}
void initDynamicLinks() async {
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
}
.
.
.
}
The mydemoapp.page.link must be added to Authorized domains in Firebase console
Is it appname.page.link or appname.page.link/email you have to specify only one email in order to achieve that
If coming to this answer in March 2022, this error is happening again and it's a bug on Flutterfire.
Here is the issue with a Pull Request that hasn't been merged yet.

How to send email with flutter?

I tried all packages to send email ( flutter_email_sender - flutter_mailer -url_launcher), copy and paste the example, but always the same error message : " MissingPluginException(No implementation found for methode ...), I serach a simple example to send email on press button.
thank you
To use latest version of url_launcher or above version of 4.1.0+1
, you have to migrate to android x.
[https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility][1]
Example:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class SendEmail extends StatelessWidget {
void _contact() async {
final url = 'mailto:dude#gmail.com';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){_contact()},
child: Text('Mail'),
),
}
}
try adding these lines on AndroidManifest.xml
<!-- Provide required visibility configuration for API level 30 and above -->
<queries>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<!-- If your app checks for call support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
</queries>
then run flutter clean, then build again
it work for me but this is specific for url_launcher