iOS 環信離線推送

這幾天項目裏又用到了友盟的推送,雖然以前作過,可是好久不作仍是有不少細節沒有注意到,因此仍是決定從頭開始作一遍,把每個環節都詳細記錄下來,一樣的把每個坑也記錄下來.方便本身之後作的時候忘記哪一個流程了能夠在看一遍.我很能理解那種遇到問題網上百度一堆相似答案可是並很差使的狀況,因此我會將我在項目中遇到的問題都貼出來,但願能給你們帶來些許參考和幫助,文章原創爲http://www.jianshu.com/p/389ff299dc75css

一.推送的原理和流程(着急作推送的能夠跳過這一步)

首先給你們推薦一個介紹推送機制很優秀的帖子:http://www.jianshu.com/p/e347f999ed95 ,裏面關於本地推送和遠程推送的介紹都很詳細,至少我看了感受仍是收穫不少的.尤爲是裏面有幾張圖片不知道是博主在哪裏找的,可是真的是一看就透,太讚了,因此我果斷盜過來了0.0. 這裏我對推送的流程作了一個簡單的敘述,力求用最簡單的語言能說明整個推送的機制.c++

先搬過來一張圖再說git

再搬一張:sql

當咱們的蘋果手機聯網的時候,會自動與蘋果的服務器創建長鏈接,長鏈接的好處有不少,好比系統升級、時間校準、數據傳輸和響應比較快以及數據能夠保持最新狀態等功能.上面這兩張圖片簡單的講述了推送的流程:xcode

  • 1.首先咱們須要將本身設備的UDID和應用的Bundle Identifier發送到蘋果的服務器,而後蘋果的服務器會返回給咱們一個DeviceToken,這個在我看來就是建立推送證書和描述文件的過程.
  • 2.咱們將包含手機和應用標示的打包文件上傳到作推送的服務器上去,當咱們從推送服務器的後臺發起推送消息的時候,推送服務器會將咱們的DeviceToken和須要發送的消息Message發送到蘋果的APNS(Apple push Notification Service)服務器.
  • 3.當蘋果的服務器收到DeviceToken和須要發送的消息Message時,會根據DeviceToken中的UDID查找設備,根據DeviceToken中的Bundle Identfier查找該應用,並將Message發送到該設備上.

下面是以QQ服務器爲栗子說明的即時通信的機制:服務器


圖片已經說得夠詳細明瞭了,我就不插嘴了,下面開始咱們的工程.app

二.具體流程

咱們建立一個名爲TestDemo的工程,我是使用Xcode8.1來開發的,工程名爲PushDemo,建立好的工程界面以下(Xcode8)ide


從Xcode8以後,Xcode提供了自動管理證書的功能,這個用起來很方便,我目前在工程中用到的最多的地方就是建立好一個Demo以後,若是想真機運行的話,那麼只須要在Team選擇框裏選擇個人開發帳戶,接下來下面會出現一個加載提示圈,等它加載完了就能夠在真機上運行了,這個過程其實是Xcode使用你當前的BundleId去該帳戶的開發這中心建立了對應的AppId和描述文件,可是咱們既然是做爲一個開發流程的記錄,就本身來建立這些東西,因此,咱們取消選擇Automatically manage signing選項.此時界面以下:測試

好了,咱們要正式開始咱們的工做了GO GO GO!ui

1. 首先咱們先去官網建立AppID和描述文件.

咱們是要集成推送的,因此咱們須要用到cer文件,這個東西實際上就是蘋果給開發者頒發的一個證書,咱們須要將它導入到咱們的AppId配置裏,不然的話是沒法集成推送的,還記得安裝應該的時候會提示"沒法安裝爲認證發佈者的應用"之類的信息麼,我猜想這個cer文件就是咱們身份的標示,使咱們開發的應用能夠供人們正常安裝使用,關於證書有一篇很詳細的帖子,但願瞭解證書之類信息的看官能夠去瞅瞅:http://m.blog.csdn.net/article/details?id=8617788

建立cer文件的流程很簡單,打開"鑰匙串訪問"(雖然很好找,可是仍是把圖貼出來吧,怕小朋友迷路)

打開鑰匙串以後點擊"從證書頒發機構請求證書"

郵箱和經常使用名隨便填寫,記住下面的選擇框選擇"存儲到磁盤"

點擊存儲

已經在桌面保存了

到此,咱們已經建立好了cer文件,接着咱們去開發者中心建立AppId和描述文件

2. 建立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文件啦

如今咱們就完成了全部的證書的建立,能夠去環信上建立咱們的應用啦.

3.建立真機調試文件以及導入到項目中

由於必需要進行真機測試,並且咱們關閉了自動管理證書,就致使Xcode8不會自動幫咱們生成證書,因此咱們要本身建立真機調試證書並導入到項目中去,流程以下:

建立描述文件:

選擇開發模式,下一步:

選擇對應的AppID,選擇咱們剛纔建立的AppId:

選擇開發團隊,我通常都是全選的,下一步:

選擇真機調試的機器,全選,下一步:

下一步:

將建立好的描述文件下載下來,放到桌面上:

建立好的描述文件:

首先選擇debug模式下載的真機調試描述文件:

選擇桌面上剛剛下載的描述文件:

使用一樣的步驟,選擇Release模式下的真機調試文件,如出一轍的操做,不貼圖了.兩個文件都導入進去以後,插上真機,就能夠進行真機調試了.

4.在環信建立咱們的應用

首先百度搜索環信,打開他們的官網,先註冊帳戶,註冊過的能夠跳過了,上圖:
註冊的時候選擇"註冊即時通信雲"

註冊的時候須要填寫各類信息,按照格式填寫就行了,填寫完以後登錄,點擊建立應用

填寫應用信息

填寫完以下圖咯

而後須要上傳咱們的P12文件,圖片很清晰- -,很少說,第一次我選擇上傳的是生產證書:

第二次上傳開發證書:

至此,咱們的證書開發也都上傳完了,路漫漫其修遠兮,開始集成環信到代碼裏吧

5.集成環信到項目中

首先在這裏下載最新的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文件添加

ifdef OBJC

#import <UIKit/UIKit.h>

endif

將咱們全部定義和添加的頭文件和宏定義,都放在#ifdef OBJC和#endif中間
就能夠解決這個問題.

而後在項目裏打開推送:

6.測試是否集成成功

首先,咱們去環信的後臺給咱們的應用添加一個用戶

用戶名我設置成了:13051698888 密碼設置成了:222222

接着咱們要去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 !!!!我在這裏踩了坑,切記!!.

測試推送:

  1. 在應用徹底退出的狀況下(使用在環信註冊的帳戶登陸一次,確認登陸成功以後再徹底退出),選中咱們的用戶,點擊發送消息:

點擊發送:

測試結果:

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

  • 設置推送過來時候的apns暱稱:
    [[EMClient sharedClient] setApnsNickname:@"推送暱稱"];
相關文章
相關標籤/搜索