这几天项目里又用到了友盟的推送,虽然以前作过,可是好久不作仍是有不少细节没有注意到,因此仍是决定从头开始作一遍,把每个环节都详细记录下来,一样的把每个坑也记录下来.方便本身之后作的时候忘记哪一个流程了能够在看一遍.我很能理解那种遇到问题网上百度一堆相似答案可是并很差使的状况,因此我会将我在项目中遇到的问题都贴出来,但愿能给你们带来些许参考和帮助,文章原创为http://www.jianshu.com/p/389ff299dc75css
首先给你们推荐一个介绍推送机制很优秀的帖子:http://www.jianshu.com/p/e347f999ed95 ,里面关于本地推送和远程推送的介绍都很详细,至少我看了感受仍是收获不少的.尤为是里面有几张图片不知道是博主在哪里找的,可是真的是一看就透,太赞了,因此我果断盗过来了0.0. 这里我对推送的流程作了一个简单的叙述,力求用最简单的语言能说明整个推送的机制.c++
先搬过来一张图再说git
再搬一张:sql
当咱们的苹果手机联网的时候,会自动与苹果的服务器创建长链接,长链接的好处有不少,好比系统升级、时间校准、数据传输和响应比较快以及数据能够保持最新状态等功能.上面这两张图片简单的讲述了推送的流程:xcode
下面是以QQ服务器为栗子说明的即时通信的机制:服务器
图片已经说得够详细明了了,我就不插嘴了,下面开始咱们的工程.app
咱们建立一个名为TestDemo的工程,我是使用Xcode8.1来开发的,工程名为PushDemo,建立好的工程界面以下(Xcode8)ide
从Xcode8以后,Xcode提供了自动管理证书的功能,这个用起来很方便,我目前在工程中用到的最多的地方就是建立好一个Demo以后,若是想真机运行的话,那么只须要在Team选择框里选择个人开发帐户,接下来下面会出现一个加载提示圈,等它加载完了就能够在真机上运行了,这个过程其实是Xcode使用你当前的BundleId去该帐户的开发这中心建立了对应的AppId和描述文件,可是咱们既然是做为一个开发流程的记录,就本身来建立这些东西,因此,咱们取消选择Automatically manage signing选项.此时界面以下:测试
好了,咱们要正式开始咱们的工做了GO GO GO!ui
咱们是要集成推送的,因此咱们须要用到cer文件,这个东西实际上就是苹果给开发者颁发的一个证书,咱们须要将它导入到咱们的AppId配置里,不然的话是没法集成推送的,还记得安装应该的时候会提示"没法安装为认证发布者的应用"之类的信息么,我猜想这个cer文件就是咱们身份的标示,使咱们开发的应用能够供人们正常安装使用,关于证书有一篇很详细的帖子,但愿了解证书之类信息的看官能够去瞅瞅:http://m.blog.csdn.net/article/details?id=8617788
建立cer文件的流程很简单,打开"钥匙串访问"(虽然很好找,可是仍是把图贴出来吧,怕小朋友迷路)
打开钥匙串以后点击"从证书颁发机构请求证书"
邮箱和经常使用名随便填写,记住下面的选择框选择"存储到磁盘"
点击存储
已经在桌面保存了
到此,咱们已经建立好了cer文件,接着咱们去开发者中心建立AppId和描述文件
首先进入开发者中心,百度搜索Apple Developer,(哎 真的是详细到家了啊,我都人不下去了)
上图
输入开发者帐户,登陆进去
你将看到这个页面
点击看到:
输入AppId文件名和BundleId
选中下面的PushNotifications
点击Continue:
点击register:
点击Done回到AppId列表页面
在AppId列表页面能够看到咱们的AppID了
可是,尚未完成,由于咱们是要作推送的,因此须要上传咱们的cer文件
,点击咱们的AppId,在展开的详情里能够看到:
Push Notification的两个指示灯仍是黄色的状态,咱们要将它启用,点击Edit,在点开的页面里滑动至底部,记得要选中Push Notification按钮,接着点击上方的开发证书下的建立证书按钮:
点击Continue
点击 choose file:
将咱们从开发机构请求的证书传上去,以后点击Register:
点击Register以后的页面,点击download,将其下载到桌面上,download以后记得点击done完成文件建立:
桌面上的文件:
如今咱们就完成了给AppID建立开发者证书,而后咱们要给它建立发布者证书,点击Done以后回到AppIds列表,若是找不到的话,点击右边的App IDs
点开项目的AppId,此时界面以下,点击最下面的CreateCertificate,开始给AppID建立发布者证书,给AppId建立发布者证书流程跟建立开发者证书是同样的!给AppId建立发布者证书流程跟建立开发者证书是同样的!给AppId建立发布者证书流程跟建立开发者证书是同样的!重要的事情说三遍!!由于我不贴出来建立发布证书的图了,因此各位根据建立开发证书的流程再走一遍就好,一样也要将发布者证书下载到本地.:
当建立好以后在回到这个页面时,应该显示以下所示:
此时本地咱们下载的文件以下:
而后将这两个证书拖到钥匙串里,步骤以下:
首先打开钥匙串:
而后先点击:系统-证书,而后将两个文件拖进去,会提示你输入开机密码,输入就行了(建议添加以前先对这个界面截屏,添加完以后能够对比刚刚添加了那些文件)
添加完以后是这个样子,画框的是咱们的证书
而后选择左边的"登陆"选项,能够看到咱们刚才建立的证书
选中第一个证书,而后右键(你懂得右键的意思),选择导出...
选择导出为P12文件,存储在桌面上,获取到P12文件.对这两个证书进行一样的操做.(记得标题有(Develop)的起名为Product文件,第二个证书导出的时候起名为Develop,名字能够本身定,只是为了区别)
而后会提示你输入密码,这里我设置的密码是zx123456,本身设定好必定要记住,一下子要用.
而后能够在桌面上看到咱们导出的P12文件啦
如今咱们就完成了全部的证书的建立,能够去环信上建立咱们的应用啦.
由于必需要进行真机测试,并且咱们关闭了自动管理证书,就致使Xcode8不会自动帮咱们生成证书,因此咱们要本身建立真机调试证书并导入到项目中去,流程以下:
建立描述文件:
选择开发模式,下一步:
选择对应的AppID,选择咱们刚才建立的AppId:
选择开发团队,我通常都是全选的,下一步:
选择真机调试的机器,全选,下一步:
下一步:
将建立好的描述文件下载下来,放到桌面上:
建立好的描述文件:
首先选择debug模式下载的真机调试描述文件:
选择桌面上刚刚下载的描述文件:
使用一样的步骤,选择Release模式下的真机调试文件,如出一辙的操做,不贴图了.两个文件都导入进去以后,插上真机,就能够进行真机调试了.
首先百度搜索环信,打开他们的官网,先注册帐户,注册过的能够跳过了,上图:
注册的时候选择"注册即时通信云"
注册的时候须要填写各类信息,按照格式填写就行了,填写完以后登录,点击建立应用
填写应用信息
填写完以下图咯
而后须要上传咱们的P12文件,图片很清晰- -,很少说,第一次我选择上传的是生产证书:
第二次上传开发证书:
至此,咱们的证书开发也都上传完了,路漫漫其修远兮,开始集成环信到代码里吧
首先在这里下载最新的SDK(截至到写本文时最新的SDK为)
http://www.easemob.com/download/im 环信推送SDK下载连接
点击iOS的最新SDK下载,这里下载的是V3.x的SDK
下载到桌面是这个鬼样子
咱们只须要将画圈的两个文件夹导进去工程里就行了,其余的用不上
导进去以后文件列表是这样,编译会出错别急,慢慢改.
向项目里添加须要的库
上面的图片是截取的环信官方文档,我添加完是这个样子的:
方便复制库名的文字:
CoreMedia.framework
AudioToolbox.framework
AVFoundation.framework
MobileCoreServices.framework
ImageIO.framework
libc++.dylib
libz.dylib
libstdc++.6.0.9.dylib
libsqlite3.dylib
(若是使用的是 xcode7,后缀为 tbd。)
这一步很重要,由于SDK 不支持 bitcode,因此要将 Build Settings → Linking → Enable Bitcode 中设置 NO。
command+B编译工程,大量爆红.别着急,修改咱们的PCH文件就行了
在PCH文件添加
#import <UIKit/UIKit.h>
将咱们全部定义和添加的头文件和宏定义,都放在#ifdef OBJC和#endif中间
就能够解决这个问题.
而后在项目里打开推送:
首先,咱们去环信的后台给咱们的应用添加一个用户
用户名我设置成了:13051698888 密码设置成了:222222
接着咱们要去appledate.m文件里添加东西了,很重要一步,废话很少说,直接贴出来须要配置的代码,直接拿去用0.0,须要添加的东西我在注释里注释的很明白...
记得要导进去头文件
@interface AppDelegate ()<EMChatManagerDelegate> @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //AppKey:注册的AppKey,点击"应用概述"能够看到AppKey,粘贴过来就能够。 //apnsCertName:推送证书名,填写你的开发证书或者发布证书名,就是上传到环信后台的两个中的一个,什么环境下测试使用什么环境的证书。 EMOptions *options = [EMOptions optionsWithAppkey:@"1192161108178165#testpushdemo"]; options.apnsCertName = @"Develop"; [[EMClient sharedClient] initializeSDKWithOptions:options]; //登陆环信 这里使用的是我刚才在环信后台建立的帐户名和密码,使用这个帐户登陆,到时候若是在后台给客户端发消息的话,就能够找到该用户 [[EMClient sharedClient] loginWithUsername:@"13051698888" password:@"222222" completion:^(NSString *aUsername, EMError *aError) { if (!aError) { NSLog(@"环信登录成功"); EMPushOptions *emoptions = [[EMClient sharedClient] pushOptions]; //设置有消息过来时的显示方式:1.显示收到一条消息 2.显示具体消息内容. //本身能够测试下 emoptions.displayStyle = EMPushDisplayStyleSimpleBanner; [[EMClient sharedClient] updatePushOptionsToServer]; } else { NSLog(@"环信登录失败"); } }]; /** 注册APNS离线推送 iOS8 注册APNS */ if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) { [application registerForRemoteNotifications]; UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert; UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil]; [application registerUserNotificationSettings:settings]; } else{ UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert; [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes]; } //添加监听在线推送消息 [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; return YES; } //监听环信在线推送消息 - (void)messagesDidReceive:(NSArray *)aMessages{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到环信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"肯定", nil]; [alertView show]; //aMessages是一个对象,包含了发过来的全部信息,怎么提取想要的信息我会在后面贴出来. } // 将获得的deviceToken传给SDK - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{ [[EMClient sharedClient] bindDeviceToken:deviceToken]; } // 注册deviceToken失败 - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{ NSLog(@"error -- %@",error); } // APP进入后台 - (void)applicationDidEnterBackground:(UIApplication *)application { [[EMClient sharedClient] applicationDidEnterBackground:application]; } // APP将要从后台返回 - (void)applicationWillEnterForeground:(UIApplication *)application { [[EMClient sharedClient] applicationWillEnterForeground:application]; }
上面的几个方法在appdelegate里是必须重写的,否则会直接致使推送不成功.其中.须要重点说明的是:
测试推送:
点击发送:
测试结果:
2.程序在线的时候测试推送,仍是发送"你好啊",而后咱们在messagesDidReceive拦截环信的EMMessage对象,针对EMMessage对象的解析方式以下,完整的抽取环信推送消息的方法:
- (void)messagesDidReceive:(NSArray *)aMessages{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到环信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"肯定", nil]; [alertView show]; for (EMMessage *message in aMessages) { EMMessageBody *msgBody = message.body; switch (msgBody.type) { case EMMessageBodyTypeText: { // 收到的文字消息 EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody; NSString *txt = textBody.text; NSLog(@"收到的文字是 txt -- %@",txt); } break; case EMMessageBodyTypeImage: { // 获得一个图片消息body EMImageMessageBody *body = ((EMImageMessageBody *)msgBody); NSLog(@"大图remote路径 -- %@" ,body.remotePath); NSLog(@"大图local路径 -- %@" ,body.localPath); // // 须要使用sdk提供的下载方法后才会存在 NSLog(@"大图的secret -- %@" ,body.secretKey); NSLog(@"大图的W -- %f ,大图的H -- %f",body.size.width,body.size.height); NSLog(@"大图的下载状态 -- %u",body.downloadStatus); // 缩略图sdk会自动下载 NSLog(@"小图remote路径 -- %@" ,body.thumbnailRemotePath); NSLog(@"小图local路径 -- %@" ,body.thumbnailLocalPath); NSLog(@"小图的secret -- %@" ,body.thumbnailSecretKey); NSLog(@"小图的W -- %f ,大图的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height); NSLog(@"小图的下载状态 -- %u",body.thumbnailDownloadStatus); } break; case EMMessageBodyTypeLocation: { EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody; NSLog(@"纬度-- %f",body.latitude); NSLog(@"经度-- %f",body.longitude); NSLog(@"地址-- %@",body.address); } break; case EMMessageBodyTypeVoice: { // 音频sdk会自动下载 EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody; NSLog(@"音频remote路径 -- %@" ,body.remotePath); NSLog(@"音频local路径 -- %@" ,body.localPath); // 须要使用sdk提供的下载方法后才会存在(音频会自动调用) NSLog(@"音频的secret -- %@" ,body.secretKey); NSLog(@"音频文件大小 -- %lld" ,body.fileLength); NSLog(@"音频文件的下载状态 -- %u" ,body.downloadStatus); NSLog(@"音频的时间长度 -- %u" ,body.duration); } break; case EMMessageBodyTypeVideo: { EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody; NSLog(@"视频remote路径 -- %@" ,body.remotePath); NSLog(@"视频local路径 -- %@" ,body.localPath); // 须要使用sdk提供的下载方法后才会存在 NSLog(@"视频的secret -- %@" ,body.secretKey); NSLog(@"视频文件大小 -- %lld" ,body.fileLength); NSLog(@"视频文件的下载状态 -- %u" ,body.downloadStatus); NSLog(@"视频的时间长度 -- %u" ,body.duration); NSLog(@"视频的W -- %f ,视频的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height); // 缩略图sdk会自动下载 NSLog(@"缩略图的remote路径 -- %@" ,body.thumbnailRemotePath); NSLog(@"缩略图的local路径 -- %@" ,body.thumbnailLocalPath); NSLog(@"缩略图的secret -- %@" ,body.thumbnailSecretKey); NSLog(@"缩略图的下载状态 -- %u" ,body.thumbnailDownloadStatus); } break; case EMMessageBodyTypeFile: { EMFileMessageBody *body = (EMFileMessageBody *)msgBody; NSLog(@"文件remote路径 -- %@" ,body.remotePath); NSLog(@"文件local路径 -- %@" ,body.localPath); // 须要使用sdk提供的下载方法后才会存在 NSLog(@"文件的secret -- %@" ,body.secretKey); NSLog(@"文件文件大小 -- %lld" ,body.fileLength); NSLog(@"文件文件的下载状态 -- %u" ,body.downloadStatus); } break; default: break; } } }
发送成功以后打印结果以下:
2016-12-01 16:03:26.060088 PushDemo[1392:450230] 收到的文字是 txt -- 你好啊
至此,咱们就成功集成了环信推送到咱们的项目中.另外提供一些在作推送的时候常常会用到的小方法
设置应用图标右上角数字角标.
UIApplication *application = [UIApplication sharedApplication]; [application setApplicationIconBadgeNumber:3];
若是推送证书那里没看特别明白的话,提供一个建立推送证书的连接:http://www.jianshu.com/p/78282e16db66
[[EMClient sharedClient] setApnsNickname:@"推送昵称"];