在 Xamarin.iOS 上的应用升级期间"UIKit.UIKitThreadAccessException: 'UIKit Consistency error: you are calling



我们刚刚为Xamarin.forms应用程序实现了一个新的推送通知功能,使用azure通知中心作为提供商。在iOS上,当应用程序新安装在iOS设备上时,即设备上未安装该应用程序的先前版本时,通知工作非常正常。但当我试图通过在iOS设备上安装新版本来升级现有应用程序时,我不会收到任何通知。

调试时,我发现只有在应用程序升级场景中,iOS应用程序才会抛出UIKit.UIKitThreadAccessException:"UIKit一致性错误:您正在调用只能从UI线程调用的UIKit方法。">由于此异常,设备未在Apple推送通知服务中注册,因此不会收到任何推送通知。

以下是stacktrace的完整例外:

UIKit.UIKitThreadAccessException: 'UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread.'
UIKit.UIKitThreadAccessException
Message=UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread.
Source=mscorlib
StackTrace:
at UIKit.UIApplication.EnsureUIThread () [0x00020] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/UIKit/UIApplication.cs:96 
at UIKit.UIGestureRecognizer..ctor (Foundation.NSObject target, System.IntPtr action) [0x00016] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/UIGestureRecognizer.g.cs:102 
at UIKit.UIGestureRecognizer..ctor (System.IntPtr sel, UIKit.UIGestureRecognizer+Token token) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/UIKit/UIGestureRecognizer.cs:66 
at UIKit.UITapGestureRecognizer..ctor (System.Action`1[T] action) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/UIKit/UIGestureRecognizer.cs:208 
at Xamarin.Forms.Platform.iOS.EventTracker.CreateTapRecognizer (System.Int32 numTaps, System.Action`1[T] action, System.Int32 numFingers) [0x00000] in D:a1sXamarin.Forms.Platform.iOSEventTracker.cs:462 
at Xamarin.Forms.Platform.iOS.EventTracker.GetNativeRecognizer (Xamarin.Forms.IGestureRecognizer recognizer) [0x00049] in D:a1sXamarin.Forms.Platform.iOSEventTracker.cs:258 
at Xamarin.Forms.Platform.iOS.EventTracker.LoadRecognizers () [0x00042] in D:a1sXamarin.Forms.Platform.iOSEventTracker.cs:572 
at Xamarin.Forms.Platform.iOS.EventTracker.ModelGestureRecognizersOnCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) [0x00000] in D:a1sXamarin.Forms.Platform.iOSEventTracker.cs:624 
at (wrapper delegate-invoke) <Module>.invoke_void_object_NotifyCollectionChangedEventArgs(object,System.Collections.Specialized.NotifyCollectionChangedEventArgs)
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00018] in <b912bfaf235d4ed8af62226c84967349>:0 
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00009] in <b912bfaf235d4ed8af62226c84967349>:0 
at System.Collections.ObjectModel.ObservableCollection`1[T].InsertItem (System.Int32 index, T item) [0x0001a] in <b912bfaf235d4ed8af62226c84967349>:0 
at System.Collections.ObjectModel.Collection`1[T].Add (T item) [0x00020] in <cbddc4225b2f45f09f3a1d43a1268bc0>:0 
at Xamarin.Forms.View.<.ctor>g__AddItems|14_1 (Xamarin.Forms.View+<>c__DisplayClass14_0& ) [0x00032] in D:a1sXamarin.Forms.CoreView.cs:85 
at Xamarin.Forms.View.<.ctor>b__14_0 (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x0002f] in D:a1sXamarin.Forms.CoreView.cs:101 
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00018] in <b912bfaf235d4ed8af62226c84967349>:0 
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00009] in <b912bfaf235d4ed8af62226c84967349>:0 
at System.Collections.ObjectModel.ObservableCollection`1[T].InsertItem (System.Int32 index, T item) [0x0001a] in <b912bfaf235d4ed8af62226c84967349>:0 
at System.Collections.ObjectModel.Collection`1[T].Add (T item) [0x00020] in <cbddc4225b2f45f09f3a1d43a1268bc0>:0 
at SWAPA.MemberMobileApp.UI.Views.Login.CommonSetup () [0x002a1] in C:MemberMobileAppSWAPA.MemberMobileApp.UISWAPA.MemberMobileApp.UISWAPA.MemberMobileApp.UIViewsLogin.xaml.cs:369 
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_1 (System.Object state) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1037 
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context (System.Object state) [0x0000d] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1370 
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:968 
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:910 
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00021] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1341 
at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00074] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:899 
at ObjCRuntime.Runtime.ThreadPoolDispatcher (System.Func`1[TResult] callback) [0x00006] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.18.2.1/src/Xamarin.iOS/ObjCRuntime/Runtime.cs:288 
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () [0x00009] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/referencesource/mscorlib/system/threading/threadpool.cs:1258 

我在AppDelegate中完成的唯一实现是向Apple Push Notification Services注册设备,然后将该设备注册id发送到主UI应用程序,以向Azure通知中心注册设备。

下面是我的代码和一些评论:

[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IUNUserNotificationCenterDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this 
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
//----Block needed for App Center Testing-----
#if ENABLE_TEST_CLOUD
//Xamarin.Calabash.Start();
#endif
//----Block needed for App Center Testing-----
new SfCalendarRenderer();
LoadApplication(new App());
SfImageEditorRenderer.Init();
SfListViewRenderer.Init();
SfCheckBoxRenderer.Init();
SfPdfDocumentViewRenderer.Init();
SfPickerRenderer.Init();
Syncfusion.SfChart.XForms.iOS.Renderers.SfChartRenderer.Init();
new Syncfusion.SfAutoComplete.XForms.iOS.SfAutoCompleteRenderer();
UITabBar.Appearance.SelectedImageTintColor = UIColor.FromRGB(213, 84, 39);
// Color of the tabbar background:
UITabBar.Appearance.BarTintColor = UIColor.LightGray;
// Color of the selected tab text color:
UITabBarItem.Appearance.SetTitleTextAttributes(
new UITextAttributes()
{
TextColor = UIColor.FromRGB(213, 84, 39)
},
UIControlState.Selected);
// Color of the unselected tab icon & text:
UITabBarItem.Appearance.SetTitleTextAttributes(
new UITextAttributes()
{
TextColor = UIColor.FromRGB(65, 64, 66)
},
UIControlState.Normal);
base.FinishedLaunching(app, options);
/*Register device with Apple Push Notification Service*/
RegisterForRemoteNotifications();
if (options != null && options.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
{
NSDictionary userInfo = (NSDictionary)options[UIApplication.LaunchOptionsRemoteNotificationKey];
if (userInfo != null)
{
PushNotifications.IsNotifictaionClick_AppInActive = true;
// To remove all delivered notifications
RemoveAllDeliveredPushNotifications();
}
}
return true;
}
//Register device with Apple Push Notification Services
void RegisterForRemoteNotifications()
{
//register for remote notifications based on system version
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Sound |
UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications); // Ask user for permission to receive notifications on device.
});
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
UNUserNotificationCenter.Current.Delegate = this;
}
//Send the PNS handle to UI app for device installation with Azure Notificaiton Hub.
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
//Format the pns handle before registering with Azure notification hub.
PushNotifications.PNSHandle = deviceToken.DebugDescription.Replace("<", string.Empty)
.Replace(">", string.Empty)
.Replace(" ", string.Empty)
.ToUpper();
}
// Process notification when received.
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
ProcessNotification(userInfo);
}
void ProcessNotification(NSDictionary options)
{
// make sure we have a payload
if (options != null && options.ContainsKey(new NSString("aps")))
{
// get the APS dictionary and extract message payload. Message JSON will be converted
// into a NSDictionary so more complex payloads may require more processing
NSDictionary aps = options.ObjectForKey(new NSString("aps")) as NSDictionary;
NSDictionary alertMessage = aps.ObjectForKey(new NSString("alert")) as NSDictionary;
//Extract notification content
NSString messageKey = new NSString("body");
NSString titleKey = new NSString("title");
string messageBody = alertMessage.ContainsKey(messageKey) ? alertMessage[titleKey].ToString() : string.Empty;
string title = alertMessage.ContainsKey(titleKey) ? alertMessage[titleKey].ToString() : string.Empty;
if (!string.IsNullOrWhiteSpace(title) || !string.IsNullOrWhiteSpace(messageBody))
{
var content = new UNMutableNotificationContent();
content.Title = title;
content.Body = messageBody;
var requestID = title;
var request = UNNotificationRequest.FromIdentifier(requestID, content, null);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
// TODO: log error messages in error data table.
Debug.WriteLine($"Received request to process notification but something went wrong.");
}
});
}
}
else
{
// TODO: log error messages in error data table.
Debug.WriteLine($"Received request to process notification but there was no payload.");
}
}
[Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
completionHandler(UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Alert);
}
[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action
completionHandler)
{
completionHandler();
/*Logic to open NotificationInboxPage onclick of notification when app was active */
if (!App.IsAppLaunching)
{
var modalStack = App.Current.MainPage.Navigation.ModalStack;
if (modalStack.Count > 0 && modalStack.Last().ToString().Contains("NotificationInbox"))
App.Current.MainPage.Navigation.PopModalAsync();
App.Current.MainPage.Navigation.PushModalAsync(new NotificationInboxPage());
}
App.IsAppLaunching = false;
//To remove all delivered notifications
RemoveAllDeliveredPushNotifications();
}
private void RemoveAllDeliveredPushNotifications()
{
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.RemoveAllDeliveredNotifications();
}
else
{
UIApplication.SharedApplication.CancelAllLocalNotifications();
}
}
}

异常表示我正在调用UIKit方法,该方法只能从UI线程调用。我调用的唯一操作是InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications(我已经在主线程上调用了它。所以我不确定还有什么功能是例外。为什么它只在我升级应用程序时抱怨,而不是在我刚安装应用程序时。

我在这里查看了这篇帖子,但没有得到太多帮助。在这一点上,我完全陷入了困境,真的需要一些帮助来解决这个问题。知道我可能错过了什么吗?

提前谢谢。

正如您在问题中提供的堆栈跟踪中所读到的,错误实际上发生在"Login.xaml.cs"文件的第369行。

如果你放置一个";异常捕获点";它应该准确地告诉你是哪条线引起了这个问题。在它周围放置一个try-catch应该可以修复崩溃,但也要尝试解决问题,因为异常通常是不好的。

除此之外,您还可以使用DispatchAsync代替

最新更新