Expose Android package output items#11674
Conversation
Add metadata-rich AndroidPackageOutput and AndroidPublishedPackageOutput item groups so custom MSBuild targets and CI can discover final APK/AAB outputs without recalculating file names. Wire the publish target to consume the package output items, cover publish/signing scenarios in tests, and document the new item metadata. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR makes Android packaging outputs discoverable by introducing a stable @(AndroidPackageOutput) item group (and a GetAndroidPackageOutputs target) so custom targets and CI workflows can consume authoritative APK/AAB paths without reimplementing packaging logic.
Changes:
- Add
_CollectAndroidPackageOutputs+GetAndroidPackageOutputs, and wire collection into build/sign/package order so outputs are available after packaging/signing. - Update
dotnet publishflow to publish packages via@(AndroidPackageOutput)(instead of filename globs) and then rewrite the item group to point at$(PublishDir)copies. - Add test coverage and documentation for the new item group.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | Adds package-output collection target and public target returning @(AndroidPackageOutput) with metadata. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets | Schedules _CollectAndroidPackageOutputs after package/sign/universal APK creation and in related target dependency chains. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Publish.targets | Publishes using @(AndroidPackageOutput) and updates items to the final publish paths after copy. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs | Adds dotnet publish assertions ensuring package outputs flow into ResolvedFileToPublish and @(AndroidPackageOutput). |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs | Adds assertions that signed APK outputs (including per-ABI) appear in @(AndroidPackageOutput) with correct metadata. |
| Documentation/docs-mobile/building-apps/build-targets.md | Mentions @(AndroidPackageOutput) for SignAndroidPackage (needs a section for the new GetAndroidPackageOutputs target). |
| Documentation/docs-mobile/building-apps/build-items.md | Documents the new @(AndroidPackageOutput) item group and its metadata. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prove that GetApplicationArtifactsDependsOn targets observe Android-produced ApplicationArtifact items before adding MAUI-style metadata, including publish outputs and per-ABI APK artifacts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Route Android Publish through GetApplicationArtifacts so targets appended through GetApplicationArtifactsDependsOn can observe and augment ApplicationArtifact items before Publish calculates and returns them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add command-line target-result examples for GetApplicationArtifacts and Publish so callers can discover returned ApplicationArtifact items from the documented target surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
State that GetApplicationArtifactsDependsOn extension targets run after platform ApplicationArtifact items are populated so later imports can update existing items with additional metadata. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep Build outside the user-extensible GetApplicationArtifactsDependsOn property so overriding the property cannot skip platform ApplicationArtifact population before metadata extension targets run. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prefer dotnet build for ApplicationArtifact target-result examples instead of dotnet msbuild. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
macios equivalent: dotnet/macios#25723 |
Write ApplicationArtifact test output with item transforms so WriteLinesToFile receives the full item list in one invocation instead of batching per item. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep artifact creation behind a mandatory internal target that runs Build and then explicitly packages, signs, and collects application artifacts before public extension targets can enrich the items. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep GetApplicationArtifacts directly dependent on Build before extension targets run, avoiding an extra private artifact-production wrapper. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The PackagingTest.CheckSignApk and XASdkTests.DotNetPublish additions injected ~80 lines of inline MSBuild XML plus file-based bookkeeping into existing matrix tests to validate the new `@(ApplicationArtifact)` behavior. That coupled the new feature to unrelated test surfaces and inflated test runtime across the `[Values]` matrix. Instead, parameterize `BuildTest.DotNetBuildReturnsApplicationArtifacts` to cover the same contract from one focused test that uses the JSON emitted by `-getTargetResult:` rather than `WriteLinesToFile`/read-back. Added cases: * `aab` package format - asserts 3 items (unsigned aab, signed aab, signed universal apk from the bundle). * Per-ABI apk with explicit RuntimeIdentifiers - asserts the per-ABI items carry `Abi` metadata. * Extension hook - validates the `_CreateApplicationArtifacts` -> `$(GetApplicationArtifactsDependsOn)` ordering contract by appending a target that runs `Update` to add `MauiArtifact=true`. If the order regresses, `Update` would have nothing to update and the metadata wouldn't appear on the returned items. Reverted all changes to PackagingTest.cs and XASdkTests.cs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…title/description
The Phase 4 prompt forced a rewrite of the PR title/description on every
review ("restate them cleaned-up") using a generic 1-sentence + bullets
template. On PRs that already have strong, detailed descriptions this
produced a STRICTLY WORSE result — e.g. it shortened
"Add MAUI ApplicationArtifact metadata for net11p6" to the vaguer
"Add MAUI metadata to application artifacts" and dropped the critical
"Platform dependencies" links (dotnet/android#11674, dotnet/macios).
Rework Phase 4 to apply the pr-finalize skill's core "Preserve Quality"
principle:
- Inject the PR's CURRENT title + description into the prompt so the agent
can evaluate-first (fetch body via gh pr view; truncate to 4k chars).
- Only recommend a rewrite when the current title/description is stale,
inaccurate, vague, or missing key info; otherwise emit a "keep as-is"
assessment and NO degraded replacement.
- When a change is warranted, require a STRICT IMPROVEMENT that preserves
dependency links, platform sections, specific type/term names and issue
refs, following the skill's "[Platform] Component: What changed" title
formula.
No change to post-ai-summary-comment.ps1 rendering; Pester 15/15 still pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ze evaluate-first `gh pr view` is unreliable in the CopilotReview phase after the squash-merge checkout (the previous fix's fresh gh fetch returned empty, so the prompt hit the "could not fetch" fallback and the agent rebuilt the description from the diff — dropping author-only context like external dependency links). Persist the PR title+body to pr-metadata.json during the Setup phase, where gh provably works and $prInfo is populated, then read it back in STEP 5b via the same cross-phase shared-dir mechanism the setup-complete sentinel uses. gh fetch / $prInfo / non-degrading text remain as ordered fallbacks. Now the evaluate-first prompt reliably sees the real current title and description, so it can correctly choose keep-as-is and preserve specifics (e.g. dotnet/android#11674 dependency links) instead of regenerating. Verified: parses cleanly; Setup→CopilotReview file round-trip preserves title + dep-links; Pester 15/15. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the unsupported per-ABI target-result case from DotNetBuildReturnsApplicationArtifacts. The callable-target coverage now matches the default-project scenarios requested in review while keeping APK, Publish, AAB, and extension metadata coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the ProjectBuilder AssertHasAtMostWarnings helper used by the packaging tests so the test project builds cleanly before running the application artifact coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-outputs # Conflicts: # src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs # src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/AssertionExtensions.cs
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Code Review — Expose Android package output items
Verdict:
Solid, well-scoped MSBuild change. The new @(ApplicationArtifact) item group and GetApplicationArtifacts / Publish return contract are clean, the metadata surface (PackageFormat, Signed, PackageId, Abi) is intentionally small, and the docs are thorough. I verified:
- ✅
PackageId="$(_AndroidPackage)"correctly maps to the resolved Android package name (ApplicationId), matching the docs. - ✅ The
aab;apkcase is handled:_AndroidAdditionalPackageFormats=apkproduces the signed universal APK at$(ApkFileSigned), which the unguardedExists('$(ApkFileSigned)')include captures (3 items for AAB — matches the test). - ✅
_CollectApplicationArtifactsis wired into all the build/sign/package dependency chains after signing runs.
Issues (2 inline)
⚠️ MSBuild targets —_UpdateApplicationArtifactsForPublishsilently drops any artifact not found in$(PublishDir)(Publish.targets).- 💡 Testing — Test comment references the wrong target name
_CreateApplicationArtifacts(BuildTest.cs).
Notes (not blocking)
- PR description vs. diff: The description lists added coverage in
XASdkTests.DotNetPublishandPackagingTest.CheckSignApk(Releaseaab;apk,@(ResolvedFileToPublish)flow, per-ABI signed APKs). Those files are not in this diff — onlyBuildTest.cswas changed. Please reconcile the description with the actual test coverage, or add the missing tests. The per-ABI (AndroidCreatePackagePerAbi=true) andaab;apkpublish paths in particular are currently exercised only indirectly. - CI has no completed statuses yet (pending) — verdict assumes the pipeline goes green.
Nice work on the documentation and the extension-hook ordering test.
Generated by Android PR Reviewer for #11674 · 140.5 AIC · ⌖ 13.1 AIC · ⊞ 6.8K
Comment /review to run again
- Drop the Exists() filter in _UpdateApplicationArtifactsForPublish so a missing copy in $(PublishDir) surfaces as a failure downstream instead of silently dropping the artifact from the returned item group. - Fix a stale target name in the DotNetBuildReturnsApplicationArtifacts extension-hook comment (_CreateApplicationArtifacts -> _CollectApplicationArtifacts). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5bbc94fa-010d-48af-9bfc-7b29ef7f2a43
## Why this change is necessary The platform SDK owns the authoritative final application artifact metadata for all Android consumers. Project properties are not sufficient because custom manifests can override them and `GenerateApplicationManifest=false` bypasses generated values entirely. This follows the `@(ApplicationArtifact)` contract introduced by [#11674](#11674) and provides the producer-owned metadata consumed by [dotnet/maui#35973](dotnet/maui#35973) without making the values MAUI-specific defaults. ## What changed - Extended the existing final merged-manifest read path to expose the resolved package, application `android:label`, `android:versionName`, and `android:versionCode`. - Stamped every APK/AAB `@(ApplicationArtifact)` with: - `ApplicationId` - `ApplicationTitle` - `ApplicationName` - `ApplicationDisplayVersion` - `ApplicationVersion` - Preserved `PackageId`, `PackageFormat`, `Signed`, and per-ABI `Abi` metadata. - Preserved all producer-owned common and Android metadata when `Publish` recreates artifact items under `$(PublishDir)`. - Kept `GetApplicationArtifactsDependsOn` overrides effective for both direct target results and Publish recreation. - Kept resource-backed labels such as `@string/app_name` unchanged instead of resolving a locale. - Documented final merged-manifest precedence and resource-reference behavior. ## Tests Focused host-side coverage validates generated manifests, custom manifest precedence, `GenerateApplicationManifest=false`, resource-backed labels, APK/AAB signed and unsigned outputs, per-ABI items, extension overrides, `GetApplicationArtifacts`, and Publish recreation. ```text Passed: 9 Failed: 0 Skipped: 0 Duration: 40 s ``` Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Why this change is necessary
Android package outputs are difficult for custom targets, CI workflows, and higher-level workloads to discover reliably. Final APK and AAB paths are calculated by the Android build, while
dotnet publishpreviously rediscovered packages indirectly. Consumers therefore had to duplicate Android-specific naming and packaging logic.This change exposes the authoritative final package outputs through
@(ApplicationArtifact)and a callableGetApplicationArtifactstarget. The item name is intentionally platform-neutral so workloads such as MAUI and other .NET mobile platforms can enrich or populate the same contract.What changed
@(ApplicationArtifact)collection after Android package, signing, and universal APK generation.PackageFormat:apkoraabSigned: whether the package is signedPackageId: the resolved Android package nameAbi: the ABI for per-ABI APKsGetApplicationArtifacts, which builds the project and returns@(ApplicationArtifact).$(GetApplicationArtifactsDependsOn)as an extension point that runs after Android creates the items, allowing later imports such as MAUI to add metadata before eitherGetApplicationArtifactsorPublishreturns them.Publishto:@(ApplicationArtifact)as the source of package entries in@(ResolvedFileToPublish);$(PublishDir);@(ApplicationArtifact)with identities updated to the published paths while preserving metadata.DotNetCLIhelper to accept arbitrary MSBuild command-line arguments, including-getTargetResult.@(ApplicationArtifact),GetApplicationArtifacts, thePublishreturn contract, metadata, extension behavior, and command-line query examples.Tests
Added
BuildTest.DotNetBuildReturnsApplicationArtifactscoverage for:GetApplicationArtifacts.Publish.$(GetApplicationArtifactsDependsOn)extension that observes the Android-produced items and enriches their metadata before they are returned.The tests parse MSBuild
-getTargetResultJSON and validate artifact count, file name, package format, signed status, package ID, ABI, and extension-provided metadata.Issues fixed
N/A