在 Android 上使用 Compose Multiplatform 的 Skia(Skiko)版本。
项目名称源自于魔法少女ノ魔女裁判中的角色二階堂ヒロ
- 使得更低版本的安卓设备(API 28,安卓 9)都尽可使用 GPU 渲染与 SkSl 的 Shader,弥补低版本安卓设备没办法吃上特殊效果(如液态玻璃、华丽质感材料)的缺憾。
- 这使得您(样式创建者)只需要提供一套适用于
skiko或desktop(继承自skiko)的样式(SkSl Shader等),无需另外改动您的库或提供 AndroidX(AGSL)的版本,即可通过让他们(样式使用者)在安卓上套用完整的效果。
- 由于这走的是自提供的 Skia,打包相应的
.so(动态共享库)与相关资源不可避,这将在向安装包打入 x86_64、arm64-v8a 双架构本机库以及相关资源的情况下导致您的安装包增大 6MB 左右,我已竭尽全力减小裁剪以缩减体积。 - 目前接入体系尚不 100% 完善,在一些极冷门的使用场景可能有 Bug/Todo,且性能未必全场景最优,详见下文已知限制。
- Hiro Skia:对 Skia(Skiko)的打包,在安卓上提供
SkiaLayer和SkiaSurfaceView。这也是 Hiro Compose 的根基。 - Hiro Compose:基于 Compose Multiplatform 的 UI/Runtime/Foundation 等的 SkikoDesktop 版本以及相关组件作为底版制作,并深度修补,尽力补齐在安卓上的体验(接入各种事件,并提供 HiroComposeView等)。
- Hiro Material 3:对 Compose Multiplatform 的 Material 3 的 Skia(Skiko)/Desktop(即 Jvm)的打包与体验补齐。
- Hiro Gradle Plugin:帮助用户实现无感对第三方 Compose 包的 Skia(Skiko)/Desktop 模块转用( Android 转用 Skia(Skiko)/Desktop,并阻断对 AndroidX Compose / Compose Multiplatform 的 Android 的依赖引入),把这些第三方包中的桌面平台类型(如
SavedState)重新链接到安卓,还能在纯安卓模块中代为生成 JetBrains Compose 资源(Res)。 - Examples,几个使用例:不但是我们开发测试时的参考面,也可以让您深度体验和了解 Hiro 各方面能力。
- Whole App Example:一个简单但架构完整的 App,用以展示 Hiro 在开发可用 App 上的可行性。
- 创建一个标准的 Android 项目(AGP 9、Kotlin 2.2 及以上,minSdk 28)。
- 配置 Maven 仓库:在项目根目录的
settings.gradle.kts文件中进行以下配置: 在pluginManagement和dependencyResolutionManagement的repositories块中均添加我的仓库:Skiko 已随 Hiro Skia 一同发布,无需再添加 JetBrains Compose Dev 仓库。maven("https://earzuchan.github.io/Maven/") // 注意:请确保“Maven”中的字母“M”为大写
- 应用 Gradle 插件:在根目录
build.gradle.kts文件的plugins块中添加:在您的 Android 模块的id("me.earzuchan.hiro") version "<VERSION>" apply false
build.gradle.kts文件的plugins块中添加:id("me.earzuchan.hiro") - 添加依赖:在您的 Android 模块的
build.gradle.kts文件的dependencies块中添加:关于其他模块的说明:implementation("me.earzuchan.hiro:compose:<VERSION>")- Hiro Skia:
hiro:compose已传递暴露其 API,使用 Hiro Compose 时无需显式再引入其依赖;仅在独立使用 Skia 时需显式引入。 - Hiro Material 3:Material 3 未捆绑在
hiro:compose中。如需使用它们,须添加此模块。
// 仅在需要时添加: implementation("me.earzuchan.hiro:skia:<VERSION>") // 用于独立使用 Hiro Skia implementation("me.earzuchan.hiro:material3:<VERSION>") // 用于使用 Material 3 组件
- Hiro Skia:
- 使用方法:在您的 Activity 中导入
me.earzuchan.hiro.compose.setHiroComposeContent,然后在onCreate中使用:setHiroComposeContent { // Compose 内容 }
- 原版安卓资源(R 与 Assets):提供与 AndroidX 同名的接口,如
stringResource、pluralStringResource、colorResource、dimensionResource、painterResource、ImageVector.vectorResource、ImageBitmap.imageResource,以及LocalContext、LocalConfiguration、LocalResources;语言、深色模式等配置变化时自动重组。painterResource支持矢量图(含渐变)、位图、九宫格(.9.png)与形状(shape);动画矢量请用AnimatedImageVector.animatedVectorResource搭配rememberAnimatedVectorPainter。- 字体支持
Font(R.font.xxx)与Font("fonts/xxx.ttf", assets)。
- JetBrains 的 Compose 资源(Res):纯安卓模块下,请您应用与 Hiro 所跟随版本一致的 Compose 插件,并把资源放进
src/main/composeResources,Hiro Gradle 插件会代为生成Res(默认包名为<group>.<模块名>.generated.resources,可经compose.resources {}自定义包名与类名)。该插件仅作为构建期的资源编译工具与配置入口,不会引入官方 Compose 运行库:plugins { id("org.jetbrains.compose") version "1.12.2" }
Hiro 的日志在不可调试的 App(Release)中只输出警告与错误,且经 R8 压缩后连同字符串一并移除;可调试的 App 默认输出调试级别,可按需调整:
import me.earzuchan.hiro.log.HiroLogLevel
import me.earzuchan.hiro.log.HiroLogging
HiroLogging.level = HiroLogLevel.Verbose // 查看触摸、波纹等逐事件日志- 本项目的 Compose 和 Skiko 内部上游依赖会随 Compose Multiplatform(CMP)的主要稳定版本一同更新。当使用 Hiro Compose 或 Hiro Material 3 时,您无需引入官方(原始)的 Compose 依赖项(无论是 AndroidX 还是 CMP),这能确保所有 Compose 内容都基于我特定的类路径(Hiro 独家的 Android Compose Skiko)进行解析。我的 Hiro Gradle 插件(HGP)也会帮您使您和您的依赖不额外引入原版 Compose。
- Hiro Compose 的 Compose 和 Skia/GL 跑在独立渲染线程,通过状态机模型与安卓主线程往来。它补齐了基本的安卓事件输入(点击、导航对接等)、Lifecycle 和 SavedState 适配(并提供了作为添头的
Kotlinx Serialization @Serializable在 SavedState 中的开箱即用支持,以及用户可选(需要用户实现接口)提供的自定义类型 SeDes(序列化反序列化)SavedState 支持)。关于 Hiro Compose 的更多,建议查看架构说明。 - Hiro Skia 基本上是为 Hiro Compose 打造的。我没有直接依赖存在已知 Bug(比如把
Rect.makeWH的参数传成了width, width)的 JetBrains 官方安卓代码,而是实现了一套轻量级的 Skia Layer 和 SurfaceView,对于 Hiro Compose 的显示基本够用。 - 我根据 AOSP Material 3 水波纹动画的底层原理,使用 Skia 图形栈复刻了该效果。这使得在低版本 Android、魔改 ROM 上也能有一致的 Material 3 水波纹体验。这个复刻已内含在 Hiro Material 3 中,我或许之后会另外贡献给上游 CMP。
- 我修复了 JetBrains Skiko 原生代码中存在的
JNI Critical Section Violation: using JNI after critical get问题,Hiro Skia 含有修复后的本机库。该修复的 PR 已被 Skiko 合并,待其随上游版本发布后 Hiro 将不再需要自行修补;此外,BreakIterator 的数组类型问题上游已自行修复。
- 多线程与组件隔离:
- 由于 Compose 运行在 Hiro 独立渲染线程,
LocalContext等只宜用于读取资源等线程安全的操作;需要主线程的操作(如Toast)请自行切回主线程。 - Hiro Compose 世界中的
ViewModelStore与安卓世界中的(如 Activity)不互通(这是出于性能考量的刻意设计)。
- 由于 Compose 运行在 Hiro 独立渲染线程,
- 本机库架构与图形后端:
- 本机库仅含
arm64-v8a(Arm64)与x86_64(x64)。在雷电等依赖 ARM 转译的 x86 模拟器上,或会因转译层无法加载 Skiko 本机库而崩溃(官方库同样如此),针对它们请使用x86_64。 - 出于包体积、设备兼容性与实现逻辑复杂度的考量,Skia 图形后端暂只对接 OpenGL ES 而不引入 Vulkan(要支持 Vulkan 比较麻烦,留待以后考虑)。
- 本机库仅含
- Skia 裁剪与独立使用限制:
- Hiro Skia 的本机库按 Compose 所需进行了裁剪构建——
Codec、Skottie、TextBlobBuilder等包装已移除;TextBlob、TextLine、Pixmap、Drawable、Blender、Shaper等虽仍保留类型,但调用会抛出UnsatisfiedLinkError。 - 将 Hiro Skia 用于非 Hiro Compose 的独立 Skia 承载用途,未经深度测试。
- Hiro Skia 的本机库按 Compose 所需进行了裁剪构建——
- 暂不支持的系统特性与资源:
- 尚未接入无障碍(TalkBack 等读屏读不到 Hiro 内容)与拖放。
painterResource暂不支持selector、layer-list等其他 XML Drawable。- 暂不支持 XML 字体族(含可下载字体)。
参见我的待办项。
