所以你想制作一个音乐流媒体应用程序,但你不知道从哪里开始?好吧,你来对地方了。本指南将概述创建应用程序时要考虑的重要因素,并将比较三个开源音频播放器插件的功能和优势:Just Audio、AudioPlayers和Assets Audio Player。作为奖励,本文还将提供有关如何在第三方包停止工作的潜在情况下使您的应用程序面向未来的信息。
让我们开始吧!
音频流应用注意事项
后台音频系统通知
权限
处理耳机
闪避
从应用程序中隐藏插件(可选)
选择音频播放器插件
只是音频
音频播放器
资产音频播放器
Flutter 音乐流包对比
您可能想直接选择音频播放器插件,但最好尽可能推迟这样的实现细节。首先,您需要仔细考虑您希望您的应用程序做什么以及它的用户界面的外观。
要规划您的应用程序,您可以使用 Sketch、Adobe XD 或 Figma 等工具。或者,您可以选择优质的笔记本纸。画出每个屏幕并决定哪些用户交互是可能的。经历这个过程将迫使你考虑你之前没有考虑过的场景。
在规划应用程序的 UI/UX 时,您可能会发现以下一些主题和问题对您有所帮助:
播放列表:您将如何按流派艺术家或专辑组织歌曲?用户可以创建自己的自定义播放列表吗?
洗牌:你会允许用户随机重新排序播放列表吗?
循环播放:用户可以重复歌曲或专辑吗?
下载:除了流媒体,用户是否可以下载歌曲以供离线播放?
播放状态:您想如何使用圆形进度指示器显示歌曲正在加载?您是否也想显示缓冲进度?
除非您有直播(例如广播),否则您还需要考虑应用程序从哪里获取歌曲。音乐流媒体应用程序需要从某个地方流式传输歌曲。
另外,您将在哪里托管音频文件?您会将它们放在 AWS 之类的云存储中,使用 SoundCloud 之类的服务,还是将歌曲托管在您自己的服务器上?如果您决定在自己的服务器上托管,您是否有足够的带宽来处理所有流媒体?如果没有,您可以考虑使用内容交付网络包装您的服务器。
与托管有关的另一个项目是版权问题。您需要拥有音乐的权利或有权将歌曲流式传输给您的用户。Google Play 和 Apple 的 App Store 都不允许提供盗版内容的应用程序。
除了 UI/UX 和托管相关问题之外,考虑与制作音乐流应用程序相关的某些技术因素也很重要,例如通知、权限、处理耳机和闪避。
对于您的音乐流媒体应用程序,您几乎肯定会希望支持背景音频播放。即使用户切换到不同的应用程序或将手机放在口袋里,这也可以让音乐继续播放。
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →
将音频播放器与系统连接后,用户可以在通知栏和锁定屏幕上进行 UI 控制,以便他们可以暂停音频或跳到播放列表中的下一首歌曲。
音乐流媒体应用程序从互联网流式传输,因此您显然需要获得访问互联网的权限。如果歌曲 URL 使用 HTTP 而不是 HTTPS,那么您也需要为此进行特殊设置。
根据您的应用程序,您可能还需要使用蓝牙、保持屏幕打开和允许前台服务的权限。您需要在应用的配置文件中请求这些权限。
当用户拔下耳机时,您需要决定您的应用是继续播放还是暂停。
当用户在汽车中从您的应用中流式传输音乐同时使用 Google 地图进行导航时,他们可能希望在导航助手说话时降低音乐音量。这被称为闪避。另一方面,播客播放器通常会暂停播放。
此步骤不是必需的,但您永远不知道第三方软件包何时会停止工作。Pub 上的大多数开源软件包都是由好心的开发人员制作的,他们自愿花时间帮助社区。这是很多工作。
包维护者总是可能因为太累、太病或太忙而无法维护包。您的应用也可能需要插件不支持的功能。
让您的应用适应这种情况的一种方法是将插件隐藏在界面后面。这将插件代码限制在单个位置,而不是分散在您的应用程序中。只有应用程序知道界面,因此切换插件相对轻松。您可以尝试一个插件,如果您不喜欢它,则只需将其换成其他插件即可。
创建界面当然不是必需的,它确实为您的应用程序增加了一层额外的复杂性。但是,现在从架构上思考可以为您在未来省去很多麻烦。
要创建接口,请使用类似于以下的 API 创建一个抽象类:
抽象类MusicPlayer { Futureinit (); 未来 加载(字符串url );无效播放();无效暂停();无效搜索(持续时间位置);流<时长>获取位置;流< Duration >获取totalDuration ;未来 dispose (); }
以下是每种方法的说明:
init: 一些 Flutter 插件需要自己初始化,所以你会在应用启动时调用这个方法
load:加载一首歌曲以从 URL 流式传输
play:从头开始播放歌曲,如果歌曲之前暂停,则继续播放
pause: 暂停歌曲
seek:改变播放位置;如果用户滑动到音频进度条上的新位置,您将调用它
position流:报告当前播放位置,以便您可以为进度条上的标记设置动画
totalDurationstream:报告当前歌曲的长度;当您第一次加载歌曲时,此持续时间可能不可用,因此将其报告为流可让您的 UI 对当前播放状态做出反应
dispose:关闭音频播放器并释放其资源
这个 API 是简约的。在完整的应用程序中,您可能想要加载整个播放列表并启用其他功能,例如跳到下一首歌曲、循环播放和随机播放。此外,您可能希望收听更多流,例如播放状态流(初始、播放、暂停、加载)和缓冲位置流。
您将为您选择的任何插件制作此 API 的具体实现,但您的 Flutter 小部件或状态管理代码将只知道该接口。他们不在乎您使用的是什么插件。
为简单起见,以下示例将MusicPlayer界面代码直接混合在 Flutter 小部件中。在更复杂的应用程序中,您可能希望将MusicPlayer调用移动到您的状态管理层,无论是使用 Bloc、Provider、RiverPod 还是其他东西。
插件初始化需要在应用程序运行之前进行。将其添加到您的main函数中,如下所示:
未来main () async { WidgetsFlutterBinding . 确保初始化();等待玩家。初始化(); runApp ( const MyApp ()); }
player``MusicPlayer是具体实现的一个实例。您可以使用GetIt或某种形式的依赖注入来实例化它。
在有状态小部件的生命周期方法中处理加载和处置,如下所示:
@override void initState () { super . 初始化状态(); _loadSong (); } 未来_loadSong () async { const url = 'https://www.example.com/song.mp3' ; 等待玩家。加载(网址);} @override void dispose () { player . 处置();超级。处置();}
您可以通过收听总持续时间和位置流来更新进度条:
StreamBuilder <持续时间>( 流:播放器。totalDuration ,构建 器:(上下文,totalDurationSnapshot ){返回流构建器<持续时间>( 流:播放器。位置, 构建器:(上下文,位置快照){返回进度条( 进度:位置快照。数据?? 持续时间。零, 总计:totalDurationSnapshot 。数据??持续时间。零, onSeek :播放器。寻找, ); }, ); }, ),
与其嵌套两个流构建器,您可能希望将流与类似的包组合rxdart或重新设计您的MusicPlayerAPI 以在单个流中提供位置和总持续时间。
上面代码中的ProgressBar小部件来自我为在我自己的音频应用程序中使用而制作的audio_video_progress_bar包。
您还可以使用Slider小部件实现类似的功能。
不要错过来自 LogRocket 的精选时事通讯The Replay
使用 React 的 useEffect优化应用程序的性能
在多个 Node 版本之间切换
了解如何使用 AnimXYZ 为您的 React 应用程序制作动画
探索 Tauri,一个用于构建二进制文件的新框架
比较NestJS 与 Express.js
发现TypeScript 领域中使用的流行 ORM
现在您已经设置了用户界面,您可以使用任何您喜欢的音频插件自由地实现它。让我们仔细看看三个流行的音频流包。
有许多音频播放器包支持 Flutter 应用程序中的流式音乐。本文将回顾三个流行包的特性和优点:Just Audio、AudioPlayers 和 Assets Audio Player。
不过,在您选择包之前,请考虑按照本文前面讨论的方式对您的应用进行面向未来的验证。
Just Audio 是一个音频插件,可以在 Flutter 支持的所有主要平台上播放音乐。它提供播放列表、随机播放、循环播放和更多内置功能。在本文回顾的三个音频包中,Just Audio 在 Pub 上的点赞数最多(在撰写本文时超过 2,200 个),并且是唯一一个被指定为 Flutter 收藏夹的音频包。
Just Audio 本身不支持背景音频和系统通知。但是,Just Audio 的作者还创建了另一个名为Audio Service的包。此包处理在后台播放音乐并与系统通信以在锁定屏幕和通知区域上显示 UI 控件。您仍将使用 Just Audio,但您将使用音频服务对其进行包装。我在这个深入的教程中描述了如何做到这一点。
音频服务不是最容易使用的插件,因为它需要管理音频播放器和系统通知。不过,这并非不可能,并且通过一些研究和实验,您可以让这一切正常工作。
同一包作者还创建了另一个名为Just Audio Background的插件,它结合了 Just Audio 和 Audio Service。对于标准用例,这可能是您的最佳选择。如果您需要具有更复杂功能的功能,例如同时播放两个音频源的能力,则必须分别使用 Just Audio 和 Audio Service。
MusicPlayer以下是使用 Just Audio Background实现API 的方法:
类JustAudioPlayer实现MusicPlayer { final AudioPlayer _player = AudioPlayer (); @override Futureinit () async { await JustAudioBackground 。init ( androidNotificationChannelId : 'com.logrocket.demo.channel.audio' , androidNotificationChannelName : '音频播放' , androidNotificationOngoing : true , ); } @override Future < Duration > load ( String url ) async { final source = AudioSource . uri ( Uri . parse ( url ), tag : const MediaItem ( id : '1' , title : "My song" , ), ); 返回等待_player 。setAudioSource (来源) ?? Duration.zero; } @override void play() => _player.play(); @override void pause() => _player.pause(); @override void seek(Duration position) => _player.seek(position); @override Stream get position => _player.positionStream; @override Stream get totalDuration => _player.durationStream.map( (duration) => duration ?? Duration.zero, ); @override Future dispose() async => await _player.dispose(); }
大多数这些方法只是将您的MusicPlayerAPI 转发到插件的音频播放器。该init方法对背景音频进行了一些注册工作。AudioSource是 Just Audio 用来设置当前歌曲或播放列表的东西。MediaItem是音频服务跟踪当前歌曲以显示在系统通知区域中的方式。
除了编码工作之外,您还必须在 Android 和 iOS 配置文件中进行一些设置。这在文档中有所描述,但这里有一个摘要:
对于 Android,编辑您的 Android Manifest 并请求INTERNET、WAKE_LOCK和FOREGROUND_SERVICE;的权限 您还需要添加服务和接收器元素
对于 iOS,在文件中添加audio为项目;如果您的应用不需要录制音频,您还应该编辑您的以去除一些音频录制 APIUIBackgroundModesInfo.plist
Podfile
如果您的音频文件 URL 是 HTTP 而不是 HTTPS,则需要进行其他更改,因为默认情况下 Android 和 iOS 不启用 HTTP 源
以下是一些使用 Just Audio、Audio Service 或 Just Audio Background 的开源存储库:
https://github.com/w99910/wazplay(只是音频背景)
https://github.com/tsacdop/tsacdop(只是音频)
https://github.com/o-ifeanyi/musicPlayer(只是音频)
https://github.com/immadisairaj/radiosai(只是音频和音频服务)
您可能还希望查阅Just Audio、Just Audio Background和Audio Service的官方示例应用程序。
AudioPlayers 插件最初是另一个名为AudioPlayer的插件的分支。然而,AudioPlayers 已经远远超越了它的前身。在本文回顾的三个插件中,AudioPlayers 是最古老的,比 Flutter 的第一个稳定版本早两年半。尽管在 Pub 上的支持率略低于 Just Audio(撰写本文时超过 1,720),但 Pub 神秘计算的受欢迎度指标为 100%,绕过了 Just Audio 99% 的受欢迎度。
AudioPlayers 的作者也参与了Flame 游戏引擎的开发。这大概解释了为什么 AudioPlayers 被嵌入在可以用于在 Flutter 游戏中播放声音的Flame Audio 插件中。
与 Just Audio 一样,AudioPlayers 本身不支持背景音频。因此,如果您希望用户能够从锁定屏幕控制您的歌曲,您需要使用音频服务插件包装 AudioPlayers。没有像 AudioPlayers 的 Just Audio Background 这样的便利包。
以下是为 AudioPlayers 设置音频服务的基本步骤:
创建一个自定义AudioHandler类来包装您的 AudioPlayers 播放器
对于您在音频处理程序中实现的每个方法,您需要将音频服务方法转发给音频播放器,然后告诉系统您在做什么,以便它可以更新锁定屏幕和通知 UI
main在之前的方法中初始化音频处理程序runApp
Android 和 iOS 配置设置类似于前面 Just Audio 部分中描述的设置;有关其他信息,请参阅音频服务文档
AudioPlayers 播放器本身的方法与 Just Audio 播放器类似。这是一个简短的比较:
_玩家。setAudioSource ( AudioSource . uri (...)); // 只是音频 _player 。setSourceUrl (网址); // 音频播放器 _玩家。播放();// 只是音频 _player 。简历();// 音频播放器 _玩家。暂停();// 只是音频 _player 。暂停();// 音频播放器 _玩家。寻求(持续时间);// 只是音频 _player 。寻求(持续时间);// 音频播放器 _玩家。处置();// 只是音频 _player 。释放();// 音频播放器
Just Audio 和 AudioPlayers 之间最大的区别之一是 Just Audio 支持开箱即用的播放列表。使用 AudioPlayers,您必须自己实现该功能。
以下是一些使用 AudioPlayers 的开源存储库:
https://github.com/KRTirtho/spotube
https://github.com/minikin/soundcloud_audio_player
https://github.com/lohanidamodar/flutter_audiobooks_app
https://github.com/obnil/flutter_music_app
https://github.com/iampawan/AI-Radio
https://github.com/AdnanKamali/Flutter_musicApp
https://github.com/ivlie1495/flutter-music-player
另请查看官方 AudioPlayer 示例应用程序。
与其名称所暗示的相反,Assets Audio Player 插件可以做的不仅仅是播放 assets 文件夹中的音频。在其众多功能中,它可以从 URL 流式传输音频,这意味着您也可以在音乐流式传输应用程序中使用此插件。
Assets Audio Player 为播放列表、随机播放、循环播放、系统通知、蓝牙、暂停通话、音频闪避等提供内置支持。开发人员显然在这个插件上投入了大量时间。为了便于使用,它可能是本文所回顾的三个插件中最好的一个。
与 Just Audio 和 AudioPlayers 相比,Assets Audio Player 插件在 Pub 上的点赞数较少(撰写本文时接近 800 个),但它的受欢迎程度得分紧随其后。而且,与本文中介绍的其他两个插件一样,Assets Audio Player 也得到了积极维护。
MusicPlayer这是由您的界面包装的资产音频播放器设置:
类AssetsAudioPlayerPlayer实现MusicPlayer { final _player = AssetsAudioPlayer (); @override Futureinit () async { AssetsAudioPlayer . setupNotificationsOpenAction (( notification ) { return true ; }); } @override Future load ( String url ) async { await _player . open ( Audio.network ( url , metas : Metas ( title : “我的歌” ), ) , showNotification : true , ) ; } @override void pause () => _player 。暂停(); @override void play() => _player.play(); @override Stream get position => _player.currentPosition; @override Stream get totalDuration => _player.current.map( (playing) => playing?.audio.duration ?? Duration.zero, ); @override无效搜索(持续时间位置)=> _player 。寻找(位置); @override Future dispose () => _player 。处置();}
此设置与 Just Audio Background 的设置非常相似。但是,Android 和 iOS 方面的工作较少。Android 只需要请求INTERNET权限。与其他插件一样,如果 Android 和 iOS 对 URL 使用 HTTP,而不是 HTTPS,则需要通知系统。
以下是一些使用 Assets Audio Player 的开源存储库:
https://github.com/rohit5krish/Music_player
https://github.com/Lutetium-Vanadium/Music-Flutter
https://github.com/Ansh-Rathod/Flutter-Musive-app
另外,查看官方 Assets Audio Player 示例应用程序
为了帮助您做出最终决定,这里总结了 Just Audio、AudioPlayers 和 Assets Audio Player Flutter 音乐流包的优缺点。
Flutter 音乐流包 | 优点 | 缺点 |
---|---|---|
只是音频 | 对所有主要平台(Android、iOS、Web、macOS、Windows、Linux)的可靠支持对播放本地资产和文件以及从 URL 流式传输的可靠支持功能丰富,具有完善的播放列表处理系统具有良好的关注点分离,音频播放由 Just Audio 处理,系统通知由 Audio Service 处理;还有一个比较好用的 Just Audio Background 插件,它结合了两者开发人员积极维护项目并快速响应格式良好的 GitHub 问题文档相当广泛(完全披露:我编写了一些基于社区的教程)支持缓存,因此您无需继续流式传输同一首歌曲颤振最爱 | 如果您需要自己设置音频服务,学习曲线陡峭Just Audio Background 仍处于测试阶段,没有很多文档 |
音频播放器 | 对所有主要平台(Android、iOS、Web、macOS、Windows、Linux)的可靠支持对播放本地资产和文件以及从 URL 流式传输的可靠支持发展历史悠久,依然强劲;该软件包被采用为 Flame 游戏引擎的音频播放器是对其长期稳定性的信任票提供用于播放短音频剪辑的低延迟模式,这在游戏中很有用强大的社区支持 | 没有对播放列表的内置支持,这意味着没有随机播放和循环播放;用户必须自己编写此逻辑没有对背景音频和系统通知的内置支持;用户必须使用相对难以使用的音频服务插件来实现这一点文档在更高级的主题上有些缺乏 |
资产音频播放器 | 支持 Android、iOS、Web 和 macOS对播放本地资产和文件以及从 URL 流式传输的可靠支持提供许多内置功能支持随机播放和循环播放列表提供内置的背景音频和系统通知比较容易使用 | 这个名字有点误导;该插件不仅限于资产目前不支持 Windows 和 Linux缺少一些一般的整洁(例如,API 文档在一种情况下已过时,发布者尚未在 Pub 上验证,GitHub 问题没有响应,示例项目有些杂乱无章,注释掉的代码尚未删除) |
如果你想构建一个流式传输音乐的 Flutter 应用程序,这里介绍的三个音频播放器插件中的任何一个都可以完成工作。为了简单起见,请考虑 Assets Audio Player 或 Just Audio 的 Just Audio Background 版本。如果您想更好地控制正在发生的事情,请尝试使用音频服务包装 Just Audio 或 AudioPlayers。但是,如果您比较 Just Audio 和 AudioPlayers,Just Audio 更适合音乐流媒体应用,因为它提供了对播放列表的内置支持。
在写这篇文章的时候,我让自己相信了用接口包装音频插件的好处。在测试期间,我只需更改一行代码即可在插件实现之间进行交换。
制作音乐流媒体应用程序可能具有挑战性。如果您遇到困难,请研究插件仓库中的示例应用程序是如何工作的。只要有一点毅力,你就会得到它。
现在,出去做点音乐吧!
成千上万的工程和产品团队使用LogRocket来减少了解技术和可用性问题的根本原因所需的时间。使用 LogRocket,您将减少与客户来回对话的时间,并消除无休止的故障排除过程。LogRocket 让您可以花更多时间构建新事物,而减少修复错误的时间。