Comments (13)
Hey @Bharavi26, @nhimrmh I used port communication between the isolates:
fcmBackgroundHandler() async {
...
ReceivePort receiver = ReceivePort();
IsolateNameServer.registerPortWithName(receiver.sendPort, portName);
receiver.listen((message) async {
if (message == "stop") {
await FlutterRingtonePlayer.stop()
}
});
}
And then whenever I want to stop it:
IsolateNameServer.lookupPortByName(portName)?.send("stop");
@Bharavi26 regarding the exception are you sure flutter is intialized correctly and your backgroundhandler is a top-level function?
from flutter_ringtone_player.
@liquidiert thank you so much that worked like a charm :)
For anyone who would stumble upon this issue, Here's the complete code sample. Where I am trying to stop the audio on tapping notification (The audio was played while the app was terminated).
code sample
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart=2.9
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'dart:ui';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_ringtone_player/flutter_ringtone_player.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'message.dart';
import 'message_list.dart';
import 'permissions.dart';
import 'token_monitor.dart';
AndroidNotificationChannel channel;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
const String isolateName = 'isolate';
/// Define a top-level named handler which background/terminated messages will
/// call.
///
/// To verify things are working, check out the native platform logs.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
ReceivePort receiver = ReceivePort();
IsolateNameServer.registerPortWithName(receiver.sendPort, isolateName);
receiver.listen((message) async {
if (message == "stop") {
await FlutterRingtonePlayer.stop();
}
});
playAudio();
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// Set the background messaging handler early on, as a named top-level function
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
/// Create a [AndroidNotificationChannel] for heads up notifications
channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.high,
);
/// Initialize the [FlutterLocalNotificationsPlugin] package.
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
runApp(MessagingExampleApp());
}
/// Entry point for the example application.
class MessagingExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging Example App',
theme: ThemeData.dark(),
routes: {
'/': (context) => Application(),
'/message': (context) => MessageView(),
},
);
}
}
// Crude counter to make messages unique
int _messageCount = 0;
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String token) {
_messageCount++;
return jsonEncode({
'to': token,
'data': {
'via': 'FlutterFire Cloud Messaging!!!',
'count': _messageCount.toString(),
},
'notification': {
'title': 'Hello FlutterFire!',
'body': 'This notification (#$_messageCount) was created via FCM!',
},
});
}
void playAudio() {
FlutterRingtonePlayer.play(
android: AndroidSounds.ringtone,
ios: const IosSound(1023),
looping: false,
volume: 0.8,
);
}
Future<void> stopAudio() async {
IsolateNameServer.lookupPortByName(isolateName)?.send("stop");
await FlutterRingtonePlayer.stop();
}
/// Renders the example application.
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
String _token;
@override
void initState() {
super.initState();
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
if (message != null) {
print("Got initial message $message");
stopAudio();
// Navigator.pushNamed(context, '/message',
// arguments: MessageArguments(message, true));
}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
print('A new onMessage event was published!');
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
));
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('App launched!');
stopAudio();
});
}
Future<void> sendPushMessage() async {
if (_token == null) {
print('Unable to send FCM message, no token exists.');
return;
}
try {
var resp = json.decode((await http.post(
Uri.parse('https://fcm.googleapis.com/fcm/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization':
'key=AAAAcVC6H8o:APA91bF9eBcw6f4RbqJ89uYUGJ7RpMm2w0-yU8T8TIJ5LgXbjc91z_WxlOOzsUotZc6kYpqIQs7EnO5Im00xrLNuLpbkZ7VHgtFQ_Jv19W-XMi2dvWLteOZDTo77u8SzPHy-qF1bxBgp'
},
body: constructFCMPayload(_token),
))
.body);
print(resp);
if (resp['failure'] == 1) {
print(
"Failed to send to $_token due to ${resp['results'][0]['error']}");
}
} catch (e) {
print(e);
}
}
Future<void> onActionSelected(String value) async {
switch (value) {
case 'subscribe':
{
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test".');
await FirebaseMessaging.instance.subscribeToTopic('fcm_test');
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test" successful.');
}
break;
case 'unsubscribe':
{
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test".');
await FirebaseMessaging.instance.unsubscribeFromTopic('fcm_test');
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test" successful.');
}
break;
case 'get_apns_token':
{
if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
print('FlutterFire Messaging Example: Getting APNs token...');
String token = await FirebaseMessaging.instance.getAPNSToken();
print('FlutterFire Messaging Example: Got APNs token: $token');
} else {
print(
'FlutterFire Messaging Example: Getting an APNs token is only supported on iOS and macOS platforms.');
}
}
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Cloud Messaging'),
actions: <Widget>[
PopupMenuButton(
onSelected: onActionSelected,
itemBuilder: (BuildContext context) {
return [
const PopupMenuItem(
value: 'subscribe',
child: Text('Subscribe to topic'),
),
const PopupMenuItem(
value: 'unsubscribe',
child: Text('Unsubscribe to topic'),
),
const PopupMenuItem(
value: 'get_apns_token',
child: Text('Get APNs token (Apple only)'),
),
];
},
),
],
),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: () {
playAudio();
// FlutterRingtonePlayer.stop();
// sendPushMessage,
},
backgroundColor: Colors.white,
child: const Icon(Icons.send),
),
),
body: SingleChildScrollView(
child: Column(
children: [
MetaCard('Permissions', Permissions()),
MetaCard('FCM Token', TokenMonitor((token) {
print('Token monitor set $_token');
_token = token;
return Column(
children: [
token == null
? const CircularProgressIndicator()
: Text(token, style: const TextStyle(fontSize: 12)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () async {
var before = _token;
print('Before: $_token');
var token;
if (kIsWeb) {
token = await FirebaseMessaging.instance.getToken(
vapidKey:
"BHOPmb4Gz7mSLtue-BSzZGOzIO1LTiHThiHl1_ZbUtRaj5PhHJhR2Isr9hGBH1gfw4jhcKJVTyDPneau8kdLyVw");
} else {
token = await FirebaseMessaging.instance.getToken();
}
_token = token;
print('After: $_token');
if (_token == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: const Text("No token!")));
return;
}
if (before == _token) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content:
const Text("Current token is valid!")));
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text("Got new token!")));
}
},
icon: const Icon(Icons.refresh),
tooltip: "Get token",
),
if (_token != null)
IconButton(
onPressed: () {
Clipboard.setData(ClipboardData(text: _token));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content:
const Text("Copied token to clipboard!")));
},
icon: const Icon(Icons.copy),
tooltip: "Copy token to clipboard",
),
if (_token != null)
IconButton(
onPressed: () async {
await FirebaseMessaging.instance.deleteToken();
print('Deleted token $_token');
var token =
await FirebaseMessaging.instance.getToken();
print("New token $token");
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: const Text("Deleted token!")));
},
icon: const Icon(Icons.delete_forever),
tooltip: "Delete token",
),
],
),
],
);
})),
MetaCard('Message Stream', MessageList()),
],
),
),
);
}
}
/// UI Widget for displaying metadata.
class MetaCard extends StatelessWidget {
final String _title;
final Widget _children;
// ignore: public_member_api_docs
MetaCard(this._title, this._children);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
Container(
margin: const EdgeInsets.only(bottom: 16),
child:
Text(_title, style: const TextStyle(fontSize: 18))),
_children,
]))));
}
}
from flutter_ringtone_player.
Hello,
I was facing the same issue with the ringtone not stopping when expected. After some debugging, I found that the issue was with the way the ringtone
instance was being managed in the FlutterRingtonePlayerPlugin
class. Here's the root cause and the solution:
Root Cause:
When the play
method is called, the plugin checks if a ringtone
instance exists. If it does, it stops that instance and creates a new ringtone
instance. However, when the stop
method is called, the plugin stops the ringtone
instance, but it does not nullify it. As a result, there is no persistent reference to the ringtone that's currently playing. So, when FlutterRingtonePlayer.stop()
is called from the Flutter code, the plugin tries to stop the current ringtone
. But if ringtone
is null
, nothing is stopped, and the ringtone continues to play.
Solution:
To fix this, I made the ringtone
instance static so it's shared across all instances of FlutterRingtonePlayerPlugin
. I also added code to nullify the ringtone
instance after stopping it in the stop
method. This ensures that the correct ringtone
is stopped when FlutterRingtonePlayer.stop()
is called from the Flutter code.
Here's a link to my forked repository with the fix: Forked Repository
You can use this repository in your Flutter application by replacing the flutter_ringtone_player
dependency in your pubspec.yaml
file as follows:
dependencies:
flutter:
sdk: flutter
flutter_ringtone_player:
git:
url: https://github.com/KawindaWAD/flutter_ringtone_player.git
from flutter_ringtone_player.
I also facing this issues. Is there any workaround?
from flutter_ringtone_player.
Yes, even I am facing this issue, I'm using this package to play the ringtone whenever I receive a firebase push notification even when the app is in the background, and when the app is resumed I'm calling FlutterRingtonePlayer.stop() which is not stopping the ringtone from playing.
from flutter_ringtone_player.
@LaxmikanthMadhyastha sir, have you found solutiontion for this ? if yes then can you please share solution ?
i also want to play ringtone when app is in background..thank you
from flutter_ringtone_player.
Unfortunately, i haven't found any solutions around for this. I think we can only wait for FlutterRingtonePlayer package to be updated as they fix this.
from flutter_ringtone_player.
@nhimrmh sir, i am using FlutterRingtonePlayer.playRingtone() in BackgroundMessageHandler of notification
whenever i receive notificaiton then ringtone generate MissingPluginException.
Unhandled Exception: MissingPluginException(No implementation found for method play on channel flutter_ringtone_player)
have you idea about this error..can you please guide me ?
from flutter_ringtone_player.
@Bharavi26 sorry but I can't help you with this because I stopped using this package for a long time since there's no other ways to work around the bug of not capable to stop the ringtone in background, and I haven't been through your kind of exception yet.
from flutter_ringtone_player.
in your flutter_project/android/app/src/main/your.package.name/Application.java | MainActivity.java add this import :
import io.inway.ringtone.player.FlutterRingtonePlayerPlugin;
then add this line in the overrided registerWith function:
FlutterRingtonePlayerPlugin.registerWith(registry.registrarFor("io.inway.ringtone.player.FlutterRingtonePlayerPlugin"));
your problem should be solved
from flutter_ringtone_player.
This issue has stalled.
from flutter_ringtone_player.
This issue has been closed due to inactivity.
from flutter_ringtone_player.
Any update regarding this issue?
from flutter_ringtone_player.
Related Issues (20)
- Play sound on speaker even if headphone is connected HOT 4
- Ringtone not playing in release mode HOT 2
- Android V2 embedding HOT 2
- deprecated version of the Android embedding HOT 2
- Module 'flutter_ringtone_player' not found on iOS HOT 4
- Unable to stop Ringtone HOT 3
- Playing default ringtone when changing ringtone. HOT 2
- W/MediaPlayer(14698): java.io.FileNotFoundException: No content provider: /data/user/0/com.example.apk/cache/assets/sounds/ringtone.mp3 HOT 3
- Support custom ringtone as URI HOT 2
- Notification Sound Not Stopped After App is Killed or Foreground HOT 9
- Couldn't be able to stop ringtone in IOS. Any clue, when would this gets addressed. HOT 6
- Please Fix this pressing issue and add flutter 3.3.7 support HOT 2
- Not able to play sound in ios. HOT 7
- FlutterRingtonePlayer not working in Samsung galaxy s22 ultra HOT 3
- Please release a new version using flutter 3.3 in pub.dev HOT 2
- How to use custom sound from directory HOT 2
- FlutterRingtonePlayer may crash in OPPO mobile (system version is Android5,6,7,8,9,10) HOT 2
- Gradle 8 Support HOT 1
- Member not found: 'FlutterRingtonePlayer.play'. HOT 4
- When can we expect notification sound for Flutter web apps? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from flutter_ringtone_player.