這幾天項目里又用到了環(huán)信的推送,雖然之前做過,但是很久不做還是有很多細節(jié)沒有注意到,所以還是決定從頭開始做一遍,把每一個環(huán)節(jié)都詳細記錄下來,同樣的把每一個坑也記錄下來.方便自己以后做的時候忘記哪個流程了可以在看一遍.我很能理解那種遇到問題網上百度一堆類似答案但是并不好使的情況,所以我會將我在項目中遇到的問題都貼出來,希望能給大家?guī)硇┰S參考和幫助,
一.推送的原理和流程(著急做推送的可以跳過這一步)
首先給大家推薦一個介紹推送機制很優(yōu)秀的帖子:http://www.reibang.com/p/e347f999ed95 ,里面關于本地推送和遠程推送的介紹都很詳細,至少我看了感覺還是收獲很多的.尤其是里面有幾張圖片不知道是博主在哪里找的,但是真的是一看就透,太贊了,所以我果斷盜過來了0.0. 這里我對推送的流程做了一個簡單的敘述,力求用最簡單的語言能說明整個推送的機制.
先搬過來一張圖再說
<img src="http://upload-images.jianshu.io/upload_images/692194-fc99211b942ffb8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" >
再搬一張:
<img src="http://upload-images.jianshu.io/upload_images/692194-a1764a5b6ef76592.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
當我們的蘋果手機聯(lián)網的時候,會自動與蘋果的服務器建立長連接,長連接的好處有很多,比如系統(tǒng)升級脖旱、時間校準、數(shù)據(jù)傳輸和響應比較快以及數(shù)據(jù)可以保持最新狀態(tài)等功能.上面這兩張圖片簡單的講述了推送的流程:
- 1.首先我們需要將自己設備的UDID和應用的Bundle Identifier發(fā)送到蘋果的服務器,然后蘋果的服務器會返回給我們一個DeviceToken,這個在我看來就是創(chuàng)建推送證書和描述文件的過程.
- 2.我們將包含手機和應用標示的打包文件上傳到做推送的服務器上去,當我們從推送服務器的后臺發(fā)起推送消息的時候,推送服務器會將我們的DeviceToken和需要發(fā)送的消息Message發(fā)送到蘋果的APNS(Apple push Notification Service)服務器.
- 3.當蘋果的服務器收到DeviceToken和需要發(fā)送的消息Message時,會根據(jù)DeviceToken中的UDID查找設備,根據(jù)DeviceToken中的Bundle Identfier查找該應用,并將Message發(fā)送到該設備上.
下面是以QQ服務器為栗子說明的即時通訊的機制:
<img src="http://upload-images.jianshu.io/upload_images/692194-42cd5b5723039e84.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
圖片已經說得夠詳細明了了,我就不插嘴了,下面開始我們的工程.
二.具體流程
我們創(chuàng)建一個名為TestDemo的工程,我是使用Xcode8.1來開發(fā)的,工程名為PushDemo,創(chuàng)建好的工程界面如下(Xcode8)
從Xcode8之后,Xcode提供了自動管理證書的功能,這個用起來很方便,我目前在工程中用到的最多的地方就是創(chuàng)建好一個Demo之后,如果想真機運行的話,那么只需要在Team選擇框里選擇我的開發(fā)賬戶,接下來下面會出現(xiàn)一個加載提示圈,等它加載完了就可以在真機上運行了,這個過程實際上是Xcode使用你當前的BundleId去該賬戶的開發(fā)這中心創(chuàng)建了對應的AppId和描述文件,但是我們既然是作為一個開發(fā)流程的記錄,就自己來創(chuàng)建這些東西,所以,我們取消選擇Automatically manage signing選項.此時界面如下:
好了,我們要正式開始我們的工作了GO GO GO!
1. 首先我們先去官網創(chuàng)建AppID和描述文件.
我們是要集成推送的,所以我們需要用到cer文件,這個東西實際上就是蘋果給開發(fā)者頒發(fā)的一個證書,我們需要將它導入到我們的AppId配置里,否則的話是無法集成推送的,還記得安裝應該的時候會提示"無法安裝為認證發(fā)布者的應用"之類的信息么,我猜測這個cer文件就是我們身份的標示,使我們開發(fā)的應用可以供人們正常安裝使用,關于證書有一篇很詳細的帖子,希望了解證書之類信息的看官可以去瞅瞅:http://m.blog.csdn.net/article/details?id=8617788
創(chuàng)建cer文件的流程很簡單,打開"鑰匙串訪問"(雖然很好找,但是還是把圖貼出來吧,怕小朋友迷路)
打開鑰匙串之后點擊"從證書頒發(fā)機構請求證書"
郵箱和常用名隨便填寫,記住下面的選擇框選擇"存儲到磁盤"
點擊存儲
已經在桌面保存了
到此,我們已經創(chuàng)建好了cer文件,接著我們去開發(fā)者中心創(chuàng)建AppId和描述文件
2. 創(chuàng)建AppId和描述文件
首先進入開發(fā)者中心,百度搜索Apple Developer,(哎 真的是詳細到家了啊,我都人不下去了)
上圖
輸入開發(fā)者賬戶,登錄進去
你將看到這個頁面
點擊看到:
輸入AppId文件名和BundleId
選中下面的PushNotifications
點擊Continue:
點擊register:
點擊Done回到AppId列表頁面
在AppId列表頁面可以看到我們的AppID了
但是,還沒有完成,因為我們是要做推送的,所以需要上傳我們的cer文件
,點擊我們的AppId,在展開的詳情里可以看到:
Push Notification的兩個指示燈還是黃色的狀態(tài),我們要將它啟用,點擊Edit,在點開的頁面里滑動至底部,記得要選中Push Notification按鈕,接著點擊上方的開發(fā)證書下的創(chuàng)建證書按鈕:
點擊Continue
點擊 choose file:
將我們從開發(fā)機構請求的證書傳上去,之后點擊Register:
點擊Register之后的頁面,點擊download,將其下載到桌面上,download之后記得點擊done完成文件創(chuàng)建:
桌面上的文件:
現(xiàn)在我們就完成了給AppID創(chuàng)建開發(fā)者證書,然后我們要給它創(chuàng)建發(fā)布者證書,點擊Done之后回到AppIds列表,如果找不到的話,點擊右邊的App IDs
點開項目的AppId,此時界面如下,點擊最下面的CreateCertificate,開始給AppID創(chuàng)建發(fā)布者證書,給AppId創(chuàng)建發(fā)布者證書流程跟創(chuàng)建開發(fā)者證書是一樣的!給AppId創(chuàng)建發(fā)布者證書流程跟創(chuàng)建開發(fā)者證書是一樣的!給AppId創(chuàng)建發(fā)布者證書流程跟創(chuàng)建開發(fā)者證書是一樣的!重要的事情說三遍!!因為我不貼出來創(chuàng)建發(fā)布證書的圖了,所以各位根據(jù)創(chuàng)建開發(fā)證書的流程再走一遍就好,同樣也要將發(fā)布者證書下載到本地.:
當創(chuàng)建好之后在回到這個頁面時,應該顯示如下所示:
此時本地我們下載的文件如下:
然后將這兩個證書拖到鑰匙串里,步驟如下:
首先打開鑰匙串:
然后先點擊:系統(tǒng)-證書,然后將兩個文件拖進去,會提示你輸入開機密碼,輸入就好了(建議添加之前先對這個界面截屏,添加完之后可以對比剛剛添加了那些文件)
添加完之后是這個樣子,畫框的是我們的證書
然后選擇左邊的"登錄"選項,可以看到我們剛才創(chuàng)建的證書
選中第一個證書,然后右鍵(你懂得右鍵的意思),選擇導出...
選擇導出為P12文件,存儲在桌面上,獲取到P12文件.對這兩個證書進行同樣的操作.(記得標題有(Develop)的起名為Product文件,第二個證書導出的時候起名為Develop,名字可以自己定,只是為了區(qū)別)
然后會提示你輸入密碼,這里我設置的密碼是zx123456,自己設定好一定要記住,一會兒要用.
然后可以在桌面上看到我們導出的P12文件啦
現(xiàn)在我們就完成了所有的證書的創(chuàng)建,可以去環(huán)信上創(chuàng)建我們的應用啦.
3.創(chuàng)建真機調試文件以及導入到項目中
因為必須要進行真機測試,而且我們關閉了自動管理證書,就導致Xcode8不會自動幫我們生成證書,所以我們要自己創(chuàng)建真機調試證書并導入到項目中去,流程如下:
創(chuàng)建描述文件:
選擇開發(fā)模式,下一步:
選擇對應的AppID,選擇我們剛才創(chuàng)建的AppId:
選擇開發(fā)團隊,我一般都是全選的,下一步:
選擇真機調試的機器,全選,下一步:
下一步:
將創(chuàng)建好的描述文件下載下來,放到桌面上:
創(chuàng)建好的描述文件:
首先選擇debug模式下載的真機調試描述文件:
選擇桌面上剛剛下載的描述文件:
使用同樣的步驟,選擇Release模式下的真機調試文件,一模一樣的操作,不貼圖了.兩個文件都導入進去之后,插上真機,就可以進行真機調試了.
4.在環(huán)信創(chuàng)建我們的應用
首先百度搜索環(huán)信,打開他們的官網,先注冊賬戶,注冊過的可以跳過了,上圖:
注冊的時候選擇"注冊即時通訊云"
注冊的時候需要填寫各種信息,按照格式填寫就好了,填寫完之后登陸,點擊創(chuàng)建應用
填寫應用信息
填寫完如下圖咯
然后需要上傳我們的P12文件,圖片很清晰- -,不多說,第一次我選擇上傳的是生產證書:
第二次上傳開發(fā)證書:
至此,我們的證書開發(fā)也都上傳完了,路漫漫其修遠兮,開始集成環(huán)信到代碼里吧
5.集成環(huán)信到項目中
首先在這里下載最新的SDK(截至到寫本文時最新的SDK為)
http://www.easemob.com/download/im 環(huán)信推送SDK下載鏈接
點擊iOS的最新SDK下載,這里下載的是V3.x的SDK
下載到桌面是這個鬼樣子
我們只需要將畫圈的兩個文件夾導進去工程里就好了,其他的用不上
導進去之后文件列表是這樣,編譯會出錯別急,慢慢改.
向項目里添加需要的庫
上面的圖片是截取的環(huán)信官方文檔,我添加完是這個樣子的:
方便復制庫名的文字:
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.測試是否集成成功
首先,我們去環(huán)信的后臺給我們的應用添加一個用戶
用戶名我設置成了: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:推送證書名,填寫你的開發(fā)證書或者發(fā)布證書名,就是上傳到環(huán)信后臺的兩個中的一個,什么環(huán)境下測試使用什么環(huán)境的證書。
EMOptions *options = [EMOptions optionsWithAppkey:@"1192161108178165#testpushdemo"];
options.apnsCertName = @"Develop";
[[EMClient sharedClient] initializeSDKWithOptions:options];
//登錄環(huán)信 這里使用的是我剛才在環(huán)信后臺創(chuàng)建的賬戶名和密碼,使用這個賬戶登錄,到時候如果在后臺給客戶端發(fā)消息的話,就可以找到該用戶
[[EMClient sharedClient] loginWithUsername:@"13051698888"
password:@"222222"
completion:^(NSString *aUsername, EMError *aError) {
if (!aError) {
NSLog(@"環(huán)信登陸成功");
EMPushOptions *emoptions = [[EMClient sharedClient] pushOptions];
//設置有消息過來時的顯示方式:1.顯示收到一條消息 2.顯示具體消息內容.
//自己可以測試下
emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;
[[EMClient sharedClient] updatePushOptionsToServer];
} else {
NSLog(@"環(huán)信登陸失敗");
}
}];
/**
注冊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];
}
//添加監(jiān)聽在線推送消息
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
return YES;
}
//監(jiān)聽環(huán)信在線推送消息
- (void)messagesDidReceive:(NSArray *)aMessages{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到環(huán)信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
[alertView show];
//aMessages是一個對象,包含了發(fā)過來的所有信息,怎么提取想要的信息我會在后面貼出來.
}
// 將得到的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里是必須重寫的,不然會直接導致推送不成功.其中.需要重點說明的是:
- 只有在應用完全退出被殺掉的狀態(tài)下,才可以收到環(huán)信推送的通知;
- 如果要發(fā)送在線的通知,需要在messagesDidReceive方法里獲取到環(huán)信推送的消息之后給用戶發(fā)起一個本地通知,這個大家可以自己研究下.
- 通過設置emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;(上面代碼有)可以設置有通知過來的時候的顯示方式,顯示一個提示或者顯示完整的消息.
- 上傳證書下面填寫的應用包名毁葱,指的是你的BundleID !!!!我在這里踩了坑垫言,切記!倾剿!.
測試推送:
-
在應用完全退出的情況下(使用在環(huán)信注冊的賬戶登錄一次,確認登錄成功之后再完全退出),選中我們的用戶,點擊發(fā)送消息:
點擊發(fā)送:
測試結果:
2.程序在線的時候測試推送,還是發(fā)送"你好啊",然后我們在messagesDidReceive攔截環(huán)信的EMMessage對象,針對EMMessage對象的解析方式如下,完整的抽取環(huán)信推送消息的方法:
- (void)messagesDidReceive:(NSArray *)aMessages{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到環(huán)信通知" 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(@"大圖的下載狀態(tài) -- %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(@"小圖的下載狀態(tài) -- %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(@"音頻文件的下載狀態(tài) -- %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(@"視頻文件的下載狀態(tài) -- %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(@"縮略圖的下載狀態(tài) -- %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(@"文件文件的下載狀態(tài) -- %u" ,body.downloadStatus);
}
break;
default:
break;
}
}
}
發(fā)送成功之后打印結果如下:
2016-12-01 16:03:26.060088 PushDemo[1392:450230] 收到的文字是 txt -- 你好啊
三.結語
至此,我們就成功集成了環(huán)信推送到我們的項目中.另外提供一些在做推送的時候經常會用到的小方法
- 設置應用圖標右上角數(shù)字角標.
UIApplication *application = [UIApplication sharedApplication]; [application setApplicationIconBadgeNumber:3];
補充一個環(huán)信坑:
編譯通過后筷频,運行的時候爆炸,提示:dyld: Library not loaded: @rpath/Hyphenate.framework/Hyphenate
需要設置Hyphenate.frameword的Embedded Binariew屬性
- 如果推送證書那里沒看特別明白的話,提供一個創(chuàng)建推送證書的鏈接:http://www.reibang.com/p/78282e16db66
- 設置推送過來時候的apns昵稱:
[[EMClient sharedClient] setApnsNickname:@"推送昵稱"];
一直在抽時間寫這篇博客,平常比較忙沒有大塊的時間來寫和記錄這些東西,不過東拼西湊,沒事寫一點最終還是寫完了.希望看到這里的小伙伴都可以成功集成環(huán)信推送,有問題可以在下面留言,我看到了肯定會回復的.希望圍觀的小伙伴可以不吝指點這篇博客中出現(xiàn)的錯誤,不管是文字錯誤還是邏輯錯誤等等,我一定會盡快修正,不給后人留坑.....
給出項目gitHub地址:
https://github.com/TheRuningAnt/PushDemo.git 喜歡的話,記得給小星星哈
簡書上的排版可能有點問題,原博客地址:http://blog.csdn.net/mumubumaopao/article/details/53423393
加入審核被拒交流群前痘,一起交流審核上架經驗吧~~ 群號:689757099