Skip to content

ADFA-4128 (10/11): gradle-plugin — generating the proxy app - #1722

Open
fryanpan wants to merge 2 commits into
feature/ADFA-4128-qb-09-daemonfrom
feature/ADFA-4128-qb-10-gradle-plugin
Open

ADFA-4128 (10/11): gradle-plugin — generating the proxy app#1722
fryanpan wants to merge 2 commits into
feature/ADFA-4128-qb-09-daemonfrom
feature/ADFA-4128-qb-10-gradle-plugin

Conversation

@fryanpan

@fryanpan fryanpan commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Part 10/11 of the stacked split of #1669 (requested by Akash). Base: feature/ADFA-4128-qb-09-daemon. Stack overview + review mechanics: PR 1 (#1713). Terms are defined in quickbuild/README.md (lands in PR 1).

Produces the stand-in app that Quick Build reloads into, so it behaves like the user's real app. Ordinary Gradle builds are untouched by it.

flowchart TB
    init["CoGo's init script applies<br/>AndroidIDEGradlePlugin (existing path)"] --> gate
    subgraph gp["<b>This PR: inside :gradle-plugin</b>"]
        gate{"quick-build Gradle property<br/>(GradlePluginConfig) == true?<br/><i>AndroidIDEGradlePlugin.kt</i>"}
        gate -- "yes: QB provisioning only" --> qbp["QuickBuildPlugin<br/><i>QuickBuildPlugin.kt</i>"]
        qbp --> px["ProxySourceGenerator<br/>Proxy&lt;N&gt;&lt;Type&gt; subclasses;<br/>proxiability decisions with named rejections<br/><i>ProxySourceGenerator.kt</i>"]
        qbp --> mf["manifest rewrite + activity-alias synthesis<br/>explicit-class navigation keeps resolving<br/><i>QuickBuildManifestTransformer.kt</i>"]
        qbp --> js["quickbuild.json —<br/>the contract the device side reads back<br/><i>QuickBuildJson.kt</i>"]
    end
    gate -- "no: every ordinary build" --> off["QuickBuildPlugin never applied —<br/>this PR's code does not run"]
    js --> core["consumed by :quickbuild:core / :app (PRs 7, 11)"]
    classDef thisPrBox fill:#dbeafe,stroke:#93c5fd,color:#1e3a5f
    classDef inPr fill:#ffffff,stroke:#64748b,color:#000
    class gp thisPrBox
    class gate,qbp,px,mf,js inPr
Loading

What to review

  • AndroidIDEGradlePlugin.kt — the property gate; review first, it contains everything else.
  • ProxySourceGenerator.kt — which components can be proxied, and each rejection's reason. Line-by-line.
  • QuickBuildManifestTransformer.kt — activity-alias synthesis keeps explicit-class navigation resolving.
  • QuickBuildJson.kt — SCHEMA_VERSION must move in step with the reader's COMPONENT_SCHEMA_VERSION.
  • No :quickbuild:* dependency; this PR's stack position is reading order only.
  • QuickBuildPlugin.kt — applied only during provisioning; a revert changes nothing otherwise.

How this PR Was Tested

  • 13 test files (12 suites), including functional Gradle builds asserting real build output.
  • TestKit covers AGP 8.11.0 on Gradle 8.14.3; real Gradle 9 remains unproven.
  • [verified 2026-08-21] At this cut: :gradle-plugin:test green with PRs 1–10 applied — 13 test files (12 suites; utils.kt is a helper), 136 tests, 0 failures, 0 errors. The 6 skips are all pre-existing @disabled logsender / init-script cases on an AGP 7.3.0 fixture; no Quick Build test skipped, and both the functional QuickBuildProxyAppBuildTest and the Gradle-version-parameterized init-script test ran in full. Coverage reads 43.1% line / 48.9% branch, but that number is a measurement artifact: the functional tests run the plugin in a separate Gradle process via TestKit, which the JaCoCo agent cannot instrument, so the most-exercised classes read 0%.
  • End-to-end evidence: PR 11.

Coverage (JaCoCo at the stack tip, single run):

Package Line Branch Note
com.itsaky.androidide.gradle 2.7% 6.4% plugin entry points; run inside a real Gradle build
com.itsaky.androidide.gradle.quickbuild 59.6% 61.1% task classes, same
NON-UI TOTAL 43.1% 48.9% 1,012 lines, 423 branches

Both rows are depressed by the TestKit artifact, not by absent tests: this code executes inside a separate real Gradle process that the JaCoCo agent cannot instrument, so the most-exercised classes read 0%. It is covered by the plugin's own functional tests and the device passes rather than by JVM-unit measurement here. The four classes carrying the artifact are QuickBuildTasks (0% over 290 lines), QuickBuildPlugin (0% over 186), COTGSettingsPlugin, and AndroidIDEGradlePlugin. Excluding those four, the remaining nine files read 100% line, with branch coverage from 70.0% to 100.0%.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Kj9YeCDHGp9DU8LPtfWJ7W

fryanpan and others added 2 commits August 21, 2026 23:58
…Gradle build: proxy classes, manifest rewrite, quickbuild.json

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kj9YeCDHGp9DU8LPtfWJ7W
…ection, min-AGP guard

Review finding 1 (renamed services/receivers silently break explicit intents) → services and
receivers now keep their real manifest names, per the design doc's own no-proxy path: the
appComponentFactory instantiates the manifest name through the payload loader (like the
Application), Android has no service/receiver alias to compensate a rename with, and neither
kind uses the activity-only getClassLoader injection. They stay recorded in setup.json (null
proxyClass) so the restart rule still sees them; resolver-skipped library components stay out,
as before. Covered by QuickBuildManifestTransformerTest ("services keep their real manifest
names so explicit start-service intents still resolve", "receivers keep their real name...",
"project-owned services stay recorded...", plus the rewritten skip/numbering tests). Docs
updated in step (component-proxying-design.md, quickbuild/README.md, ComponentInfo.kt,
live-reload-alternatives.md).

Review finding 3 (fail-quiet runtime-AAR injection) → the injection path now goes through
QuickBuildPlugin.requireRuntimeConfiguration, which throws a GradleException naming the
variant and the unrecognized AGP variant type instead of silently producing a proxy APK that
crashes at launch; the .flat-overlay caller keeps its documented graceful degrade. Covered by
QuickBuildPluginTest ("requireRuntimeConfiguration fails the build loudly on an unrecognized
variant type", "runtimeConfigurationOrNull degrades to null for the resources overlay path").

Review finding 2 (deleted min-AGP guard) → restored as a minAgpCheck source set wired into
`check`: it recompiles every non-Quick-Build plugin source against AGP_VERSION_MINIMUM, so an
AGP-8-only API in LogSenderPlugin/AndroidIDEGradlePlugin goes red again. Quick Build sources
are excluded (they genuinely need the newer AGP and load only when enabled); to keep that
exclusion compilable, AndroidIDEGradlePlugin applies QuickBuildPlugin by name, pinned to the
real class by QuickBuildPluginTest ("the reflective quick build plugin name resolves to the
real class"). The guard task itself is the red light for build-file regressions. This restore
is the conservative option; dropping the guard again can be re-proposed separately with
rationale if the team prefers compile-against-latest only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kj9YeCDHGp9DU8LPtfWJ7W
@fryanpan
fryanpan force-pushed the feature/ADFA-4128-qb-10-gradle-plugin branch from a7dd77e to 45a0fcc Compare August 22, 2026 07:05
@fryanpan
fryanpan marked this pull request as ready for review August 23, 2026 02:31

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant