Flutter: url_launcher package can not encode body for sms - ios

i using url_launcher package to redirect from my app to SMS. i wanna passing content of SMS but it's display like this
enter image description here
version:
Iphone OS: 15.6
Flutter: 3.0.5
url_launcher: ^6.1.5
my code
Future<void> sendSMS(String registerSyntax) async {
final Uri smsLaunchUri = Uri(
scheme: 'sms',
path: '0123456789',
queryParameters: <String, String>{
'body': Uri.encodeComponent(registerSyntax),
},
);
if (!await launchUrl(smsLaunchUri)) {
throw 'Could not launch $smsLaunchUri';
}
}

Related

xCode error causing app to crash immediately after launch

I am having an issue with my flutter app on iOS. It is working well on android and on web but I am getting this error on iOS. I come from a web dev background and do not have a lot of experience in iOS.
I am getting the error below and have zero idea of where to even begin. It appears to be an issue with one of the plugins... but I honestly have not idea. Any help on a direction would be incredibly helpful.
Error from xCode
This is a fairly large app
Here is my pubspec.
version: 1.6.0+18
environment:
sdk: ^2.7.0
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
http: ^0.13.0
responsive_builder: ^0.3.0
bloc: ^7.0.0
flutter_bloc: ^7.0.0
equatable: ^2.0.0
meta: ^1.1.6
hive: ^2.0.0
hive_flutter: ^1.0.0
flutter_appauth: ^0.9.2+6
intl: ^0.17.0
table_calendar: ^2.3.3
js: ^0.6.0
floating_action_bubble: ^1.1.2
badges: ^1.1.6
plaid_flutter:
git:
url: https://github.com/cwesterhold/plaid_flutter
ref: master
font_awesome_flutter: ^8.11.0
auth0_spa:
git:
url: https://github.com/cwesterhold/auth0-spa-flutter
ref: master
multiple_select:
git:
url: https://github.com/cwesterhold/multiple_select
ref: master
#catcher: ^0.6.2
flutter_localizations:
sdk: flutter
#package_info_plus: ^1.0.0
purchases_flutter: ^3.0.0
url_launcher: ^6.0.0
syncfusion_flutter_charts: ^18.4.47
progress_indicator: ^0.1.1
uuid:
dev_dependencies:
flutter_test:
sdk: flutter
hive_generator:
build_runner: ^1.10.0
flutter_launcher_icons: ^0.9.0
flutter_icons:
image_path: 'assets/ic_launcher.png'
android: false
ios: true
#flutter pub run flutter_launcher_icons:main
flutter:
uses-material-design: true
assets:
- assets/
fonts:
- family: Comfortaa
fonts:
- asset: fonts/Comfortaa-VariableFont_wght.ttf
Here is the main
import 'dart:async';
import 'package:clicket/bloc/theme/theme.dart';
import 'package:clicket/models/errorModel.dart';
import 'package:clicket/screens/login/loginMain.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() async {
bool isInDebugMode = false;
assert(isInDebugMode = true);
ErrorModel errorModel = ErrorModel();
WidgetsFlutterBinding.ensureInitialized();
bool isDev = false;
assert(isDev = true);
if (isDev == true) {
runApp(Clicket());
} else {
runZoned<Future<void>>(
() async {
runApp(Clicket());
},
onError: (dynamic error, StackTrace stackTrace) {
errorModel.reportError(error, stackTrace);
// Send report
},
);
}
}
class Clicket extends StatefulWidget {
#override
_ClicketState createState() => _ClicketState();
}
class _ClicketState extends State<Clicket> {
var s;
ThemeBloc _themeBloc = ThemeBloc();
final navigatorKey = GlobalKey<NavigatorState>();
#override
Widget build(BuildContext context) {
// make sure to close out all blocs to prevent memory leaks
#override
void dispose() {
_themeBloc.close();
super.dispose();
}
// Includes all blocs so they are available across the entire application
return BlocProvider<ThemeBloc>(
create: (context) => _themeBloc,
child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
if (state is ThemeStart) {
_themeBloc.add(CheckTheme());
} else if (state is ThemeLight) {
s = state.themeData;
} else if (state is ThemeDark) {
s = state.themeData;
}
return MaterialApp(
navigatorKey: navigatorKey,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
],
debugShowCheckedModeBanner: false,
title: "Clicket - Personal Budgeting",
onGenerateRoute: (rt) {
return MaterialPageRoute(
builder: (context) {
return LoginMain();
},
);
},
theme: s,
);
},
),
);
}
}
If I remove the LogIn route and rerun it in xCode, I get this.
Second xCode error
Which is just as cryptic....
When I run things through android studio it doesnt give any insights at all...
NOthing in Android Studio
Even if I remove everything except for a basic scaffold, I still get the same second error as above. But if I create a new project with the same pubspec, it works just fine.
Any help would be greatly appreciated.
So I found the issues...
it had to do with a bad line in the info.plist file.
I had this..
<key>NSAppTransportSecurity</key>
<true/>
and it should be this...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Lesson learned - dont just blindly copy code you find on the internet :-)

Login with facebook error on iOS in flutter project

I wrote a flutter login with facebook app.
It works correctly on Android.
On iOS simulator and on real iPhone device it does not work. Both having iOS 13.2.
pub spec.yaml file
firebase_auth: ^0.6.6
flutter_facebook_login: ^1.1.1
flutter_auth_buttons: ^0.3.1
main.dart file
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_facebook_login/flutter_facebook_login.dart';
import 'package:flutter_auth_buttons/flutter_auth_buttons.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
FirebaseAuth _auth = FirebaseAuth.instance;
bool isLogged = false;
FirebaseUser myUser;
Future<FirebaseUser> _loginWithFacebook() async {
var facebookLogin = new FacebookLogin();
var result = await facebookLogin.logInWithReadPermissions(['email']);
debugPrint(result.status.toString());
if (result.status == FacebookLoginStatus.loggedIn) {
FirebaseUser user =
await _auth.signInWithFacebook(accessToken: result.accessToken.token);
return user;
}
return null;
}
void _login() {
_loginWithFacebook().then((response) {
if (response != null) {
myUser = response;
setState(() {
isLogged = true;
});
}
});
}
void _logout() async {
await _auth.signOut().then((response) {
setState(() {
isLogged = false;
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Login App',
home: Scaffold(
appBar: AppBar(
title: Text(isLogged ? 'Profile Page' : 'Login App'),
actions: <Widget>[
IconButton(
onPressed: _logout,
icon: Icon(Icons.power_settings_new),
)
],
),
body: Center(
child: isLogged
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Name: ' + myUser.displayName),
Image.network(myUser.photoUrl),
],
)
: FacebookSignInButton(
onPressed: _login,
),
),
),
);
}
}
I added the plist file in the Xcode project correctly. And configured the iOS version of the Facebook developer correctly based on the following steps:
https://developers.facebook.com/docs/facebook-login/ios
I changed the project workspace settings in Xcode between Legacy build and new build system. I still get error.
I tried to add the following to the pod file, and still get error
pod 'FBSDKCoreKit', '~> 4.44'
And even all proposed solutions in here
How to fix build error with FBSDKLoginKit in Xcode
The error that I get is
No known class method for selector 'dictionary:setObject:forKey:'
I also tried to change the Firebase version and the Facebook Flutter login version in pub spec file (between 1.1.1 and 1.2.0 because I do not want to use AndroidX) but still getting the error.
Note that I updated Xcode to latest version, and error was not fixed.
I changed the iOS deployment version in Xcode for all pods to version 8. And error not fixed!
UPDATE (JULY 2020)
You can use a new package that works for both Android and iOS:
flutter_login_facebook
If you want to use the flutter_facebook_login, below is a solution:
UPDATE (APRIL 2020)
Add flutter_facbook_login version 3.0.0 from pub.dev to your flutter project
Create your app on Facebook developers and configure your flutter app accordingly
Change your iOS target version to 9 in Xcode
Open in terminal the Podfile.lock which is located in the iOS folder of your flutter project and change all facebook api versions to 5.8.0. If the Podfile.lock does not exist, run your app once (so the file is created) and after it fires an error edit Podfile.lock then run it again. If your app still fails, run pod install manually form terminal.
There are two problems:
the compatibility between Facebook Login API and Firebase.
iOS update to version 13.x.
In pubspec.yaml file updated the firebase version to latest version.
Also, I am using version 1.2.0 for facebook login but still 1.1.1 works.
firebase_auth: ^0.14.0+5
flutter_facebook_login: ^1.2.0
flutter_auth_buttons: ^0.3.1
I opened Runner.xcworkspace in Xcode (located in iOS folder inside flutter project), then File->WorkSpace settings, and selected New Build System option.
For all pods, change iOS deployment version to 8.0 (or above).
Now the application builds successfully and runs on iOS. But I get CancelledByUser each time I click on the Login with Facebook button.
This is a bug when having iOS update 13.x running the facebook login api.
I found a turnaround that made the login works.
final facebookLogin = new FacebookLogin();
facebookLogin.loginBehavior = FacebookLoginBehavior.webViewOnly;
You can directly use my function as it works on both android and iOS and also registers the user in firebase console.
I have simply opening the login page in the WebView and when the user register himself, I am storing the credential in the firebase and then printing his name .
final FacebookLogin fblogin = FacebookLogin();
FirebaseAuth auth = FirebaseAuth.instance;
Future loginwihFacebook() async {
fblogin.loginBehavior = FacebookLoginBehavior.webViewOnly;
final result = await fblogin.logInWithReadPermissions(["email"]);
switch (result.status) {
case FacebookLoginStatus.loggedIn:
final token = result.accessToken.token;
await auth.signInWithCredential(FacebookAuthProvider.credential(token));
var url =
'https://graph.facebook.com/v2.12/me?fields=name,first_name,picture,last_name,email&access_token=$token';
var graphapiresponse = await http.get(url);
var profileData = jsonDecode(graphapiresponse.body);
var name = profileData["name"];
print(name);
break;
case FacebookLoginStatus.cancelledByUser:
print("cancelled by user");
break;
case FacebookLoginStatus.error:
print("error");
break;
}
}

How do I open an external url in flutter web in new tab or in same tab

I have a simple web app I have created with flutter web. I would like to know how I can open new an external url either in a new tab or in the same tab in my flutter web app. say I want to open the url https://stackoverflow.com/questions/ask
I think you want this — dart:js enables interoperability between Dart and JS —:
import 'dart:js' as js;
// ...
FlatButton(
child: Text('Button'),
onPressed: () {
js.context.callMethod('open', ['https://stackoverflow.com/questions/ask']);
},
)
One simple way is to just create a button and use dart:html's window.open() method:
import 'dart:html' as html;
// ...
html.window.open('https://stackoverflow.com/questions/ask', 'new tab');
The name parameter — which I left as 'new tab' — refers to the new tab's window name, about which you can learn more from MDN's documentation.
https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_web
url_launcher has been the solution for android and ios, recently it added support for web.
You can use the url_launcher plugin
Then in your code
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher_string.dart';
void main() {
runApp(Scaffold(
body: Center(
child: RaisedButton(
onPressed: _launchURL,
child: Text('Show Flutter homepage'),
),
),
));
}
_launchURL() async {
const url = 'https://flutter.io';
if (await canLaunchUrlString(url)) {
await launchUrlString(url);
} else {
throw 'Could not launch $url';
}
}
Example taken from the package site
As of url_launcher: ^6.1.0 The plugin introduces support for webOnlyWindowName property and few Other new apis like launchUrl, For web support now you longer have to depend on dart:html You can simply declare the below function
Future<void> launchLink(String url, {bool isNewTab = true}) async {
await launchUrl(
Uri.parse(url),
webOnlyWindowName: isNewTab ? '_blank' : '_self',
);
}
and use it like this
onTap:(){
launchLink('https://stackoverflow.com/questions/ask', isNewTab: true)
}
Answered here https://stackoverflow.com/a/56656885/361832
Flutter Web does not support plugins (yet), so you have to use replacements from dart:html
https://api.dartlang.org/stable/2.4.0/dart-html/Window/open.html window.open(url, 'tab');
or
https://api.dartlang.org/stable/2.4.0/dart-html/Window/location.html window.location.assign(url);
Extending the answer of #xuyanjun which works fine when to want to open an external link from flutter web to a new tab. But if you want to open an external link to the website in the same tab in which the flutter web app is currently running.
then you can do it like this.
import 'dart:js' as js;
// ...
FlatButton(
child: Text('Button'),
onPressed: () {
js.context.callMethod('open', ['https://blup.in/','_self']); //<= find explanation below
},
)
Explanation :- dart:js package from flutter provide the functionality to call web-specific functions like open function from flutter and all the strings in the list are parameter which are passed to the function refer this.
So if you want to open new tab then not need to pass seconds parameter but if you wan to open in same tab then pass _self as second parameter.
You can use the below code to launch the URL in the same tab.
window.top.location.href = '<your url>'
Must import
import 'dart:html';
package url_launcher now has web support.
just import url_launcher_web, and url_launcher to your pubspec.yaml
import 'package:url_launcher/url_launcher.dart';
const String _url = 'https://flutter.dev';
void _launchURL() {
launch(_url);
}
To launch URL you need to import url_launcher with latest version and you are good to launch URL through following code:
//Launch Github
_launchGithub() async {
const url = 'https://github.com/Pranav2918'; //Paste your URL string here
if (await canLaunchUrlString(url)) {
await launchUrlString(url);
} else {
throw 'Could not launch $url';
}
}
For non string URLs:
Another approach :
final Uri _url = Uri.parse('https://flutter.dev');
Future<void> _launchUrl() async {
if (!await launchUrl(_url)) {
throw 'Could not launch $_url';
}
}
Happy Fluttering !!

How to send a message directly from my Flutter app to WhatsApp using UrlLauncher?

I am building an app that has to be able to take an order and send it to a specific WhatsApp number. What exactly am I supposed to do? I can open WhatsApp but I can't figure out how to send a message when opening it.
title: new Text("WhatsApp"),
trailing: new Icon(Icons.message),
onTap: () async {
int phone = 962770593839;
var whatsappUrl = "whatsapp://send?phone=$phone";
await UrlLauncher.canLaunch(whatsappUrl) != null
? UrlLauncher.launch(whatsappUrl)
: print(
"open WhatsApp app link or do a snackbar with
notification that there is no WhatsApp installed");
},
I expect that when I input a TextField and press send that saved String will be able to be sent to the WhatsApp number after launching WhatsApp.
Use the plugin.
url_launcher
Using the following link : https://api.whatsapp.com/send?phone=XXXXXXXXXXX (In place of the Xs type the phone number of the person you want to contact, including the country code, but without the + sign.)
RaisedButton(
onPressed: () async => await launch(
"https://wa.me/${number}?text=Hello"),,
child: Text('Open Whatsapp'),
),
Alternatively
You can use this other plugin.
whatsapp_unilink
The whatsapp_unilink package helps you build HTTP links and provides you with an idiomatic Dart interface that:
import 'package:whatsapp_unilink/whatsapp_unilink.dart';
import 'package:url_launcher/url_launcher.dart';
launchWhatsApp() async {
final link = WhatsAppUnilink(
phoneNumber: '+001-(555)1234567',
text: "Hey! I'm inquiring about the apartment listing",
);
await launch('$link');
}
Try flutter_open_whatsapp plugin.You Directly Send Message to Number
FlutterOpenWhatsapp.sendSingleMessage("918179015345", "Hello");
Link
Open in WhatsApp
You can do it like this.
onPressed: () async {
for (var msg in msgList) {
if (msg["phone"] != null) {
var url = "${baseURL}91${msg['phone']}&text=${msg['messages']}";
print(url);
AndroidIntent intent = AndroidIntent(
action: 'action_view',
data: Uri.encodeFull(url),
package: "com.whatsapp.w4b");
intent.launch();
}
}
},
child: Icon(Icons.send),
),
Use whatsapp_share package
This launches whatsApp with respective number and prefills the text field.
for text and link
Future<void> share() async {
await WhatsappShare.share(
text: 'Whatsapp share text',
linkUrl: 'https://flutter.dev/',
phone: '911234567890',
);
}
Share images, files
_image.path is the file path which you wanna share to whatsapp
Future<void> shareFile() async {
await WhatsappShare.shareFile(
text: 'Whatsapp share text',
phone: '911234567890',
filePath: "${_image.path}",
);
}
Complete example here
I use url_launcher: ^6.1.7 like this.
void launchWhatsapp(
String phone,
String message,
) async {
final url = 'https://wa.me/967$phone?text=$message';
await launchUrlString(
url,
mode: LaunchMode.externalApplication,
);
}
what I want to refer here is the launch model default set to
LaunchMode.platformDefault
and that opens a web page and not WhatsApp when I try to launch WhatsApp
so set the launch model to
model: LaunchMode.externalApplication
has fixed the issue

How to get bundle id in flutter

I used the below method to get the app name and packageName but I need Bundle id for iPhone users.
I want to share an app link.
I did it in android but on iPhone, I need bundle id.
Future<Null> _initPackageInfo() async {
final PackageInfo info = await PackageInfo.fromPlatform();
setState(() {
_packageInfo = info;
packageName = info.packageName;
appName = info.appName;
buildNumber = info.buildNumber;
});
}
To find the project name manually, you can look in AndroidManifest.xml or in Info.plist.
Android
In Android the package name is in the AndroidManifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
package="com.example.appname">
iOS
In iOS the package name is the bundle identifier in Info.plist:
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
which is found in Runner.xcodeproj/project.pbxproj:
PRODUCT_BUNDLE_IDENTIFIER = com.example.appname;
See also
How to change package name in flutter?
In iOS portion of a Flutter project Product Bundle Identifier is in project.pbxproj file in path:
[your-flutter-project-dir]\ios\Runner.xcodeproj\project.pbxproj
and that is specified as following:
PRODUCT_BUNDLE_IDENTIFIER = com.app.flutter.example;
Note in that this value is same as Android Package Name in Flutter projects.
If you just need to get the IOS bundle ID manually, here is how
In Android Studio select the root folder (ex. flutte_name)
In the taskbar go to Tools>>Flutter>>Open IOS Modules in Xcode
In Xcode open Runner and under Identity/Bundle Identifier there is your ID
You probably want to update it to a custom name rather than com.example.appName anyways so you can check out this package called change_app_name on pub.dev here https://pub.dev/packages/change_app_package_name
Super simple I just did it myself. Add the package to your pubspec file and than in a terminal in the root folder type in "flutter pub run change_app_package_name:main com.company.app" change the last part to whatever you want and it will update your whole project with the new name you chose
what i see you have already get the package name by info.packageName; and appName info.appName;
try request to http://itunes.apple.com/search?media=software&country={countryID}&term={appName}
you can test by curl instead of browser ( this will return file.txt )
curl --location -g --request GET 'http://itunes.apple.com/search?media=software&country=id&term=appName' \
--header 'Accept: application/json' | jq
in other solution some people can get it from
// if doesnt work try with these lookup
itunes.apple.com/lookup?bundleId=com.apple.Pages
| jq // these for make response beutifull
response json
....
....
bundleId: '212312xxxxxx'
trackViewUrl: 'https://apps.apple.com/id/app/appName/id212312xxxxxx'
....
....
i use these concept to self update from backend ( SplashScreen / check app version ) will popUP alert forced user to go to the market place.
Use get_version package . It's the easiest way
Installing :
dependencies:
get_version: any
Usage:
String projectAppID;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
projectAppID = await GetVersion.appID;
} on PlatformException {
projectAppID = 'Failed to get app ID.';
}
You can use it as String inside anything you want like Text widget etc ...
Another extract of get_version in a small application :
import 'package:get_version/get_version.dart';
class _MyAppState extends State<MyApp> {
String _projectAppID = '';
#override
initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
initPlatformState() async {
String projectAppID;
try {
projectAppID = await GetVersion.appID;
} catch (e) {
projectAppID = 'Failed to get app ID.';
}
setState(() {
_projectAppID = projectAppID;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListTile(
leading: new Icon(Icons.info),
title: const Text('App ID'),
subtitle: new Text(_projectAppID),
),
),
);
}
}
Output :

Resources