Git Product home page Git Product logo

Comments (13)

liquidiert avatar liquidiert commented on June 23, 2024 9

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.

maheshmnj avatar maheshmnj commented on June 23, 2024 4

@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.

KawindaWAD avatar KawindaWAD commented on June 23, 2024 1

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.

JohnPang1204 avatar JohnPang1204 commented on June 23, 2024

I also facing this issues. Is there any workaround?

from flutter_ringtone_player.

LaxmikanthMadhyastha avatar LaxmikanthMadhyastha commented on June 23, 2024

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.

Bharavi26 avatar Bharavi26 commented on June 23, 2024

@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.

nhimrmh avatar nhimrmh commented on June 23, 2024

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.

Bharavi26 avatar Bharavi26 commented on June 23, 2024

@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 ?

ringtoneplayer

from flutter_ringtone_player.

nhimrmh avatar nhimrmh commented on June 23, 2024

@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.

benyamin218118 avatar benyamin218118 commented on June 23, 2024

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.

github-actions avatar github-actions commented on June 23, 2024

This issue has stalled.

from flutter_ringtone_player.

github-actions avatar github-actions commented on June 23, 2024

This issue has been closed due to inactivity.

from flutter_ringtone_player.

pranavo72bex avatar pranavo72bex commented on June 23, 2024

Any update regarding this issue?

from flutter_ringtone_player.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.