How To Create A Music Player In Flutter Using Web API

Introduction

In this article, we will learn how to create a music player app in a flutter. Since flutter applications can run cross-platform using a single codebase, this application can also run on the iOS platform.

How To Make Music Player In Flutter Using Web API

Prerequisite

  • Having the latest version of Android Studio
  • Having Installed Flutter and Dart in Android Studio
  • Having Basic knowledge of Flutter Development  

Let's start with Android Studio,

Create New Flutter Project In Android Studio

Open your Android Studio and create a new project. Edit the project name, android language, iOS language, and platform, and click Create button.

How To Make Music Player In Flutter Using Web API 

Add Required Dependancy In Pubspec.yaml 

Add the following dependency in pubspec.yaml file, and please click on the pub get button.

  http: ^0.13.5
  audioplayers: ^3.0.1

HTTP Package -

HTTP is a network library that allows us to make HTTP requests to the web server and receive responses. HTTP package allows us to perform operations such as making GET and POST requests.

AudioPlayers Package -

This package allows us to play multiple audio files simultaneously. Using the audio player's package, we can play audio files from various sources, such as networks, file systems, and assets. We can use the AudioPlayer object to stop, play, pause, or complete a music file.

Open Main.dart 

Go to main. dart and replace the existing code with the below code 

import 'package:flutter/material.dart';
import 'Screens/HomePage.dart';

void main(){
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(),
      title: "Home Page",
      home: HomePage(),
    );
  }
}

Explanation

main.dart is the entry point of a Flutter application. When the Flutter application is launched, then the main method is executed. We must return the MaterialApp here and set basic properties such as theme, title name, debug banner, etc. Here, We are calling the HomePage class.

We are going to use the below API URL and response data

API URL - https://storage.googleapis.com/uamp/catalog.json

API Response

{
	"music": [{
			"id": "wake_up_01",
			"title": "Intro - The Way Of Waking Up (feat. Alan Watts)",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/01_-_Intro_-_The_Way_Of_Waking_Up_feat_Alan_Watts.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 1,
			"totalTrackCount": 13,
			"duration": 90,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_02",
			"title": "Geisha",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/02_-_Geisha.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 2,
			"totalTrackCount": 13,
			"duration": 267,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_03",
			"title": "Voyage I - Waterfall",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/03_-_Voyage_I_-_Waterfall.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 3,
			"totalTrackCount": 13,
			"duration": 264,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_04",
			"title": "The Music In You",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/04_-_The_Music_In_You.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 4,
			"totalTrackCount": 13,
			"duration": 223,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_05",
			"title": "The Calm Before The Storm",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/05_-_The_Calm_Before_The_Storm.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 5,
			"totalTrackCount": 13,
			"duration": 229,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_06",
			"title": "No Pain, No Gain",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/06_-_No_Pain_No_Gain.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 6,
			"totalTrackCount": 13,
			"duration": 304,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_07",
			"title": "Voyage II - Satori",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/07_-_Voyage_II_-_Satori.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 7,
			"totalTrackCount": 13,
			"duration": 256,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		},
		{
			"id": "wake_up_08",
			"title": "Reveal the Magic",
			"album": "Wake Up",
			"artist": "The Kyoto Connection",
			"genre": "Electronic",
			"source": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/08_-_Reveal_the_Magic.mp3",
			"image": "https://storage.googleapis.com/uamp/The_Kyoto_Connection_-_Wake_Up/art.jpg",
			"trackNumber": 8,
			"totalTrackCount": 13,
			"duration": 293,
			"site": "http://freemusicarchive.org/music/The_Kyoto_Connection/Wake_Up_1957/"
		}
	]
}

Create a Model Class 

Create a new directory named Model inside the lib folder. Now create a new file named MusicDataResponse.dart inside the Model folder and add the below code. 

import 'package:flutter/material.dart';

class MusicDataResponse{

  String? id;
  String? title;
  String? album;
  String? artist;
  String? genre;
  String? source;
  String? image;
  int? trackNumber;
  int? totalTrackCount;
  int? duration;
  String? site;

  MusicDataResponse({
    required this.id,
    required  this.title,
    required this.album,
    required this.artist,
    required this.genre,
    required this.source,
    required  this.image,
    required this.trackNumber,
    required  this.totalTrackCount,
    required this.duration,
    required this.site});

  factory MusicDataResponse.fromJson(Map<String,dynamic> json){

    return MusicDataResponse(
        id:json["id"],
        title:json['title'],
        album:json['album'],
        artist:json['artist'],
        genre:json['genre'],
        source:json['source'],
        image:json['image'],
        trackNumber:json['trackNumber'],
        totalTrackCount:json['totalTrackCount'],
        duration:json['duration'],
        site:json['site']);
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['id'] = this.id;
    data['title'] = this.title;
    data['album'] = this.album;
    data['artist'] = this.artist;
    data['genre'] = this.genre;
    data['source'] = this.source;
    data['image'] = this.image;
    data['trackNumber'] = this.trackNumber;
    data['totalTrackCount'] = this.totalTrackCount;
    data['duration'] = this.duration;
    data['site'] = this.site;
    return data;
  }
}

Explanation

Based on the API response data, we need to create a model class as above and define all the parameters we will use in our application.

Create an API Call Class 

Create a new directory named Services inside the lib folder. Now create a new file named ApiService.dart inside the Services folder and add the below code. 

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:musicplayer/Model/MusicDataResponse.dart';
import 'dart:developer' as devLog;

class ApiService{

  Future<List<MusicDataResponse>> getAllFetchMusicData()async {
    const url = "https://storage.googleapis.com/uamp/catalog.json";
    Uri uri = Uri.parse(url);
    try {
      final response = await http.get(uri);

      if (response.statusCode == 200) {

            final body=response.body;
            final json=jsonDecode(body);
            final result=json['music'] as List<dynamic>;
            final musicList=result.map( (e) {
              return MusicDataResponse.fromJson(e);
            }).toList();

            debugPrint(response.body.toString());
            devLog.log(musicList.toString(),name: "MyMusicData");
            return musicList;

          } else {
            return  throw("Data fetch failed");
          }
    } catch (e) {
      print(e);
      return  throw("Data fetch failed");
    }
  }
}

Explanation

Here we are going to make our API request and get the response. First, we declare the API URL and then make a request using the HTTP package. If we get a response status code is 200, it means API is executed successfully and maps JSON data to the model class; otherwise, we are throwing an error. 

Set Path Of Images

Create a new directory named assets inside the lib folder. Now create a new directory named images inside the assets folder and paste any sample music image. This image is used as a placeholder. We need to set the path of this image in pubspec.yaml file.

imagepath

Design Home Page 

Create a new directory named Screens inside the lib folder. Now create a new file named HomePage.dart inside the Screens folder and add the below code. 

import 'package:flutter/material.dart';
import 'package:musicplayer/Services/ApiService.dart';
import 'package:musicplayer/Model/MusicDataResponse.dart';
import 'MusicDetailPage.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  List<MusicDataResponse> musicList = [];

  @override
  void initState() {
    super.initState();
    fetchMusicData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Music App"),
        ),
        body: customListCard());
  }

  Future<void> fetchMusicData() async {
    final musiclist = await ApiService().getAllFetchMusicData();
    setState(() {
      musicList = musiclist;
    });
  }

  Widget customListCard() {
    return ListView.builder(
      padding: EdgeInsets.zero,
      itemBuilder: (context, index) {
        return InkWell(
          onTap: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>
                      MusicDetailPage(response: musicList[index]),
                ));
          },
          child: Row(
            children: [
              Padding(
                padding: const EdgeInsets.only(left: 8),
                child: Padding(
                  padding: const EdgeInsets.only(
                      left: 8, bottom: 8, right: 8, top: 4),
                  child: SizedBox(
                    child: FadeInImage.assetNetwork(
                        height: 60,
                        width: 60,
                        placeholder: "lib/assets/images/musicplaceholder.png",
                        image: musicList[index].image.toString(),
                        fit: BoxFit.fill),
                  ),
                ),
              ),
              Flexible(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      musicList[index].title.toString(),
                      style: TextStyle(color: Colors.white, fontSize: 18),
                    ),
                    SizedBox(
                      height: 8,
                    ),
                    Text(
                      musicList[index].artist.toString(),
                      style: TextStyle(color: Colors.grey, fontSize: 12),
                    ),
                  ],
                ),
              )
            ],
          ),
        );
      },
      itemCount: musicList.length,
    );
  }
}

Explanation

Here we design our home screen and bind data that we get from API. Inside the initState() method, we call the fetchMusicData method to get API data, and once we get data, we initialize it into the list. Now we have to design a custom card to show an image, title, and subtitle inside the customListCard method and bind the data for each index using the ListView widget. In Flutter, to navigate from the home screen to the detail screen, we are using Navigator.

Home Screen Output

How To Make Music Player In Flutter Using Web API 

Design Music Detail Page

Inside the Screens directory, create a new file MusicDetailPage.dart, and add the below code.

import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:musicplayer/Model/MusicDataResponse.dart';

class MusicDetailPage extends StatefulWidget {
  MusicDetailPage({Key? key, required this.response}) : super(key: key);
  final MusicDataResponse response;
  @override
  State<MusicDetailPage> createState() => _MusicDetailPageState();
}

class _MusicDetailPageState extends State<MusicDetailPage> {
  final audioPlayer = AudioPlayer();
  bool isPlaying = false;
  Duration duration = Duration.zero;
  Duration position = Duration.zero;

  @override
  void initState() {
    super.initState();

    setAudio();

    audioPlayer.onPlayerStateChanged.listen((state) {
      setState(() {
        isPlaying = state == PlayerState.playing;
      });
    });

    // listen to audio duration
    audioPlayer.onDurationChanged.listen((newDuration) {
      setState(() {
        duration = newDuration;
      });
    });

    // listen to audio position
    audioPlayer.onPositionChanged.listen((newPosition) {
      position = newPosition;
    });
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final url = widget.response.image.toString();

    return Scaffold(
      appBar: AppBar(
        title: Text("Music Detail Page"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ClipRRect(
              borderRadius: BorderRadius.circular(20),
              child: Image.network(
                height: MediaQuery.of(context).size.height/2.75,
                url,
                width: double.infinity,
                fit: BoxFit.cover,
              ),
            ),
            SizedBox(height: 32,),
            Text(
              widget.response.title.toString(),
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 4,),
            Text(widget.response.artist.toString(),
              style: TextStyle(
                fontSize: 20,
              ),
            ),
            Slider(
                value: position.inSeconds.toDouble(),
                min: 0,
                activeColor: Colors.white,
                max: duration.inSeconds.toDouble(),
                onChanged: (value) async {
                  final position = Duration(seconds: value.toInt());
                  await audioPlayer.seek(position);
                  // optional :Play audio if was paused
                  await audioPlayer.resume();
                }),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(formatTime(position)),
                  Text(formatTime(duration-position)),
                ],
              ),
            ),
            CircleAvatar(
              radius: 35,
              child: IconButton(
                onPressed: () async {
                  if (isPlaying) {
                    await audioPlayer.pause();
                  } else {
                    await audioPlayer.resume();
                  }
                },
                icon: Icon(isPlaying ? Icons.pause : Icons.play_arrow),
                iconSize: 50,
              ),
            )
          ],
        ),
      ),
    );
  }
  Future<void> setAudio()async  {
    // Repeat song when completed
    audioPlayer.setReleaseMode(ReleaseMode.loop);
    await audioPlayer.setSourceUrl(widget.response.source.toString());
  }
  String formatTime(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, "0");
    final hours=twoDigits(duration.inHours);
    final twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
    final twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
    return [
      if(duration.inHours>0)hours,
      twoDigitMinutes,
      twoDigitSeconds
    ].join(':');
  }
}

Explanation

Here we are going to play audio. First, we create an AudioPlayer object and declare some other variables. Inside initState() method, we listen to whether the audio is playing or not, listen to the audio duration, and listen to the position of the audio. Inside the body, we design our detail screen and bind the data. We use the ClipRRect() widget to show an image and set its height using MediaQuery. Here we are using a Slider widget; when music is played, this slider moves from left to right. Lastly, we are using an IconButton to play and pause music.

Music Detail Screen Output

How To Make Music Player In Flutter Using Web API

Launch your Application

Press the run button or press(shift+F10) and launch the application.

Output

 

Conclusion

This article shows how to create a music player using Web API in a flutter. You can read my other articles by clicking here. Please share your thoughts on this article if you have any suggestions or queries. Thanks for reading.

Happy learning, friends!


Similar Articles