【问题标题】:Xamarin.iOS handle push notification when app is not closedXamarin.iOS 在应用未关闭时处理推送通知
【发布时间】:2018-11-14 00:16:58
【问题描述】:

如果应用程序在后台,我设法使用didReceiveRemoteNotification 方法处理推送通知。如果应用程序处于前台且未关闭,是否有办法处理推送通知?谢谢

【问题讨论】:

标签: c# push-notification xamarin.ios


【解决方案1】:

我通过下面显示的示例 app.delegte.cs 代码在 Xamarin iOS 中获得了前台和后台通知。

   using Foundation;
   using System;
   using System.Diagnostics;
   using System.Linq;
   using UIKit;
   using UserNotifications;
   using WindowsAzure.Messaging;
   using Firebase.Core;
   using Firebase.CloudMessaging;
   using System.Runtime.CompilerServices;
   using ObjCRuntime;

   namespace NotificationHubSample.iOS

{ [注册("AppDelegate")]

   public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    private SBNotificationHub Hub { get; set; }
    

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        global::Xamarin.Forms.Forms.Init();
        LoadApplication(new App());

        

        base.FinishedLaunching(app, options);

        Firebase.Core.App.Configure();

        RegisterForRemoteNotifications();

        UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);


        return true;
    }

    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);
                });
        }
        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);
        }
        UIApplication.SharedApplication.RegisterForRemoteNotifications();
    }

    public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
    {
        Hub = new SBNotificationHub(AppConstants.ListenConnectionString, AppConstants.NotificationHubName);

        // update registration with Azure Notification Hub
        Hub.UnregisterAll(deviceToken, (error) =>
        {
            if (error != null)
            {
                Debug.WriteLine($"Unable to call unregister {error}");
                return;
            }

            var tags = new NSSet(AppConstants.SubscriptionTags.ToArray());
            Hub.RegisterNative(deviceToken, tags, (errorCallback) =>
            {
                if (errorCallback != null)
                {
                    Debug.WriteLine($"RegisterNativeAsync error: {errorCallback}");
                }
            });

            var templateExpiration = DateTime.Now.AddDays(120).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
            Hub.RegisterTemplate(deviceToken, "defaultTemplate", AppConstants.APNTemplateBody, templateExpiration, tags, (errorCallback) =>
            {
                if (errorCallback != null)
                {
                    if (errorCallback != null)
                    {
                        Debug.WriteLine($"RegisterTemplateAsync error: {errorCallback}");
                    }
                }
            });
        });

        // Firebase ios Registration
        Messaging.SharedInstance.ApnsToken = deviceToken;
        
       }
   // Process the notification when the app is open.
   
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
    {
        ProcessNotification(userInfo, false);
        

    }   // End of the ReceiveRemoteNotification method

    

    // Process the notification when the app is closed.
    public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
    {
        ProcessNotification(userInfo, false);            
        
    }


    void ProcessNotification(NSDictionary options, bool fromFinishedLaunching)
    {
        // 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;
            
            string payload = string.Empty;
            NSString payloadKey = new NSString("alert");
            
            if (aps.ContainsKey(payloadKey))
            {
                payload = aps[payloadKey].ToString();
            }

          
            
            if (!string.IsNullOrWhiteSpace(payload))
            {
                (App.Current.MainPage as MainPage)?.AddMessage(payload);
            }

        }
        else
        {
            Debug.WriteLine($"Received request to process notification but there was no payload.");
        } 
     } // End of the ProcessNotification method





}

}

【讨论】:

    【解决方案2】:

    无论应用程序在前台还是后台运行,都可以处理推送通知事件。按照这些步骤获取 DidReceiveRemoteNotification 总是被调用

    1) 重写 AppDelegate.cs 中的 DidReceiveRemoteNotification 方法

    public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
    

    2) 在 info.plist 中添加所需的后台模式 - remote-notification(value)

    3) 将有效负载中的内容可用设置为 1

    {
    "aps" : {
        "alert" : {
            "title" : "Game Request",
            "body" : "Bob wants to play poker"
        },
        "badge" : 5,
        "content-available" : 1
    }
    

    }

    【讨论】:

      【解决方案3】:

      你实现UserNotification了吗?如果您在 iOS 10+ 上部署您的项目,您可以尝试订阅FinishedLaunching(UIApplication application, NSDictionary launchOptions) 中的通知,例如:

      if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
      {
          var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
          UNUserNotificationCenter.Current.RequestAuthorization(authOptions, (granted, error) => {
              Console.WriteLine(granted);
          });
          UNUserNotificationCenter.Current.Delegate = new MyNotificationCenterDelegate();
      }
      

      然后当通知到来并且应用程序在前台时,WillPresentNotification() 将被触发,这个句柄事件返回当通知到来时这个应用程序将响应哪个动作。终于可以在DidReceiveNotificationResponse()事件中获取userInfo了:

      public class MyNotificationCenterDelegate : UNUserNotificationCenterDelegate
      {
          public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
          {
              completionHandler();
          }
      
          public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
          {
              completionHandler(UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Alert);
      
          }       
      }
      

      但是,如果您不想实现UserNotification,或者您只是使用键content-available true 推送一个静默远程通知,即使应用程序在前台,didReceiveRemoteNotification() 也会被触发。

      【讨论】:

      • 我确实已经订阅了通知,但是我找不到WillPresentNotification() 方法,当我添加它们时,我遇到了同样的问题。
      • 我将weakDelegate修改为strong delegate。此外,如果你们都订阅了 DidReceiveRemoteNotificationReceivedRemoteNotification 事件。 ReceivedRemoteNotification 永远不会被解雇,阅读 documentation 你会发现这个 api 在 ios 10+ 上被弃用了。
      • 仍然是同样的问题,接收通知不会触发这些方法,唯一触发的方法是 DidReceiveRemoteNotification 仅当应用程序在后台时.. 我不确定我在做什么这里不见了。
      • 这很奇怪。您使用的是哪个第三方库以及您使用的是哪个 ios 版本?
      • ios 11.2 并且不使用第三方库进行通知。
      【解决方案4】:

      AppDelegate 中的覆盖方法ReceivedRemoteNotificationDidReceiveRemoteNotification,当您在前台收到推送通知时将被触发。

      通过这种方法,您可以检查您的应用是否处于Active 状态,并根据它来处理您的通知。

      if (UIApplication.SharedApplication.ApplicationState == UIApplicationState.Active) 
      {
          //You app is in Foreground state.
          //Process the Pushnotification data, or show alert.
      }
      

      Apple's doc.

      实施 应用程序(:didReceiveRemoteNotification:fetchCompletionHandler:) 尽可能使用这种方法而不是这种方法。如果你的代表 实现了这两种方法,应用程序对象调用 应用程序(:didReceiveRemoteNotification:fetchCompletionHandler:) 方法。

      因此,如果您在 AppDelegate 中实现了这两种方法(ReceivedRemoteNotificationDidReceiveRemoteNotification),那么将调用 DidReceiveRemoteNotification 方法。

      【讨论】:

      • 遗憾的是,一旦我在前台收到通知,ReceivedRemoteNotification 就没有触发。这是我的代码:public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo) { var userInfo1 = userInfo; } public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action&lt;UIBackgroundFetchResult&gt; completionHandler) { var value = userInfo; } 第二个方法在后台应用时正确调用,第一个根本不会触发。
      • 根据苹果的文档,当应用程序处于后台或前台时,DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action completionHandler) 会触发。你有没有试过在这个方法中添加上述条件?
      • 是的,我确实添加了检查应用状态的条件,但仍然没有成功。
      • 它会进入 if 块吗?当您的应用程序处于前台时,Apple 不会在任何地方显示推送通知。您必须手动处理它,就像在这种情况下显示来自应用程序的警报一样。如果应用程序在前台,您实际上认为应该怎么做?
      • 它根本不进入区块,但只有当应用程序在后台时才会进入。应该做的是,如果前台的应用程序我可以设法显示警报,稍后如果用户在前台并单击它应该重定向他的通知,如果应用程序在后台使用@987654332,我确实设法做到了@.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      • 2020-08-30
      • 2014-08-10
      • 1970-01-01
      • 2013-04-19
      • 1970-01-01
      相关资源
      最近更新 更多