推送通知

1、作用:让不在前台(后台或者关闭)的APP知道APP内部发生的事情

2、在“设置”——>“通知中心”-----> 可以关闭推送通知

3、发送推送通知时,如果程序运行在前台,推送通知就不会呈现。

4、点击推送通知会打开对应的app

5、不管应用程序出于后台还是被杀死,推送通知都会发出

一、本地推送通知
概念:由APP本身给应用程序推送消息,不需要服务器的支持
常见场景:记账软件/闹钟/定时提醒记账/番茄工作法/系统电池没电中提醒你时间等等
注意:不是非常常用。

1、发送本地推送

//点击按钮发送本地通知
- (IBAction)fireLocalNoti {
    //无论程序在前台、后台、退出了,都可以接收到本地通知
    //1.创建本地通知
    UILocalNotification *localNote = [[UILocalNotification alloc] init];
    
    //2.设置通知显示的内容
    //2.1.设置通知发出的时间,即5秒后发出通知
    localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];
    //2.2.设置通知的内容
    localNote.alertBody = @"吃饭了吗?";
    //2.3.设置锁屏界面滑块下显示的文字
    localNote.alertAction = @"聊天";
    //2.4.决定alertAction是否生效
    localNote.hasAction = NO;
    //2.5.设置通知中心的标题
    localNote.alertTitle = @"一般是app的名字";
    //2.6.设置通知时的音效
    localNote.soundName = UILocalNotificationDefaultSoundName;
    //2.7.设置app右上角的数字
    localNote.applicationIconBadgeNumber = 10;
    //2.8.设置额外的信息,暂时没有用处
    localNote.userInfo = @{@"name":@"张三", @"age":@23};
    //2.9.本地通知的类型标志符,做快捷回复通知使用
    localNote.category = @"11";
    //2.10、通知重复调用的时间-->设置以后,则调度池不会自动销毁通知
    localNote.repeatInterval = NSCalendarUnitMinute;
    
    
    //3.调度通知,让通知在特定的时间发送本地通知,ios8.0以后才出现
    [[UIApplication sharedApplication] scheduleLocalNotification:localNote];
    
    //4、注册通知,ios8.0,请求用户权限的事情,如果只有一次,则在代码直接在代码处写,多次在appDelegate中写
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    
    //5、获取本地通知,并删除重复通知
    //获取所有通知
//    NSArray *notifcationArr = [[UIApplication sharedApplication] scheduledLocalNotifications];
//    for (UILocalNotification *locationNoti in notifcationArr) {
//        //可以根据userInfo来删除某个通知
//        if (locationNoti.userInfo) {
//            [[UIApplication sharedApplication] cancelLocalNotification:locationNoti];
//        }
//    }
}

- (IBAction)removeLocalNote {
    //关闭所有的通知
    [[UIApplication sharedApplication] cancelAllLocalNotifications];
}



2、在前台/后台接收到通知后进行跳转

//当(前台/后台)接收到一个本地通知时,会调用该方法
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    /**
     *  UIApplicationStateActive  前台
     *  UIApplicationStateInactive  进入前台
     *  UIApplicationStateBackground  后台
     */
    if(application.applicationState == UIApplicationStateActive){
        NSLog(@"在前台时,不要进行跳转;要么提示用户进行跳转");
        //当然也可以跳转到指定界面
        return;
    }
    //在后台进入前台时,跳转到某个固定的页面
    NSLog(@"根据%@跳转到一个固定的页面:%s", notification.userInfo, __func__);
}



3、在应用程序被杀死时,接收到本地推送通知后进行跳转

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0){
        //1.iOS8之后,如果想要发出通知(无论本地还是远程),必须先进行注册.(iOS8之前不需要)
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        [application registerUserNotificationSettings:setting];
    }else{
        
        //ios8.0之前的注册推送通知
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    }
    
    //如果应用程序被杀死了,但是任然要实现接收到通知进行跳转,则需要在此处实现跳转。因为程序被杀死后,接收到通知不会调用didReceiveLocalNotification方法。
    // 判断是否是通过点击通知打开了应用程序
    if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        // 跳转代码
        NSLog(@"接收到本地通知,跳转到一个固定的界面");
    }
    return YES;
}



4、本地推送快捷回复调用的方法


通过分类来实现

//无论程序在前台、后台、退出了,都可以接收到本地通知
    //1.创建本地通知
    UILocalNotification *localNote = [[UILocalNotification alloc] init];
    
    //2.9.本地通知的类型标志符
    localNote.category = @"category";



- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    //1、创建本地推送通知分类
    UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
    //2、设置标志符
    category.identifier = @"category";
    
    //3、设置前台按钮
    UIMutableUserNotificationAction *action1 = [[UIMutableUserNotificationAction alloc] init];
    action1.identifier = @"qiantai";
    //3.1、设置前台按钮模式
    action1.activationMode = UIUserNotificationActivationModeForeground;
    //3.2、设置按钮的标题
    action1.title = @"qiantai哈哈";
    
    
    //3、设置后台按钮
    UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];
    action2.identifier = @"houtai";
    //3.1、设置前台按钮模式
    action2.activationMode = UIUserNotificationActivationModeBackground;
    //3.2、设置按钮的标题
    action2.title = @"houtai哈哈";
    
    
    //4、设置按钮
    [category setActions:@[action1, action2] forContext:UIUserNotificationActionContextDefault];
    
    //5、设置分类的集合
    NSSet *categorySet = [NSSet setWithObject:category];
    
    
    
    
    if([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0){
        //1.iOS8之后,如果想要发出通知(无论本地还是远程),必须先进行注册.(iOS8之前不需要)
        /**
         *  @param types:显示收到本地通知时的样式
         *         UIUserNotificationTypeNone  无
         *         UIUserNotificationTypeBadge  app图像显示通知的数字
         *         UIUserNotificationTypeSound  声音
         *         UIUserNotificationTypeAlert  弹窗
         *
         */
        //6、设置分类集合
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:categorySet];
        [application registerUserNotificationSettings:setting];
    }else{
        
        //ios8.0之前的注册推送通知
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    }

    return YES;
}

//处理分类按钮调用的方法
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
    
    NSLog(@"根据标识符进行逻辑操作%@", identifier);
    
    //一旦接收到本地推送通知,必需调用,告诉系统进行资源分配
    completionHandler();
    
}



iOS开发 点击通知跳转到指定页面_推送通知







二、远程推送

1、概念

概念:由服务器推送消息给用户,弹出消息的通知(需要联网),需要服务器的支持。远程推送服务,又称为APNs(Apple PushNotification Services)。
常见场景:微信提醒新消息/淘宝提醒有新活动/视频软件提供您有最新电影
注意:非常常用.但是如果仅仅是给用户提醒,客户端(你)做的事情就非常简单.
 
例子:淘宝最近双11搞活动,各种送红包,想告知用户.但是该用户不经常打包淘宝APP.淘宝如何通知该用户有最新的活动呢?
传统方式(以前):只有用户打开了淘宝客户端,客户端向服务器请求是否有最新的活动,才能在APP中告知用户活动。
传统方式局限性:只要用户关闭了app,就无法跟app的服务器沟通,无法从服务器上获得最新的数据内容。
远程推送通知的好处:不管用户打开还是关闭app,只要联网了,都能接收到服务器推送的远程通知。
 

2、原理

远程通知的原理:淘宝服务器把“红包活动” --> 推送 -->  苹果的APNs服务器  --> 推送 --> 淘宝客户端app

iOS开发 点击通知跳转到指定页面_推送通知_02

 

2.1、为什么淘宝服务器不直接推消息给用户?
在通常情况下服务器端是不能主动向客户端推消息的。
如果想服务器端给客户端推消息,必须建立长连接,淘宝客户端在处于后台时不能和服务器端建立长连接。

2.2、为什么苹果服务器可以推消息给用户?
所有的苹果设备,在联网状态下,都会与苹果的服务器建立长连接
苹果建立长连接的作用:时间校准、系统升级提示、查找我的iPhone、远程推送通知

短链接:客户端app给服务器发送请求,服务器返回数据,客户端app收到数据,链接断开。此时,服务器则不能给客户端推送消息。
长链接:通过socket来建立。即时通讯中使用。建立长链接对服务器的负荷特别大。高并发后台人才的技术,可以节省服务器。

2.3、苹果在推送消息时,如何准确的推送给某一个用户,并且知道是哪一个APP?
在淘宝服务器把消息给苹果的APNs服务器时,必须告知苹果DeviceToken
什么是DeviceToken?
DeviceToken是由用户手机的UDID和应用程序的BundleID共同生成的
通过DeviceToken可以找到唯一手机中的唯一应用程序
如何获得DeviceToken?
客户端到苹果的APNs注册即可获得。

2.4、如何实现远程推送通知
首先,BundleID对应的APPID必须是明确的(特殊功能)
该APPID必须配置两个证书
调试证书:用于调试远程推送
发布证书:用于发布后给用户推送消息
根据上面的APPID重新配置描述文件
安装对应的证书,即可开始测试远程推送

3、苹果自带的远程推送通知

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if([[UIDevice currentDevice].systemVersion doubleValue]>= 8.0){
        //注册推送通知
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        
        [application registerUserNotificationSettings:settings];
        
        //注册远程通知,获取DeviceToken
        [application registerForRemoteNotifications];
        
    }else{
        
        //ios8.0之前的注册推送通知
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    }
    
    //如果应用程序被杀死了,但是任然要实现接收到通知进行跳转,则需要在此处实现跳转。因为程序被杀死后,接收到通知不会调用didReceiveRemoteNotification方法。
    // 判断是否是通过点击通知打开了应用程序
    if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        // 跳转代码
        NSLog(@"接收到本地通知,跳转到一个固定的界面");
        //获取通知的消息
        NSDictionary *remoteDict = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
        
    }
    
    return YES;
}

//通过代理方法获取deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    
    //deviceToken:用于发送给公司的服务器,让公司的服务器作存储
    NSLog(@"%@", deviceToken);
    
    /**
     *  UIApplicationStateActive  前台
     *  UIApplicationStateInactive  进入前台
     *  UIApplicationStateBackground  后台
     */
    if(application.applicationState == UIApplicationStateActive){
        NSLog(@"在前台时,不要进行跳转");
        return;
    }
    NSLog(@"跳转到一个固定的页面:%s", __func__);
}

#pragma mark - 当接收到远程推送时,调用该方法
//前台/后台时,可以在此方法接收到通知,在杀死时需要在didFinishLaunchingWithOptions
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    NSLog(@"%@", userInfo);
}

#pragma mark - 当接收到远程推送时,调用该方法,ios7推出
//前台/后台/退出时,可以在此方法接收到通知
//如果此方法和“application:didReceiveRemoteNotification:”方法都实现,则此方法有效,另外一个方法无效
//如果实现了此方法,还需要打开一个选项值 --> 点击项目 --> capabilites --> backgroundModes --> remoteNotification,即打开了后台远程通知
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
    
    //必须调用一下block,否则报错。此block告诉苹果服务器推送是否成功
//    UIBackgroundFetchResultNewData
//    UIBackgroundFetchResultNoData
//    UIBackgroundFetchResultFailed
    completionHandler(UIBackgroundFetchResultNewData);
}



三、第三方平台的远程推送通知

友盟、极光推送

推送的作用非常简单,就是将我们服务器需要做的事情用激光推送服务器作为替代。

极光推送给任何用户不需要交钱,但是如果推送给特定的用户则需要交钱。