web-to-app 背景音乐(BGM)功能详解:播放模式、LRC 同步歌词与 APK 加密打包
2026/9/17 19:17:52 网站建设 项目流程

web-to-app 背景音乐(BGM)功能详解:播放模式、LRC 同步歌词与 APK 加密打包

【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app

本文基于 web-to-app 仓库的 BGM 官方文档 与对应源码,系统讲解如何在生成的应用中配置带同步歌词的背景音乐:从「编辑通用配置」中的 BGM 卡片各选项,到BgmConfig数据模型、BgmPlayer播放引擎的三种播放模式实现、LRC 歌词的解析与持久化规则,再到音频文件打包进导出 APK 时的加密与解密链路。读完本文,你可以完整掌握该功能的配置方法、参数含义与底层实现机制。

BGM 卡片的位置与核心选项

BGM 功能入口位于 编辑通用配置编辑器 中的背景音乐卡片,用于在生成的应用里播放背景音乐并显示同步歌词。卡片对应 UI 实现为 BgmCard.kt。文档定义了五个选项:

  • 启用—— 打开背景音乐,对应数据模型中的bgmEnabled字段(见 WebApp.kt#L107-L108,默认false)。
  • 播放列表—— 添加音乐曲目;支持同步LRC 歌词与歌词动画。
  • 播放模式—— 循环、顺序或随机(BgmPlayMode)。随机模式首曲即随机,每轮每首播一次不重复,播完重洗。
  • 歌词样式—— 自定义字体、颜色、描边和阴影。
  • 在线搜索—— 在线搜索音乐。

数据模型:BgmConfigBgmItem与播放模式

所有配置收敛在 WebApp.kt 中定义的一组数据类上。WebApp应用模型通过bgmEnabled(是否启用)与bgmConfig(具体配置)两个字段持有 BGM 状态。

BgmConfig:播放器配置

定义见 WebApp.kt#L1162-L1169,字段与默认值如下:

字段类型默认值含义
playlistList<BgmItem>空列表播放列表,为空时播放器直接返回不播放
playModeBgmPlayModeLOOP循环 / 顺序 / 随机
volumeFloat0.5f音量,取值 0~1
autoPlayBooleantrue初始化后是否自动开唱首曲
showLyricsBooleantrue是否显示歌词
lrcThemeLrcTheme?null歌词样式主题

BgmItem:曲库条目

BgmItem(WebApp.kt#L1149-L1160)描述单首曲目:name(曲目名)、path(音频路径)、coverPath(封面,可选)、isAsset(是否为 assets 预置曲目)、tags(曲风标签)、lrcData(解析后的歌词)等。

path的取值有两种形态,这也是后续解密链路分叉的根源:

  • asset:///bgm/xxx.mp3—— 预置在 APK assets 中的音乐;
  • 绝对路径(如/data/user/0/.../files/bgm/xxx.mp3)—— 用户导入的音乐文件。

BgmPlayMode与随机模式的「洗牌」语义

BgmPlayMode枚举包含LOOPSEQUENTIALSHUFFLE三个值(WebApp.kt#L1042-L1046)。文档中「随机模式首曲即随机,每轮每首播一次不重复,播完重洗」的完整实现在 BgmPlayer.kt 中:

  • 首曲即随机initialize()在配置为SHUFFLE时立即生成shuffledIndices = playlist.indices.shuffled()(BgmPlayer.kt#L67-L69),因此第一轮第一首就是随机抽中的;
  • 每轮不重复:播放索引currentIndex在洗牌数组上顺序前进,playCurrentTrack()通过shuffledIndices[currentIndex]映射回真实曲目(BgmPlayer.kt#L80-L83),保证一轮内不重复;
  • 播完重洗playNext()中索引取模回绕到 0 时重新shuffled()(BgmPlayer.kt#L153-L164),开启新一轮洗牌。

另外两种模式的细节:

  • LOOP(循环):单曲列表时直接置isLooping = true交给MediaPlayer硬件级循环;多曲时每首播完调用playNext()轮转(BgmPlayer.kt#L101、BgmPlayer.kt#L127-L135)。
  • SEQUENTIAL(顺序):按列表顺序播放,末曲播完后回到第一首继续(BgmPlayer.kt#L136-L145)。

进度上报由主线程Handler每 100ms 轮询MediaPlayer.currentPosition并回调onProgressListener(BgmPlayer.kt#L33-L47),供歌词高亮与进度条使用。

LRC 歌词:格式解析、旁挂持久化与样式

解析规则

LRC 文本解析在 BgmStorage.parseLrcText() 中完成,使用两条正则:

  • 时间戳行:[mm:ss.xx]歌词,毫秒支持两位或三位((\d{2,3}));
  • 元数据行:[ti:标题][ar:歌手][al:专辑](大小写不敏感)。

每行解析为LrcLine(startTime, endTime, text, translation?)endTime的推断策略是:先默认给 5000ms 的占位时长,随后统一把每一行的endTime修正为下一行的startTime(BgmStorage.kt#L491-L493),即「当前句持续到下一句开始」,这正是歌词高亮换行的时间依据。LrcLine还带可选的translation字段,支撑歌词翻译场景。

旁挂(sidecar)持久化

文档强调:歌词和标签的修改会持久化到曲库(旁挂.lrc与标签文件),即使曲目尚未保存进应用配置,刷新和重启后依然保留。对应实现:

  • .lrc旁挂文件路径由 getLrcPathForBgm() 统一约定:用户音乐与其同目录同名的.lrc;assets 预置音乐因为 assets 只读,改写为写入filesDir/bgm/<同名>.lrc,扫描时优先采用该用户覆盖版本(BgmStorage.kt#L81-L93)。
  • 保存歌词时通过 saveLrc() 重写标准 LRC 文本,其中翻译行以「同一时间戳双行」形式写出,注释说明这与导出管线(ApkBuilder.convertLrcDataToLrcString)的 wire 格式保持一致,保证翻译在旁挂文件往返中不丢失。
  • 曲风标签(BgmTag,如PURE_MUSICANIMESLEEP等,见 WebApp.kt#L1048-L1092)不随曲目配置保存,而是集中持久化在曲库级文件bgm/library_tags.json中,键为asset/<曲目名>user/<曲目名>(saveTagsForBgm())。源码注释解释了这样设计的原因:否则标签只存在于恰好引用了该曲目的应用配置里,重新扫描就会丢失。
  • 歌词的编辑与手动对齐入口在 UI 层的 LrcEditorDialog.kt 与 ManualLrcAligner.kt。

歌词样式:LrcTheme

文档中的「歌词样式 —— 自定义字体、颜色、描边和阴影」对应 LrcTheme:

字段默认值含义
fontFamily"default"字体
fontSize18f字号
textColor#FFFFFF普通歌词颜色
highlightColor#FFD700当前句高亮颜色
backgroundColor#80000000背景色(半透明黑)
strokeColor/strokeWidthnull/0f描边颜色与宽度
shadowEnabledtrue是否启用阴影
animationTypeFADE歌词动画类型
positionBOTTOM歌词位置(TOP/CENTER/BOTTOM
showTranslationtrue是否显示翻译

歌词动画类型枚举 LrcAnimationType 提供 7 种:NONEFADESLIDE_UPSLIDE_LEFTSCALETYPEWRITER(打字机)、KARAOKE(卡拉 OK 逐字高亮),即文档所说的「歌词动画」。

曲库扫描:assets 预置与用户导入

曲库扫描由 BgmStorage.scanAllBgm() 完成,合并两个来源:

  1. assets 预置曲库app/src/main/assets/bgm/目录。其 README.txt 定义了预置文件的命名规则:
    • 音乐文件:小乔.mp3
    • 封面图片:小乔.png(或.jpg/.jpeg);
    • 同名音乐与图片自动配对,图片作为封面图标显示;封面可选,仅用于选择界面识别;
    • 示例:小乔.mp3 + 小乔.png背景音乐1.mp3 + 背景音乐1.jpgbgm_01.mp3(无封面)。
  2. 用户曲库:应用私有目录filesDir/bgm/,通过 scanUserBgm() 扫描,封面与 LRC 均按同名旁挂匹配。

两个扫描器对音频格式的约定一致,即 MUSIC_EXTENSIONS:mp3m4aaacoggflacwav—— 与文档「在线音乐搜索按真实格式下载曲目 —— MP3、M4A、AAC、OGG、FLAC 或 WAV —— 都会出现在选择器中」的描述完全吻合。封面识别扩展名为png/jpg/jpeg/jpe/jfif/webp/bmp/gif/heic/heif,且jpeg/jpe/jfif会规范化为jpg(normalizeCoverExtension())。

用户从系统导入音频时,saveBgm() 会把 ContentResolver 中的 URI 拷贝为bgmDir/<安全文件名>.mp3:文件名经sanitizeBgmName()清洗(仅保留字母、数字、中文、_-,空白时回退为bgm_<UUID>),并在写入后校验文件非空。封面保存 saveCover() 会先删除旧扩展名的同名文件再写入,扩展名解析顺序为 MIME → URI 路径提示 → 文件头魔数(支持识别 JPEG/PNG/GIF/WEBP/BMP 头),最终兜底jpg

选择器 UI 实现在 BgmSelector.kt,运行时展示则挂载在壳应用界面(ShellBgmPlayer.kt),由 ShellScreen.kt 等壳组件装配。

在线音乐搜索

「在线搜索」选项的 API 与下载逻辑位于core/bgm包下的 OnlineMusicApi.kt 与 OnlineMusicDownloader.kt,UI 入口为 OnlineMusicSearchDialog.kt。下载的曲目按真实音频格式落盘,只要扩展名在上述MUSIC_EXTENSIONS六者之列,就会在下次曲库扫描中进入选择器——这就是文档中「按真实格式下载曲目都会出现在选择器中」的保证机制。

BGM 在导出 APK 中的打包与加密

文档说明「BGM 音频文件被打包进导出的 APK(并可加密)」,这条链路在 BgmPlayer.setAssetDataSource() 中完整可见:

  1. 播放asset:///路径的曲目时,先探测是否存在<assetPath>.enc加密副本;
  2. 有加密副本:通过AssetDecryptor.loadAsset()解密为字节流,写入cacheDir下临时文件(命名bgm_<hash>.mp3),随后用本地文件路径喂给MediaPlayer。临时文件缓存在tempFileCache中,同一曲目反复切歌不再重复解密;release()时统一清理临时文件(BgmPlayer.kt#L315-L337);
  3. 无加密副本:直接assets.openFd()获取AssetFileDescriptor,以 fd + 偏移 + 长度方式设置数据源,避免整文件读入内存。

用户曲目(非 asset 路径)则直接setDataSource(绝对路径)播放,不参与 assets 打包。

另外,bgmEnabled还会影响导出 APK 的运行时权限集合:RuntimePermissionSync.kt#L88 处按「若bgmEnabled则追加相应权限」的逻辑参与权限同步,保证生成应用具备播放所需的系统权限。

小结

web-to-app 的 BGM 功能是一条完整的「配置 → 曲库 → 播放 → 导出」链路:

  • 配置侧:bgmEnabled开关 +BgmConfig(播放列表、BgmPlayMode、音量、自动播放、歌词显示、LrcTheme样式);
  • 曲库侧:assets 预置(app/src/main/assets/bgm/,同名配对封面)与用户目录filesDir/bgm/双来源扫描,支持六种音频格式、多格式封面识别、LRC 旁挂与library_tags.json标签持久化,刷新和重启后修改不丢失;
  • 播放侧:BgmPlayer基于MediaPlayer实现循环 / 顺序 / 洗牌随机三种模式,随机模式保证「首曲随机、每轮不重复、播完重洗」;
  • 导出侧:音频打入 APK assets 并支持.enc加密,运行时解密到缓存播放;

关键源码入口一览:BgmPlayer.kt、BgmStorage.kt、WebApp.kt(BGM 数据模型)、BgmCard.kt、assets/bgm 预置说明。

【免费下载链接】web-to-appThe most full featured web-to-app toolkit on Android, a complete APK workshop that runs entirely on your phone项目地址: https://gitcode.com/GitHub_Trending/web/web-to-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询