iOS —— 極光推送和極光IM

前言

(環境:iOS12.0、極光推送SDK3.1.0、極光IM3.7.0)前端

iOS 推送(蘋果原生態)時,筆者就是爲研究極光打下基礎。git

結果三個月快過去了,筆者猶如鹹魚,一直未開始研究極光,真是墮落啊。github

極光推送的坑 大多都是 蘋果原生態的推送的問題。若是你對蘋果原生態推送不瞭解,建議先看上面筆者寫的小白文章,瞭解原生態的蘋果推送方法及調用時機。數據庫

本文主要記錄一些筆者對極光IM的理解。極光推送略提,弄懂原生態,極光推送就沒什麼難的地方。數組


極光推送的初步瞭解

極光推送的一些小知識

  • 設備標籤(Tag)和設備別名(Alias)

一個設備只能有一個別名,但能有多個標籤。因此別名能夠用userId,針對一個用戶;標籤能夠用用戶所處分組,方便針對目標用戶推送,針對一批用戶。bash

筆者舉一個不那麼恰當的例子。假設想推送裙子消息給男性用戶,那麼前端就能夠綁定性別到Tag。服務器

  • 開發環境和生產環境:

推送證書也分爲開發環境和生產環境。虛擬機和真機調試屬於開發環境。測試包、企業包和App Store屬於生產環境。微信

SDK中,上線時,咱們要改爲生產環境。筆者建議你們弄個宏之類的,到時候別忘了切換。 網絡

經筆者驗證,若是App不是API下載的話,即便參數改爲「1」,也收不到生產環境推送。不過不用擔憂,開發環境和生產環境都是同樣的,開發環境只是讓咱們調試用。app

[JPUSHService setupWithOption:launchOptions
                           appKey:@"***"
                          channel:@"Publish channel"
                 apsForProduction:isProduction
            advertisingIdentifier:nil];
複製代碼
  • IDFA

iOS 6.0+,IDFA爲設備廣告標示符,用於廣告投放。一般不會改變,不一樣App獲取到都是同樣的。但若是用戶徹底重置系統((設置程序 -> 通用 -> 還原 -> 還原位置與隱私) ,這個廣告標示符會從新生成。

IDFA,同一設備下的不一樣app信息共享。

獲取:[[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

可是要注意審覈問題。筆者不用這個就不研究了。在RegistrationID中會再說。

  • RegistrationID

原生是採用deviceToken來標識設備惟一性。在極光中採用RegistrationID。其生成原則優先採用IDFA(若是設備未還原IDFA,卸載App後從新下載,能被識別出老用戶),次採用deviceToken。

集成了 JPush SDK 的應用程序在第一次 App 啓動後,成功註冊到 JPush 服務器時,JPush 服務器會給客戶端返回惟一的該設備的標識 - RegistrationID。

極光推送的消息形式

  • 通知(APNS):手機的通知欄(狀態欄)上會顯示的一條通知信息。
  • 自定義消息(應用內消息):不會被 SDK 展現到通知欄上。自定義消息主要用於應用的內部業務邏輯。朋友圈紅點就能夠用這個。
  • 本地通知:SDK集成蘋果實現本地通知。

極光推送的實現原理

經過咱們的App服務器或極光Web端調用極光的API能發起極光推送。

換言之,開發過程當中,登陸帳號後,將userId(setAlias)綁定到RegistrationID。而後在iOS端發起一個網絡請求到App服務器後(經過目標userId可知 推送目標registrationId),由後臺調用極光API。另外咱們還能經過極光Web端調試,以下圖。

(筆者的親身體驗!!!)iOS開發調試時,儘可能用Web調用調用API。由於咱們不知道後臺的代碼(若是後臺在推送上也是個新手,推送環境或者推送配置字段弄錯了,咱們這半天也收不到推送。。。 )。固然,最後仍是要測試一遍發請求給後臺推送正不正常。

  • 關於自定義消息的原理。

極光採用的是長鏈接。因此自定義消息在網絡正常、App處於前臺的狀況下會立刻收到。

  • 關於通知(APNs)的原理

舉個例子,用戶A(userIdA)發消息給用戶B(userIdB)。這裏只考慮兩個都綁定好了deviceToken等,不存在離線消息。

在蘋果原生態下的流程圖。

在極光下的流程圖。

後臺服務器瘦身。


極光推送的使用

通知

  • iOS7之後的機型實現這些方法
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

官方文檔裏,極光推送就是親生的,IM充話費送的。

官方開發指南並不夠友好,給到的信息少之又少,連基本的通信都沒說清楚,SDK Reference可讀性又差。OC版示例項目也很久不更新了,筆者又須要用OC。。。網上相關的資料也難查。

筆者想要的效果是帳號用App服務器帳號,不額外新建一個。

下面就記錄筆者的研究成果。


接口Code的定義查看官方文檔,本文不處理。IM SDK ErrorCode 定義

極光IM註冊

(默認用userId當IM帳號密碼)。

NSString *userId = @"Hsusue1";
    [JMSGUser registerWithUsername:userId password:userId completionHandler:^(id resultObject, NSError *error) {
        NSLog(@"%@-----%@", resultObject, error);
    }];
複製代碼

註冊成功,resultObject值爲success。

若是已經註冊過這個帳號,回調的error會顯示如下內容。

極光IM登陸

[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就沒這須要。

IM發送消息

注意此處會發送推送和應用內消息。

// 對方的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);
}
複製代碼

IM接收消息

也是在代理方法中(推送調用的方法此處再也不介紹)。

- (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

相關文章
相關標籤/搜索