flutter开发音乐APP(简单的音乐播放demo)

效果如下:

音乐播放界面

锁屏音乐播放展示

主要使用的插件如下

just_audio : 是一个功能丰富的音频播放器,适用于Android、iOS、macOS、Web、Linux和Windows平台。它提供了多种功能,包括从URL、文件、资产或字节流读取音频,支持DASH、HLS等流媒体协议,处理ICy元数据,以及更多高级特性如播放列表管理、无缝播放、循环播放、随机播放等。

just_audio_background : 使用该插件可以让应用在后台播放音频并且响应来自锁屏界面、媒体通知、头戴耳机、AndroidAuto/CarPlay 或 智能手表的控制。

audio_service :负责音乐的后台、通知栏展示功能

dio:用于网络请求

permission_handler:系统权限处理

device_info_plus:用于获取当前设备的信息

flutter_screenutil:适配屏幕尺寸和屏幕密度的 Flutter 插件

pubspec.yaml

name: simple_music_app
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0environment:sdk: '>=3.3.0 <4.0.0'# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:flutter:sdk: flutterjust_audio: ^0.9.34just_audio_background: ^0.0.1-beta.13audio_service: ^0.18.15dio: ^5.7.0flutter_screenutil: ^5.9.3permission_handler: ^11.3.1device_info_plus: ^11.2.0# The following adds the Cupertino Icons font to your application.# Use with the CupertinoIcons class for iOS style icons.cupertino_icons: ^1.0.8dev_dependencies:flutter_test:sdk: flutter# The "flutter_lints" package below contains a set of recommended lints to# encourage good coding practices. The lint set provided by the package is# activated in the `analysis_options.yaml` file located at the root of your# package. See that file for information about deactivating specific lint# rules and activating additional ones.flutter_lints: ^4.0.0get: ^4.6.6fluttertoast: ^8.2.4cached_network_image: ^3.3.1# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec# The following section is specific to Flutter packages.
flutter:# The following line ensures that the Material Icons font is# included with your application, so that you can use the icons in# the material Icons class.uses-material-design: true# To add assets to your application, add an assets section, like this:# assets:#   - images/a_dot_burr.jpeg#   - images/a_dot_ham.jpeg# An image asset can refer to one or more resolution-specific "variants", see# https://flutter.dev/to/resolution-aware-images# For details regarding adding assets from package dependencies, see# https://flutter.dev/to/asset-from-package# To add custom fonts to your application, add a fonts section here,# in this "flutter" section. Each entry in this list should have a# "family" key with the font family name, and a "fonts" key with a# list giving the asset and other descriptors for the font. For# example:# fonts:#   - family: Schyler#     fonts:#       - asset: fonts/Schyler-Regular.ttf#       - asset: fonts/Schyler-Italic.ttf#         style: italic#   - family: Trajan Pro#     fonts:#       - asset: fonts/TrajanPro.ttf#       - asset: fonts/TrajanPro_Bold.ttf#         weight: 700## For details regarding fonts from package dependencies,# see https://flutter.dev/to/font-from-package

下载所需要的插件后,首先要在AndroidManifest.xml中配置所需要的文件访问权限和网络请求权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"package="com.ryanheise.just_audio_example"tools:ignore="Instantiatable"><!-- 配置网络权限 --><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.WAKE_LOCK"/><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/><uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/><uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/><!-- for below android 13--><uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><!-- for above android 13--><uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /><uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /><uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /><applicationandroid:label="simple_music_app"android:name="${applicationName}"android:icon="@mipmap/ic_launcher"android:usesCleartextTraffic="true" android:enableOnBackInvokedCallback="true"><activityandroid:name="com.ryanheise.audioservice.AudioServiceActivity"android:exported="true"android:launchMode="singleTop"android:taskAffinity=""android:theme="@style/LaunchTheme"android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"android:hardwareAccelerated="true"android:windowSoftInputMode="adjustResize"><!-- <meta-dataandroid:name="io.flutter.embedding.android.NormalTheme"android:resource="@style/NormalTheme"/> --><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><!-- Don't delete the meta-data below.This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --><meta-data android:name="flutterEmbedding" android:value="2"/><serviceandroid:name="com.ryanheise.audioservice.AudioService"android:foregroundServiceType="mediaPlayback"android:exported="true" tools:ignore="Instantiatable"><intent-filter><action android:name="android.media.browse.MediaBrowserService" /></intent-filter></service><receiverandroid:name="com.ryanheise.audioservice.MediaButtonReceiver"android:exported="true" tools:ignore="Instantiatable"><intent-filter><action android:name="android.intent.action.MEDIA_BUTTON" /></intent-filter></receiver></application><!-- Required to query activities that can process text, see:https://developer.android.com/training/package-visibility andhttps://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --><queries><intent><action android:name="android.intent.action.PROCESS_TEXT"/><data android:mimeType="text/plain"/></intent></queries>
</manifest>

main.dart入口文件

// ignore_for_file: depend_on_referenced_packagesimport 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:simple_music_app/common/music_service.dart';
import 'package:simple_music_app/common/utils.dart';
import 'package:simple_music_app/components/float_music_player.dart';
import 'package:simple_music_app/components/song_everyday_recommond.dart';
import 'package:simple_music_app/control/music_control.dart';
import 'package:simple_music_app/model/common_model.dart';
import 'package:simple_music_app/model/everyday_recommond_res.dart';
import 'package:get/get.dart';void main() async {WidgetsFlutterBinding.ensureInitialized();Get.put(MusicController());final MusicController audioController = Get.put(MusicController());await storagePermission();await JustAudioBackground.init(androidNotificationChannelId: 'com.ryanheise.bg_demo.channel.audio',androidNotificationChannelName: 'Audio playback',androidNotificationOngoing: true,);audioController.playerStateStream();runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});// This widget is the root of your application.@overrideWidget build(BuildContext context) {return ScreenUtilInit(designSize: const Size(375, 812), // 设计稿尺寸(单位:逻辑像素)minTextAdapt: true, // 允许字体根据屏幕缩放splitScreenMode: true, // 支持分屏模式builder: (context, child) {return const MaterialApp(debugShowCheckedModeBanner: false,home: MyHomePage(),);},);}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key});@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {final MusicController audioController = Get.put(MusicController());List<EverydayRecommondSongList> everyRecommondList = [];Future<void> _fetchEveryRecommond() async {fetchEveryRecommond().then((everyRecommondRes) {if (everyRecommondRes.status == 1) {setState(() {everyRecommondList = everyRecommondRes.data.songList;});}});}void handlePlayMusic(index) async{if (audioController.storePlaylist.isNotEmpty) {var currentHash = audioController.storePlaylist[index].audioHash;audioController.updateCurrentHash(currentHash);}// print(everyRecommondList[index].singerinfo[0].id);var listTemp = List<AudioSource>.filled(everyRecommondList.length,AudioSource.uri(Uri.parse(''),tag: MediaItem(id: '0',title: '歌曲加载中',artUri: Uri.parse('https://pic.downk.cc/item/5f9e1f771cd1bbb86bf49c90.jpg'),album: 'music')),);List<PlayList> storePlaylist = everyRecommondList.map((song) => PlayList(filesize128: song.filesize128,filesize320: song.filesize320,filesizeFlac: song.filesizeFlac,audioHash320: song.hash320,audioHashFlac: song.hashFlac,songName: song.songname,songDuration: song.timeLength,hasQuality: 1,singerName: song.authorName,coverUrl: song.sizableCover.replaceAll('{size}', '720').replaceAll('http', 'https'),audioId: song.songid,audioHash: song.hash,mixsongid: song.albumAudioId)).toList();audioController.updatePlayList(storePlaylist);audioController.updateCurrentPlaylist(listTemp);String audioHash = everyRecommondList[index].hash;await audioController.play(index, audioHash);}@overridevoid initState() {_fetchEveryRecommond();// TODO: implement initStatesuper.initState();}@overrideWidget build(BuildContext context) {return MaterialApp(theme: ThemeData(colorScheme: const ColorScheme.dark(),scaffoldBackgroundColor: Colors.black,appBarTheme: const AppBarTheme(backgroundColor: Colors.transparent,elevation: 0,scrolledUnderElevation: 0)),home: Scaffold(appBar: AppBar(backgroundColor: Colors.black,title: const Text('Music'),),body: Stack(children: [Column(children: [Expanded(child: ListView.builder(padding: const EdgeInsets.all(10).r,itemCount: everyRecommondList.length,itemBuilder: (context, index) {return SongEverydayRecommond(posterUrl: everyRecommondList[index].sizableCover.replaceAll('/{size}', '').replaceAll('http', 'https'),sognName: everyRecommondList[index].songname,singerName: everyRecommondList[index].authorName,songTag: everyRecommondList[index].recSubCopyWrite.toString(),handelClickFn: () {handlePlayMusic(index);},);},),),Obx(() {if (audioController.currentIndex.value != 100000) {return SizedBox(height: 60.h,);} else {return Container();}},),],),Obx(() {if (audioController.currentIndex.value != 100000) {return const FloatMusicPlayer();} else {return Container();}},),],)),);}
}

项目lib

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css中盒模型有哪些

标准盒模型&#xff08;w3c盒模型&#xff09; 在标准盒模型中&#xff0c;元素的width和height只包括内容区域&#xff0c;不包括内边距、边框、外边距。也就是元素的实际宽高是内容区域加上内边距、边框、外边距。 例如&#xff1a;一个元素的宽度设置为100px&#xff0c;内…

第3篇:请求参数处理与数据校验

在 Web 开发中&#xff0c;请求参数处理与数据校验是保障系统稳定性的第一道防线。本文将深入探讨 Egg.js 框架中参数处理的完整解决方案&#xff0c;涵盖常规参数获取、高效校验方案、文件流处理等核心功能&#xff0c;并分享企业级项目中的最佳实践。 一、多场景参数获取策略…

2025年-redis(p1-p10)

1.redis介绍 &#xff08;1&#xff09;基础&#xff1a;常见的数据结构及命令、jedis的应用和优化、springDataRedis的应用和优化 &#xff08;2&#xff09;企业实战的应用场景&#xff1a;共享session、缓存解决问题、秒杀中的redis应用、社交app中的redis应用、redis特殊结…

【AI模型学习】GPT——从v1到v3

文章目录 GPT-1GPT vs BERTGPT-2GPT-3Ai代码 GPT-1 GPT-1&#xff08;Generative Pretrained Transformer 1&#xff09;是 OpenAI 在2018年发布的第一个大规模预训练生成模型。它开创了基于 Transformer 的 预训练-微调 (pretraining-finetuning) 框架&#xff0c;在自然语言…

数字智慧方案6178丨智慧医院医疗信息化建设之以评促建(61页PPT)(文末有下载方式)

资料解读&#xff1a;智慧医院医疗信息化建设之以评促建 详细资料请看本解读文章的最后内容。 在当今数字化时代&#xff0c;医疗行业正经历着深刻变革&#xff0c;智慧医院的建设成为提升医疗服务质量、优化医疗资源配置的关键所在。这份智慧医院医疗信息化建设之以评促建的资…

浅谈C# record关键字

环境:.net8控制台 init关键字 通常我们会有一个常见的需求就是需要实现一个实例化后不可变的类型. 我通常会如下实现,将类的属性的set设为私有,这样只能使用构造函数来实例一个不可变对象. 但是如果内部再声明一个public的方法还是有可能会将我这个对象改变. internal class…

实时数仓dim层设计的一些疑惑点

0.dim层组件的选择 dim层存储要求&#xff1a;需要满足永久存储&#xff08;需要长期保存历史数据&#xff09;和支持根据主键查询单条数据明细&#xff0c;所以排除Kafka&#xff08;时效短&#xff09;&#xff1b; 候选框架&#xff1a;MySQL、Redis、Hive、Doris、HBase …

模型之FIM(Fill-In-the-Middle)补全

文章目录 模型之FIM(Fill-In-the-Middle)补全什么是FIM(Fill-In-the-Middle)FIM 的工作原理FIM 示例:代码补全场景常见模型fim 测试deepseek fim阿里completions 接口要判断模型是否支持特定的特殊标记**1. 模型可以自动推断生成区域****2. `suffix` 是可选的****3. 模型的…

使用CubeMX新建DMA工程——存储器到外设模式

目录 1、新建板级支持包 1、usart.c: 2、修改的地方&#xff1a;在usart.c中添加了这些 3、usart.h: 4、在usart.h中添加了这些&#xff1a; 5、dma.c: 6、dma.h: 2、修改main.c文件 1、在main.c文件中添加头文件 2、添加外部变量声明 3、添加简单延时函数 4、添加…

el-transfer穿梭框数据量过大的解决方案

一&#xff1a;背景 我们这个穿梭框获取的是项目的全量数据&#xff0c;在左边大概有5000条&#xff0c;自己测试了一下5000条数据的效果&#xff0c;发现异常的卡顿&#xff0c;本来打算像el-select一样去解决的&#xff08;只显示一部分&#xff0c;在搜索的时候去全量搜索&a…

2025年- H17-Lc125-73.矩阵置零(矩阵)---java版

1.题目描述 2.思路 &#xff08;1&#xff09;计算矩阵的行数 &#xff08;2&#xff09;计算矩阵的列数 &#xff08;3&#xff09;设计一个行列的bool数组 &#xff08;4&#xff09;遍历矩阵&#xff08;二维数组&#xff09;&#xff0c;如果遇到元素0&#xff0c;则把…

Qt二维码demo

使用QZXing库生成的二维码demo 运行结果 实现代码 c文件 #include "mainwindow.h" #include "ui_mainwindow.h" #include "src/myqrcodeheader.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow) {ui-&…

怪物猎人:世界-冰原10000+mod整合包5月最新更新!

700A大全套精美服装 800M大全套精美服装 3月31日更新 新增 新武器 新特效MOD 当前共计5800MOD整合包 好看的发型mod 实用的功能mod 炫酷的武器mod 新服装新特效新武器实用模组美化&#xff0c;等。 1月14日更新 新增皮肤MOD 500 当前共计2000MOD 1月16日更新 新增超…

华纳云:centos如何实现JSP页面的动态加载

JSP(JavaServer Pages)作为Java生态中常用的服务器端网页技术&#xff0c;具有动态内容生成、可扩展性强、与Java无缝结合等优势。 而CentOS作为一款稳定、高效、安全的Linux服务器操作系统&#xff0c;非常适合部署JSP应用。 想要让JSP页面实现动态更新加载&#xff0c;避免…

gradle-tasks.register(‘classesJar‘, Jar)解析

在使用gradle作为构建工具的android或者java web项目中&#xff0c;我们经常能遇到以下格式 tasks.register(classesJar, Jar) {from "$buildDir/intermediates/javac/release/classes" // 假设使用 release 构建变体 }artifact sourcesJar使用伪代码解释 class Cu…

数据处理1

一、常用数据处理模块Numpy Numpy常用于高性能计算&#xff0c;在机器学习常常作为传递数据的容器。提供了两种基本对象&#xff1a;ndarray、ufunc。 ndarray具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。 ufunc提供了对数组快速运算的标准数学函数。 ndar…

电力市场的交易品种

双边交易&#xff08;Bilateral Trading&#xff09; 定义&#xff1a;是电力市场中最基本的交易方式之一&#xff0c;指具备市场交易资格的买方和卖方&#xff0c;通过自主协商、双边协商的形式&#xff0c;确定交易电量、交易价格、交割曲线等交易要素&#xff0c;并签订中长…

uniapp 实现时分秒 分别倒计时

效果 <view class"issue-price-countdown"> <CountDown :endTimestamp"1745996085000"></CountDown> </view> 引入组件 import CountDown from /components/CountDown.vue; <template> <view class&qu…

从CRUD到复杂业务:AI自动生成电商优惠券叠加逻辑(新手救星指南)

在 Java 编程的广阔天地中,据统计,高达 80% 的新手会在业务逻辑编写环节陷入困境。业务逻辑作为软件系统的核心灵魂,承载着从用户需求到代码实现的关键转化过程,为何却成为新手难以逾越的 “鸿沟”?飞算 JavaAI 的出现,又将如何打破这一僵局? 一、Java 新手卡在业务逻辑的根…

23页PDF | 数据治理实施方案 :规划、执行、评价、改进四步走的管控模式

在当今数字化时代&#xff0c;数据已经成为企业和组织的核心资产之一。然而&#xff0c;随着数据量的不断增长和数据来源的日益多样化&#xff0c;数据治理变得愈发重要。有效的数据治理能够确保数据的质量、安全和合规性&#xff0c;提升数据的价值和利用效率。那么&#xff0…