美文网首页ios开发整理
iOS集成环信推送,最详细流程(证书创建、环信集成、测试)

iOS集成环信推送,最详细流程(证书创建、环信集成、测试)

作者: 贝勒老爷 | 来源:发表于2017-06-28 10:05 被阅读353次

    一.推送的原理和流程(着急做推送的可以跳过这一步)
    首先给大家推荐一个介绍推送机制很优秀的帖子:http://www.jianshu.com/p/ac397a033dec ,里面关于本地推送和远程推送的介绍都很详细,至少我看了感觉还是收获很多的.尤其是里面有几张图片不知道是博主在哪里找的,但是真的是一看就透,太赞了,所以我果断盗过来了0.0. 这里我对推送的流程做了一个简单的叙述,力求用最简单的语言能说明整个推送的机制.

    1.png 2.png

    当我们的苹果手机联网的时候,会自动与苹果的服务器建立长连接,长连接的好处有很多,比如系统升级、时间校准、数据传输和响应比较快以及数据可以保持最新状态等功能.上面这两张图片简单的讲述了推送的流程:

    1.首先我们需要将自己设备的UDID和应用的Bundle Identifier发送到苹果的服务器,然后苹果的服务器会返回给我们一个DeviceToken,这个在我看来就是创建推送证书和描述文件的过程.
    2.我们将包含手机和应用标示的打包文件上传到做推送的服务器上去,当我们从推送服务器的后台发起推送消息的时候,推送服务器会将我们的DeviceToken和需要发送的消息Message发送到苹果的APNS(Apple push Notification Service)服务器.
    3.当苹果的服务器收到DeviceToken和需要发送的消息Message时,会根据DeviceToken中的UDID查找设备,根据DeviceToken中的Bundle Identfier查找该应用,并将Message发送到该设备上.

    下面是以QQ服务器为栗子说明的即时通讯的机制:

    3.png

    二.具体流程

    我们创建一个名为TestDemo的工程,我是使用Xcode8.1来开发的,工程名为PushDemo,创建好的工程界面如下(Xcode8)

    3.png

    从Xcode8之后,Xcode提供了自动管理证书的功能,这个用起来很方便,我目前在工程中用到的最多的地方就是创建好一个Demo之后,如果想真机运行的话,那么只需要在Team选择框里选择我的开发账户,接下来下面会出现一个加载提示圈,等它加载完了就可以在真机上运行了,这个过程实际上是Xcode使用你当前的BundleId去该账户的开发这中心创建了对应的AppId和描述文件,但是我们既然是作为一个开发流程的记录,就自己来创建这些东西,所以,我们取消选择Automatically manage signing选项.此时界面如下:

    4.png
    1. 首先我们先去官网创建AppID和描述文件.
      我们是要集成推送的,所以我们需要用到cer文件,这个东西实际上就是苹果给开发者颁发的一个证书,我们需要将它导入到我们的AppId配置里,否则的话是无法集成推送的,还记得安装应该的时候会提示"无法安装为认证发布者的应用"之类的信息么,我猜测这个cer文件就是我们身份的标示,使我们开发的应用可以供人们正常安装使用,关于证书有一篇很详细的帖子,希望了解证书之类信息的看官可以去瞅瞅:http://m.blog.csdn.net/article/details?id=8617788
      创建cer文件的流程很简单,打开"钥匙串访问"(虽然很好找,但是还是把图贴出来吧,怕小朋友迷路)
      ![Uploading 6_078927.png . . .]
      5.png
    6.png

    打开钥匙串之后点击"从证书颁发机构请求证书"

    7.png

    邮箱和常用名随便填写,记住下面的选择框选择"存储到磁盘"

    8.png

    点击存储

    9.png

    已经在桌面保存了

    10.png

    到此,我们已经创建好了cer文件,接着我们去开发者中心创建AppId和描述文件

    1. 创建AppId和描述文件

    首先进入开发者中心,百度搜索Apple Developer,(哎 真的是详细到家了啊,我都人不下去了)
    上图

    11.png

    输入开发者账户,登录进去

    12.png

    你将看到这个页面

    13.png

    点击看到:

    14.png

    输入AppId文件名和BundleId

    15.png

    选中下面的PushNotifications

    16.png

    点击Continue:

    17.png

    点击register:

    18.png

    点击Done回到AppId列表页面

    19.png

    在AppId列表页面可以看到我们的AppID了

    20.png

    但是,还没有完成,因为我们是要做推送的,所以需要上传我们的cer文件
    ,点击我们的AppId,在展开的详情里可以看到:

    21.png

    Push Notification的两个指示灯还是黄色的状态,我们要将它启用,点击Edit,在点开的页面里滑动至底部,记得要选中Push Notification按钮,接着点击上方的开发证书下的创建证书按钮:

    22.png

    点击Continue

    23.png

    点击 choose file:

    24.png

    将我们从开发机构请求的证书传上去,之后点击Register:

    25.png

    点击Register之后的页面,点击download,将其下载到桌面上,download之后记得点击done完成文件创建:

    26.png

    桌面上的文件:

    27.png

    现在我们就完成了给AppID创建开发者证书,然后我们要给它创建发布者证书,点击Done之后回到AppIds列表,如果找不到的话,点击右边的App IDs

    28.png

    点开项目的AppId,此时界面如下,点击最下面的CreateCertificate,开始给AppID创建发布者证书,给AppId创建发布者证书流程跟创建开发者证书是一样的!给AppId创建发布者证书流程跟创建开发者证书是一样的!给AppId创建发布者证书流程跟创建开发者证书是一样的!重要的事情说三遍!!因为我不贴出来创建发布证书的图了,所以各位根据创建开发证书的流程再走一遍就好,同样也要将发布者证书下载到本地.:

    29.png 30.png

    当创建好之后在回到这个页面时,应该显示如下所示:

    31.png

    此时本地我们下载的文件如下:

    32.png

    然后将这两个证书拖到钥匙串里,步骤如下:
    首先打开钥匙串:

    33.png 34.png

    然后先点击:系统-证书,然后将两个文件拖进去,会提示你输入开机密码,输入就好了(建议添加之前先对这个界面截屏,添加完之后可以对比刚刚添加了那些文件)

    35.png

    添加完之后是这个样子,画框的是我们的证书

    36.png

    然后选择左边的"登录"选项,可以看到我们刚才创建的证书

    37.png

    选中第一个证书,然后右键(你懂得右键的意思),选择导出...

    38.png

    选择导出为P12文件,存储在桌面上,获取到P12文件.对这两个证书进行同样的操作.(记得标题有(Develop)的起名为Product文件,第二个证书导出的时候起名为Develop,名字可以自己定,只是为了区别)

    39.png

    然后会提示你输入密码,这里我设置的密码是123456,自己设定好一定要记住,一会儿要用.

    40.png

    然后可以在桌面上看到我们导出的P12文件啦

    41.png

    现在我们就完成了所有的证书的创建,可以去环信上创建我们的应用啦.

    3.创建真机调试文件以及导入到项目中

    因为必须要进行真机测试,而且我们关闭了自动管理证书,就导致Xcode8不会自动帮我们生成证书,所以我们要自己创建真机调试证书并导入到项目中去,流程如下:

    创建描述文件:

    42.png

    选择开发模式,下一步:

    43.png

    选择对应的AppID,选择我们刚才创建的AppId:

    44.png

    选择开发团队,我一般都是全选的,下一步:

    45.png

    选择真机调试的机器,全选,下一步:

    46.png

    下一步:

    47.png

    将创建好的描述文件下载下来,放到桌面上:

    48.png

    创建好的描述文件:

    49.png

    首先选择debug模式下载的真机调试描述文件:

    50.png

    选择桌面上刚刚下载的描述文件:

    51.png

    使用同样的步骤,选择Release模式下的真机调试文件,一模一样的操作,不贴图了.两个文件都导入进去之后,插上真机,就可以进行真机调试了.

    4.在环信创建我们的应用

    首先百度搜索环信,打开他们的官网,先注册账户,注册过的可以跳过了,上图:
    注册的时候选择"注册即时通讯云"

    52.png

    注册的时候需要填写各种信息,按照格式填写就好了,填写完之后登陆,点击创建应用

    53.png

    填写应用信息

    54.png

    填写完如下图咯

    55.png

    然后需要上传我们的P12文件,图片很清晰- -,不多说,第一次我选择上传的是生产证书:

    56.png

    第二次上传开发证书:

    57.png

    至此,我们的证书开发也都上传完了,路漫漫其修远兮,开始集成环信到代码里吧
    5.集成环信到项目中
    首先在这里下载最新的SDK(截至到写本文时最新的SDK为)
    http://www.easemob.com/download/im 环信推送SDK下载链接
    点击iOS的最新SDK下载,这里下载的是V3.x的SDK

    58.png

    下载到桌面是这个样子

    59.png

    我们只需要将画圈的两个文件夹导进去工程里就好了,其他的用不上

    60.png

    导进去之后文件列表是这样,编译会出错别急,慢慢改.

    61.png

    向项目里添加需要的库

    62.png

    上面的图片是截取的环信官方文档,我添加完是这个样子的:

    63.png

    方便复制库名的文字:
    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。

    64.png

    command+B编译工程,大量爆红.别着急,修改我们的PCH文件就好了
    在PCH文件添加

    #ifdef __OBJC__
        #import <UIKit/UIKit.h>
    #endif
    

    将我们所有定义和添加的头文件和宏定义,都放在#ifdef OBJC和#endif中间
    就可以解决这个问题.

    然后在项目里打开推送:

    65.png

    6.测试是否集成成功

    首先,我们去环信的后台给我们的应用添加一个用户

    66.png

    用户名我设置成了:13088888888 密码设置成了:222222

    67.png

    接着我们要去appledate.m文件里添加东西了,很重要一步,废话不多说,直接贴出来需要配置的代码,直接拿去用0.0,需要添加的东西我在注释里注释的很明白...
    记得要导进去头文件

    import "EMSDK.h"
    @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里是必须重写的,不然会直接导致推送不成功.其中.需要重点说明的是:

    只有在应用完全退出被杀掉的状态下,才可以收到环信推送的通知;
    如果要发送在线的通知,需要在messagesDidReceive方法里获取到环信推送的消息之后给用户发起一个本地通知,这个大家可以自己研究下.
    通过设置emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;(上面代码有)可以设置有通知过来的时候的显示方式,显示一个提示或者显示完整的消息.
    上传证书下面填写的应用包名,指的是你的BundleID !!!!我在这里踩了坑,切记!!.
    测试推送:

    在应用完全退出的情况下(使用在环信注册的账户登录一次,确认登录成功之后再完全退出),选中我们的用户,点击发送消息:

    68.png

    点击发送:

    69.png

    测试结果:

    70.png

    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/79061dda87e3

    设置推送过来时候的apns昵称:

    [[EMClient sharedClient] setApnsNickname:@"推送昵称"];
    
    

    相关文章

      网友评论

        本文标题:iOS集成环信推送,最详细流程(证书创建、环信集成、测试)

        本文链接:https://www.haomeiwen.com/subject/nhdmqxtx.html