-
-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't stop the alarm with FlutterRingtonePlayer.stop() after killing the app. #7
Comments
I also facing this issues. Is there any workaround? |
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. |
@LaxmikanthMadhyastha sir, have you found solutiontion for this ? if yes then can you please share solution ? |
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. |
@nhimrmh sir, i am using FlutterRingtonePlayer.playRingtone() in BackgroundMessageHandler of notification Unhandled Exception: MissingPluginException(No implementation found for method play on channel 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. |
in your flutter_project/android/app/src/main/your.package.name/Application.java | MainActivity.java add this import :
then add this line in the overrided registerWith function: your problem should be solved |
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? |
@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=DTo77u8SzdrrwPHy-qF1bxBgpfdd'
},
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,
]))));
}
}
|
This issue has stalled. |
This issue has been closed due to inactivity. |
Any update regarding this issue? |
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 Root Cause: Solution: 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 dependencies:
flutter:
sdk: flutter
flutter_ringtone_player:
git:
url: https://github.com/KawindaWAD/flutter_ringtone_player.git |
@maheshmnj It appears that you have an active Firebase secret included in code sample from your comment, please revoke it.... |
Thanks @SPodjasek, However that secret was for a sample project and I removed it. |
I'm currently using flutter_ringtone_player package to implement an Alarm application on mobile. I have AlarmManager to help schedule the time to fire FlutterRingtonePlayer.play() when time comes. If i play and stop the alarm without closing my app then everything works fine, but after closing (killing) my app, the command FlutterRingtonePlayer.stop() on the previous scheduled alarm no longer works when the app is reopened.
How can i resolve this? Thank you.
The text was updated successfully, but these errors were encountered: