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.pswp.cn/pingmian/79048.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/79048.shtml
英文地址,請注明出處:http://en.pswp.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…