iOS 環信離線推送


這幾天項目里又用到了友盟的推送,雖然之前做過,但是很久不做還是有很多細節沒有注意到,所以還是決定從頭開始做一遍,把每一個環節都詳細記錄下來,同樣的把每一個坑也記錄下來.方便自己以后做的時候忘記哪個流程了可以在看一遍.我很能理解那種遇到問題網上百度一堆類似答案但是並不好使的情況,所以我會將我在項目中遇到的問題都貼出來,希望能給大家帶來些許參考和幫助,文章原創為http://www.jianshu.com/p/389ff299dc75

一.推送的原理和流程(着急做推送的可以跳過這一步)

首先給大家推薦一個介紹推送機制很優秀的帖子:http://www.jianshu.com/p/e347f999ed95 ,里面關於本地推送和遠程推送的介紹都很詳細,至少我看了感覺還是收獲很多的.尤其是里面有幾張圖片不知道是博主在哪里找的,但是真的是一看就透,太贊了,所以我果斷盜過來了0.0. 這里我對推送的流程做了一個簡單的敘述,力求用最簡單的語言能說明整個推送的機制.

先搬過來一張圖再說

再搬一張:

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

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

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


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

二.具體流程

我們創建一個名為TestDemo的工程,我是使用Xcode8.1來開發的,工程名為PushDemo,創建好的工程界面如下(Xcode8)


從Xcode8之后,Xcode提供了自動管理證書的功能,這個用起來很方便,我目前在工程中用到的最多的地方就是創建好一個Demo之后,如果想真機運行的話,那么只需要在Team選擇框里選擇我的開發賬戶,接下來下面會出現一個加載提示圈,等它加載完了就可以在真機上運行了,這個過程實際上是Xcode使用你當前的BundleId去該賬戶的開發這中心創建了對應的AppId和描述文件,但是我們既然是作為一個開發流程的記錄,就自己來創建這些東西,所以,我們取消選擇Automatically manage signing選項.此時界面如下:

好了,我們要正式開始我們的工作了GO GO GO!

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:@"推送昵稱"];


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM