(環境:iOS12.0、極光推送SDK3.1.0、極光IM3.7.0)前端
寫iOS 推送(蘋果原生態)時,筆者就是爲研究極光打下基礎。git
結果三個月快過去了,筆者猶如鹹魚,一直未開始研究極光,真是墮落啊。github
極光推送的坑 大多都是 蘋果原生態的推送的問題。若是你對蘋果原生態推送不瞭解,建議先看上面筆者寫的小白文章,瞭解原生態的蘋果推送方法及調用時機。數據庫
本文主要記錄一些筆者對極光IM的理解。極光推送略提,弄懂原生態,極光推送就沒什麼難的地方。數組
一個設備只能有一個別名,但能有多個標籤。因此別名能夠用userId,針對一個用戶;標籤能夠用用戶所處分組,方便針對目標用戶推送,針對一批用戶。bash
筆者舉一個不那麼恰當的例子。假設想推送裙子消息給男性用戶,那麼前端就能夠綁定性別到Tag。服務器
推送證書也分爲開發環境和生產環境。虛擬機和真機調試屬於開發環境。測試包、企業包和App Store屬於生產環境。微信
SDK中,上線時,咱們要改爲生產環境。筆者建議你們弄個宏之類的,到時候別忘了切換。 網絡
經筆者驗證,若是App不是API下載的話,即便參數改爲「1」,也收不到生產環境推送。不過不用擔憂,開發環境和生產環境都是同樣的,開發環境只是讓咱們調試用。app
[JPUSHService setupWithOption:launchOptions
appKey:@"***"
channel:@"Publish channel"
apsForProduction:isProduction
advertisingIdentifier:nil];
複製代碼
iOS 6.0+,IDFA爲設備廣告標示符,用於廣告投放。一般不會改變,不一樣App獲取到都是同樣的。但若是用戶徹底重置系統((設置程序 -> 通用 -> 還原 -> 還原位置與隱私) ,這個廣告標示符會從新生成。
IDFA,同一設備下的不一樣app信息共享。
獲取:[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
可是要注意審覈問題。筆者不用這個就不研究了。在RegistrationID中會再說。
原生是採用deviceToken來標識設備惟一性。在極光中採用RegistrationID。其生成原則優先採用IDFA(若是設備未還原IDFA,卸載App後從新下載,能被識別出老用戶),次採用deviceToken。
集成了 JPush SDK 的應用程序在第一次 App 啓動後,成功註冊到 JPush 服務器時,JPush 服務器會給客戶端返回惟一的該設備的標識 - RegistrationID。
經過咱們的App服務器或極光Web端調用極光的API能發起極光推送。
換言之,開發過程當中,登陸帳號後,將userId(setAlias)綁定到RegistrationID。而後在iOS端發起一個網絡請求到App服務器後(經過目標userId可知 推送目標registrationId),由後臺調用極光API。另外咱們還能經過極光Web端調試,以下圖。
(筆者的親身體驗!!!)iOS開發調試時,儘可能用Web調用調用API。由於咱們不知道後臺的代碼(若是後臺在推送上也是個新手,推送環境或者推送配置字段弄錯了,咱們這半天也收不到推送。。。 )。固然,最後仍是要測試一遍發請求給後臺推送正不正常。
極光採用的是長鏈接。因此自定義消息在網絡正常、App處於前臺的狀況下會立刻收到。
舉個例子,用戶A(userIdA)發消息給用戶B(userIdB)。這裏只考慮兩個都綁定好了deviceToken等,不存在離線消息。
在蘋果原生態下的流程圖。
在極光下的流程圖。
後臺服務器瘦身。
1. - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger options))completionHandler;
2. - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler;
3. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0);
4. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
複製代碼
方法一:iOS10+ 點擊推送調用。
方法二:iOS10+ App前臺 收到推送調用。
方法三:iOS10+ ,收到靜默推送或者後臺推送調用。
方法三:iOS7+,iOS10-,先後臺收到任何遠程類型推送調用。
方法四:iOS7+ ~ iOS10-,收到本地推送調用。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[defaultCenter addObserver:self
selector:@selector(receivePushMessage:)
name:kJMSGNetworkDidReceiveMessageNotification // 收到自定義消息
object:nil];
return YES;
}
// 收到自定義消息
- (void)receivePushMessage:(NSNotification *)notification {
NSLog(@"Event - 收到自定義消息");
NSDictionary *info = notification.userInfo;
if (info) {
NSLog(@"The message - %@", info);
} else {
NSLog(@"Unexpected - 沒有用戶信息no user info in jpush mesasge");
}
// 弄個工具類處理
// [PushUtil handleNotification:info];
}
複製代碼
官方文檔裏,極光推送就是親生的,IM充話費送的。
官方開發指南並不夠友好,給到的信息少之又少,連基本的通信都沒說清楚,SDK Reference可讀性又差。OC版示例項目也很久不更新了,筆者又須要用OC。。。網上相關的資料也難查。
筆者想要的效果是帳號用App服務器帳號,不額外新建一個。
下面就記錄筆者的研究成果。
接口Code的定義查看官方文檔,本文不處理。IM SDK ErrorCode 定義
(默認用userId當IM帳號密碼)。
NSString *userId = @"Hsusue1";
[JMSGUser registerWithUsername:userId password:userId completionHandler:^(id resultObject, NSError *error) {
NSLog(@"%@-----%@", resultObject, error);
}];
複製代碼
註冊成功,resultObject值爲success。
若是已經註冊過這個帳號,回調的error會顯示如下內容。
[JMSGUser loginWithUsername:userId password:userId completionHandler:^(id resultObject, NSError *error) {
NSLog(@"%@-----%@", resultObject, error);
// 查看本身IM的我的信息
//JMSGUser *user = [JMSGUser myInfo];
}];
複製代碼
補充點筆者遇到的問題和解決思路,以爲不太好,但願有大神提出更好的方法。
極光IM發送消息,若是接收方沒有註冊,消息會發空,而且不會保存在極光服務器。這就會形成一些問題。
由於App帳號採用後臺的數據(包括我的信息),不肯定這個帳號有沒有註冊過極光IM。App帳號和極光IM帳號是兩個獨立的帳號。
極光IM發送消息不要求極光IM內是好友關係。
App有兩種類型,一種是添加好友,另外一種是企業內規定好友。
第一種就像微信,好友關係由極光IM服務器決定,添加好友後聊天,那就沒有這種問題。能添加好友說明已經註冊了。
另外一種狀況,舉個例,大學教務系統規定了同窗的App帳號,而且同班級內的人都是好友關係。
那麼這時候的好友列表就是老師和同窗(App服務器的數據),這些人不必定都註冊過極光IM,發送消息就會發空。用戶就會莫名其妙,明明看到通信錄有人。。。這時候就要解決這個問題了。
筆者想了好久,這種狀況,註冊功能由iOS端實現的話解決不了。應該由後臺錄入App帳號進數據庫時註冊,才能保證好友的IM帳號不是空的。
另外,後臺修改密碼的接口,記得順便修改IM密碼。筆者的項目中極光IM帳號密碼都是userId就沒這須要。
注意此處會發送推送和應用內消息。
// 對方的Id
NSString *targetId = @"hsusue";
JMSGTextContent *textContent = [[JMSGTextContent alloc] initWithText:@"textContent"];
JMSGMessage *message = [JMSGMessage createSingleMessageWithContent:textContent username:targetId];
[JMSGMessage sendMessage:message];
複製代碼
發送的推送以下
發送結果回調在代理方法中
注意這裏,是add,不是set。意味着只要實現了代理方法的target,都會調用。
- (void)viewDidLoad {
[super viewDidLoad];
// nil表示全部會話的回調都接收
[JMessage addDelegate:self withConversation:nil];
}
- (void)onSendMessageResponse:(JMSGMessage *)message
error:(NSError *)error {
NSLog(@"%@-----%@", message, error);
}
複製代碼
也是在代理方法中(推送調用的方法此處再也不介紹)。
- (void)onReceiveMessage:(JMSGMessage *)message
error:(NSError *)error {
NSLog(@"%@-----%@", message, error);
}
複製代碼
在這裏能夠判斷消息所屬類型,筆者發送了文本消息測試。
下載媒體文件失敗的回調。
- (void)onReceiveMessageDownloadFailed:(JMSGMessage *)message;
複製代碼
極光IM,App本地保存了各個帳號的最近聯繫人列表和聊天記錄。
SDK中JMSGConversation
包含了一堆有用的信息。
這裏只列出部分。
獲取會話及其餘操做
/*!
* @abstract 獲取單聊會話
*
* @param username 單聊對象 username
*
* @discussion 若是會話還不存在,則返回 nil
*/
+ (JMSGConversation * JMSG_NULLABLE)singleConversationWithUsername:(NSString *)username;
/*!
* @abstract 刪除單聊會話
*
* @param username 單聊用戶名
*
* @discussion 除了刪除會話自己,還會刪除該會話下全部的聊天消息。
*/
+ (BOOL)deleteSingleConversationWithUsername:(NSString *)username;
/*!
* @abstract 返回 conversation 列表(異步,已排序)
*
* @param handler 結果回調。正常返回時 resultObject 的類型爲 NSArray,數組裏成員的類型爲 JMSGConversation
*
* @discussion 當前是返回全部的 conversation 列表,不包括聊天室會話,默認是已經排序。
*/
+ (void)allConversations:(JMSGCompletionHandler)handler;
/*!
* @abstract 獲取當前全部會話的未讀消息的總數
*
* @discussion 獲取全部會話未讀消息總數,開啓免打擾的會話未讀數不會加入計數
*/
+ (NSNumber *)getAllUnreadCount;
/*!
* @abstract 同步分頁獲取最新的消息
*
* @param offset 開始的位置。nil 表示從最初開始。
* @param limit 獲取的數量。nil 表示不限。
*
* @return 返回消息列表(數組)。數組成員的類型是 JMSGMessage*
*
* @discussion 排序規則是:最新
*
* 參數舉例:
*
* - offset = nil, limit = nil,表示獲取所有。至關於 allMessages。
* - offset = nil, limit = 100,表示從最新開始取 100 條記錄。
* - offset = 100, limit = nil,表示從最新第 100 條開始,獲取餘下全部記錄。
*/
- (NSArray JMSG_GENERIC(__kindof JMSGMessage *) *)messageArrayFromNewestWithOffset:(NSNumber *JMSG_NULLABLE)offset limit:(NSNumber *JMSG_NULLABLE)limit;
複製代碼
會話對象的屬性。
/*!
* @abstract 會話標題
*/
@property(nonatomic, strong, readonly) NSString * JMSG_NULLABLE title;
/*!
* @abstract 最後一條消息
*/
@property(nonatomic, strong, readonly) JMSGMessage * JMSG_NULLABLE latestMessage;
/*!
* @abstract 會話最近一條消息的建立時間
*
* @discussion 可用於會話排序,單位爲毫秒
*/
@property(nonatomic, strong, readonly) NSNumber *latestMsgTime;
/*!
* @abstract 未讀數
* @discussion 有新消息來時, SDK 會對未讀數自動加 1
*/
@property(nonatomic, strong, readonly) NSNumber * JMSG_NULLABLE unreadCount;
///--------------------------------------------------------
/// @name Conversation Extend Properties 會話擴展屬性:用於聊天
///--------------------------------------------------------
/*!
* @abstract 會話類型 - 單聊,羣聊,聊天室
* @discussion 詳細定義見 JMSGConversationType
*/
@property(nonatomic, assign, readonly) JMSGConversationType conversationType;
/*!
* @abstract 聊天對象
*
* @discussion 須要根據會話類型轉型。單聊時轉型爲 JMSGUser,羣聊時轉型爲 JMSGGroup,聊天時轉型爲 JMSGChatRoom
*
* 注意: 在會話列表上, 請不要使用此屬性, 不然有性能問題. 只在進入聊天界面(單個會話) 時使用此屬性.
*
* 進入會話(聊天界面)後, 訪問會話對象的各類信息, 包括羣聊的羣組成員, 都應使用此屬性,
* 而沒有必要再經過接口查詢 UserInfo / GroupInfo / ChatRoomInfo.
*/
@property(nonatomic, strong, readonly) id target;
/*!
* @abstract 會話目標用戶所在的 appKey
*
* @discussion 這是爲了跨應用聊天而新增的一個字段.
* 若是此字段爲空, 則表示爲默認的主應用.
*
* 單聊會話時, 若是單聊對象用戶不屬於主應用, 則此字段會有值.
*
*/
@property(nonatomic, strong, readonly) NSString *targetAppKey;
複製代碼
看完這些能基本掌握它們的原理,但在推送和UI層上仍存在很多難度。
好比,消息發送失敗在聊天界面展現紅色的感嘆號這個功能。在* iOS 極光IM 集成之旅有探討。
極光也推出了IMUI,github地址:Aurora IMUI