Skip to content

Fix missing font and splash outputs after incremental builds - #35962

Closed
jfversluis wants to merge 5 commits into
mainfrom
jfversluis/investigating-resources-issue
Closed

Fix missing font and splash outputs after incremental builds#35962
jfversluis wants to merge 5 commits into
mainfrom
jfversluis/investigating-resources-issue

Conversation

@jfversluis

@jfversluis jfversluis commented Jun 17, 2026

Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

Fixes an incremental Resizetizer invalidation gap where ProcessMauiFonts and ProcessMauiSplashScreens could be skipped even when their generated intermediate outputs were missing. This could produce Android packages without MauiFont assets and splash screen rasters after stale/incomplete incremental build state.

The fix tracks generated font and splash outputs in obj-scoped .outputs manifests, reads them before the MSBuild incremental check, and includes those generated files in target Outputs. If a generated font or splash file disappears after a previous successful build, only the relevant font/splash target reruns. Separate font/splash stamp files are no longer generated.

Issues Fixed

Fixes #33092

Related Issues / Scope

Issue Relationship
#25540 Related Android evidence: intermittent fonts missing from APK/runtime after builds; also reports splash missing when fonts are missing.
#28502 Recent discussion/testing thread. This PR may help only if the repro is actual packaged font/splash omission; it is not intended to fix Windows FontManager fallback/noisy missing-font logging.
#26889 Related custom-font symptoms, but appears broader/naming/Windows/Blazor-specific; linked for awareness, not claimed fixed.
#24059 EmbeddedResource/cache font warning path; distinct from MauiFont package omission and not claimed fixed.
#21771, #19804 MAUI library/NuGet asset propagation issues; distinct from stale app Resizetizer intermediates and not claimed fixed.
#35584 Artifact-testing blocker encountered by one tester, unrelated to this fix.

Artifact Testing

@danies8 @rokmeglicbit if your recent #28502/#33092 repro involves actual missing packaged fonts/splash resources rather than only Windows fallback logging, please try this PR's artifacts and let us know whether it resolves your issue. The validation here shows Android APK package contents are restored after the stale-incremental state described in #33092.

Requesting review from @jonathanpeppers.

Validation

  • Temporarily reverted this fix and reproduced the Android package omission 3/3 times by keeping the old pre-fix mauifont.stamp/mauisplash.stamp target outputs newer while deleting generated obj\...\resizetizer\f and obj\...\resizetizer\sp outputs, then rebuilding an Android APK.
  • Reapplied the fix and verified the same stale-output Android rebuild passed 3/3 times.
  • After review updates, validated the current target logic by deleting generated font/splash output folders after a successful build while preserving the new output manifests; the Android APK still contained fonts and splash rasters, and a following no-op build skipped both font/splash targets.
  • Confirmed APK contents include:
    • assets/OpenSans-Regular.ttf
    • assets/OpenSans-Semibold.ttf
    • res/drawable-*-v4/splash.png
  • Built Microsoft.Maui.IntegrationTests.csproj with the existing unrelated CS9336 warning suppressed: dotnet build .\src\TestUtils\src\Microsoft.Maui.IntegrationTests\Microsoft.Maui.IntegrationTests.csproj -v:minimal -p:NoWarn=CS9336.

jfversluis and others added 2 commits June 17, 2026 11:00
Track generated font and splash outputs alongside their stamp files so missing intermediates invalidate the narrow Resizetizer targets instead of producing packages without resources.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Write font and splash output manifests normally instead of combining WriteOnlyWhenDifferent with an unconditional Touch. The manifests are declared target outputs, so their timestamps should advance when the target runs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35962

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35962"

@github-actions github-actions Bot added the area-tooling XAML & C# Hot Reload, XAML Editor, Live Visual Tree, Live Preview, Debugging label Jun 17, 2026
@kubaflo

kubaflo commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

/review -b feature/enhanced-reviewer -p android

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jun 17, 2026
@rokmeglicbit

Copy link
Copy Markdown

@jfversluis wanted to test this, but I get:

06-17 14:21:11.364 E/AndroidRuntime( 3351): FATAL EXCEPTION: main
06-17 14:21:11.364 E/AndroidRuntime( 3351): Process: si.jantar.android.codekssmarthouse, PID: 3351
06-17 14:21:11.364 E/AndroidRuntime( 3351): android.runtime.JavaProxyThrowable: [System.MissingMethodException]: Method not found: void AndroidX.Core.View.Accessibility.AccessibilityNodeInfoCompat.set_Checked(bool)
06-17 14:21:11.364 E/AndroidRuntime( 3351): 	at Microsoft.Maui.Platform.MauiAccessibilityDelegateCompat.OnInitializeAccessibilityNodeInfo(/_/src/Core/src/Platform/Android/MauiAccessibilityDelegateCompat.cs:28)

... so I can't really tell if this works or not. This is #35584.

I have tested using
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35962"
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.90-ci.pr35962.26317.7" />

@MauiBot MauiBot added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jun 17, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 17, 2026
@jfversluis

Copy link
Copy Markdown
Member Author

@rokmeglicbit Can you try the workaround here to get past it and see if it fixes the issue we're talking about? #35584 (comment)

@rokmeglicbit

Copy link
Copy Markdown

@jfversluis looks good on our side. Thank you.

@kubaflo

kubaflo commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

@rokmeglicbit thank you for looking at this!

@kubaflo
kubaflo changed the base branch from main to inflight/current June 17, 2026 16:26

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you please resolve conflicts?

Comment thread src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs Outdated
Comment thread src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs Outdated
Comment thread src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs Outdated
@jfversluis
jfversluis changed the base branch from inflight/current to main June 18, 2026 08:34
Stop creating separate font and splash stamp files now that the generated output manifests drive incremental checks, add a splash DependsOnTargets extension point, and verify no-op builds skip font and splash targets.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis

Copy link
Copy Markdown
Member Author

Conflict update: retargeted this bug-fix PR to main, which removes the unrelated inflight/current diff/conflict and leaves only the two intended Resizetizer files. Pushed follow-up commit 4979d7f33e addressing Jonathan's review comments.

Comment thread src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs Outdated
Use a plain multi-target build in the Resizetizer regression test, covering the font and splash intermediate outputs for each built platform instead of Android packaging only.

Also make font and splash output manifest writes defensive and consistent with the image output manifest pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jfversluis

Copy link
Copy Markdown
Member Author

Pushed follow-up commit df49e70a25 addressing the latest feedback:

  • switched the regression from SignAndroidPackage to plain Build
  • removed Android-only TFM stripping and now validates generated Resizetizer font/splash intermediates across the built target platforms
  • kept the no-op binlog assertion for ProcessMauiFonts and ProcessMauiSplashScreens
  • added WriteOnlyWhenDifferent to the font/splash output manifest writes and a defensive MakeDir before the font manifest write

@github-actions github-actions Bot added the s/agent-ready-for-rerun AI review has a new PR-author comment or commit and is ready for rerun label Jun 19, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 1 findings

See inline comments for details.

MauiBot

This comment was marked as outdated.

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added s/agent-review-in-progress AI review is currently running for this PR and removed s/agent-ready-for-rerun AI review has a new PR-author comment or commit and is ready for rerun labels Jun 21, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 1 findings

See inline comments for details.

MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 22, 2026
Exclude the generated iOS MauiInfo.plist from the copied-font glob so it is only tracked through the explicit plist output item.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

@jfversluis — new AI review results are available based on this last commit: cd570fc. To request a fresh review after new comments or commits, comment /review rerun.

Gate Inconclusive Confidence Low Platform Android


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ INCONCLUSIVE

Platform: ANDROID

⚠️ verify-tests-fail.ps1 exited before writing a verification report. Diagnostics below.

Exit code: 3

Likely cause:

  • Test detection failed — no runnable tests were found in the PR diff.
Gate output log (last 60 lines)
📁 Output directory: CustomAgentLogsTmp/PRState/35962/PRAgent/gate/verify-tests-fail
🔍 Detecting base branch and merge point...
No PR detected, scanning remote branches for closest base...
✅ Base branch: main (via closest-merge-base)
✅ Merge base commit: 4567a055
   (1 commits ahead of main)
╔═══════════════════════════════════════════════════════════╗
║         FULL VERIFICATION MODE                            ║
╠═══════════════════════════════════════════════════════════╣
║  Fix files detected - will verify:                        ║
║  1. Tests FAIL without fix                                ║
║  2. Tests PASS with fix                                   ║
╚═══════════════════════════════════════════════════════════╝
✅ Fix files (1):
   - src/SingleProject/Resizetizer/src/nuget/buildTransitive/Microsoft.Maui.Resizetizer.After.targets
🔍 Auto-detecting test filter from changed test files...
⚠️ No tests detected in this PR.
   Searched for: UI tests, unit tests, XAML tests, device tests
   Consider adding tests via write-tests-agent.

📋 Pre-Flight — Context & Validation

Issue: #33092 - Resizetizer generated font/splash outputs can remain missing after stale stamp-based incremental skip
PR: #35962 - Resizetizer font/splash incremental output tracking
Platforms Affected: android primarily; build-time Resizetizer target logic also affects iOS, MacCatalyst, Windows, Tizen where applicable
Files Changed: 1 implementation, 1 test

Key Findings

  • PR replaces mauifont.stamp/mauisplash.stamp with .outputs manifests so MSBuild tracks generated font and splash files as incremental outputs.
  • This mirrors the existing mauiimage.outputs pattern and should rerun targets when generated output folders are deleted but the target metadata remains.
  • GitHub PR metadata, linked issue, comments, reviews, and required checks could not be fetched because gh is unauthenticated; the supplied gate result is INCONCLUSIVE and is not treated as a failing fix.
  • The added integration test validates regenerated intermediate outputs and no-op target skips, but not final Android package contents.

Code Review Summary

Verdict: NEEDS_DISCUSSION
Confidence: low
Errors: 0 | Warnings: 1 | Suggestions: 0

Key code review findings:

  • ⚠️ src/TestUtils/src/Microsoft.Maui.IntegrationTests/ResizetizerTests.cs: automated coverage checks regenerated intermediate files, not packaged Android APK asset contents.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35962 Replace font/splash stamp files with output manifests and include previously generated files in target Outputs ⚠️ INCONCLUSIVE (Gate) Microsoft.Maui.Resizetizer.After.targets, ResizetizerTests.cs Original PR; technically sound by local review

🔬 Code Review — Deep Analysis

Code Review — PR #35962

Independent Assessment

What this changes: Replaces stamp-file-based MSBuild incremental tracking for ProcessMauiFonts and ProcessMauiSplashScreens with manifest-file-based tracking. Each target writes absolute paths of generated outputs to a .outputs manifest and reads that manifest before incremental checks so missing intermediate outputs make the target rerun.
Inferred motivation: A stamp file only proves the target ran. If generated font or splash output folders are deleted while the stamp remains, MSBuild can skip regeneration and later packaging can miss assets.

Reconciliation with PR Narrative

Author claims: Unavailable through GitHub CLI because gh is unauthenticated in this environment. Local squashed branch and diff indicate a Resizetizer incremental build fix with integration coverage.
Agreement/disagreement: Local code evidence supports the inferred fix strategy. PR metadata, comments, and CI could not be fetched.

Prior Review Reconciliation

GitHub review/comment surfaces could not be queried because gh is unauthenticated. No prior ❌ Error findings could be verified locally.

Blast Radius Assessment

  • Runs for all instances: Yes — build-time font and splash targets run for MAUI projects when processing is enabled.
  • Startup impact: No runtime startup path; this is MSBuild target logic.
  • Static/shared state: No; state is per-intermediate-output manifest files.

CI Status

  • Required-check result: Undetermined. gh pr checks/PR metadata cannot run without GitHub CLI authentication, and the provided gate result is INCONCLUSIVE.
  • Classification: Undetermined.
  • Action taken: Confidence capped at low; do not treat gate as a failing fix.

Findings

⚠️ Warning — Automated test checks regenerated intermediate outputs, not packaged APK contents

The test verifies obj/.../resizetizer/f fonts and obj/.../resizetizer/sp splash outputs are regenerated and targets no-op afterward. It does not verify the Android package contains the regenerated assets, while the reported impact appears packaging-visible.

Failure-Mode Probing

  • Manifest exists but lists deleted output: target should rerun because the listed output is missing.
  • Manifest deleted: target should rerun because the manifest output itself is missing.
  • First build: manifest missing, target runs and creates it.
  • MacCatalyst without splash assets: empty manifest is sufficient for no-op skip.

Verdict: NEEDS_DISCUSSION

Confidence: low
Summary: The PR approach is technically sound and follows the existing mauiimage.outputs pattern, but CI and PR discussion are unavailable locally. The main review caveat is that the test validates intermediate regeneration rather than final packaged Android assets.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix In-directory sentinel files under resizetizer/f and resizetizer/sp; font Outputs also include source-derived copied font paths ⚠️ BLOCKED 2 files Environment blocked targeted integration test: missing .dotnet/packs/Microsoft.Maui.Sdk. Less robust than PR for partial splash deletion. See ../try-fix-1/content.md.
2 try-fix Static MSBuild font Outputs plus pre-target splash stamp invalidation when splash output directory is empty/missing ⚠️ BLOCKED 2 files Same environment blocker. Less complete cross-platform tracking than PR; iOS font plist and partial splash deletion remain risks. See ../try-fix-2/content.md.
3 try-fix Preserve original mauifont.stamp/mauisplash.stamp; validate output dirs and delete stale stamps before incremental checks ⚠️ BLOCKED 2 files Same environment blocker. Simpler but only detects missing/empty dirs, not partial output deletion. See ../try-fix-3/content.md.
PR PR #35962 Manifest output files (mauifont.outputs, mauisplash.outputs) read before incremental checks and included in target Outputs ⚠️ INCONCLUSIVE (Gate) 2 files Original PR; strongest approach by code review because it tracks actual generated outputs rather than directory/sentinel heuristics.

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 2 No NO NEW IDEAS: manifest approach is the correct pragmatic solution because font/splash generated output paths are not fully statically derivable before the tasks run. Sentinel/static/stamp-validation alternatives are subsets or have known blind spots.

Test Environment

All candidate test runs used:

pwsh .github/skills/run-integration-tests/scripts/Run-IntegrationTests.ps1 -TestFilter "FullyQualifiedName~BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing" -SkipBuild -SkipInstall

Each run reached the integration-test runner and stopped at the same environment blocker:

ERROR: Microsoft.Maui.Sdk packs not found at: /home/vsts/work/1/s/.dotnet/packs/Microsoft.Maui.Sdk

Baseline establishment was also blocked because the shared worktree already had unrelated dirty files outside the PR target/test files. Per autonomous-execution instructions, the blocked baseline phase was recorded and candidate exploration continued without modifying unrelated files.

Exhausted: Yes
Selected Fix: PR #35962 — The PR's manifest-readback approach is not empirically verified in this environment, but it is demonstrably more robust on code merits than the alternatives generated here because it tracks actual generated outputs for both fonts and splash screens. No passing alternative was found, and no candidate was demonstrably better than the PR fix.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the description is accurate and complete, but the title should name the Resizetizer component.

Recommended title

Resizetizer: Fix missing font and splash outputs after incremental builds

Recommended description

### Description of Change

Fixes an incremental Resizetizer invalidation gap where `ProcessMauiFonts` and `ProcessMauiSplashScreens` could be skipped even when their generated intermediate outputs were missing. This could produce Android packages without `MauiFont` assets and splash screen rasters after stale/incomplete incremental build state.

The fix tracks generated font and splash outputs in obj-scoped `.outputs` manifests, reads them before the MSBuild incremental check, and includes those generated files in target `Outputs`. If a generated font or splash file disappears after a previous successful build, only the relevant font/splash target reruns. Separate font/splash stamp files are no longer generated.

### Issues Fixed

Fixes #33092

### Related Issues / Scope

| Issue | Relationship |
| --- | --- |
| #25540 | Related Android evidence: intermittent fonts missing from APK/runtime after builds; also reports splash missing when fonts are missing. |
| #28502 | Recent discussion/testing thread. This PR may help only if the repro is actual packaged font/splash omission; it is not intended to fix Windows FontManager fallback/noisy missing-font logging. |
| #26889 | Related custom-font symptoms, but appears broader/naming/Windows/Blazor-specific; linked for awareness, not claimed fixed. |
| #24059 | EmbeddedResource/cache font warning path; distinct from `MauiFont` package omission and not claimed fixed. |
| #21771, #19804 | MAUI library/NuGet asset propagation issues; distinct from stale app Resizetizer intermediates and not claimed fixed. |
| #35584 | Artifact-testing blocker encountered by one tester, unrelated to this fix. |

### Artifact Testing

@danies8 @rokmeglicbit if your recent #28502/#33092 repro involves actual missing packaged fonts/splash resources rather than only Windows fallback logging, please try this PR's artifacts and let us know whether it resolves your issue. The validation here shows Android APK package contents are restored after the stale-incremental state described in #33092.

Requesting review from @jonathanpeppers.

### Validation

- Temporarily reverted this fix and reproduced the Android package omission 3/3 times by keeping the old pre-fix `mauifont.stamp`/`mauisplash.stamp` target outputs newer while deleting generated `obj\...\resizetizer\f` and `obj\...\resizetizer\sp` outputs, then rebuilding an Android APK.
- Reapplied the fix and verified the same stale-output Android rebuild passed 3/3 times.
- After review updates, validated the current target logic by deleting generated font/splash output folders after a successful build while preserving the new output manifests; the Android APK still contained fonts and splash rasters, and a following no-op build skipped both font/splash targets.
- Confirmed APK contents include:
  - `assets/OpenSans-Regular.ttf`
  - `assets/OpenSans-Semibold.ttf`
  - `res/drawable-*-v4/splash.png`
- Built `Microsoft.Maui.IntegrationTests.csproj` with the existing unrelated `CS9336` warning suppressed: `dotnet build .\src\TestUtils\src\Microsoft.Maui.IntegrationTests\Microsoft.Maui.IntegrationTests.csproj -v:minimal -p:NoWarn=CS9336`.

🏁 Report — Final Recommendation

Comparative Analysis — PR #35962

Candidate ranking

Rank Candidate Regression result Assessment
1 pr ⚠️ Inconclusive / blocked, not failed Best code-level fix. Tracks actual generated font and splash outputs using obj-scoped manifests read before MSBuild incremental checks. Handles deleted output manifests, deleted output directories, and partial deletion of previously generated files.
2 pr-plus-reviewer ⚠️ Inconclusive / blocked, not failed Equivalent to pr; the expert reviewer produced no actionable findings, so no sandbox changes were applied. Ranked immediately after pr only because it adds no improvement over the submitted fix.
3 try-fix-1 ⚠️ Blocked, not failed Uses in-directory sentinel files plus static font outputs. Simpler, but splash tracking is sentinel-granularity and can miss partial splash output deletion when the sentinel remains.
4 try-fix-2 ⚠️ Blocked, not failed Uses static font outputs plus splash stamp invalidation for missing/empty splash directory. Less complete than the PR because iOS font plist output is not included in static font Outputs, and partial splash deletion can be missed when the directory remains non-empty.
5 try-fix-3 ⚠️ Blocked, not failed Preserves stamp files and deletes stale stamps only when generated directories are missing or empty. This catches total loss but not partial deletion when at least one font or splash output remains.

Regression-test rule application

No candidate had a passing regression result in this environment. The PR gate was explicitly inconclusive, and all try-fix candidate runs were blocked by the same missing local MAUI SDK/workload setup (.dotnet/packs/Microsoft.Maui.Sdk). None of these results is treated as a failing regression test, so ranking is based on code merits and known failure-mode coverage.

Key comparison

The PR's manifest-readback approach is the only candidate that records the actual files produced by the previous successful target execution and feeds those files back into MSBuild Outputs before the next incremental decision. That directly models the failure mode: stale incremental state plus missing generated intermediates.

The try-fix alternatives rely on sentinels, static transforms, or directory emptiness checks. Those approaches can detect broad deletion scenarios, but they do not reliably detect partial output loss across the font/splash output sets. try-fix-2 also narrows font tracking too much for non-Android outputs such as the generated iOS font plist.

Winning candidate

Winner: pr

The raw PR fix is the winning candidate because it is the most complete and robust implementation on code merits, and no candidate produced a passing test result that would outweigh that assessment. pr-plus-reviewer is equivalent because the expert reviewer returned no actionable findings.


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@kubaflo

kubaflo commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

🔍 AI-generated comment (GitHub Copilot CLI), posted on behalf of @kubaflo

Closing in favor of #33919, which we're using as the single consolidation point for the Resizetizer font/splash incremental-build fixes.

Thanks @jfversluis for the outputs-manifest approach here, and @jonathanpeppers for the thorough review — that work isn't lost. The two PRs fixed orthogonal failure modes in the same targets file:

Rather than merge-conflict two overlapping rewrites of the same regions, I'm porting this PR's outputs-manifest mechanism into #33919, including the review refinements from here:

  • drop mauifont.stamp / mauisplash.stamp entirely (per @jonathanpeppers)
  • _ReadMauiFontOutputs / _ReadMauiSplashOutputs read-targets + generated files in Outputs
  • the ProcessMauiSplashScreensDependsOnTargets property
  • the all-platform BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing regression test

Full credit for the approach stays attributed to @jfversluis. Follow along in #33919.

@kubaflo kubaflo closed this Jul 1, 2026
kubaflo pushed a commit that referenced this pull request Jul 1, 2026
Ports the outputs-manifest incremental invalidation from #35962 (now closed)
into this PR so deleting generated font/splash intermediates re-triggers
ProcessMauiFonts/ProcessMauiSplashScreens (fixes #33092), complementing the
first-build registration fix for #23268.

- Replace mauifont.stamp/mauisplash.stamp with mauifont.outputs/mauisplash.outputs
  manifests, read back via _ReadMauiFontOutputs/_ReadMauiSplashOutputs and fed into
  each target's Outputs, so a missing generated file invalidates only that target.
- Drop the font/splash stamp files entirely (per jonathanpeppers review on #35962).
- Add ProcessMauiSplashScreensDependsOnTargets.
- De-duplicate fonts by intermediate filename before CreatePartialInfoPlistTask to
  avoid duplicate UIAppFonts entries (addresses open review suggestion on #33919).
- Port the all-platform BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing
  regression test (macOS-gated; adds iOS/MacCatalyst coverage).
- Update resizetizer.instructions.md for the outputs-manifest mechanism.

Co-authored-by: Gerald Versluis <939291+jfversluis@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo added a commit that referenced this pull request Jul 17, 2026
…tputs are deleted (#33919)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

The Resizetizer copies and registers `MauiFont` / `MauiSplashScreen`
assets during the build. Two incremental-build gaps could leave an app
packaged **without** its fonts or splash screen:

1. **First build (Android/Tizen)** — item *registration*
(`AndroidAsset`, `BundleResource`, …) lived **inside** the incremental
`ProcessMauiFonts` target. On a clean build the target's
output-inference glob was empty, so the platform items were never
registered and fonts were missing until a *second* build. The fix splits
registration into an always-run `_CollectMauiFontItems` target that maps
font paths predictively from `@(MauiFont)`.

2. **Incremental build (all platforms)** — `ProcessMauiFonts` /
`ProcessMauiSplashScreens` tracked freshness with `mauifont.stamp` /
`mauisplash.stamp` files. A stamp could stay newer than a generated
output that was later deleted (partial `obj` clean or concurrent build),
so MSBuild skipped the target and the package shipped without the
missing font/splash. The fix replaces stamps with `mauifont.outputs` /
`mauisplash.outputs` manifests. `_ReadMauiFontOutputs` /
`_ReadMauiSplashOutputs` run before freshness evaluation, delete the
manifest when a listed generated output is missing, and each processor
uses the manifest as its sole `Outputs`. This makes only the affected
processor rerun without re-stamping unchanged generated assets and
unnecessarily invalidating downstream consumers such as Android aapt2.

This PR **consolidates** #35962 (closed): it drops the font/splash
stamps, adds `ProcessMauiSplashScreensDependsOnTargets`, and
de-duplicates fonts by intermediate filename before
`CreatePartialInfoPlistTask`, so colliding names (for example an app and
a `ProjectReference` both shipping `OpenSans.ttf`) do not emit duplicate
`UIAppFonts` entries.

The related runtime-side symptom (noisy missing-font fallback logging)
is intentionally out of scope here and handled separately in #35963.

### Issues Fixed

Fixes #23268
Fixes #33092

### Tests

- `ResizetizerTests.FontsAreCopiedToAndroidAssetsOnFirstBuild` — clean
Release build of the `maui` template asserts the font lands in the
Android `assets` folder on the **first** build, then an incremental
build confirms `ProcessMauiFonts` is skipped while the always-run
`_CollectMauiFontItems` still registers the asset.
-
`ResizetizerTests.BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing`
(macOS-gated) — builds Android/iOS/MacCatalyst template targets, deletes
only the generated iOS/MacCatalyst `MauiInfo.plist` files and verifies
both font processors rerun and restore them, then deletes generated
font/splash folders, verifies recovery, and finally verifies a no-op
build skips both processors.

### Validation

- A focused MSBuild sequence verified initial generation, no-op
skipping, regeneration after deleting a recorded output, and a
subsequent no-op skip using the same manifest-invalidation protocol.
- The full integration workflow could not complete locally because
Android workload installation exhausted the shared disk; the updated
Build integration test will validate on CI.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Gerald Versluis <939291+jfversluis@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
kubaflo added a commit that referenced this pull request Jul 22, 2026
…tputs are deleted (#33919)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

The Resizetizer copies and registers `MauiFont` / `MauiSplashScreen`
assets during the build. Two incremental-build gaps could leave an app
packaged **without** its fonts or splash screen:

1. **First build (Android/Tizen)** — item *registration*
(`AndroidAsset`, `BundleResource`, …) lived **inside** the incremental
`ProcessMauiFonts` target. On a clean build the target's
output-inference glob was empty, so the platform items were never
registered and fonts were missing until a *second* build. The fix splits
registration into an always-run `_CollectMauiFontItems` target that maps
font paths predictively from `@(MauiFont)`.

2. **Incremental build (all platforms)** — `ProcessMauiFonts` /
`ProcessMauiSplashScreens` tracked freshness with `mauifont.stamp` /
`mauisplash.stamp` files. A stamp could stay newer than a generated
output that was later deleted (partial `obj` clean or concurrent build),
so MSBuild skipped the target and the package shipped without the
missing font/splash. The fix replaces stamps with `mauifont.outputs` /
`mauisplash.outputs` manifests. `_ReadMauiFontOutputs` /
`_ReadMauiSplashOutputs` run before freshness evaluation, delete the
manifest when a listed generated output is missing, and each processor
uses the manifest as its sole `Outputs`. This makes only the affected
processor rerun without re-stamping unchanged generated assets and
unnecessarily invalidating downstream consumers such as Android aapt2.

This PR **consolidates** #35962 (closed): it drops the font/splash
stamps, adds `ProcessMauiSplashScreensDependsOnTargets`, and
de-duplicates fonts by intermediate filename before
`CreatePartialInfoPlistTask`, so colliding names (for example an app and
a `ProjectReference` both shipping `OpenSans.ttf`) do not emit duplicate
`UIAppFonts` entries.

The related runtime-side symptom (noisy missing-font fallback logging)
is intentionally out of scope here and handled separately in #35963.

### Issues Fixed

Fixes #23268
Fixes #33092

### Tests

- `ResizetizerTests.FontsAreCopiedToAndroidAssetsOnFirstBuild` — clean
Release build of the `maui` template asserts the font lands in the
Android `assets` folder on the **first** build, then an incremental
build confirms `ProcessMauiFonts` is skipped while the always-run
`_CollectMauiFontItems` still registers the asset.
-
`ResizetizerTests.BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing`
(macOS-gated) — builds Android/iOS/MacCatalyst template targets, deletes
only the generated iOS/MacCatalyst `MauiInfo.plist` files and verifies
both font processors rerun and restore them, then deletes generated
font/splash folders, verifies recovery, and finally verifies a no-op
build skips both processors.

### Validation

- A focused MSBuild sequence verified initial generation, no-op
skipping, regeneration after deleting a recorded output, and a
subsequent no-op skip using the same manifest-invalidation protocol.
- The full integration workflow could not complete locally because
Android workload installation exhausted the shared disk; the updated
Build integration test will validate on CI.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Gerald Versluis <939291+jfversluis@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
kubaflo added a commit that referenced this pull request Jul 28, 2026
…tputs are deleted (#33919)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

The Resizetizer copies and registers `MauiFont` / `MauiSplashScreen`
assets during the build. Two incremental-build gaps could leave an app
packaged **without** its fonts or splash screen:

1. **First build (Android/Tizen)** — item *registration*
(`AndroidAsset`, `BundleResource`, …) lived **inside** the incremental
`ProcessMauiFonts` target. On a clean build the target's
output-inference glob was empty, so the platform items were never
registered and fonts were missing until a *second* build. The fix splits
registration into an always-run `_CollectMauiFontItems` target that maps
font paths predictively from `@(MauiFont)`.

2. **Incremental build (all platforms)** — `ProcessMauiFonts` /
`ProcessMauiSplashScreens` tracked freshness with `mauifont.stamp` /
`mauisplash.stamp` files. A stamp could stay newer than a generated
output that was later deleted (partial `obj` clean or concurrent build),
so MSBuild skipped the target and the package shipped without the
missing font/splash. The fix replaces stamps with `mauifont.outputs` /
`mauisplash.outputs` manifests. `_ReadMauiFontOutputs` /
`_ReadMauiSplashOutputs` run before freshness evaluation, delete the
manifest when a listed generated output is missing, and each processor
uses the manifest as its sole `Outputs`. This makes only the affected
processor rerun without re-stamping unchanged generated assets and
unnecessarily invalidating downstream consumers such as Android aapt2.

This PR **consolidates** #35962 (closed): it drops the font/splash
stamps, adds `ProcessMauiSplashScreensDependsOnTargets`, and
de-duplicates fonts by intermediate filename before
`CreatePartialInfoPlistTask`, so colliding names (for example an app and
a `ProjectReference` both shipping `OpenSans.ttf`) do not emit duplicate
`UIAppFonts` entries.

The related runtime-side symptom (noisy missing-font fallback logging)
is intentionally out of scope here and handled separately in #35963.

### Issues Fixed

Fixes #23268
Fixes #33092

### Tests

- `ResizetizerTests.FontsAreCopiedToAndroidAssetsOnFirstBuild` — clean
Release build of the `maui` template asserts the font lands in the
Android `assets` folder on the **first** build, then an incremental
build confirms `ProcessMauiFonts` is skipped while the always-run
`_CollectMauiFontItems` still registers the asset.
-
`ResizetizerTests.BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing`
(macOS-gated) — builds Android/iOS/MacCatalyst template targets, deletes
only the generated iOS/MacCatalyst `MauiInfo.plist` files and verifies
both font processors rerun and restore them, then deletes generated
font/splash folders, verifies recovery, and finally verifies a no-op
build skips both processors.

### Validation

- A focused MSBuild sequence verified initial generation, no-op
skipping, regeneration after deleting a recorded output, and a
subsequent no-op skip using the same manifest-invalidation protocol.
- The full integration workflow could not complete locally because
Android workload installation exhausted the shared disk; the updated
Build integration test will validate on CI.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Gerald Versluis <939291+jfversluis@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
kubaflo added a commit that referenced this pull request Jul 29, 2026
…tputs are deleted (#33919)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Description of Change

The Resizetizer copies and registers `MauiFont` / `MauiSplashScreen`
assets during the build. Two incremental-build gaps could leave an app
packaged **without** its fonts or splash screen:

1. **First build (Android/Tizen)** — item *registration*
(`AndroidAsset`, `BundleResource`, …) lived **inside** the incremental
`ProcessMauiFonts` target. On a clean build the target's
output-inference glob was empty, so the platform items were never
registered and fonts were missing until a *second* build. The fix splits
registration into an always-run `_CollectMauiFontItems` target that maps
font paths predictively from `@(MauiFont)`.

2. **Incremental build (all platforms)** — `ProcessMauiFonts` /
`ProcessMauiSplashScreens` tracked freshness with `mauifont.stamp` /
`mauisplash.stamp` files. A stamp could stay newer than a generated
output that was later deleted (partial `obj` clean or concurrent build),
so MSBuild skipped the target and the package shipped without the
missing font/splash. The fix replaces stamps with `mauifont.outputs` /
`mauisplash.outputs` manifests. `_ReadMauiFontOutputs` /
`_ReadMauiSplashOutputs` run before freshness evaluation, delete the
manifest when a listed generated output is missing, and each processor
uses the manifest as its sole `Outputs`. This makes only the affected
processor rerun without re-stamping unchanged generated assets and
unnecessarily invalidating downstream consumers such as Android aapt2.

This PR **consolidates** #35962 (closed): it drops the font/splash
stamps, adds `ProcessMauiSplashScreensDependsOnTargets`, and
de-duplicates fonts by intermediate filename before
`CreatePartialInfoPlistTask`, so colliding names (for example an app and
a `ProjectReference` both shipping `OpenSans.ttf`) do not emit duplicate
`UIAppFonts` entries.

The related runtime-side symptom (noisy missing-font fallback logging)
is intentionally out of scope here and handled separately in #35963.

### Issues Fixed

Fixes #23268
Fixes #33092

### Tests

- `ResizetizerTests.FontsAreCopiedToAndroidAssetsOnFirstBuild` — clean
Release build of the `maui` template asserts the font lands in the
Android `assets` folder on the **first** build, then an incremental
build confirms `ProcessMauiFonts` is skipped while the always-run
`_CollectMauiFontItems` still registers the asset.
-
`ResizetizerTests.BuildRegeneratesFontsAndSplashWhenIntermediateOutputsAreMissing`
(macOS-gated) — builds Android/iOS/MacCatalyst template targets, deletes
only the generated iOS/MacCatalyst `MauiInfo.plist` files and verifies
both font processors rerun and restore them, then deletes generated
font/splash folders, verifies recovery, and finally verifies a no-op
build skips both processors.

### Validation

- A focused MSBuild sequence verified initial generation, no-op
skipping, regeneration after deleting a recorded output, and a
subsequent no-op skip using the same manifest-invalidation protocol.
- The full integration workflow could not complete locally because
Android workload installation exhausted the shared disk; the updated
Build integration test will validate on CI.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Gerald Versluis <939291+jfversluis@users.noreply.github.com>
Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-tooling XAML & C# Hot Reload, XAML Editor, Live Visual Tree, Live Preview, Debugging s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compilation randomly missing custom fonts & splashScreen

5 participants