音视频【免费下载链接】SimpMusicA cross-platform music app using YouTube Music for backend项目地址https://gitcode.com/gh_mirrors/si/SimpMusic点击查看免费下载导读本文以仓库内 AI 开发规范文档.claude/skills/android-architecture/SKILL.md为核心骨架系统讲解现代 Android及 Compose Multiplatform应用的 Clean Architecture 三层架构、Hilt/依赖注入规范与多模块化策略并对照 SimpMusic 仓库的真实代码给出可落地的验证证据。读完你将掌握如何划分 UI / Domain / Data 三层的职责与依赖方向、如何用注解与模块组织依赖注入、如何设计:core:*与:feature:*的多模块工程结构以及如何在 SimpMusic 这种 Compose Multiplatform 项目中落地同一套原则。一、High-Level Layers三层架构与依赖方向SKILL 文档给出的第一条铁律是将应用拆分为三个主层依赖必须严格向内向下流动到核心逻辑绝不允许反向依赖。1. UI Layer表现层职责展示数据、处理用户交互。组成Activity、Fragment、Composable、ViewModel。依赖只依赖 Domain 层简单项目也可直接依赖 Data 层接口绝不能直接依赖 Data 层的实现细节。在 SimpMusic 中表现层集中在composeApp的 commonMain 与androidAppAndroid 入口 MainActivity.kt 负责组装 Koin 模块、绑定媒体服务、最终以setContent { App(viewModel) }挂载 Compose 界面共享 UI 根组件 App.kt 只收集SharedViewModel暴露的StateFlow如sleepTimerState、nowPlayingState、themeMode通过collectAsStateWithLifecycle()订阅——这正是UI 层只面向 ViewModel不触碰数据实现的体现全部 ViewModel 位于composeApp/src/commonMain/kotlin/com/maxrave/simpmusic/viewModel/它们统一继承自 BaseViewModel.kt。2. Domain Layer业务逻辑层【可选但推荐】职责封装复杂业务规则、促进复用。组成Use Case如GetLatestNewsUseCase、Domain Model纯 Kotlin data class。纯 Kotlin不得包含任何 Android 框架依赖不能出现android.*import。依赖只依赖 Repository 接口。SKILL 特别强调 Domain 层的纯 Kotlin属性。SimpMusic 对此的执行非常彻底settings.gradle.kts将:common、:data、:domain三个核心模块显式映射到仓库根目录下的coregit 子模块project(:domain).projectDir File(coreDir, domain)而core/domain从 CLAUDE.md 的架构说明看承载的是领域模型、用例、Repository 接口、业务规则是纯 Kotlin 逻辑层不依赖任何 Android 框架。3. Data Layer数据层职责管理应用数据拉取、缓存、保存。组成Repository 实现、Data SourceRetrofit API、Room DAO。依赖只依赖外部数据源与第三方库。对应到 SimpMusiccore/data提供 Repository 实现与 Room 数据库core/service/*提供网络服务实现。仓库中AlbumViewModel依赖的是com.maxrave.domain.repository.AlbumRepository接口而具体的 Room/网络实现被屏蔽在 Domain 层之后——UI 层永远看不到 SQLite 与网络细节。二、Dependency InjectionHilt 规范与 SimpMusic 的 Koin 等价实现SKILL 规定使用 Hilt 完成所有依赖注入并给出了四个注解用法。但必须指出一个仓库实测事实当前 SimpMusic 工程中不存在任何 dagger/hilt 依赖全仓库检索零命中实际选用的是 Koin。两者的角色等价——都是把谁依赖谁从手工new中解放出来。下面先完整保留 SKILL 的 Hilt 规范再逐条给出仓库中的 Koin 对应物。SKILL 中的 Hilt 用法规范原文HiltAndroidApp标注Application类。AndroidEntryPoint标注 Activity 与 Fragment。HiltViewModel标注 ViewModel并使用标准的构造函数注入。ModulesModuleInstallIn(SingletonComponent::class)用于应用级单例如 Network、Database。抽象类中使用Binds绑定接口实现比Provides更干净。SimpMusic 中的 Koin 等价实现HiltSKILL 规范SimpMusicKoin 实现HiltAndroidAppApplicationSimpMusicApplication.kt 继承KoinComponent在onCreate()里startKoin { androidContext(...); loadAllModules(...); loadKoinModules(viewModelModule) }AndroidEntryPointActivityMainActivity.kt 通过by injectSharedViewModel()注入并在onCreate/onDestroy中loadKoinModules/unloadKoinModules(viewModelModule)以重建 ViewModelHiltViewModel构造函数注入ViewModelModule.kt 中viewModel { AlbumViewModel(get(), get()) }声明全部 ViewModel 及其构造依赖Module单例loadAllModules(AppIdentity(...))从core/data的 Koin 模块加载网络、数据库等单例Koin 在commonMain同样可用App.kt 中SharedViewModel: SharedViewModel koinInject()这是它能在 Compose Multiplatform 的共享代码中取代 Hilt 的关键优势——Hilt 依赖 Android Gradle 插件无法直接服务 jvmMain/iosMain。值得一提的设计细节SKILL 推荐用Binds绑接口实现比Provides更干净。Koin 侧 SimpMusic 也贯彻了面向接口思想——例如ViewModelModule.kt中LoginSyncHostViewModel(get())/LoginSyncSenderViewModel(get())的注释写明Koin resolves dependencies when a ViewModel is created各平台分别绑定自己的 Repository 实现UI 层只依赖 Domain 的 Repository 接口。三、Modularization Strategy多模块工程结构SKILL 建议生产级应用采用多模块策略以提升构建速度与关注点分离并给出标准模块划分:app主入口连接各 feature:core:model共享领域模型纯 Kotlin:core:dataRepository、DataSource、Database、Network:core:domainUse Case 与 Repository 接口:core:ui共享 Composable、主题、资源:feature:[name]独立 feature 模块自带 UI 与 ViewModel只依赖:core:domain与:core:ui。SimpMusic 的实际模块拓扑对照 settings.gradle.kts仓库的模块命名做了自己的取舍但分层思想与 SKILL 完全一致主入口:androidAppAndroid 壳、:vivoAndroidAppvivo 定制壳、:composeApp共享 UI 业务可运行 Desktop、:desktopApp核心三模块:common、:domain、:data——全部通过project(...).projectDir File(coreDir, ...)指向core子模块服务模块对应 SKILL 的 Data Source:ktorExt、:kotlinYtmusicScraper、:spotify、:aiService、:lyricsService、:listenTogether、:loginSync等映射到core/service/*媒体模块:media3、:media3-uiAndroid 播放、:media-jvm、:media-jvm-ui桌面播放映射到core/media/*功能开关型成对模块:crashlytics/:crashlytics-empty、:cast/:cast-empty、:lastfm/:lastfm-empty——Full 版与 FOSS 版通过isFullBuild属性在构建期二选一保证 F-Droid 构建不含任何闭源依赖。可以看到 SimpMusic 并没有生搬硬套:core:model、:core:ui、:feature:[name]的命名而是按共享代码放在composeApp 多平台 commonMain、平台专属能力拆成 expect/actual 或独立模块的思路组织——这是 Compose Multiplatform 对 SKILL 模块化原则的合理演绎。依赖方向也严格执行高层只能依赖低层CLAUDE.md 给出的依赖链为UI(composeApp) → Domain(core/domain) → Data(core/data) → Service(core/service/*) → Common(core/common)与 SKILL 的依赖向内流动一致。例如core/service/loginSync的说明明确写道服务层只负责传输、不携带业务语义Domain 层持有LoginSyncHostRepository/LoginSyncSenderRepository接口Data 层才是唯一知道 payload 含义的地方——这正是三层边界在真实工程中的贯彻。四、Checklist落地实现自检清单SKILL 提供了三条实施检查项结合仓库代码逐条验证确保 Domain 层无 Android 依赖从源码结构看core/domain被独立映射到core子模块且不引入android.*composeApp的 commonMain 虽然包含 UI 与 ViewModel但 ViewModel 只 importandroidx.lifecycle.ViewModel如 BaseViewModel.kt领域模型与业务规则全部经由com.maxrave.domain.*引用边界清晰。Repository 默认提供主线程安全的 suspend 函数内部按需使用Dispatchers.IOAlbumViewModel.kt 中albumRepository.getAlbumData(browseId)、albumRepository.getAlbumAsFlow(browseId)均为挂起函数或 FlowUI 侧统一在viewModelScope.launch中订阅没有在主线程直接执行 I/O 的写法。ViewModel 通过StateFlow与 UI 层交互这是 SimpMusic 最显著的统一模式。以 AlbumViewModel.kt 为例private val _uiState: MutableStateFlowAlbumUIState MutableStateFlow(AlbumUIState.initial()) val uiState: StateFlowAlbumUIState _uiState再配合_uiState.update { it.copy(...) }线程安全地更新状态UI 侧用collectAsStateWithLifecycle()收集。此模式在仓库中被 Systematically 使用AnalyticsViewModel、ArtistViewModel、AutoEqViewModel等同构与配套规范.claude/skills/android-viewmodel/SKILL.md中StateFlow 必须有初始值、对外只暴露只读 StateFlow、用.update {}更新的建议完全一致。五、在 Compose Multiplatform 中执行架构原则的补充要点SKILL 面向传统 Android 工程编写SimpMusic 则把它平移到了 KMP 共享代码上有三点值得注意ViewModel 不再需要AndroidEntryPointcommonMain 的 ViewModel 通过BaseViewModel : ViewModel(), KoinComponent直接使用by inject...()如mediaPlayerHandler、SongRepository绕开了 Activity/ViewModelStore 的 Hilt 桥接天然跨 Android/Desktop 复用。纯 Kotlin 边界要延伸到服务层由于:data以implementation依赖服务模块UI 无法直接看到服务层如lyricsService的说明the dependency stops there andcomposeAppcannot see it——the layering rule working as intended。UI 需要的数据一律经 Domain 的 Repository 接口中转这是三层原则在依赖图上最直观的体现。成对空实现模块是平台/发行版边界的另一种表现cast-empty、crashlytics-empty、lastfm-empty都以同名公开 API 返回 false/no-op 的桩实现隔离闭源 SDK功能代码与发行策略解耦属于多模块化的高级用法。参考资料仓库内规范原文.claude/skills/android-architecture/SKILL.md配套 ViewModel 规范.claude/skills/android-viewmodel/SKILL.md模块清单与子模块映射settings.gradle.kts依赖版本目录gradle/libs.versions.toml依赖注入装配ViewModelModule.kt、SimpMusicApplication.ktViewModel 基类与 StateFlow 示例BaseViewModel.kt、AlbumViewModel.kt架构总览CLAUDE.md赞分享音视频【免费下载链接】SimpMusicA cross-platform music app using YouTube Music for backend项目地址https://gitcode.com/gh_mirrors/si/SimpMusic点击查看免费下载相关推荐Koin Android 库绑定模式实战Retrofit、Room、WorkManager 与 Clean Architecture 的依赖注入方案Koin Android 库绑定模式实战Retrofit、Room、WorkManager 与 Clean Architecture 的依赖注入方案 导读 本后端如何用pyLast实现Last.fm用户认证两种授权方式完整对比如何用pyLast实现Last.fm用户认证两种授权方式完整对比 pyLast是一个功能强大的Python库提供了与Last.fm和Libre.fm音乐平台后端LivePortrait技术深度解析高效肖像动画生成与拼接重定向控制LivePortrait技术深度解析高效肖像动画生成与拼接重定向控制 LivePortrait是由快手科技开发的实时肖像动画解决方案通过创新的拼接与重定向控人工智能计算机视觉媒体生成数字人上一篇终极指南Air与Docker完美集成实现Go开发热重载下一篇如何3分钟上手DSH Desktop从下载macOS安装包到第一次官方DSH会话创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考