Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions IOS推送分享
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
消息推送
APNS的推送机制
首先我们看一下苹果官方给出的对IOS推送机制的解释。如下图

Provider就是我们自己程序的后台服务器,APNS是Apple Push Notification Service的缩写,也就是苹果的推送服务器。
上图可以分为三个阶段:
第一阶段:应用程序的服务器端把要发送的消息、目的iPhone的标识打包,发给APNS。
第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。
第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。




APNS推送通知的详细工作流程
下面这张图是说明APNS推送通知的详细工作流程:


根据图片我们可以概括一下:
1、应用程序注册APNS消息推送。
2、IOS从APNS Server获取devicetoken,应用程序接收device token。
3、应用程序将device token发送给程序的PUSH服务端程序。
4、服务端程序向APNS服务发送消息。
5、APNS服务将消息发送给iPhone应用程序。


客户端实现起来相对容易,但后台要支持APNS的话还是比较复杂的,因此,我使用口碑较好的第三方推送-极光推送。
准备工作
1, 申请推送证书
http://www.2cto.com/kf/201604/500620.html
2, 将推送证书导出为p12文件,并上传至极光推送
3, 导入JPUSH框架
xcode 8以下 建议手动导入JPUSH,由于缺少系统库UserNotifications.framework会导致框架无法使用
• 在极光官网下载最新SDK
• 将SDK包解压,在Xcode中选择“Add files to 'Your project name'...”,将解压后的lib子文件夹(包含JPUSHService.h、jpush-ios-x.x.x.a、jcore-ios-x.x.x.a)添加到你的工程目录中。 
• 添加Framework
o CFNetwork.framework
o CoreFoundation.framework
o CoreTelephony.framework
o SystemConfiguration.framework
o CoreGraphics.framework
o Foundation.framework
o UIKit.framework
o Security.framework
o libz.tbd (Xcode7以下版本是libz.dylib)
o AdSupport.framework (获取IDFA需要;如果不使用IDFA,请不要添加)
o UserNotifications.framework (Xcode8及以上)
o libresolv.tbd (JPush 2.2.0及以上版本需要, Xcode7以下版本是libresolv.dylib)
• 设置 Search Paths 下的 User Header Search Paths 和 Library Search Paths,比如SDK文件夹(默认为lib)与工程文件在同一级目录下,则都设置为"$(SRCROOT)/{静态库所在文件夹名称}"即可。
允许Xcode7支持Http传输方法
如果您使用的是2.1.9及以上的版本则不需要配置此步骤
如果用的是Xcode7或更新版本,需要在App项目的plist手动配置下key和值以支持http传输:
选择1:根据域名配置
• 在项目的info.plist中添加一个Key:NSAppTransportSecurity,类型为字典类型。
• 然后给它添加一个NSExceptionDomains,类型为字典类型;
• 把需要的支持的域添加給NSExceptionDomains。其中jpush.cn作为Key,类型为字典类型。
• 每个域下面需要设置2个属性:NSIncludesSubdomains、NSExceptionAllowsInsecureHTTPLoads。 两个属性均为Boolean类型,值分别为YES、YES。
如图:

选择2:全局配置
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>



代码集成


初始化JPUSH, types属性设置收到通知时,APP的一些相应方式,包括bageValue,提示音或者震动,来提示用户接收到通知。在XCODE8以下,由于缺少UserNotifications.framework框架,所以无法使用IOS的特性,而极光的代理属性洽洽需要配合UserNotifications才能使用,因此此处传nil即可。
appKey:极光开发者后台提供,你可以通过注册账号并创建应用获得
channel:通常为Publish channel
func setPushNoti(launchOptions:[NSObject: AnyObject]?){
//setup apns
let entity = JPUSHRegisterEntity()
entity.types = (1 << 0) | (1 << 1) | (1 << 2)
JPUSHService.registerForRemoteNotificationConfig(entity, delegate: nil)

//set jpush
JPUSHService.setupWithOption(launchOptions, appKey: K_APP_KEY, channel: K_CHANNEL, apsForProduction: false)
setJPUSH()
}

依次添加以下代码
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData){
JPUSHService.registerDeviceToken(deviceToken)
}//将苹果通知中心的deviceToken返回给极光推送后台

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError){
print("注册apns失败 \n \(error.localizedDescription)")
}//当然了,你需要关键的LOG

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
JPUSHService.handleRemoteNotification(userInfo)
completionHandler(UIBackgroundFetchResult.NewData)
print("ios7, 及以上系统收到通知\(userInfo)")
urlString = userInfo["url"] as? String
if urlString != nil && (application.applicationState == .Active){
NSNotificationCenter.defaultCenter().postNotification(NSNotification(name: "NewVersion", object: urlString, userInfo: nil))
}
}//XCODE7 的环境下,消息的解析在这里实现。

至此IOS的推送的集成基本完成了。但是要做到接收通知,打开通知栏就打开一个URL,还需要进一步的研究。(推送的消息中,content-alive字段必须为true否则将无法从服务器获取通知的内容)

1, 当程序进程被杀死,通过通知栏启动程序(注意,如果收到通知,仍然通过ICON去启动程序,通知的内容是无法获取到的,必须通过通知才可以)
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
print("launchOptions ----",launchOptions)
if launchOptions != nil{
let remoteNoti = launchOptions![UIApplicationLaunchOptionsRemoteNotificationKey]
urlString = remoteNoti!["url"] as? String
}
}//获取通知内容
2, 当程序 处于后台,程序可以正常通过通知进入,并触发一个特定的操作

3. 当程序处于前台
ios 10以下,是没有什么反应的,不弹出横幅,也无通知的声音。因此,可以通过添加这么一个判断来触发界面提示更新
if urlString != nil && (application.applicationState == .Active){
NSNotificationCenter.defaultCenter().postNotification(NSNotification(name: "NewVersion", object: urlString, userInfo: nil))
}
IOS10 及以上则既可以弹出横幅又可以有声音,相关的逻辑可以在JPUSH的代理方法里去实现

关于分组推送和精确推送
极光推送里面的精准推送是通过idfa去实现的,但前提是app里面需要有明显的广告功能,如果没有的话,app将无法上架,再者,这个东西也不是完全的可靠,如果用户在设置里面停止广告跟踪的话,精准推送还是会失效的。
思路:jpush中又一个registuserID这个id有个特点,就是程序如果被卸载,则重新生成一个新的来唯一表示设备,我们可以将用户ID作为key registuserID为value,如果重新安装,只需更新这个registuserID的值,即可唯一表示设备

分组推送
思路:先给用于一个别名alias,再给这个用户打上他所具备的标签,如 alias:liming, tag1:汽车 tag2:游戏 tag3:旅游
laias:jone tag1:美食 tag2:游戏 tag3:电影
推送的时候,可以通过对tag的交并补等集合操作,实现对不同群体用户的信息的分类推送,如游戏这条推送,liming和jone都能收到