I'm trying to get my custom audio player working in background. I'm using the just_audio_background
pub dependency but it doesn't. When I go on my apps screen or even when I turn off my phone the music stop.
Here is my custom code:
// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/backend/schema/structs/index.dart';
import '/backend/supabase/supabase.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/widgets/index.dart'; // Imports other custom widgets
import '/custom_code/actions/index.dart'; // Imports custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom widget code
// DO NOT REMOVE OR MODIFY THE CODE ABOVE!
// Set your widget name, define your parameter, and then add the
// boilerplate code using the green button on the right!
import 'package:just_audio_background/just_audio_background.dart';
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
import 'package:just_audio/just_audio.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:rxdart/rxdart.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
class BackWidget extends StatefulWidget {
const BackWidget({
super.key,
this.width,
this.height,
this.song,
});
final double? width;
final double? height;
final PodcastStruct? song;
@override
State<BackWidget> createState() => _BackWidgetState();
}
class _BackWidgetState extends State<BackWidget> {
AudioPlayer _audioPlayer = AudioPlayer();
ConcatenatingAudioSource getplaylist() {
List<AudioSource> songs = [];
final song = widget.song!;
String urlsong = song.urlsong;
String title = song.title;
String artUri = song.artUri;
String showName = song.showName;
String podcastId = song.id;
songs.add(AudioSource.uri(
Uri.parse(urlsong),
tag: MediaItem(
id: podcastId,
title: title,
artUri: Uri.parse(artUri),
album: showName,
),
));
return ConcatenatingAudioSource(children: songs);
}
@override
void initState() {
super.initState();
_init();
}
Future<void> _init() async {
if (kIsWeb) {
await JustAudioBackground.init(
androidNotificationChannelId: 'com.qalbeen.qalbeen.channel.audio',
androidNotificationChannelName: 'Audio playback',
androidNotificationOngoing: true,
);
}
await _audioPlayer.setLoopMode(LoopMode.all);
await _audioPlayer.setAudioSource(getplaylist());
}
Stream<PositionData> get _positionDataStream =>
Rx.combineLatest3<Duration, Duration, Duration?, PositionData>(
_audioPlayer.positionStream,
_audioPlayer.bufferedPositionStream,
_audioPlayer.durationStream,
(position, bufferedPosition, duration) =>
PositionData(position, bufferedPosition, duration ?? Duration.zero),
);
@override
void dispose() {
_audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
StreamBuilder<SequenceState?>(
stream: _audioPlayer.sequenceStateStream,
builder: (context, snapshot) {
final state = snapshot.data;
if (state?.sequence.isEmpty ?? true) {
return const SizedBox();
}
final metadata = state!.currentSource!.tag as MediaItem;
return MediaMetadata(
imageUrl: metadata.artUri.toString(),
title: metadata.title,
);
}),
const SizedBox(height: 20),
StreamBuilder<PositionData>(
stream: _positionDataStream,
builder: (context, snapshot) {
final positionData = snapshot.data;
return ProgressBar(
barHeight: 8,
progressBarColor: Colors.white,
baseBarColor: Colors.grey[600],
bufferedBarColor: Colors.grey,
thumbColor: Colors.green,
timeLabelTextStyle: const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.w600,
),
progress: positionData?.position ?? Duration.zero,
buffered: positionData?.bufferedPosition ?? Duration.zero,
total: positionData?.duration ?? Duration.zero,
onSeek: _audioPlayer.seek,
);
},
),
SizedBox(height: 20),
Controls(audioPlayer: _audioPlayer),
],
),
),
);
}
}
class MediaMetadata extends StatelessWidget {
final String imageUrl;
final String title;
MediaMetadata({
required this.imageUrl,
required this.title,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.transparent,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: CachedNetworkImage(
imageUrl: imageUrl,
width: 300,
height: 300,
fit: BoxFit.cover,
),
),
),
SizedBox(height: 8.0),
],
);
}
}
class PositionData {
const PositionData(
this.position,
this.bufferedPosition,
this.duration,
);
final Duration position;
final Duration bufferedPosition;
final Duration duration;
}
class Controls extends StatelessWidget {
const Controls({Key? key, required this.audioPlayer}) : super(key: key);
final AudioPlayer audioPlayer;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: audioPlayer.seekToPrevious,
iconSize: 60,
color: Colors.grey,
icon: const Icon(Icons.skip_previous_rounded),
),
StreamBuilder<PlayerState>(
stream: audioPlayer.playerStateStream,
builder: (context, snapshot) {
final playerState = snapshot.data;
final processingState = playerState?.processingState;
final playing = playerState?.playing;
if (!(playing ?? false)) {
return IconButton(
onPressed: audioPlayer.play,
iconSize: 80,
color: Colors.grey,
icon: const Icon(Icons.play_arrow_rounded),
);
} else if (processingState != ProcessingState.completed) {
return IconButton(
onPressed: audioPlayer.pause,
iconSize: 80,
color: Colors.grey,
icon: const Icon(Icons.pause_circle_rounded),
);
}
return const Icon(
Icons.play_arrow_rounded,
size: 80,
color: Colors.grey,
);
},
),
IconButton(
onPressed: audioPlayer.seekToNext,
iconSize: 60,
color: Colors.grey,
icon: const Icon(Icons.skip_next_rounded),
),
],
);
}
}
The music plays well while I'm on the player screen.