NET8 MAUI iOS上架App Store后SQLite读取崩溃求助
问题背景
我在.NET 8 MAUI应用中引入了以下SQLite相关NuGet包:
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.6" /> <PackageReference Include="sqlite-net-pcl" Version="1.9.172" /> <PackageReference Include="SQLitePCLRaw.bundle_green" Version="2.1.8" /> <PackageReference Include="SQLitePCLRaw.provider.sqlite3" Version="2.1.8" />
应用需频繁读取数据库,本地调试及真机Release测试均运行正常,但上架至App Store后,读取数据库时会立即崩溃。AppCenter捕获的错误信息:
SIGABRT: Attempting to JIT compile method '(wrapper delegate-invoke) void System.Action`2<LanguageInUse.Domain.Dictionary, System.DateTime>:invoke_callvirt_void_T1_T2 (LanguageInUse.Domain.Dictionary,System.DateTime)' while running in aot-only mode.
完整错误堆栈:
SQLite.FastColumnSetter.<>c__DisplayClass2_0`2[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.DateTime, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<CreateTypedSetterDelegate>b__0(Object o, sqlite3_stmt stmt, Int32 i) SQLite.SQLiteCommand.<ExecuteDeferredQuery>d__12`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext() System.Collections.Generic.List`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]..ctor(IEnumerable`1 ) System.Linq.Enumerable.ToList[Dictionary](IEnumerable`1 ) SQLite.SQLiteCommand.ExecuteQuery[Dictionary]() SQLite.TableQuery`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ToList() SQLite.AsyncTableQuery`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].<ToListAsync>b__11_0(SQLiteConnectionWithLock conn) SQLite.AsyncTableQuery`1.<>c__DisplayClass2_0`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Collections.Generic.List`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<ReadAsync>b__0() System.Threading.Tasks.Task`1[[System.Collections.Generic.List`1[[LanguageInUse.Domain.Dictionary, LanguageInUse, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].InnerInvoke() System.Threading.Tasks.Task.<>c.<.cctor>b__281_0(Object obj) System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object ) System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread , ExecutionContext , ContextCallback , Object ) System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& , Thread ) LanguageInUse.Persistence.LIUDatabase.GetDictionariesForSearchAsync(String username, String search) LanguageInUse.ViewModels.DictionaryListViewModel.<Init>b__13_0(Object s, PopupOpenedEventArgs e) System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state) Foundation.NSAsyncSynchronizationContextDispatcher.Apply() ObjCRuntime.Runtime.ThrowException(IntPtr ) UIKit.UIApplication.UIApplicationMain(Int32 , String[] , IntPtr , IntPtr ) UIKit.UIApplication.Main(String[] , Type , Type ) LanguageInUse.Program.Main(String[] args)
此前尝试过降级SQLite版本、配置<UseInterpreter>true</UseInterpreter>和<MtouchInterpreter>-all</MtouchInterpreter>,但不想再提交存在问题的版本,需要有效解决方案。
解决方案
1. 禁用sqlite-net-pcl的FastColumnSetter
问题根源是sqlite-net-pcl的FastColumnSetter在AOT环境下会动态生成委托触发JIT编译,可在初始化SQLite连接时关闭该特性:
var connection = new SQLiteAsyncConnection(dbPath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, false); // 禁用FastColumnSetter,避免动态委托生成 connection.Connection.UserParameters.Add("FastColumnSetter", false);
2. 升级sqlite-net-pcl到最新稳定版
sqlite-net-pcl后续版本(如2.1.0及以上)针对.NET MAUI的AOT兼容性做了优化,替换NuGet引用为最新稳定版:
<PackageReference Include="sqlite-net-pcl" Version="2.1.0" /> <!-- 替换为实际最新稳定版 -->
3. 添加AOT编译提示
若无法升级包或禁用FastColumnSetter,可在项目中添加AOT提示文件(如AOTRuntimeHints.cs),告知编译器预编译相关类型和委托:
using System.Runtime.CompilerServices; using LanguageInUse.Domain; // 预编译实体类和相关委托类型 [assembly: RuntimeHelpers.RunClassConstructor(typeof(Dictionary).TypeHandle)] [assembly: RuntimeHelpers.RunClassConstructor(typeof(System.Action<Dictionary, System.DateTime>).TypeHandle)]
同时在iOS项目的.csproj中添加配置,防止编译器裁剪相关类型:
<ItemGroup> <TrimmerRootAssembly Include="LanguageInUse" /> </ItemGroup>
4. 替换为Microsoft.Data.Sqlite+Dapper组合
若sqlite-net-pcl的AOT问题无法彻底解决,可改用Microsoft.Data.Sqlite配合轻量ORM(如Dapper),完全基于静态编译避免JIT问题:
using Microsoft.Data.Sqlite; using Dapper; public async Task<List<Dictionary>> GetDictionariesForSearchAsync(string username, string search) { using var conn = new SqliteConnection($"Data Source={dbPath}"); await conn.OpenAsync(); var query = "SELECT * FROM Dictionary WHERE Username = @Username AND Name LIKE @Search"; return (await conn.QueryAsync<Dictionary>(query, new { Username = username, Search = $"%{search}%" })).ToList(); }
内容的提问来源于stack exchange,提问作者Enrico

