问题原因
Unity应用(target SDK 34)上线到GooglePlay,有用户反馈fold5设备上(Android14系统)疯狂闪退,经测试,在小米手机Android14系统的版本复现成功了,奇怪的是apk直接安装没问题,而打包成aab就是疯狂闪退。
Unity版本Unity2020.3.18f1c1。
老办法,logcat抓包,看看闪退日志。
日志有一行引起了我的注意,也就是在闪退前的报错:
No pending exception expected: java.lang.SecurityException: com.xxx.xxx: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
既然有错误,就好解决了,现在问ChatGPT没用的,因为ChatGPT经常会瞎编,所以上谷歌搜索下,立马就搜到了。 android - One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts - Stack Overflow
As discussed at Google I/O 2023, registering receivers with intention using the RECEIVER_EXPORTED / RECEIVER_NOT_EXPORTED flag was introduced as part of Android 13 and is now a requirement for apps running on Android 14 or higher (U+).
If you do not implement this, the system will throw a security exception.
To allow the broadcast receiver to receive broadcasts from other apps, register the receiver using the following code:
context.registerReceiver(broadcastReceiver, intentFilter, RECEIVER_EXPORTED);
To register a broadcast receiver that does not receive broadcasts from other apps, including system apps, register the receiver using the following code:
context.registerReceiver(broadcastReceiver, intentFilter, RECEIVER_NOT_EXPORTED);
Note: That call will need minSdkVersion to be 26 (Android 8) al least
Check https://www.delasign.com/blog/android-studio-kotlin-broadcast-recievers-export-or-not/#:~:text=As%20discussed%20at%20Google%20I,will%20throw%20a%20security%20exception.
翻译过来就是,Goole I/O 2023讨论的,使用RECEIVER_EXPORTED / RECEIVER_NOT_EXPORTED标志注册接收者是Android 13的一部分,现在是运行在Android 14或更高版本(U+)上的应用程序的要求。也就是Android14必须增加该标志。
以前使用registerReceiver不需要设置RECEIVER_EXPORTED / RECEIVER_NOT_EXPORTED这个Flag,现在Android14开始需要设置了,所以抛异常,闪退了。
解决思路
问题找到了,也分析好了,但是因为这是Unity工程直接打包出来的aab,像是一个黑箱,而问题就是Unity打包出来写的registerReceiver没有按照Android14的要求传进去Flag,这个我们可以通过日志确定,可以看到堆栈日志显示com.unity3d.player.PlayAssetDeliveryUnityWrapper.registerDownloadStatusListener这个类注册的Receiver,而这个是Unity的类,无法修改。
2024-01-12 17:45:50.379 6394-6494/? A/ongame.isoland4: thread.cc:2529] No pending exception expected: java.lang.SecurityException: com.cottongame.isoland4: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts
thread.cc:2529] at java.lang.Exception android.os.Parcel.createExceptionOrNull(int, java.lang.String) (Parcel.java:3057)
thread.cc:2529] at java.lang.Exception android.os.Parcel.createException(int, java.lang.String) (Parcel.java:3041)
thread.cc:2529] at void android.os.Parcel.readException(int, java.lang.String) (Parcel.java:3024)
thread.cc:2529] at void android.os.Parcel.readException() (Parcel.java:2966)
thread.cc:2529] at android.content.Intent android.app.IActivityManager$Stub$Proxy.registerReceiverWithFeature(android.app.IApplicationThread, java.lang.String, java.lang.String, java.lang.String, android.content.IIntentReceiver, android.content.IntentFilter, java.lang.String, int, int) (IActivityManager.java:6193)
thread.cc:2529] at android.content.Intent android.app.ContextImpl.registerReceiverInternal(android.content.BroadcastReceiver, int, android.content.IntentFilter, java.lang.String, android.os.Handler, android.content.Context, int) (ContextImpl.java:1863)
thread.cc:2529] at android.content.Intent android.app.ContextImpl.registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler) (ContextImpl.java:1803)
thread.cc:2529] at android.content.Intent android.app.ContextImpl.registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) (ContextImpl.java:1791)
thread.cc:2529] at android.content.Intent android.content.ContextWrapper.registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) (ContextWrapper.java:766)
thread.cc:2529] at void com.google.android.play.core.listener.b.b() ((null):-1)
thread.cc:2529] at void com.google.android.play.core.listener.b.f(com.google.android.play.core.listener.StateUpdatedListener) ((null):-1)
thread.cc:2529] at void com.google.android.play.core.assetpacks.i.registerListener(com.google.android.play.core.assetpacks.AssetPackStateUpdateListener) ((null):-1)
thread.cc:2529] at java.lang.Object com.unity3d.player.a.a(com.unity3d.player.IAssetPackManagerDownloadStatusCallback) ((null):-1)
thread.cc:2529] at java.lang.Object com.unity3d.player.PlayAssetDeliveryUnityWrapper.registerDownloadStatusListener(com.unity3d.player.IAssetPackManagerDownloadStatusCallback) ((null):-1)
thread.cc:2529] at boolean com.unity3d.player.UnityPlayer.nativeRender() ((null):-2)
thread.cc:2529] at boolean com.unity3d.player.UnityPlayer.access$300(com.unity3d.player.UnityPlayer) ((null):-1)
thread.cc:2529] at boolean com.unity3d.player.UnityPlayer$e$1.handleMessage(android.os.Message) ((null):-1)
thread.cc:2529] at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:102)
thread.cc:2529] at boolean android.os.Looper.loopOnce(android.os.Looper, long, int) (Looper.java:224)
thread.cc:2529] at void android.os.Looper.loop() (Looper.java:318)
thread.cc:2529] at void com.unity3d.player.UnityPlayer$e.run() ((null):-1)
thread.cc:2529]
解决
目前解决方案是targetsdk改成33,经测试就不闪退了。
如果你需要targetsdk为34,得升级下Unity版本,看看哪个版本修复了这个问题。我们的版本是Unity2020.3.18f1c1。查了3.19的Release Note没有找到相关的修复,懒得找了。