Login with facebook error on iOS in flutter project - ios

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

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

React native: TypeError: null is not an object (evaluating 'SplashScreen.preventAutoHide')

My react native app was working just fine before I used expo eject. I ejected it because I now intend to build and release the app to the ios app store. As soon as I attempt to start the ejected app using react-native run-ios after it's been ejected I get the exception below.
Please could someone help to understand what's causing this issue and how to tackle it?
react Native versions as follows:
react-native-cli: 2.0.1
react-native: 0.61.5
TypeError: null is not an object (evaluating 'SplashScreen.preventAutoHide')
This error is located at:
in AppLoading (at AppLoading.js:52)
in AppLoading (at App.js:464)
in App (at renderApplication.js:40)
in RCTView (at AppContainer.js:101)
in RCTView (at AppContainer.js:119)
in AppContainer (at renderApplication.js:39)
preventAutoHide
SplashScreen.js:4:21
AppLoading#constructor
AppLoadingNativeWrapper.js:6:8
renderRoot
[native code]:0
runRootCallback
[native code]:0
renderApplication
renderApplication.js:52:52
runnables.appKey.run
AppRegistry.js:116:10
runApplication
AppRegistry.js:197:26
callFunctionReturnFlushedQueue
[native code]:0
The AppLoading component is not available in the bare workflow. As #gaurav-roy said you have to refactor your code.
Install the expo-splash-screen package with npm install expo-splash-screen
Add a splash-screen to your Android and iOS projects. Run npm run expo-splash-screen --help and follow the instructions of this CLI tool. (Because of a bug you might have to run the command again with the -p "ios" flag if it only adds the SplashScreen for Android after running it.
Change your code inside App.tsx in a similar way as in this example.
If you're working with hooks you probably want to add an useEffect
hook with an empty dependency list which runs an async function. Here an example of how it could be done:
const App = (props: Props) => {
const [isLoadingComplete, setLoadingComplete] = useState(false);
const init = async () => {
try {
// Keep on showing the SlashScreen
await SplashScreen.preventAutoHideAsync();
await loadResourcesAsync();
} catch (e) {
console.warn(e);
} finally {
setLoadingComplete(true);
// Hiding the SplashScreen
await SplashScreen.hideAsync();
}
useEffect(() => {
init();
}, []);
const renderApp = () => {
if (!isLoadingComplete && !props.skipLoadingScreen) {
return null;
}
return (
<Main />
);
};
return <StoreProvider>{renderApp()}</StoreProvider>;
}
As its evident from docs , SplashScreen is an inbuilt api for expo apps, and since you ejected it , it throws an error since it cant be used.
You can see this in the docs expo splashscreen .
First you should download npm i expo-splash-screen
And then change your import statement to :
import * as SplashScreen from 'expo-splash-screen';
Hope it helps. feel free for doubts
After looking through this SO page and then digging into some links, especially this expo page where they kind of provide a solution for this, I was able to get my app running after about 3 hours of struggle. They haven't added any functional component example, so I am sharing my code below in case someone came here looking for the solution.
import { Asset } from "expo-asset";
import * as Font from "expo-font";
import React, { useState, useEffect } from "react";
import { Platform, StatusBar, StyleSheet, View } from "react-native";
import { Ionicons } from "#expo/vector-icons";
import * as SplashScreen from 'expo-splash-screen';
import AppNavigator from "./navigation/AppNavigator";
export default props => {
const [isLoadingComplete, setLoadingComplete] = useState(false);
const theme = {
...DefaultTheme,
roundness: 2,
colors: {
...DefaultTheme.colors,
primary: "#E4002B",
accent: "#E4002B",
},
};
useEffect(() => {
async function asyncTasks() {
try {
await SplashScreen.preventAutoHideAsync();
} catch (e) {
console.warn(e);
}
await loadResourcesAsync()
setLoadingComplete(true);
}
asyncTasks()
}, []);
return (
!isLoadingComplete && !props.skipLoadingScreen ? null :
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
<AppNavigator />
</View>
);
}
async function loadResourcesAsync() {
await Promise.all([
Asset.loadAsync([
require("./assets/images/logo.png") // Load your resources here (if any)
]),
Font.loadAsync({
// You can remove this if you are not loading any fonts
"space-mono": require("./assets/fonts/SpaceMono-Regular.ttf"),
}),
]);
await SplashScreen.hideAsync();
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
});
This solved it for me for an ejected expo app. Looks like expo was referencing it wrongly.
https://github.com/expo/expo/issues/7718#issuecomment-610508510
What worked for me was updating node_modules/expo/build/launch/splashScreen.js to the following as suggested by adamsolomon1986 in the repo (issue #7718):
import { NativeModules } from 'react-native';
import* as SplashScreen from 'expo-splash-screen'
export function preventAutoHide() {
if (SplashScreen.preventAutoHide) {
SplashScreen.preventAutoHide();
}
}
export function hide() {
if (SplashScreen.hide) {
SplashScreen.hide();
}
}
//# sourceMappingURL=SplashScreen.js.map

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

How to play a custom sound in Flutter?

I was able to play a simple sound with this line of code:
SystemSound.play(SystemSoundType.click);
How can I play a customized sound?
Let's say a short mp3
Simple solution for playing a file already defined in assets is using AudioCache.
Library: https://pub.dartlang.org/packages/audioplayers.
More about AudioCache
After adding library to pubspec.yaml, import required class:
import 'package:audioplayers/audio_cache.dart';
add an asset in the same file and place the file with sound to assets folder (if you don't have this folder, create it)
assets:
- assets/sound_alarm.mp3
then add this code:
static AudioCache player = new AudioCache();
const alarmAudioPath = "sound_alarm.mp3";
player.play(alarmAudioPath);
An example here
Thanks for checking out Flutter!
Flutter SDK today (as of May 5, 2017) doesn't have built-in support to play and control arbitrary audio. However, we designed our plugin system to support it.
This plugin adds audio support to Flutter: https://pub.dartlang.org/packages/audioplayer
From the plugin's README:
Future play() async {
final result = await audioPlayer.play(kUrl);
if (result == 1) setState(() => playerState = PlayerState.playing);
}
// add a isLocal parameter to play a local file
Future playLocal() async {
final result = await audioPlayer.play(kUrl);
if (result == 1) setState(() => playerState = PlayerState.playing);
}
Future pause() async {
final result = await audioPlayer.pause();
if (result == 1) setState(() => playerState = PlayerState.paused);
}
Future stop() async {
final result = await audioPlayer.stop();
if (result == 1) {
setState(() {
playerState = PlayerState.stopped;
position = new Duration();
});
}
}
The audioplayers works (from https://medium.com/#bennett4/adding-custom-sound-effects-to-a-flutter-mobile-app-41594f1f3305):
(1) Add the library to your pubspec.yaml: audioplayers: ^0.15.1
(2) In pubspec.yaml under flutter add the reference to your assets file:
flutter
assets:
- assets/yes.mp3
MAKE SURE it is under the assets folder. It does not work when it is in a subfolder. For example, something like: - assets/sounds/yes.mp3 will not work. Just put your audio file in the assets folder, not in its subfolder
(3) import the library in your app as: import package:audioplayers/audioplayers.dart;
(4) then define this function:
Future<AudioPlayer> playLocalAsset() async {
AudioCache cache = new AudioCache();
//At the next line, DO NOT pass the entire reference such as assets/yes.mp3. This will not work.
//Just pass the file name only.
return await cache.play("yes.mp3");
}
(5) call the function whenever you need to play a sound: await playLocalAsset();
Null-safe code:
Add dependency to your pubspec.yaml file,
dependencies:
audioplayers: ^0.19.0
Add audio file path to your pubspec.yaml file.
flutter:
assets:
- assets/audio/my_audio.mp3
Run flutter pub get
Full code:
class HomePage extends StatelessWidget {
final AudioCache _audioCache = AudioCache(
prefix: 'audio/',
fixedPlayer: AudioPlayer()..setReleaseMode(ReleaseMode.STOP),
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: ElevatedButton(
onPressed: () => _audioCache.play('my_audio.mp3'),
child: Text('Play Audio'),
),
);
}
}
[Answer updated: this approach doesn't work, see comments]
You can use the video_player plugin maintained by the Flutter team. It can reproduce many kinds of media across platforms, including sound files. More specifically, you may want to use the the VideoPlayerController class.
eg. _controller = VideoPlayerController.network('https://www.example.com/soundsFile.wav');
_controller.play();

Resources