快速开始
集成 ANIP SDK 到你的项目中。
部署依赖
ANIP SDK 的依赖发布在 Maven Central 和我们的公共存储库中,你可以使用如下方式配置存储库。
我们推荐使用 Kotlin DSL 作为 Gradle 构建脚本语言。
在你的项目 build.gradle.kts 中配置存储库。
repositories {
google()
mavenCentral()
// (可选) 你可以添加此 URL 以使用我们的公共存储库
// 当 Sonatype-OSS 发生故障无法发布依赖时,此存储库作为备选进行添加
// 详情请前往:https://github.com/HighCapable/maven-repository
// 中国大陆用户请将下方的 "raw.githubusercontent.com" 修改为 "raw.gitmirror.com"
maven("https://raw.githubusercontent.com/HighCapable/maven-repository/main/repository/releases")
}你可以使用如下方式将此模块添加到你的项目中。
Version Catalog (推荐)
在你的项目 gradle/libs.versions.toml 中添加依赖。
[versions]
anip-sdk = "<version>"
[libraries]
anip-sdk = { module = "com.highcapable.anip:anip-sdk", version.ref = "anip-sdk" }在你的项目 build.gradle.kts 中配置依赖。
dependencies {
implementation(libs.anip.sdk)
}请将 <version> 修改为此小节顶部显示的版本。
传统方式
在你的项目 build.gradle.kts 中配置依赖。
dependencies {
implementation("com.highcapable.anip:anip-sdk:<version>")
}请将 <version> 修改为此文档顶部显示的版本。
功能介绍
你可以 点击这里 查看 KDoc,或 点击这里 查看对应的演示项目来更好地了解 SDK 的使用方式。
创建实例
Anip 是 SDK 的统一创建入口,一份实例对应维护一份缓存目录和内存状态。你可以选择在应用启动时仅创建一个实例并在整个应用中复用。
示例如下
val anip = Anip(context)如果你需要指定系统类型、缓存目录或远程来源,可以传入 AnipConfig。
示例如下
val config = AnipConfig(
// 指定系统类型,用于合并厂商系统图标
systemVariant = SystemVariant.MIOS,
// 显式指定缓存目录
cacheDirectory = context.cacheDir.resolve("your-anip-resources"),
// 指定远程资源来源
source = RemoteSource.GitHub(
repository = RemoteSource.GITHUB_OFFICIAL_REPO_SLUG
)
)
val anip = Anip(context, config)systemVariant 默认为 null,此时不会加载任何系统图标。配置为 COMMON 时只加载 common 系统图标,配置为 MIOS (HyperOS/MIUI) 或 COLOROS 时,会加载 common 与对应厂商的系统图标。
配置对象会由当前 Anip 实例持续引用。修改其中的属性后,下一次更新时会直接读取最新配置,已装载到内存中的图标不会在配置变化时自动替换。
装载与更新资源
以下是 SDK 提供的装载与更新资源 API。
| API | 行为 |
|---|---|
reload | 仅从缓存目录装载最新的有效资源,不请求网络,成功返回 true |
fetch | 读取远程发布清单,资源有变化时下载并替换缓存,随后更新内存中的图标规则 |
getIcon / getIcons | 仅查询当前实例的内存状态,返回 null 或空列表 |
我们推荐在启动时先读取已有缓存,再检查是否有更新。
示例如下
anip.reload()
val cachedIcons = anip.getIcons()
val result = anip.fetch()
val latestIcons = anip.getIcons()这些装载 API 均标记为 suspend,文件与网络操作由 SDK 调度到 IO 线程。
timestamp 表示最近一次成功同步的资源提交时间,默认值为 0L,并以文本形式持久化在缓存目录的 timestamp 文件中。
更新结果
fetch 返回 Anip.FetchResult,其中 status 有以下三种状态。
| 状态 | 含义 |
|---|---|
SUCCESS | 已下载并装载新的资源 |
UP_TO_DATE | 本地资源已经是最新版本 |
FAILED | 查询、下载、校验或装载失败 |
Anip.FetchResult 同时提供了 isOk 和 message,isOk 在状态不为 FAILED 时返回 true,message 会描述本次更新结果或失败原因。
示例如下
when (result.status) {
Anip.FetchResult.Status.SUCCESS -> {
// Do something.
}
Anip.FetchResult.Status.UP_TO_DATE -> {
// Do something.
}
Anip.FetchResult.Status.FAILED -> showError(result.message)
}查询图标
你可以直接按包名查询单个图标,也可以按类别获取列表。
示例如下
val icon = anip.getIcon("com.example.app")
val apps = anip.getIcons(IconCategory.APP)
val games = anip.getIcons(IconCategory.GAME)
val systemIcons = anip.getIcons(IconCategory.SYSTEM)
val allIcons = anip.getIcons()每个 NotificationIcon 提供以下数据。
packageName:应用包名label:按照当前系统语言解析后的应用名称availableLabels:规则包含的全部本地化名称,类型为Map<Locale, String>color:图标使用的颜色,未设置时为nulloverlay:是否强制覆盖应用推送的所有通知图标,无论其是否为原生单色contributors:贡献者的名称列表
图标位图不会随实体列表一次性解码,单独使用时,请通过 loadBitmap 显式装载,解码失败会返回 null,成功结果会进入当前 Anip 实例持有的 LRU 内存缓存。
示例如下
val bitmap = anip.getIcon("com.example.app")?.loadBitmap()创建内存快照
如果你需要长期、集中使用整套图标时,可以创建不可变的 NotificationIconSnapshot。
示例如下
val snapshot = anip.createSnapshot(IconCategory.ALL)
val icon = snapshot.getIcon("com.example.app")
val bitmap = snapshot.getBitmap("com.example.app")快照会顺序装载所选类别中的图标,只保留成功解码的条目,并缓存全部位图实例,memorySizeBytes 会按实际 Bitmap 对象去重后统计占用,继承规则或多个包名使用同一资源时不会重复计算。
快照构建完成后将保持不变,后续调用 fetch 或 reload 不会修改已有快照。你可以先完整创建新快照,再替换旧引用。
释放快照引用后由 GC 回收,无需手动调用 recycle 或 close。
注意
createSnapshot 会显式承担整套图标的装载内存成本,如果你只需要偶尔获取少量图标,请直接使用 NotificationIcon.loadBitmap。
配置远程来源
RemoteSource 提供以下远程来源模板。
| 模板 | 行为 |
|---|---|
| GitHub | 从 GitHub 存储库最新 Release 读取资源清单,默认使用官方仓库 |
| GitLab | 从 GitLab 项目最新 Release 读取资源清单,支持自定义地址 |
| Static | 在基础地址后追加 anip-release.json |
| Custom | 直接使用完整的资源清单地址 |
示例如下
val github = RemoteSource.GitHub("owner/repository")
val gitLab = RemoteSource.GitLab("group/project")
val static = RemoteSource.Static("https://cdn.example.com/anip")
val custom = RemoteSource.Custom("https://resources.example.com/anip-release.json")
config.source = custom在自定义来源时,其需要提供符合 ANIP 规范的 anip-release.json 与对应的资源 Bundle。
自定义请求地址
每个模板都可以传入 RemoteSource.UrlResolver,它会在请求资源清单和 Bundle 前接收原始 URL,并返回最终请求地址。
示例如下
val source = RemoteSource.GitHub(
urlResolver = RemoteSource.UrlResolver { sourceUrl, _, _ ->
"https://some.domain/$sourceUrl"
}
)如果清单请求的 tag 为 null,Bundle 请求则会同时提供 TAG 与附件名称,因此也可以分别映射到自建 CDN。
示例如下
val source = RemoteSource.Custom(
manifestUrl = "https://origin.example.com/anip-release.json",
urlResolver = RemoteSource.UrlResolver { _, tag, assetName ->
if (tag == null)
"https://cdn.example.com/anip-release.json"
else "https://cdn.example.com/releases/$tag/$assetName"
}
)注意
回调中应进行静态地址拼接,你不能在回调中执行网络或耗时请求。
返回空白或非法 URL 时将直接导致失败。
缓存与多进程
未指定 cacheDirectory 时,SDK 使用应用缓存目录下的 anip-icon-resources。
如果你正在 Xposed 模块中使用,如需让模块进程与宿主进程共享资源,可以由调用方设置双方均可访问的同一目录,负责联网的进程执行 fetch,其他进程在收到刷新通知后执行 reload,或者在两个进程都能获得联网权限时,每个进程都持有自己的缓存目录并通知对方更新即可。
SDK 不包含任何目录权限处理功能,它只会使用标准的文件 API,你需要自行处理目录的授权与跨进程同步功能。