Flutter:Firestore事务仅在iOS真机上崩溃
看起来你遇到的问题是Firestore内部断言触发的崩溃,核心原因是事务对象在回调执行结束后被重复使用了。结合你的代码和错误日志,我来拆解一下问题:
错误原因分析
错误日志里的FIRESTORE INTERNAL ASSERTION FAILED: A transaction object cannot be used after its update callback has been invoked已经说得很清楚:当Firestore认为事务的回调函数已经执行完毕(事务已提交),你却还在使用这个tx事务对象做操作。
为什么模拟器没问题但真机崩溃?因为iOS真机和模拟器的异步任务调度逻辑有差异——模拟器上的异步操作可能跑得足够快,在回调函数返回前就完成了tx.update;但真机上的调度延迟让回调先返回(Firestore此时标记事务已完成),之后tx.update才开始执行,直接触发了内部断言。
你的代码问题
看你给出的代码,事务回调是async函数,但调用tx.update时没有加await:
Firestore.instance.runTransaction((Transaction tx) async { DocumentSnapshot docSnapshot = await tx.get(docRef); tx.update( // 这里没有await,导致update可能在回调返回后才执行 docRef, { 'title':'A Title' }, ); }
在async函数里,未被await的Future会被“丢到后台”执行,回调函数会直接返回,这时候Firestore就会认为事务已经完成,后续再用tx做操作就会触发崩溃。
修复方案
只需要给tx.update加上await,确保它在回调函数返回前完成:
Firestore.instance.runTransaction((Transaction tx) async { DocumentSnapshot docSnapshot = await tx.get(docRef); await tx.update( docRef, { 'title':'A Title' }, ); });
这样就能保证所有事务操作都在回调执行期间完成,Firestore不会提前标记事务为已结束,真机上的崩溃也就解决了。
另外再检查一下代码里有没有其他地方在回调外部使用这个tx对象,如果有的话也要移除,事务对象只能在runTransaction的回调内部使用。
内容的提问来源于stack exchange,提问作者Mr Jax

