.NET MAUI 如何更新 Android ProfiledAOT 配置文件并验证启动时间?

.NET MAUI 如何更新 Android ProfiledAOT 配置文件并验证启动时间? .NET MAUI 如何更新 Android ProfiledAOT 配置文件并验证启动时间【免费下载链接】maui.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.项目地址: https://gitcode.com/GitHub_Trending/ma/maui当 .NET MAUI 模板的页面结构发生变化或者新的 .NET 大版本发布后Android 上随模板使用的 ProfiledAOT画像式 AOT配置文件需要重新录制否则新页面/新代码路径不会命中 AOT启动时间可能回退。这篇文章基于仓库中的 ProfiledAot README、build.proj、Directory.Build.targets 和 DEVELOPMENT.md给出从“重新录制.aotprofile”到“用adb logcat核对启动时间”的完整操作路径。适用前提你已经有一个能从源码构建 .NET MAUI 的开发环境Windows 或 Mac并且能通过adb连接一台 Android 设备或模拟器。准备条件先能按 Release 构建 MAUI 源码ProfiledAot README 要求更新与测试 profile 时都按 DEVELOPMENT.md 构建 MAUI并且必须使用--configurationReleaseREADME 中的命令统一使用仓库自带的本地./.dotnet/dotnet所以本地 dotnet 环境需要先准备好。按 DEVELOPMENT.md 完成初始设置与 Build Tasks 构建Windows安装 VS 17.12 或更新版本包含 MAUI 工作负载、Open JDK 17Mac安装 VS Code 与 .NET MAUI Dev Kit注意global.json会把 main 分支固定到最新稳定 .NET SDK机器上需要安装对应的 SDK。然后在仓库根目录执行dotnet tool restore dotnet build ./Microsoft.Maui.BuildTasks.slnf这一步是 README 链接指向的 DEVELOPMENT.md 构建流程的一部分必须在打开解决方案之前完成。执行步骤对每个模板类型运行Recordtarget更新 profile 的命令在仓库根目录执行对三种项目模板各跑一次./.dotnet/dotnet build src/ProfiledAot/build.proj -bl -p:Appmaui ./.dotnet/dotnet build src/ProfiledAot/build.proj -bl -p:Appmaui-sc ./.dotnet/dotnet build src/ProfiledAot/build.proj -bl -p:Appmaui-blazor三个取值对应的模板是mauidotnet new mauimaui-scdotnet new maui -scsample content 模板maui-blazordotnet new maui-blazor如果想用 x86_64 模拟器可以在命令后追加-r android-x64build.proj 默认使用android-arm64。-bl会生成.binlog排错时需要。Recordtarget 的实际流程在 build.proj 和 Directory.Build.targets 里定义用dotnet new在src/obj/App/下生成模板项目并覆盖src/ProfiledAot/src/App/里的替换文件先Restore再执行Record目标框架为$(_MauiDotNetTfm)-android按顺序执行Clean→_ClearSystemProperties用adb shell清空debug.mono.log→BuildAndStartAotProfiling→ 等待 5 秒 →FinishAotProfiling→_StripAppMethods→_SaveMethodNames。其中两个关键细节值得知道项目固定设置AndroidUseDefaultAotProfilefalse和MauiUseDefaultAotProfilefalse并把AndroidAotProfile指向custom.aprof依赖Mono.AotProfiler.Android包Directory.Build.targets 中当前版本为10.0.0-preview1_StripAppMethods会把 profile 中属于示例工程本身的模块ProfiledAotMaui.dll过滤掉因为最终用户的应用程序集名不同这个模块留在 profile 里无效。判断录制是否成功Record成功后会打印高优先级信息Success! See changes in: $(_MauiAOTProfileLocation)$(App).aotprofile仓库里对应的产物位置是src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/每个模板有两个文件App.aotprofile二进制 profile随Microsoft.Maui.Controls.Build.Tasks打包发布App.aotprofile.txt方法名清单不发布只用于跟踪 profile 随时间的变化。方法名清单不保证有序。README 建议把.txt文件在 VS Code 中打开用 CtrlShiftP 调出命令面板执行Sort lines ascending排序后再对比。如果排序后的.txt没有变化通常就不需要更新.aotprofile文件。验证启动时间README 的要求很明确更新 profile 后一定要测试确认得到的启动时间“与之前相同或略好”。流程是再次以--configurationRelease构建 MAUI 源码同上节的 DEVELOPMENT.md 流程创建一个新的模板项目并运行。README 给出的命令是mkdir foo cd foo ../.dotnet/dotnet new maui ../.dotnet/dotnet build -c Release -t:Run -f net7.0-android注意 README 示例中写的是net7.0-android这是文档示例值build.proj录制时使用的是仓库当前的$(_MauiDotNetTfm)-android所以-f应与你本地构建的 MAUI 版本对应的 TFM 保持一致。让应用启动几次后用adb logcat抓取首帧耗时$ adb logcat -d | grep DisplayedREADME 给出的文档示例输出数值仅作示例不是固定预期02-22 15:50:50.502 1802 1962 I ActivityTaskManager: Displayed com.companyname.foo/crc64808a40cc7e533249.MainActivity: 477ms 02-22 15:50:51.703 1802 1962 I ActivityTaskManager: Displayed com.companyname.foo/crc64808a40cc7e533249.MainActivity: 477ms 02-22 15:50:52.926 1802 1962 I ActivityTaskManager: Displayed com.companyname.foo/crc64808a40cc7e533249.MainActivity: 477ms可选用脚本批量启动统计仓库还提供了 profile-android.ps1它会构建并部署项目默认连续启动应用 10 次解析Activity.*Manager.Displayed日志行并打印Average(ms)、Std Err(ms)、Std Dev(ms)。常用参数-project项目 csproj 路径-packageAndroidManifest.xml中的包名用于am force-stop和monkey启动-configurationMSBuild 配置默认Debug-iterations启动次数默认 10-sleep每次启动之间的等待秒数默认 3-extra追加 MSBuild 参数例如-extra /p:AotAssembliesTrue可测试完整 AOT。示例PS profile-android.ps1 -project .\Path\To\MyApp.csproj -package com.mycompany.myapp -iterations 3该脚本会自动检查设备没有设备时尝试列出并启动模拟器运行前请确认adb、msbuild可用且目标设备上该包名可被强制停止并重新启动。排查与限制profile 录出来是空的如果*.aotprofile.txt为空先查看build.proj生成的.binlog寻找类似下面的aprofutil输出文档示例参数和路径来自 READMECommandLineArguments D:\.nuget\packages\mono.aotprofiler.android\9.0.0-preview1\tools\aprofutil -s -v -p 9999 -o custom.aprof Reading from 127.0.0.1:9999... Read 19 bytes... Summary: Modules: 0 Types: 0 Methods: 0 Going to write the profile to custom.aprofModules/Types/Methods全为 0 说明设备端没有把画像数据回传到 socket 9999。可以打开 Mono 的详细日志再复现adb shell setprop debug.mono.log default,assembly,mono_log_leveldebug,mono_log_maskall前提是注释掉Directory.Build.targets 中_ClearSystemPropertiestarget 里把debug.mono.log置空的那行Exec否则每次Record都会先清掉你设置的属性。正常工作时的adb logcat应能看到类似内容文档示例05-21 11:38:30.032 28555 28555 W monodroid: Initializing profiler with options: aot:port9999,output/data/user/0/com.companyname.maui/files/.__override__/arm64-v8a/profile.aotprofile 05-21 11:38:30.032 28555 28555 I monodroid-assembly: Trying to load shared library .../lib/arm64/libmono-profiler-aot.so 05-21 11:38:30.033 28555 28555 W monodroid: Looking for profiler init symbol mono_profiler_init_aot? 0x7826470468 05-21 11:38:35.531 28555 28586 I mono-prof: AOT profiler data written to socket失败可能发生在三个环节加载libmono-profiler-aot.so、找不到mono_profiler_init_aot符号、或者根本没有返回数据。按 README 的说法修复通常需要新的libmono-profiler-aot.so构建也就是随每个 .NET 大版本发布一个新版本的Mono.Profiler.Android包——这类问题无法在应用侧绕过。验证某个方法是否命中 AOT要确认 profile 里具体有没有你要的方法先清日志并开启 AOT 日志adb logcat -c adb shell setprop debug.mono.log default,timingbare,assembly,mono_log_leveldebug,mono_log_maskaot重启应用后$ adb logcat -d | grep AOT命中时输出形如文档示例02-23 09:03:46.327 10401 10401 D Mono : AOT: FOUND method Microsoft.AspNetCore.Components.WebView.Maui.BlazorWebView:.ctor () [0x6f9efd0150 - 0x6f9efd0340 0x6f9efd260c]重点看是否有可疑的AOT NOT FOUND。README 说明部分NOT FOUND是预期内的例如带(wrapper runtime-invoke)、(wrapper managed-to-native)、(wrapper native-to-managed)前缀的条目。NuGet 缓存干扰“前后对比”对比新旧 profile 的启动时间时本地 NuGet 缓存里可能残留旧的*.aotprofile或过期的*-dev包需要先同步缓存。README 给出的做法是把新 profile 直接覆盖到缓存目录命令示例注意这是覆盖用户本机 NuGet 缓存中microsoft.maui.controls.build.tasks包内文件的命令9.0.100-preview.2-dev是文档中的示例版本需替换为你本地实际安装的包版本目录cp -Verbose src\Controls\src\Build.Tasks\nuget\buildTransitive\netstandard2.0\*.aotprofile ~\.nuget\packages\microsoft.maui.controls.build.tasks\9.0.100-preview.2-dev\buildTransitive\netstandard2.0\README 还提到一个更彻底但破坏性更大的可选清理它会删除本机 NuGet 缓存中所有*-dev包目录即你自己本地构建的开发包删除后这些包需要重新构建/还原。仅在确认缓存里有过期构建产物时执行rm -r ~\.nuget\packages\*\*-dev\执行前确认~\.nuget\packages确实指向你的 NuGet 缓存根目录%NUGET_PACKAGES%可能指向别处。小结与限制整条路径的验收点是明确的Record打印Success! See changes in: ...且src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/下三个模板的.aotprofile更新随后新建模板项目跑adb logcat -d | grep Displayed启动时间与更新前持平或略好。两个已知边界.aotprofile.txt方法清单不发布、只用于 diff当画像数据回传链路libmono-profiler-aot.so/Mono.Profiler.Android包失效时需要等待新的大版本配套构建不能在应用侧修复。【免费下载链接】maui.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.项目地址: https://gitcode.com/GitHub_Trending/ma/maui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考