APNS,即Apple Push Notification Service苹果推送通知服务,是苹果的服务器。

推送通知可以分为三个阶段:

第一阶段:应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。

第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。

第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

1. Push的三个步骤

如下图所示:

(1)Push服务应用程序把要发送的消息、目的iPhone的标识打包,发给APNS;

(2)APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone;

(3) iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

具体如下图5个步骤,无论是iPhone客户端跟APNS,还是Push服务器和APNS都需要通过证书进行连接的:

2. native端代码实现

推送消息时,不同时机点击,代码调用情况:
 
1. 当程序处于关闭状态收到推送消息时,点击图标会调用- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 这个方法,那么消息给通过launchOptions这个参数获取到。

2. 当程序处于前台工作时,这时候若收到消息推送,会调用- (void)application:(UIApplication*)application

didReceiveRemoteNotification:(NSDictionary *)userInfo这个方法。

3. 当程序处于后台运行时,这时候若收到消息推送,如果点击消息或者点击消息图标时,也会调用- (void)application:(UIApplication*)application

didReceiveRemoteNotification:(NSDictionary *)userInfo这个方法。

4. 当程序处于后台运行时,这时候若收到消息推送,如果点击桌面应用图标,则不会调用didFinishLaunchingWithOptions和didReceiveRemoteNotification方法,所以无法获取消息。

(1)注册通知(当然,程序关闭,推送消息时点击图标的逻辑也应该写在这里)

// 1.注册通知
#import <UserNotifications/UserNotifications.h> - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
   if ([[UIDevice currentDevice].systemVersion floatValue] >8.0){
      //iOS8 - iOS10
[[UIApplication sharedApplication] registerForRemoteNotifications];
     [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:
                  UIUserNotificationTypeAlert |       
                  UIUserNotificationTypeSound |
                  UIUserNotificationTypeBadge categories:nil]];
   }else if ([[UIDevice currentDevice].systemVersion floatValue] < 8.0) {
    //iOS8系统以下
    [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound];
   }
    
    return YES;
}

补充知识点:

  iOS 程序启动时总会调用application:didFinishLaunchingWithOptions:,其中第二个参数launchOptions为NSDictionary类型的对象,里面存储有此程序启动的原因。

    • 若用户直接启动,lauchOptions内无数据;
    • 若由其他应用程序通过openURL:启动,则UIApplicationLaunchOptionsURLKey对应的对象为启动URL(NSURL),UIApplicationLaunchOptionsSourceApplicationKey对应启动的源应用程序的bundle ID (NSString);
    • 若由本地通知启动,则UIApplicationLaunchOptionsLocalNotificationKey对应的是为启动应用程序的的本地通知对象(UILocalNotification);
    • 若由远程通知启动,则UIApplicationLaunchOptionsRemoteNotificationKey对应的是启动应用程序的的远程通知信息userInfo(NSDictionary);
    • 其他key还有UIApplicationLaunchOptionsAnnotationKey,UIApplicationLaunchOptionsLocationKey,
      UIApplicationLaunchOptionsNewsstandDownloadsKey。

所以,可以根据上面的key将lauchOptions取出来:

//apple push启动
NSDictionary *applePushDic = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
//本地通知启动
UILocalNotification *localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

(2)获得Device Token

// 2.获得Device Token
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken{
NSLog(@"regisger success:%@", pToken);
// 注册成功,将deviceToken保存到应用服务器数据库中,因为在写向ios推送信息的服务器端程序时要用到这个
} // 3.获得Device Token失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {

  如果总是失败的话,即push总是到didFailToRegisterForRemoteNotificationsWithError:里面。除了我们知道的模拟器不能接受apple push,报的3010错误之外,经常会遇到“Error: Error Domain=NSCocoaErrorDomain Code=3000 "no valid 'aps-environment' entitlement string found for application" ”这个错误。解决步骤主要有以下三步:

  (2.1)确保证书开通了push的功能:

       可以在开发者网站上的App ID下查看,其Development、Distribution是否都已经开通了Push的功能。Development Push是你用Xcode调试时用的Debug使用的,Distribution的Push是正式包使用的。

      一个Bundle ID开通了Development、Distribution的push是要生成对应的两个证书的。此时,正式证书的类型是"Apple Push Services",Development对应的证书的类型是"APNs Development iOS"。你的pp文件后面也要用的是对应的证书文件。

  (2.2)确保配置文件信息正确:

      证书开通了push之后,你的配置文件要使用的是你的对应的证书,对应的app id等,都要对应起来。本地如果重新安装配置文件的话,确保老的删掉后,重新安装,重新在Target》build setting》Provision Profile下选择你刚安装的证书。能重新选择才能确定这里选择的是新的而不是旧的。PS:删除老的provision文件的方法,可以在Xcode》Preference》Accounts》对应的Apple Id,对应的Team》View Details》Provision Profile,然后点击右键就可以选择在finder中查看,可以删除对应的Provision Profile文件了。

  (2.3)确保Xcode的push设置正确:

      Target》Capabilities下面,找到你的Push Notification,确保你的push功能开着。并且"Add the Push Notification feature to your App ID"和"Add the Push Notifications entitlement to your entitlements file"这两个steps是ok的。

(3)处理推送消息

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
//4. 处理推送消息
}

Push:iOS基于APNS的消息推送的更多相关文章

  1. iOS开发如何实现消息推送机制

    一.关于推送通知 推送通知,也被叫做远程通知,是在iOS 3.0以后被引入的功能.是当程序没有启动或不在前台运行时,告诉用户有新消息的一种途径,是从外部服务器发送到应用程序上的.一般说来,当要显示消息 ...

  2. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

  3. .NET向APNS苹果消息推送通知

    一.Apns简介: Apns是苹果推送通知服务. 二.原理: APNs会对用户进行物理连接认证,和设备令牌认证(简言之就是苹果的服务器检查设备里的证书以确定其为苹果设备):然后,将服务器的信息接收并且 ...

  4. Android 基于Netty的消息推送方案之对象的传递(四)

    在上一篇文章中<Android 基于Netty的消息推送方案之字符串的接收和发送(三)>我们介绍了Netty的字符串传递,我们知道了Netty的消息传递都是基于流,通过ChannelBuf ...

  5. Android 基于Netty的消息推送方案之字符串的接收和发送(三)

    在上一篇文章中<Android 基于Netty的消息推送方案之概念和工作原理(二)> ,我们介绍过一些关于Netty的概念和工作原理的内容,今天我们先来介绍一个叫做ChannelBuffe ...

  6. Android 基于Netty的消息推送方案之概念和工作原理(二)

    上一篇文章中我讲述了关于消息推送的方案以及一个基于Netty实现的一个简单的Hello World,为了更好的理解Hello World中的代码,今天我来讲解一下关于Netty中一些概念和工作原理的内 ...

  7. Knative 实战:基于 Kafka 实现消息推送

    作者 | 元毅 阿里云智能事业群高级开发工程师 导读:当前在 Knative 中已经提供了对 Kafka 事件源的支持,那么如何基于 Kafka 实现消息推送呢?本文作者将以阿里云 Kafka 产品为 ...

  8. 基于FCM的消息推送功能

    需求背景 我方项目需要支持客户端消息推送,iOS终端可以借由苹果本身的apns很方便的实现,但是对于Android来说,必须集成第三方的SDK来处理.考虑到项目需要以及成本,我们选择使用谷歌的FCM框 ...

  9. Easy APNs Provider 消息推送测试工具

    1.Easy APNs Provider 简介 Easy APNs Provider 是一款为 iOS.Mac App 提供推送测试的小工具. App Store 下载地址 Easy APNs Pro ...

随机推荐

  1. SQL表新增触发(触发器)

    ALTER TRIGGER [InsertStoreJITOnloadQuantity] ON [dbo].[Sourceing] After INSERT AS --登記計劃數量(新增時YN=0) ...

  2. jQuery插件写法总结以及面向对象方式写法总结

    前两个是jQuery插件,后面2个是以对象的形式开发,都类似. 写法一 (function($, window){ // 初始态定义 var _oDialogCollections = {}; // ...

  3. .NET LINQ概述

    LINQ      语言集成查询 (LINQ) 是 Visual Studio 2008 中引入的一组功能,它在对象领域和数据领域之间架起了一座桥梁.可为 C# 和 Visual Basic 语言语法 ...

  4. hdu 1358 Period

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1358 思路:Next数组的用法,在第i个位置上如果有i%(i-Next[i])==0的话最小循环节就是 ...

  5. Maven 更换远程仓库地址

    1.第一种方式,通过setting.xml的方式配置数据源 该文件路径D:\IDE\apache-maven-3.2.3\conf\setting.xml 该文件大部分内容都已经注释,我们需要添加如下 ...

  6. 【记录】尝试用android-logging-log4j去实现log输出内容到sd卡中的文件的功能

    [背景] 折腾: [记录]给Android中添加log日志输出到文件 期间,已经试了: [记录]尝试用android中microlog4android实现log输出到文件的功能 但是不好用. 然后就是 ...

  7. mysql中,通过脚本设置表的自增列,及自增步长

    设置自增列(其实通过navicate可以直接设置的,也方便:要不然可能需要删除列了) ALTER TABLE `domain_dns_tucows` CHANGE `id` `id` INT(11) ...

  8. iOS 之 Cocoapods安装

    进入正题前,先来点前奏:了解cocoapods是某天看一个博客,那时才明白原来写项目不用一个个将三方库拷进项目里啊,惊讶的我是一塌糊涂的啊...(原谅我那时还没进入过正规的IT公司....好多你们自然 ...

  9. HLG1116-选美大赛

    Description 一年一度的哈理工选美大赛开始了.来自各个院系的N个美女们都在一起排成一排,然后从左到右给他们标号(1-N),评委叫兽开始观摩,由于身高高低都不同, 叫兽想从中选出尽可能多的人使 ...

  10. Ext3文件系统mount选项和文件属性介绍

    mount选项 设置方式 ext3 mount选项可以通过多个方式进行设置:1)内核编译时: 内核menuconfig通过CONFIG_EXT3_DEFAULTS_TO_ORDERED编译控制选项,来 ...