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

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 :)

Related

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';
}
}

Flutter URL Launcher for HTML content is not working

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>

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.

Flutter email sender

I have this error when I send an email from form in flutter.
Unhandled Exception: PlatformException(UNAVAILABLE, defualt mail app not available, null)
class _MyAppState extends State<MyApp> {
List<String> attachment = <String>[];
TextEditingController _subjectController =
TextEditingController(text: 'ct');
TextEditingController _bodyController = TextEditingController(
text: ''' a
''');
final GlobalKey<ScaffoldState> _scafoldKey = GlobalKey<ScaffoldState>();
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> send() async {
// Platform messages may fail, so we use a try/catch PlatformException.
final MailOptions mailOptions = MailOptions(
body: 'Ro',
subject: 'the Email Subject',
recipients: ['rodrigo#houlak.com'],
isHTML: true,
attachments: [ 'path/to/image.png', ],
);
await FlutterMailer.send(mailOptions);
String platformResponse;
try {
await FlutterMailer.send(mailOptions);
platformResponse = 'success';
} catch (error) {
platformResponse = error.toString();
}
if (!mounted) return;
_scafoldKey.currentState.showSnackBar(SnackBar(
content: Text(platformResponse),
));
}
I had the same issue on iPhone, it was caused because I hadn't set up the default iOS default Mail App.
Adding in AndroidManifest.xml this for me on Android solve the issue:
<application .... />
// add queries tag for mailto intent out side of application tag
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
make sure the Android Gradle Plugin is higher then 4.1.0 you will find it inside android\build.gradle file some thing like this
dependencies { classpath 'com.android.tools.build:gradle:4.1.1' "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.4' }
2 . add this to your android/app/src/main/AndroidManifest.xml file just after where you add the <uses-permission>
<queries> <intent> <action android:name="android.intent.action.SENDTO" /> <data android:scheme="mailto" /> </intent> </queries>
run flutter clean
run flutter pub get or you can run your code it will do this for you after that Flutter email sender package should works for you
this solve the issue for me

How can I dial the phone from Flutter?

I am building a Flutter app, and I'd like to dial a phone number in response to a button tap. What's the best way to do this?
Thanks!
This method will open the dialer :
_launchCaller() async {
const url = "tel:1234567";
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
EDIT:
In case anybody facing errors:
Add url_launcher: in the pubspec.yaml & run flutter get
Also import 'package:url_launcher/url_launcher.dart';
Typically, to interact with the underlying platform, you have to write platform specific code and communicate with the same using platform channels. However, Flutter provides some points of integration with the platform out of the box. To dial the phone for instance, you can use the UrlLauncher.launch API with the tel scheme to dial the phone.
Something like UrlLauncher.launch("tel://<phone_number>"); should work fine on all platforms.
Do note that this will not work in the simulators. So make sure you are using an actual device to test this.
You can use the url_launcher widget (https://pub.dev/packages/url_launcher)
Add this to your package's pubspec.yaml file: dependencies: url_launcher: ^5.7.10
Install it: $ flutter pub get
Import it import 'package:url_launcher/url_launcher.dart';
Inside your class, define this method so you can call from any action in your code:
Future<void> _makePhoneCall(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
inside the build widget:
IconButton(icon: new Icon(Icons.phone),
onPressed: ()
{
setState(() {
_makePhoneCall('tel:0597924917');
});
},
),
Note 1: you should write the phone number with prefix 'tel': 'tel:0123456789'
Note 2: sometimes it will not work well until you close the app in your mobile and reopen it, so flutter can inject the code of the new widget successfully.
Its too easy
import 'package:flutter/material.dart';
import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
void main() {
runApp(Scaffold(
body: Center(
child: RaisedButton(
onPressed: _callNumber,
child: Text('Call Number'),
),
),
));
}
_callNumber() async{
const number = '08592119XXXX'; //set the number here
bool res = await FlutterPhoneDirectCaller.callNumber(number);
}
URL launcher has updated their dependency so here is the updated way to do the job. it will work for android ios
final Uri launchUri = Uri(
scheme: 'tel',
path: number,
);
await launchUrl(launchUri);
Who has not used this plugin just imoprt this plugin.
UrlLauncher
Use url_launcher.
import 'package:url_launcher/url_launcher.dart';
openDialPad(String phoneNumber) async {
Uri url = Uri(scheme: "tel", path: phoneNumber);
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
print("Can't open dial pad.");
}
}
Note: Don't forgot to update info.plist and AndroidManifest.xml as per the documentation.
Follow the below steps:
add the url_launcher: Latest version dependency in your pubspec.yaml
Go to \android\app\src\main\AndroidManifest.xml.
add the queries lines before the <application, like this :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flutter">
<queries>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
</queries>
<application ...
For more queries, follow this more queries
4.Add the dialer function, and set the url, final url ="tel:$phoneNumber"; like this:
Future<void> dialNumber(
{required String phoneNumber, required BuildContext context}) async {
final url = "tel:$phoneNumber";
if (await canLaunch(url)) {
await launch(url);
} else {
ShowSnackBar.showSnackBar(context, "Unable to call $phoneNumber");
}
return;
}
Done
This is what worked for me as of January 2023
NB: The major difference from the other answers above is my #4
ALSO: You can now use test this in Emulator
Steps:
1.Add url_launcher: latest to pubspec.yaml
2.Configuration:
For IOS: Add tel scheme passed to canLaunchUrl as LSApplicationQueriesSchemes entries in your Info.plist file.
Like this:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>tel</string>
</array>
For Android: Add tel scheme passed to canLaunchUrl as queries entries in your AndroidManifest.xml [ie \android\app\src\main\AndroidManifest.xml] file.
Just like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flutApp">
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
</queries>
<application
3.Import url_launcher to your file: ie import 'package:url_launcher/url_launcher.dart';
4.Code
Future<void> _dialNumber(String phoneNumber) async {
final Uri launchUri = Uri(
scheme: 'tel',
path: phoneNumber,
);
await launchUrl(launchUri);
}
Source: url_launcher