You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Migrate build to Gradle 9.6.1 / AGP 9 and update dependencies (#792)
Gradle 9.6 removed the internal API that AGP 8.13 relied on, forcing the
AGP 9 upgrade and the surrounding build-script changes.
Toolchain:
- Gradle wrapper 9.3.1 -> 9.6.1; AGP 8.13.1 -> 9.3.1; apksig follows AGP.
- Adopt AGP 9 built-in Kotlin: remove org.jetbrains.kotlin.android from all
Android modules; Kotlin stdlib 2.3.10 -> 2.4.10.
- compileSdk/targetSdk 36 -> 37, build-tools 37.0.0.
Build-script migration:
- Root build configures the shared CommonExtension through its getters, since
AGP 9 dropped the action-DSL methods on that type.
- daemon generates SignInfo through androidComponents.onVariants and a typed
task; android.applicationVariants was removed.
Resource generators (replace the rikka autoResConfig / materialthemebuilder
plugins, whose entry points use removed AGP variant APIs):
- buildSrc/GenerateLangListTask scans the translated locales.
- buildSrc/GenerateMaterialThemeTask computes the accent-color theme overlays,
reusing the materialthemebuilder color library without applying its plugin.
Drop android.nonFinalResIds=false:
AGP 9 enables optimized resource shrinking by default, and that shrinker
requires non-final resource IDs. With isShrinkResources=true the manager's
release build now fails :app:minifyReleaseWithR8 with "Optimized resource
shrinking requires non-final IDs". AGP offers two remedies: make the IDs
non-final, or opt out of optimized shrinking (r8.optimizedResourceShrinking=
false). We take the former, because the false setting turns out to be dead
weight:
- It was added in 348f049 (Aug 2023), an unrelated "show packagename" feature
commit, as a one-line drop-in beside the now-removed experimental flags
enableAppCompileTimeRClass / enableNewResourceShrinker.preciseShrinking. Those
siblings were cleaned up later; this line was simply missed.
- Final IDs are only actually required to use R.* as Java switch/case labels.
There are zero `case R.*` occurrences in the tree at 348f049 and at every
commit since, so the flag never protected anything here.
- Non-final IDs are the modern AGP default, so removing the line (rather than
writing =true) expresses the intent with no config at all.
It also builds smaller: the optimized shrinker trims the release APK from
~3.45 MB to ~3.13 MB (~9%). Verified end to end -- assembleRelease plus a
zygisk installKsuAndReboot run that loads the module and starts lspd on device.
Formatting task:
- Add buildSrc/src/main/kotlin to the format task so the generator sources are
formatted with the rest of the Kotlin build logic.
- Exclude daemon/**, which is intentionally kept on ktfmt's default (Meta)
style; formatting it here fought :daemon:ktfmtFormat and flipped the style
back and forth.
Dependencies:
- AGP/apksig 9.3.1, Kotlin 2.4.10, androidx.core 1.19.0 (dependabot maven group).
- coroutines 1.11.0, okhttp 5.4.0, gson 2.14.0, nav 2.9.8, glide 5.0.9,
androidx activity/browser/annotation, ktfmt 0.26.0.
- Material kept at 1.12.0; 1.13+ removes the colorPrimary/colorError attrs the
manager references.
- Submodules fmt and commons-lang bumped; CI action versions bumped
(actions/checkout 6 -> 7, actions/cache 5 -> 6).
The `buildSrc` project holds build logic that Gradle compiles before configuring the main build. It currently contains two source generators consumed by the `:app` (manager) module. Both produce data that the manager references at compile time, so they participate in every application build rather than running as a manual pre-step.
4
+
5
+
The manager exposes two user-facing settings that require precomputed, per-build data: an in-app language selector and an accent-color selector. The language selector needs the concrete set of locales the application ships translations for, and the color selector needs a full Material 3 palette for each preset seed color. These generators derive that data from the resource tree and a fixed color table, so the settings stay consistent with the translations and palette definitions actually present in the source.
6
+
7
+
## Directory Structure
8
+
9
+
```text
10
+
buildSrc/
11
+
├── build.gradle.kts # kotlin-dsl module; declares the color-generation library
The task classes live in the default package and are therefore visible to the module build scripts without an import. The `:app` build registers them per variant through the AGP variant API:
20
+
21
+
```kotlin
22
+
androidComponents {
23
+
onVariants { variant ->
24
+
val langList = tasks.register<GenerateLangListTask>("generate${cap}LangList") { … }
`addGeneratedSourceDirectory` binds each task's `outputDir` into the variant's Java or resource source set. AGP owns the output location, wires the task into the source-merge graph, and establishes the task dependency automatically, so the generated Java is compiled and the generated resources are merged like any hand-written source.
34
+
35
+
## Locale List Generation
36
+
37
+
`GenerateLangListTask` emits the `org.lsposed.manager.util.LangList` class, which the settings screen reads to populate the language dropdown (`LangList.LOCALES` for entry values, `LangList.DISPLAY_LOCALES` for the script-qualified display keys).
38
+
39
+
Inputs are the resource directories to scan (`resDirs`), the target `packageName` and `className`, and the leading `firstItem` (`SYSTEM`). The task:
40
+
41
+
* Collects every `values-<qualifier>` folder that contains a `strings.xml`, treating the qualifier as a translated locale and ignoring configuration-only qualifiers such as `values-night` or `values-v31`.
42
+
* Converts each Android qualifier to a BCP-47 tag: a `b+`-prefixed qualifier has its `+` separators replaced with `-`, and a trailing `-r<REGION>` segment drops its `r` marker (`zh-rCN` becomes `zh-CN`, `pt-rBR` becomes `pt-BR`).
43
+
* Adds `en` for the default `values/` resources, sorts the tags, and prepends `firstItem`.
44
+
* Produces `DISPLAY_LOCALES` as a parallel array in which the Simplified and Traditional Chinese tags are rewritten to their script forms (`zh-CN` to `zh-Hans`, `zh-TW` to `zh-Hant`); all other tags are identical to `LOCALES`.
45
+
46
+
Adding a new translation is therefore a matter of dropping a `values-<locale>/strings.xml` folder into the module; the list updates on the next build with no manual edits.
47
+
48
+
## Material Theme Generation
49
+
50
+
`GenerateMaterialThemeTask` emits a resource `values.xml` containing the color roles and theme-overlay styles that back the accent-color options. The manager maps each preset to a generated style through `ThemeUtil` (for example `MATERIAL_RED` to `R.style.ThemeOverlay_MaterialRed`) and applies it to recolor the interface.
51
+
52
+
Inputs are the seed color table (`seedColors`, mapping a theme name to a hex value), the `generatePalette` flag, and the `lightThemeFormat` / `darkThemeFormat` style-name templates. For each seed the task computes a Material 3 tonal palette (primary, secondary, tertiary, neutral, neutral-variant, and error ramps across the standard tone stops) and writes:
53
+
54
+
* The resolved color roles for the light and dark schemes (`colorPrimary`, `colorOnPrimary`, `colorPrimaryContainer`, and the remaining container, surface, and outline roles).
55
+
* A `ThemeOverlay.Light.Material<name>` and `ThemeOverlay.Dark.Material<name>` style that binds those roles, plus the discrete palette attributes (`palettePrimary0` through `palettePrimary100`, and the equivalent ramps for the other tonal palettes) when `generatePalette` is set.
56
+
57
+
The color science and XML serialization are provided by the `dev.rikka.tools.materialthemebuilder` artifact declared in `build.gradle.kts`. The task drives it directly: it instantiates a `MaterialThemeBuilderExtension` through the `ObjectFactory`, populates the theme container from `seedColors`, and invokes `ValuesAllGenerator`. Only the library classes are used; the artifact's Gradle plugin is not applied. Themes are keyed in a `NamedDomainObjectContainer`, so the output is ordered by theme name and is deterministic for a given seed table.
0 commit comments