Skip to content

Quick Start ​

Integrate ANIP SDK into your project.

Deploy Dependency ​

Maven CentralMaven metadata URLAndroid Min SDK

ANIP SDK's dependency is published in Maven Central and our public repository. You can use the following method to configure repositories.

We recommend using Kotlin DSL as the Gradle build script language.

Configure repositories in your project's build.gradle.kts.

kotlin
repositories {
    google()
    mavenCentral()
    // (Optional) You can add this URL to use our public repository
    // When Sonatype-OSS fails and cannot publish dependencies, this repository is added as a backup
    // For details, please visit: https://github.com/HighCapable/maven-repository
    maven("https://raw.githubusercontent.com/HighCapable/maven-repository/main/repository/releases")
}

You can add this module to your project using the following method.

Add the dependency to your project's gradle/libs.versions.toml.

toml
[versions]
anip-sdk = "<version>"

[libraries]
anip-sdk = { module = "com.highcapable.anip:anip-sdk", version.ref = "anip-sdk" }

Configure the dependency in your project's build.gradle.kts.

kotlin
dependencies {
    implementation(libs.anip.sdk)
}

Replace <version> with the version displayed at the top of this section.

Traditional Method ​

Configure the dependency in your project's build.gradle.kts.

kotlin
dependencies {
    implementation("com.highcapable.anip:anip-sdk:<version>")
}

Replace <version> with the version displayed at the top of this document.

Function Introduction ​

You can view the KDoc click here, or click here to view the corresponding demo project to better understand how to use the SDK.

Create an Instance ​

Anip is the unified entry point for creating the SDK. Each instance maintains one cache directory and one set of in-memory state. You can create a single instance when the app starts and reuse it throughout the app.

The following example

kotlin
val anip = Anip(context)

If you need to specify a system variant, cache directory, or remote source, pass an AnipConfig.

The following example

kotlin
val config = AnipConfig(
    // Specifies the system variant used to merge vendor system icons.
    systemVariant = SystemVariant.MIOS,
    // Explicitly specifies the cache directory.
    cacheDirectory = context.cacheDir.resolve("your-anip-resources"),
    // Specifies the remote resource source.
    source = RemoteSource.GitHub(
        repository = RemoteSource.GITHUB_OFFICIAL_REPO_SLUG
    )
)
val anip = Anip(context, config)

systemVariant defaults to null, which loads no system icons. COMMON loads only the common system icons, while MIOS (HyperOS/MIUI) and COLOROS load both common and the corresponding vendor system icons.

The current Anip instance keeps a reference to the configuration object. After modifying its properties, the latest configuration will be read directly during the next update. Icons already loaded into memory will not be automatically replaced when the configuration changes.

Load and Update Resources ​

The following APIs are provided by the SDK for loading and updating resources.

APIBehavior
reloadLoads only the latest valid resources from the cache directory without network requests, returning true on success.
fetchReads the remote release manifest, downloads and replaces the cache when resources have changed, then updates the in-memory icon rules.
getIcon / getIconsQueries only the current instance's in-memory state, returning null or an empty list.

We recommend reading the existing cache at startup before checking for updates.

The following example

kotlin
anip.reload()

val cachedIcons = anip.getIcons()
val result = anip.fetch()
val latestIcons = anip.getIcons()

These loading APIs are all marked as suspend, and file and network operations are dispatched by the SDK to the IO thread.

timestamp represents the resource commit time of the most recent successful synchronization. It defaults to 0L and is persisted as text in the timestamp file under the cache directory.

Update Result ​

fetch returns an Anip.FetchResult, where status has the following three states.

StatusMeaning
SUCCESSNew resources have been downloaded and loaded.
UP_TO_DATELocal resources are already up to date.
FAILEDQuerying, downloading, verification, or loading failed.

Anip.FetchResult also provides isOk and message. isOk returns true when the status is not FAILED, while message describes the update result or failure reason.

The following example

kotlin
when (result.status) {
    Anip.FetchResult.Status.SUCCESS -> {
        // Do something.
    }
    Anip.FetchResult.Status.UP_TO_DATE -> {
        // Do something.
    }
    Anip.FetchResult.Status.FAILED -> showError(result.message)
}

Query Icons ​

You can query a single icon directly by package name, or obtain a list by category.

The following example

kotlin
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()

Each NotificationIcon provides the following data.

  • packageName: App package name
  • label: App name resolved according to the current system language
  • availableLabels: All localized names included in the rule, represented as Map<Locale, String>
  • color: Color used by the icon, or null when not set
  • overlay: Whether to force overlay all notification icons pushed by the app, regardless of whether they are native monochrome
  • contributors: List of contributor names

Icon bitmaps are not decoded all at once with the entity list. When using one individually, please load it explicitly via loadBitmap. A decoding failure returns null, while a successful result enters the LRU memory cache held by the current Anip instance.

The following example

kotlin
val bitmap = anip.getIcon("com.example.app")?.loadBitmap()

Create an In-Memory Snapshot ​

If you need to use the complete icon set intensively over a long period, you can create an immutable NotificationIconSnapshot.

The following example

kotlin
val snapshot = anip.createSnapshot(IconCategory.ALL)
val icon = snapshot.getIcon("com.example.app")
val bitmap = snapshot.getBitmap("com.example.app")

The snapshot loads icons in the selected category sequentially, keeps only entries that decode successfully, and caches all Bitmap instances. memorySizeBytes measures usage by deduplicating actual Bitmap objects, so inherited rules or multiple package names using the same resource are not counted repeatedly.

The snapshot remains unchanged after construction. Later calls to fetch or reload do not modify an existing snapshot. You can finish creating a new snapshot before replacing the old reference.

After the snapshot reference is released, it is reclaimed by GC. There is no need to manually call recycle or close.

Notice

createSnapshot explicitly incurs the memory cost of loading the complete icon set. If you only need to obtain a few icons occasionally, please use NotificationIcon.loadBitmap directly.

Configure Remote Sources ​

RemoteSource provides the following remote source templates.

TemplateBehavior
GitHubReads the resource manifest from the latest GitHub repository Release; defaults to the official repository.
GitLabReads the resource manifest from the latest GitLab project Release; supports custom host addresses.
StaticAppends anip-release.json after the base URL.
CustomUses the complete resource manifest URL directly.

The following example

kotlin
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

When customizing sources, it needs to provide an ANIP-compliant anip-release.json and its corresponding resource Bundle.

Customize Request URLs ​

Every template accepts a RemoteSource.UrlResolver. Before requesting the resource manifest or Bundle, it receives the original URL and returns the final request URL.

The following example

kotlin
val source = RemoteSource.GitHub(
    urlResolver = RemoteSource.UrlResolver { sourceUrl, _, _ ->
        "https://some.domain/$sourceUrl"
    }
)

If tag is null for a manifest request, a Bundle request provides both tag and asset name, allowing each resource to be mapped to a self-hosted CDN separately.

The following example

kotlin
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"
    }
)

Notice

Static URL concatenation should be performed in the callback. You cannot execute network or time-consuming requests in the callback.

Returning a blank or invalid URL will cause failure directly.

Cache and Multiple Processes ​

When cacheDirectory is not specified, the SDK uses anip-icon-resources under the app cache directory.

If you are using the SDK in an Xposed module and need to share resources between the module process and host process, the caller can configure one directory that both sides can access. The process responsible for networking executes fetch, while other processes execute reload after receiving a refresh notification. Or, if both processes have network access, each process can maintain its own cache directory and notify the other to update.

The SDK does not include any directory permission handling functions. It only uses standard file APIs, and you need to handle directory authorization and cross-process synchronization yourself.

Released under the Apache-2.0 License