Migration from v2

SDK 3.0 (v3) is a fully innovated chat solution for mobile apps and websites. The structure is elegant and the performance has increased dramatically.

  • OpenChannel and GroupChannel classes are added for the Open Channel and Group Channel related features respectively.
  • UserMessage, FileMessage and AdminMessage are added to handle messages.
  • Callbacks and queries are neatly arranged.

We strongly encourage you in moving to v3 from the previous version and here are the migration tips.


Installation

If you are using CocoaPods, just change the version of dependencies in Podfile at app level (not project level).

// v2 
target 'YOUR_TARGET' do
  pod 'SendBirdSDK', '~> 2.2'
end

// v3
target 'YOUR_TARGET' do
  pod 'SendBirdSDK', '~> 3.0'
end

Authentication

Initialization

You still need to initialize SendBird once when your app begins.

// v2
[SendBird initAppId:APP_ID];

// v3
[SBDMain initWithApplicationId:APP_ID];

Login

login is no longer used in v3. Calling connect just once after init is all you have to do.

// v2
[SendBird loginWithUserId:USER_ID andUserName:USER_NAME]; // When you allow guest login.
[SendBird loginWithUserId:USER_ID andUserName:USER_NAME andUserImageUrl:USER_IMAGE_URL andAccessToken:ACCESS_TOKEN]; // When you allow only permitted user login.

[SendBird setEventHandlerConnectBlock:^(SendBirdChannel *channel) {
    // Connect handler block.
} errorBlock:^(NSInteger code) {

}
...

}];

// v3
[SBDMain connectWithUserId:self.userIdTextField.text completionHandler:^(SBDUser * _Nullable user, SBDError * _Nullable error) { 
    // When you allow guest login.
}];

[SBDMain connectWithUserId:USER_ID accessToken:ACCESS_TOKEN completionHandler:^(SBDUser * _Nullable user, SBDError * _Nullable error) {
    // When you allow only permitted user login.
}];

If you want to update user information such as nickname, profile image or APNS push tokens, now you can use updateCurrentUserInfoWithNickname:profileUrl:completionHandler:, updateCurrentUserInfoWithNickname:profileImage:completionHandler: and registerDevicePushToken:completionHandler: methods after connection is established.


Open Channel (previous Open Chat Channel)

From v3, we call Open Chat Channel as Open Channel. Members having entered an open channel are referred to as Participants of the channel. SBDOpenChannel and SBDOpenChannelListQuery handle Open Channel related features.

Getting a List of open channels

// v2
self.channelListQuery = [SendBird queryChannelList];
[self.channelListQuery nextWithResultBlock:^(NSMutableArray *queryResult) {

}];

// v3
self.openChannelListQuery = [SBDOpenChannel createOpenChannelListQuery];
[self.openChannelListQuery loadNextPageWithCompletionHandler:^(NSArray<SBDOpenChannel *> * _Nullable channels, SBDError * _Nullable error) {

}];

Connecting to an open channel

You don't have to do anything to connect to each open channel in v3. All required connections are automatically made once you have called connect after init. Plus, entering an open channel is much simpler in v3. In v2, you needed to fetch channel URL and call join, queryMessageList and connect.

// v2
[SendBird joinChannel:CHANNEL_URL];
[[SendBird queryMessageListInChannel:CHANNEL_URL prevWithMessageTs:LLONG_MAX andLimit:LIMIT resultBlock:^(NSMutableArray *queryResult) {
    if (queryResult != nil) {
        // Connect to SendBird with max messages timestamp to receive new messages since last query.
        [SendBird connectWithMessageTs:MAX_MESSAGE_TIMESTAMP];
    } 
}];

// v3
[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    [channel enterChannelWithCompletionHandler:^(SBDError * _Nullable error) {

    }];
}];

Disconnecting the open channel

You don't have to do anything to disconnect the open channel in v3. All connections are automatically disconnected when you call disconnect on application termination. If you want a user to leave the open channel, just call exit.

// v2
SendBird.leave(CHANNEL_URL);
SendBird.disconnect();

// v3
[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    [channel exitChannelWithCompletionHandler:^(SBDError * _Nullable error) {

    }];
}];

Sending messages

Mentioned message is NOT currently supported in v3.

// v2
[SendBird sendMessage:MESSAGE];
[SendBird sendMessage:MESSAGE withData:DATA];

[SendBird uploadFile:FILE type:TYPE hasSizeOfFile:SIZE withCustomField:CUSTOM_FIELD uploadBlock:^(SendBirdFileInfo *fileInfo, NSError *error) {
    [SendBird sendFile:fileInfo];
}];

// v3
[openChannel sendUserMessage:MESSAGE data:DATA completionHandler:^(SBDUserMessage * _Nullable userMessage, SBDError * _Nullable error) {

}];
[openChannel sendFileMessageWithBinaryData:FILE filename:FILE_NAME type:FILE_TYPE size:FILE_SIZE data:CUSTOM_DATA completionHandler:^(SBDFileMessage * _Nullable fileMessage, SBDError * _Nullable error) {

}];

Receiving messages

SBDChannelDelegate replaces blocks of [SendBird setEventHandler...]. Multiple delegates are allowed.

// v2
[SendBird setEventHandlerConnectBlock:^(SendBirdChannel *channel) {

} errorBlock:^(NSInteger code) {

} ...

}];

// v3
@interface ChattingViewController : UIViewController<SBDChannelDelegate>

@end

@implementation OpenChannelChattingViewController

- (void)initViewController {
    [SBDMain addChannelDelegate:self identifier:self.description];
}

- (void)dismissCurrentViewController {
    [SBDMain removeChannelDelegateForIdentifier:self.description];
}

- (void)channel:(SBDBaseChannel * _Nonnull)sender didReceiveMessage:(SBDBaseMessage * _Nonnull)message {

}

@end

Loading previous messages

// v2
[[SendBird queryMessageListInChannel:CHANNEL_URL prevWithMessageTs:LLONG_MAX andLimit:LIMIT resultBlock:^(NSMutableArray *queryResult) {

}];

// v3
SBDMessageListQuery *query = [self.channel createMessageListQuery];
[query loadNextMessagesFromTimestamp:EARLIEST_MESSAGE_TIMESTAMP limit:LIMIT reverse:REVERSE_ORDER completionHandler:^(NSArray<SBDBaseMessage *> * _Nullable messages, SBDError * _Nullable error) {

}];

Getting a List of All Participants in an open channel

Participant means online users in a certain open channel. Once a user leaves the open channel, the user is no longer participant of that channel and query does not include him/her.

// v2
SendBirdMemberListQuery *query = [SendBird queryMemberListInChannel:CHANNEL_URL];
[query nextWithResultBlock:^(NSMutableArray *queryResult) {

} errorBlock:^(NSError *error) {

}];

// v3
self.query = [self.channel createParticipantListQuery];
[self.query loadNextPageWithCompletionHandler:^(NSArray<SBDUser *> * _Nullable users, SBDError * _Nullable error) {

}];

Group Channel (previous Messaging Channel)

From v3, we call Messaging Channel as Group Channel. Users having joined a group channel are referred to as Members of the channel. SBDGroupChannel and SBDGroupChannelListQuery handle Group Channel related features.

Creating a group channel

All startMessaging related methods are replaced by createChannel and createChannelWithUserIds.

// v2
[SendBird startMessagingWithUserIds:USER_IDS];

// v3
[SBDGroupChannel createChannelWithUserIds:USER_IDS isDistinct:YES/NO completionHandler:^(SBDGroupChannel * _Nullable channel, SBDError * _Nullable error) {

}];

Getting a list of group channels

// v2
self.channelListQuery = [SendBird queryMessagingChannelList];
[self.channelListQuery nextWithResultBlock:^(NSMutableArray *queryResult) {

}];

// v3
self.groupChannelListQuery = [SBDGroupChannel createMyGroupChannelListQuery];
self.groupChannelListQuery.limit = LIMIT;
self.groupChannelListQuery.order = SBDGroupChannelListOrderChronological;
self.groupChannelListQuery.includeEmptyChannel = YES/OR;

[self.groupChannelListQuery loadNextPageWithCompletionHandler:^(NSArray<SBDGroupChannel *> * _Nullable channels, SBDError * _Nullable error) {

}];

Connecting to the group channel

You don't have to do anything to connect to each group channel in v3. All required connections are automatically made once you have called connect after init.

// v2
[[SendBird queryMessageListInChannel:CHANNEL_URL] loadWithMessageTs:LLONG_MAX prevLimit:PREV_LIMIT andNextLimit:NEXT_LIMIT resultBlock:^(NSMutableArray *queryResult) {
    [SendBird joinChannel:CHANNEL_URL];
    [SendBird connectWithMessageTs:MAX_MESSAGE_TIMESTAMP];
} endBlock:^(NSError *error) {

}];

// v3
// Do nothing.

Disconnecting the group channel

You don't have to do anything to disconnect the group channel in v3. All connections are automatically disconnected when you call disconnect on application termination.

// v2
[SendBird disconnect];

// v3
// Do nothing.

Inviting users to an existing channel

// v2
[SendBird inviteMessagingWithChannelUrl:CHANNEL_URL andUserIds:USER_ID];

// v3
[self.groupChannel inviteUserId:USER_IDS completionHandler:^(SBDError * _Nullable error) {

}];

Removing a user from channel members

// v2
[SendBird endMessagingWithChannelUrl:CHANNEL_URL];

// v3
[channel leaveChannelWithCompletionHandler:^(SBDError * _Nullable error) {

}];

Sending messages

Mentioned message is NOT currently supported in v3.

// v2
[SendBird sendMessage:MESSAGE];
[SendBird sendMessage:MESSAGE withData:DATA];

[SendBird uploadFile:FILE type:TYPE hasSizeOfFile:SIZE withCustomField:CUSTOM_FIELD uploadBlock:^(SendBirdFileInfo *fileInfo, NSError *error) {
    [SendBird sendFile:fileInfo];
}];

// v3
[groupChannel sendUserMessage:MESSAGE data:DATA completionHandler:^(SBDUserMessage * _Nullable userMessage, SBDError * _Nullable error) {

}];
[groupChannel sendFileMessageWithBinaryData:FILE filename:FILE_NAME type:FILE_TYPE size:FILE_SIZE data:CUSTOM_DATA completionHandler:^(SBDFileMessage * _Nullable fileMessage, SBDError * _Nullable error) {

}];

Receiving messages

SBDChannelDelegate replaces blocks of [SendBird setEventHandler...]. Multiple delegates are allowed.

// v2
[SendBird setEventHandlerConnectBlock:^(SendBirdChannel *channel) {

} errorBlock:^(NSInteger code) {

} ...

}];

// v3
@interface ChattingViewController : UIViewController<SBDChannelDelegate>

@end

@implementation OpenChannelChattingViewController

- (void)initViewController {
    [SBDMain addChannelDelegate:self identifier:self.description];
}

- (void)dismissCurrentViewController {
    [SBDMain removeChannelDelegateForIdentifier:self.description];
}

- (void)channel:(SBDBaseChannel * _Nonnull)sender didReceiveMessage:(SBDBaseMessage * _Nonnull)message {

}

@end

Loading previous messages

// v2
[[SendBird queryMessageListInChannel:CHANNEL_URL prevWithMessageTs:LLONG_MAX andLimit:LIMIT resultBlock:^(NSMutableArray *queryResult) {

}];

// v3
SBDMessageListQuery *query = [self.channel createMessageListQuery];
[query loadNextMessagesFromTimestamp:EARLIEST_MESSAGE_TIMESTAMP limit:LIMIT reverse:REVERSE_ORDER completionHandler:^(NSArray<SBDBaseMessage *> * _Nullable messages, SBDError * _Nullable error) {

}];

Monitoring multiple channels

SBDChannelDelegate replaces blocks of [SendBird registerNotificationHandlerMessagingChannel...]. For details, please refer to Event Handler.

// v2
[SendBird registerNotificationHandlerMessagingChannelUpdatedBlock:^(SendBirdMessagingChannel *channel) {

} mentionUpdatedBlock:^(SendBirdMention *mention) {

}];

// v3
@interface ChattingViewController : UIViewController<SBDChannelDelegate>

@end

@implementation OpenChannelChattingViewController

- (void)initViewController {
    [SBDMain addChannelDelegate:self identifier:self.description];
}

- (void)dismissCurrentViewController {
    [SBDMain removeChannelDelegateForIdentifier:self.description];
}
@end

Getting a list of all members

// v2
[messagingChannel members];

// v3
[messagingChannel members];

Typing Indicators

// v2
[SendBird typeStart];
[SendBird typeEnd];

// v3
[groupChannel startTyping];
[groupChannel endTyping];

Getting Read Receipt

From v3, various of methods to get read receipt are possible. You can get a timestamp for a certain member just like in v2 or the automatically calculated read receipt as well.

// v2
long timestamp = [messagingChannel getLastReadMillis:USER_ID];

// v3
long timestamp = [groupChannel getLastSeenAtByUserId:USER_ID];
int unreadCount = [channel getReadReceiptOfMessage:msg];

Broadcasting read status

// v2
[SendBird markAsRead];

// v3
[groupChannel markAsRead];

Channel Metadata

Metadata and metacounter can be created, updated and read in v3 by counter parts of methods in v2.

// v2
[SendBird queryChannelMetaDataWithChannelUrl:CHANNEL_URL] setMetaData:DATA_DICTIONARY resultBlock:^(NSDictionary *response) {

} endBlock:^(NSInteger code) {

}];
[SendBird queryChannelMetaDataWithChannelUrl:CHANNEL_URL] getMetaDataWithKeys:KEYS resultBlock:^(NSDictionary *response) {

} endBlock:^(NSInteger code) {

}];

// v3
[channel createMetaData:DATA_DICTIONARY completionHandler:^(NSDictionary<NSString *,NSString *> * _Nullable metaData, SBDError * _Nullable error) {

}];
[channel updateMetaData:DATA_DICTIONARY completionHandler:^(NSDictionary<NSString *,NSObject *> * _Nullable metaData, SBDError * _Nullable error) {

}];
[channel getMetaDataWithKeys:KEYS completionHandler:^(NSDictionary<NSString *,NSObject *> * _Nullable metaData, SBDError * _Nullable error) {

}];

Metacounter

// v2
[SendBird queryChannelMetaCounterWithChannelUrl:CHANNEL_URL] increaseMetaCounterWithKey:KEY andAmount:AMOUNT resultBlock:^(NSDictionary<NSString*,NSNumber*> *response) {

} endBlock:^(NSInteger code) {

}];
[SendBird queryChannelMetaCounterWithChannelUrl:CHANNEL_URL] getMetaCounterWithKeys:KEYS resultBlock:^(NSDictionary *response) {

} endBlock:^(NSInteger code) {

}];

// v3
[channel increaseMetaCounters:COUNTER_DICTIONARY completionHandler:^(NSDictionary<NSString *,NSNumber *> * _Nullable metaCounters, SBDError * _Nullable error) {

}];
[channel getMetaCountersWithKeys:KEYS completionHandler:^(NSDictionary<NSString *,NSNumber *> * _Nullable metaCounters, SBDError * _Nullable error) {

}];

Event Handler

SendBirdEventHandler, SendBirdSystemEventHandler and SendBirdNotificationHandler are replaced by SBDChannelDelegate. Please refer to Event Handler for details.


Push Notifications

From v3, you have to call registerDevicePushToken:completionHandler: method explicitly after connection is made to register push tokens. Please refer to Push Notifications for details.

// v2 (AppDelegate.m)
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    // We recommend to run the below code when the notification setting of your app is a default value or the setting is true.
    [SendBird registerForRemoteNotifications:devToken];
}

// v3 (AppDelegate.m)
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    // ...

    // Save devToken to your own global variable.
    [SBDMain registerDevicePushToken:tempPushToken completionHandler:^(SBDPushTokenRegistrationStatus status, SBDError * _Nullable error) {
        if (error == nil) {
            if (status == SBDPushTokenRegistrationStatusPending) {
                // Registration is pending.
                // If you get this status, invoke `+ registerDevicePushToken:completionHandler:` with `[SBDMain getPendingPushToken]` after connection.
            }
            else {
                // Registration succeeded.
            }
        }
        else {
            // Registration failed.
        }
    }];
}

// v3 (ViewController.m)
[SBDMain connectWithUserId:self.userIdTextField.text completionHandler:^(SBDUser * _Nullable user, SBDError * _Nullable error) {
    [SBDMain registerDevicePushToken:[SBDMain getPendingPushToken] completionHandler:^(SBDPushTokenRegistrationStatus status, SBDError * _Nullable error) {
        if (error == nil) {
            if (status == SBDPushTokenRegistrationStatusPending) {
                NSLog(@"Push registration is pending.");
            }
            else {
                NSLog(@"APNS Token is registered.");
            }
        }
        else {
            NSLog(@"APNS registration failed.");
        }
    }];
}];