微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在Xamarin.iOS

如何解决在Xamarin.iOS

我们刚刚使用azure通知中心作为提供程序为Xamarin.forms应用实现了新的推送通知功能。在iOS上,当将应用程序全新安装在iOS设备上(即设备上未安装该应用程序的先前版本)时,通知可以正常运行。但是,当我尝试通过在顶部安装较新版本来升级iOS设备上的现有应用程序时,我没有收到任何通知

调试时,我发现仅在应用程序升级场景中,iOS应用程序会引发 UIKit.UIKitThreadAccessException:'UIKit一致性错误:您正在调用只能从UI线程调用的UIKit方法。' 由于此例外,该设备未在Apple Push Notification Services中注册,因此也没有任何推送通知

以下是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:\a\1\s\Xamarin.Forms.Platform.iOS\EventTracker.cs:462 
  at Xamarin.Forms.Platform.iOS.EventTracker.GetNativeRecognizer (Xamarin.Forms.IGestureRecognizer recognizer) [0x00049] in D:\a\1\s\Xamarin.Forms.Platform.iOS\EventTracker.cs:258 
  at Xamarin.Forms.Platform.iOS.EventTracker.LoadRecognizers () [0x00042] in D:\a\1\s\Xamarin.Forms.Platform.iOS\EventTracker.cs:572 
  at Xamarin.Forms.Platform.iOS.EventTracker.ModelGestureRecognizersOnCollectionChanged (System.Object sender,System.Collections.Specialized.NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) [0x00000] in D:\a\1\s\Xamarin.Forms.Platform.iOS\EventTracker.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:\a\1\s\Xamarin.Forms.Core\View.cs:85 
  at Xamarin.Forms.View.<.ctor>b__14_0 (System.Object sender,System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x0002f] in D:\a\1\s\Xamarin.Forms.Core\View.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,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:\MemberMobileApp\SWAPA.MemberMobileApp.UI\SWAPA.MemberMobileApp.UI\SWAPA.MemberMobileApp.UI\Views\Login.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.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,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();
            }
        }
}

该异常表明我正在调用只能从UI线程调用的UIKit方法。我要调用的唯一操作是 InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications); ,我已经在主线程上调用了。因此,我不确定所讨论的异常还有什么其他功能。为什么只在升级应用程序时抱怨而不是在全新安装应用程序时抱怨呢?

我查看了该帖子here,但并没有太大帮助。由于这一点,我现在完全陷入困境,确实需要一些帮助来解决问题。知道我可能会缺少什么吗?

谢谢。

解决方法

正如您从问题中提供的堆栈跟踪中看到的那样,该错误实际上发生在“ Login.xaml.cs”文件的第369行。

如果放置“异常捕获点”,它应该告诉您确切的行导致该问题。在其周围放置try-catch应该可以解决崩溃问题,但由于通常情况下异常情况不好,因此也应尝试解决该问题。

除此之外,您还可以改为使用DispatchAsync

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。