zoukankan      html  css  js  c++  java
  • iOS本地推送与远程推送详解

    一、简介

    分为本地推送和远程推送2种。可以在应用没有打开甚至手机锁屏情况下给用户以提示。它们都需要注册,注册后系统会弹出提示框(如下图)提示用户是否同意,如果同意则正常使用;如果用户不同意则下次打开程序也不会弹出该提示框,需要用户到设置里面设置。一共有三种提示类型:

    • UIUserNotificationTypeBadge:应用图标右上角的信息提示    
    • UIUserNotificationTypeSound:播放提示音
    • UIUserNotificationTypeAlert:提示框

    干货——iOS本地推送与远程推送详解(一图看懂)

    二、本地推送

    1 注册与处理

    代码如下:

    /// 一般在在启动时注册通知,程序被杀死,点击通知后调用此程序
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { // iOS8
            UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
            [application registerUserNotificationSettings:setting];
        }
    
        if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
            // 这里添加处理代码
        }
        return YES;
    }
    /// 程序没有被杀死(处于前台或后台),点击通知后会调用此程序
    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
        // 这里添加处理代码
    }

    可以看到,处理代码有两个方法,一个是

    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
    另一个是
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
    如果程序没有被杀死,即处于前台或者后台,那么调用前者;如果程序被杀死,则调用后者。

    2 发送通知

    代码如下

    - (IBAction)addLocalNotification {
        // 1.创建一个本地通知
        UILocalNotification *localNote = [[UILocalNotification alloc] init];
    
        // 1.1.设置通知发出的时间
        localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
    
        // 1.2.设置通知内容
        localNote.alertBody = @"这是一个推送这是一个推送";
    
        // 1.3.设置锁屏时,字体下方显示的一个文字
        localNote.alertAction = @"赶紧!!!!!";
        localNote.hasAction = YES;
    
        // 1.4.设置启动图片(通过通知打开的)
        localNote.alertLaunchImage = @"../Documents/IMG_0024.jpg";
    
        // 1.5.设置通过到来的声音
        localNote.soundName = UILocalNotificationDefaultSoundName;
    
        // 1.6.设置应用图标左上角显示的数字
        localNote.applicationIconBadgeNumber = 999;
    
        // 1.7.设置一些额外的信息
        localNote.userInfo = @{@"qq" : @"704711253", @"msg" : @"success"};
    
        // 2.执行通知
        [[UIApplication sharedApplication] scheduleLocalNotification:localNote];
    }

    效果如下:

    干货——iOS本地推送与远程推送详解(一图看懂)

    3 取消通知

    // 取消所有本地通知
    [application cancelAllLocalNotifications];

    三、远程推送    

    与Android上我们自己实现的推送服务不一样,Apple对设备的控制非常严格,消息推送的流程必须要经过APNs(Apple Push Notification service).

    一般情况下如果一个程序退到后台就不能运行代码(Audio、VoIP等等可以在后台运行),或者程序退出后,那么它就和对应应用的后台服务器断开了链接,就收不到服务器发送的信息了,但是每台设备只要联网就会和苹果的APNs服务器建立一个长连接(persistent IP connection),这样只要通过苹果的APNs服务器,我们自己的服务器就可以间接的和设备保持连接了,示意图如下:

    干货——iOS本地推送与远程推送详解(一图看懂)

    使用步骤:

    1 勾选Backgroud Modes -> Remote notifications,主要是iOS7之后,苹果支持后台运行,如果这里打开后,当接收到远程推送后,程序在后台也可以做一些处理,如下图所示:

    干货——iOS本地推送与远程推送详解(一图看懂)

    2 远程推送的注册与本地推送不同,iOS8.0前后也不同,代码见下面。

    另外,在第一次使用推送时,可能会有这样的疑问:didFinishLaunchingWithOptions会在每次打开程序时被调用,那是不是每次都会调用注册函数,每次都会弹窗询问用户"是否允许推送通知"?其实这个窗口只会在第一次打开程序时弹出一次,无论用户允许或不允许苹果会记住用户的选择,注册函数调用多次对用户也没什么影响

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // iOS8之后和之前应区别对待
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        } else {
            [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIUserNotificationTypeSound];
        }
    
        return YES;
    }
    /// 这个函数存在的意义在于:当用户在设置中关闭了通知时,程序启动时会调用此函数,我们可以获取用户的设置
    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
        [application registerForRemoteNotifications];
    }

    3 如果注册失败,比如没有证书等等,会调用:

    /// 注册失败调用
    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
        NSLog(@"远程通知注册失败:%@",error);
    }

    4 获取deviceToken

    如果用户同意,苹果会根据应用的 bundleID 和 手机UDID 生成 deviceToken,然后调用 application 的 didregister 方法返回 devicetoken,程序应该把 devicetoken 发给应用的服务器,服务器有义务将其存储(如果允许多点登录,可能存多个 devicetoken)。deviceToken也是会变的: ”If the user restores backup data to a new device or computer, or reinstalls the operating system, the device token changes“,因此应每次都发给服务器(provider)

    /// 用户同意后,会调用此程序,获取系统的deviceToken,应把deviceToken传给服务器保存,此函数会在程序每次启动时调用(前提是用户允许通知)
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
        NSLog(@"deviceToken = %@",deviceToken);
    }

    5 用户点击了通知

    默认会打开程序。处理代码有三个函数,分iOS7之前之后和程序是否处于后台

    • 5.1 iOS7及其之之后

    此函数无论是程序被杀死还是处于后台,只要用户点击了通知,都会被调用,因此如果是iOS7,则不必在didFinishLaunchingWithOptions中做处理,只在下面函数做处理即可,此时应避免在didFinishLaunchingWithOptions函数中也做重复处理。

    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
        // userInfo
    }

    注:当在第一步打开后台运行后,用户不点击通知,也可以执行:

    - (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler
    • 5.2 iOS7之前

    当用户点击通知后,如果程序被杀死则会调用下面第一个函数,如果程序处于后台会调用下面第二个函数,因此下面两个函数应搭配使用

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // 获取远程推送消息
        NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
        if (userInfo) {
            // 有推送的消息,处理推送的消息
        }
        return YES;
    }
    /// iOS3之后才有,只有在程序处于后台时,用户点击了通知后才会被调用,应搭配didFinishLaunchingWithOptions使用
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
        // userInfo
    }

    在实际编程时,如果想兼容iOS7以前,三个函数可同时使用,都列出来,系统会自动选择合适的调用。

    6 总结下函数的调用:

    首次安装后启动:

    • didRegisterForRemoteNotificationsWithDeviceToken 被调用
    • 系统询问用户是否同意接收 Notifications
    • 不管用户选择同意或拒绝,didRegisterUserNotificationSettings 被调用

    应用非首次启动时:

    • 如果 notifications 处于拒绝状态:didRegisterUserNotificationSettings 被调用
    • 如果 notifications 处于允许状态

      • didRegisterForRemoteNotificationsWithDeviceToken 被调用
      • didRegisterUserNotificationSettings 被调用
    • 应用运行过程中用户修改 notifications 设置:

      • 从拒绝变为允许:didRegisterForRemoteNotificationsWithDeviceToken 被调用
      • 从允许变为拒绝:什么也不发生

    7 服务端推送的格式

    {
        "aps" : {                  // 必须有
            "alert" : "string",
            "body"  : "string",
            "badge" : number,
            "sound" : "string"
        },
        "NotiId"   : 20150821,     // 自定义key值
    }

    8 推送的大小限制

    远程通知负载的大小根据服务器使用的API不同而不同。当使用HTTP/2 provider API时,负载最大为4kB;当使用legacy binary interface时,负载最大为2kB。当负载大小超过规定的负载大小时,APNs会拒绝发送此通知。

    9 整体如下图所示(以微信推送为例):

    干货——iOS本地推送与远程推送详解(一图看懂)

    10 最后,还需要申请证书,这里不再详述-_-

  • 相关阅读:
    Windows Azure Storage (17) Azure Storage读取访问地域冗余(Read Access – Geo Redundant Storage, RA-GRS)
    SQL Azure (15) SQL Azure 新的规格
    Azure China (5) 管理Azure China Powershell
    Azure China (4) 管理Azure China Storage Account
    Azure China (3) 使用Visual Studio 2013证书发布Cloud Service至Azure China
    Azure China (2) Azure China管理界面初探
    Azure China (1) Azure公有云落地中国
    SQL Azure (14) 将云端SQL Azure中的数据库备份到本地SQL Server
    [New Portal]Windows Azure Virtual Machine (23) 使用Storage Space,提高Virtual Machine磁盘的IOPS
    Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())的注意点
  • 原文地址:https://www.cnblogs.com/r360/p/5741136.html
Copyright © 2011-2022 走看看