在 Xamarin iOS 中的远程通知的“默认用户操作”上推送视图控制器

Posted

技术标签:

【中文标题】在 Xamarin iOS 中的远程通知的“默认用户操作”上推送视图控制器【英文标题】:Push View Controller on Remote Notification's 'Default User Action' in Xamarin iOS 【发布时间】:2019-02-19 20:58:24 【问题描述】:

我已经设置了远程通知并向有效负载添加了一些自定义键,如果用户点击通知并想要阅读有关该主题的更多信息,这些键将提供在主页上推送特定详细信息 ViewController 的选项。

例如linkType: "services"linkPost: "main" 会告诉我的应用在应用进入前台时推送主服务页面。

我可以成功访问我的变量 topicValuelinkTypelinkPost 中的键和值,但是当用户点击通知时,我无法调试代码所采用的路径,因此我知道何时何地推送正确的 ViewController。我正在使用 Xamarin.Essentials 包,所以我可以 GetSet 这些键值对。我可以在整个应用程序的任何地方访问它们。

public class MyNotificationCenterDelegate : UNUserNotificationCenterDelegate

    public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
    
        if (response.IsDefaultAction)
        
            var userInfo = response.Notification.Request.Content.UserInfo;

            string topicValue = userInfo.ObjectForKey(new NSString("topic")).ToString();
            string linkType = userInfo.ObjectForKey(new NSString("linktype")).ToString();
            string linkPost = userInfo.ObjectForKey(new NSString("linkpage")).ToString();
            Preferences.Set("linkType", linkType);
            Preferences.Set("linkPost", linkPost);

我最初尝试在 AppDelegate 的 FinishedLaunching 方法中使用 launchOptions 参数,但是当我设置断点时,当我点击远程通知时它们似乎没有命中。在 Xamarin.ios 中完成此任务的任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

两件事(后台状态或非活动状态)

如果您的应用在后台不可用并且您使用通知,那么您应该使用DidFinishLaunching 对于这种情况,您应该设置来自通知的密钥。您将从launchOptions 中获得该密钥。 比较HomeViewControllerviewWillAppear 中的那个键,如果键匹配,则输入RedirectScreen 代码。

例如:- linkType: "services"

如果您的应用在后台可用并且通知来了,则 DidReceiveNotificationResponse 调用,您可以重定向应用中的任何屏幕。 首先,您应该获取topMostViewController,然后使用此控制器重定向到任何屏幕。

例如:- 获取topMostViewController

    public static UIViewController GetTopViewController()

    var window = UIApplication.SharedApplication.KeyWindow;
    var vc = window.RootViewController;
    while (vc.PresentedViewController != null)
        vc = vc.PresentedViewController;

    if (vc is UINavigationController navController)
        vc = navController.ViewControllers.Last();

    return vc;

【讨论】:

谢谢尼莱什!当应用程序在后台时,这有助于解决DidReceiveNotificationResponse 中的问题。当用户在应用处于非活动状态时点击通知时,我的应用仍然崩溃。我正在使用 Microsoft App Center 检查崩溃日志,因为当您关闭要测试的应用程序时,调试模式在 VS for Mac 中停止。应用程序在DidReceiveNotificationResponse 方法中崩溃!因此,在我的 iOS12 设备上,DidReceiveNotificationResponse 在应用程序处于非活动状态时也会被调用。如果不能使用断点,很难调试它,所以我会在发现更多信息时更新线程。 当应用处于非活动状态时,应用在条件逻辑if (response.IsDefaultAction)DidReceiveNotificationResponse 内更具体地崩溃。该条件逻辑是我选择将哪个详细视图控制器推送到 Home NavigationController 或选择特定 TabBarController 索引来导航用户的地方。我假设我的窗口或 tabcontroller 或全部为空,因为应用程序来自非活动状态而不是后台状态......现在在没有调试和断点的情况下解决所有问题...... 崩溃,因为当应用处于非活动状态而不是找不到最顶层控制器时,解决方案是检查状态!= 非活动确实收到远程通知,因此当应用来自非活动状态时,应用不会崩溃。 【参考方案2】:

这是针对我的特定用例的解决方案。再次感谢 Nilesh 帮助我到达这里 :)

public class MyNotificationCenterDelegate : UNUserNotificationCenterDelegate

    UIViewController detailViewController;
    public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
    
        UIApplication application = UIApplication.SharedApplication;
        if (response.IsDefaultAction)
        
            var userInfo = response.Notification.Request.Content.UserInfo;

            string linkType = userInfo.ObjectForKey(new NSString("linktype")).ToString();
            string linkPost = userInfo.ObjectForKey(new NSString("linkpage")).ToString();

//I'm using Xamarin.Essentials package to manage my User Defaults Key Value pairs with the
// Preferences method. Then I can see if those keys are set or not in ViewDidLoad in 
// my HomeViewController. This covers the case if the app had been closed 
//when the notification is tapped.

            Preferences.Set("linkType", linkType);
            Preferences.Set("linkPost", linkPost);

            var window = UIApplication.SharedApplication.KeyWindow;
            var tc = window.RootViewController as UITabBarController;

            if(tc != null) 
            
//this is essential. if app was in background then `tc != null` and this logic can run here.
//If the app was closed and `tc == null` then this logic will be carried out at the end of my 
// ViewDidLoad method in my HomeViewController instead of this method.

// carry out your logic for your app to either push a view controller or
// select a TabBarController index ...

//if you are pushing a detail view controller on your Home Navigation Controller
              var homeNavController = tc.ChildViewControllers[0] as UINavigationController;
              homeNavController.PushViewController(detailViewController, true);

              tc.SelectedIndex = 0; //select my HomeViewController via TabBarController index
//HomeViewController is where I'm pushing the detail controller so I want to make to navigate in case the user backgrounded the app on another TabBarController index.
            
      

   completionHandler();

因此,除此之外,我还需要在我的ViewDidLoad 方法的末尾在HomeViewController 中执行相同的导航逻辑(选择要推送的视图控制器或要选择的TabBarController 索引)。您可以访问设置的首选项键以选择导航位置。这涵盖了当用户点击通知时应用程序被关闭的情况。

希望这可以帮助其他人尝试在 Xamarin.iOS 中通过远程通知完成这种类型的“深度链接”!

【讨论】:

以上是关于在 Xamarin iOS 中的远程通知的“默认用户操作”上推送视图控制器的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin 推送通知,在应用程序激活后处理远程通知

在哪里删除 Xamarin iOS 中的通知观察者?

IOS 远程通知在 IOS 8 的后台不起作用

使用 Azure 中的集线器注册推送通知时,Xamarin.iOS 本机崩溃错误 SIGSEGV

Xamarin.iOS 无法在推送通知中显示照片

如何在 Xamarin Forms iOS 中的特定页面上导航?