-setFetchProfilesBlock:
.Это блок, предоставленный верхним уровнем (приложением), содержащий информацию о пользователе. ChatKit не заботится о бизнес-логике, такой как псевдонимы пользователей или их аватары. Пользователи могут использовать единственный экземпляр ChatKit для внедрения блока, предоставляющего информацию о пользователе. С помощью этого блока ChatKit может корректно отображать бизнес-логику.
Пример:
Использование:
Во-первых, необходимо создать модель User и следовать протоколу LCCKUserDelegate, в демо это LCCKUser
.
Затем реализовать -setFetchProfilesBlock:
:
#warning Внимание: метод setFetchProfilesBlock должен быть реализован, иначе ChatKit не сможет отображать аватары и псевдонимы пользователей. Ниже представлен цикл, который имитирует синхронное получение информации о пользователях по userIds. Этот код должен быть заменен на вызов API вашего приложения для синхронного запроса.
``` [[LCChatKit sharedInstance] setFetchProfilesBlock:^(NSArray<NSString *> *userIds, LCCKFetchProfilesCompletionHandler completionHandler) {
if (userIds.count == 0) {
NSInteger code = 0;
NSString *errorReasonText = @"Пользовательские идентификаторы отсутствуют";
NSDictionary *errorInfo = @{
@"code" : @(code),
NSLocalizedDescriptionKey : errorReasonText,
};
NSError *error = [NSError errorWithDomain:@"LCChatKitExample"
code:code
userInfo:errorInfo];
!completionHandler ?: completionHandler(nil, error);
return;
}
NSMutableArray *users = [NSMutableArray arrayWithCapacity:userIds.count];
#warning Внимание: ниже представлен цикл, который имитирует синхронное получение информации о пользователях по userIds. Этот код должен быть заменен на вызов API вашего приложения для синхронного запроса.```markdown
#warning Важно: блок completionHandler должен быть выполнен после **получения информации о пользователе**.
!completionHandler ?: completionHandler([users copy], nil);
}];
Обратите внимание: в методе [[LCChatKit sharedInstance] setFetchProfilesBlock:^(NSArray<NSString *> *userIds, LCCKFetchProfilesCompletionHandler completionHandler) { ... }]
параметр userIds
представляет собой коллекцию ClientId
.
Кроме того,
[LCCKUser userWithUserId:user[LCCKProfileKeyPeerId]
name:user[LCCKProfileKeyName]
avatarURL:avatarURL
clientId:clientId];
В этом методе используются два идентификатора: clientId
, который является id
в ChatKit
, и userId
, который является id
пользователя в вашей системе.
Вы можете понять роль clientId
и userId
следующим образом:
clientId
используется для создания диалога, аuserId
используется для получения информации о пользователе, таких как имя и аватар. Эти идентификаторы могут совпадать, но также могут быть разными.
Если у вас есть вопросы по этому методу, вы можете обсудить их в этом issue.
Обратите внимание: способ установки аватара и имени пользователя является пассивным, то есть ChatKit будет вызывать этот блок для получения информации о пользователе только тогда, когда ему нужно отобразить аватар и имя пользователя. Это не означает, что вы активно устанавливаете профиль пользователя в ChatKit.
Важным понятием здесь является ClientId. Для более подробного описания обратитесь к «Обзор услуг реального времени — основные понятия».
При взаимодействии ChatKit с сервером используется только ClientId, но для отображения информации о пользователе в интерфейсе требуется информация из вашей системы пользователей. В этом случае ChatKit вызывает `FetchProfilesBlock`, чтобы получить информацию о пользователе, в основном для получения аватара и имени пользователя.
```Например, в коде выше `userIds` соответствуют `ClientIds`, а `LCCKProfileKeyPeerId` — `UserId` системы пользователей приложения. Все `UserId` и `PeerId`, определенные в интерфейсе `ChatKit`, кроме `userId` в `LCCKUserDelegate`, являются `ClientIds` (если это определенно другой пользователь, а не сам пользователь, например, в списке контактов или в диалоге, используется `PeerId` вместо `UserId`). Рекомендуется устанавливать `UserId` системы пользователей приложения напрямую как `ClientId`. Если `UserId` и `ClientId` не совпадают, необходимо добавить шаги преобразования `clientIds` в `userIds` в методе `-setFetchProfilesBlock:`, а затем использовать `userIds` для вызова API системы пользователей приложения для выполнения запросов.## Кэш профиля```При успешном получении пользователем своего аватара и псевдонима, ChatKit кэширует профиль в памяти. В отношении кэширования профиля (локальное кэширование пока не реализовано, см. обсуждение в [issue](https://github.com/leancloud/ChatKit-OC/issues/28)), если пользователь изменил свой аватар или псевдоним, разработчик должен вызвать соответствующий метод очистки кэша ChatKit для получения нового профиля.```Objective-C
- (void)removeCachedProfileForPeerId:(NSString *)peerId;
- (void)removeAllCachedProfiles;
Можно настроить -[LCChatKit setOpenProfileBlock]
для обработки события нажатия на аватар в списке чатов:
Пример использования:
[[LCChatKit sharedInstance] setOpenProfileBlock:^(NSString *userId, id<LCCKUserDelegate> user, __kindof UIViewController *parentController) {
if (!userId) {
[LCCKUtil showNotificationWithTitle:@"Пользователь не найден" subtitle:nil type:LCCKMessageNotificationTypeError];
return;
}
[self exampleOpenProfileForUser:user userId:userId parentController:parentController];
}];
- (void)exampleOpenProfileForUser:(id<LCCKUserDelegate>)user userId:(NSString *)userId parentController:(__kindof UIViewController *)parentController {
// Можно выполнять различные действия в зависимости от типа чата
NSString *currentClientId = [LCChatKit sharedInstance].clientId;
NSString *title = [NSString stringWithFormat:@"Открыть страницу пользователя\nClientId: %@", userId];
NSString *subtitle = [NSString stringWithFormat:@"Имя: %@", user.name];
if ([userId isEqualToString:currentClientId]) {
title = [NSString stringWithFormat:@"Открыть свою страницу\nClientId: %@", userId];
subtitle = [NSString stringWithFormat:@"Мое имя: %@", user.name];
} else if ([parentController isKindOfClass:[LCCKConversationViewController class]]) {
LCCKConversationViewController *conversationViewController_ = [[LCCKConversationViewController alloc] initWithPeerId:user.clientId ?: userId];
[[self class] pushToViewController:conversationViewController_];
return;
}
[LCCKUtil showNotificationWithTitle:title subtitle:subtitle type:LCCKMessageNotificationTypeMessage];
}
-[LCChatKit setConversationEditActionBlock:]
для настройки пользовательской функции. В демо показано, как добавить левый свайп для отметки непрочитанных сообщений. Подробнее см. в демо.## Настройка контекстного менюПузырьки сообщений в чате по умолчанию поддерживают контекстное меню для копирования. Вы можете использовать [LCChatKit setLongPressMessageBlock:]
для настройки пользовательской функции. В демо показано, как добавить контекстное меню для пересылки сообщений. Подробнее см. в демо.
Настройка пользовательских сообщений может быть выполнена несколькими способами:
Самый простой способ:
Такие сообщения являются кратковременными и не требуют отображения пользовательской ячейки.
Вы можете прослушивать уведомление LCCKNotificationCustomTransientMessageReceived
, чтобы обрабатывать такие сообщения. Обратите внимание, что не только кратковременные сообщения, но и другие типы сообщений могут вызывать это уведомление, поэтому при обработке уведомления необходимо проверять тип сообщения.
Примеры кратковременных сообщений могут включать сообщения в чате прямого эфира, сообщения о лайках и сердечках, которые не сохраняются в истории чата и не отправляются в оффлайн-уведомлениях.
Интерфейсы для отправки сообщений:
// LCCKConversationViewController.h
/*!
* Отправка пользовательского сообщения
*/
- (void)sendCustomMessage:(AVIMTypedMessage *)customMessage;
В демо показан пример использования сообщений VCard (визитная карточка):
Эффект такой, что ChatKit по умолчанию не поддерживает такие сообщения, и требуется настройка пользовательской ячейки:
В руководстве по работе с реальным временем на iOS подробно описаны шаги настройки пользовательских сообщений.
В демо показан пример настройки сообщений VCard:
Определите пользовательское сообщение LCCKVCardMessage
, наследуя от AVIMTypedMessage
и реализуя протокол AVIMTypedMessageSubclassing
.
#pragma mark -
#pragma mark - Переопределение методов
#pragma mark -
#pragma mark - Методы AVIMTypedMessageSubclassing
+ (void)load {
[self registerSubclass];
}
+ (AVIMMessageMediaType)classMediaType {
return kAVIMMessageMediaTypeVCard;
}
При инициализации пользовательского сообщения необходимо учитывать, что нужно добавить три поля, которые используются внутри ChatKit.
-------------|-------------|-------------
degrade | Определяет, как отображать пользовательские сообщения, которые не поддерживаются в старых версиях | Добавляется в словарь атрибутов пользовательского сообщения
typeTitle | Заголовок последнего сообщения в списке недавних диалогов, например, если последнее сообщение — это изображение, можно установить это поле как `@"Изображение"`, что будет отображаться как `[Изображение]` | Добавляется в словарь атрибутов пользовательского сообщения
summary | Отображается в уведомлении push | Добавляется в словарь атрибутов пользовательского сообщения, используется для удобства настройки содержимого push-уведомлений, что требует использования облачного сервера
conversationType | Отображается в уведомлении push | Добавляется в словарь атрибутов пользовательского сообщения, тип диалога, используется для отображения в уведомлении push, чтобы добиться такого эффекта: `[Групповой чат] Tom: привет, ребята!` | Определяется с помощью перечисления LCCKConversationType, 0 — для личных сообщений, 1 — для групповыхВсе три поля должны быть добавлены в словарь атрибутов пользовательского сообщения. ChatKit предоставляет метод для удобства добавления `-lcck_setObject:forKey:` , который используется следующим образом:
```Objective-C
/*!
* Три обязательных поля:
* - degrade Определяет, как отображать пользовательские сообщения, которые не поддерживаются в старых версиях
* - typeTitle Заголовок последнего сообщения в списке недавних диалогов, например, если последнее сообщение — это изображение, можно установить это поле как `@"Изображение"`, что будет отображаться как `[Изображение]`.
* - summary Отображается в уведомлении push
* @attention Обязательно добавьте эти три поля, они используются внутри ChatKit.
*/
- (instancetype)initWithClientId:(NSString *)clientId {
self = [super init];
if (!self) {
return nil;
}
[self lcck_setObject:@"Бизнес-карта" forKey:LCCKCustomMessageTypeTitleKey];
[self lcck_setObject:@"Это бизнес-карта, текущая версия слишком старая для отображения, пожалуйста, обновите приложение для просмотра" forKey:LCCKCustomMessageDegradeKey];
[self lcck_setObject:@"Вам отправили бизнес-карту, пожалуйста, откройте приложение для просмотра" forKey:LCCKCustomMessageSummaryKey];
[self lcck_setObject:clientId forKey:@"clientId"];
return self;
}
Наследует LCCKChatMessageCell
и следует протоколу LCCKChatMessageCellSubclassing
. Переопределяет методы родительского класса:Важно, чтобы метод +classMediaType
возвращал тип, соответствующий типу пользовательского сообщения:
#pragma mark -
#pragma mark - Методы протокола LCCKChatMessageCellSubclassing
+ (void)load {
[self registerCustomMessageCell];
}
+ (AVIMMessageMediaType)classMediaType {
return kAVIMMessageMediaTypeVCard;
}
Переопределяет следующие методы родительского класса:
- (void)setup;
- (void)configureCellWithData:(AVIMTypedMessage *)message;
Размещение элементов производится в методе -setup
. По умолчанию не добавляются изображения профиля, псевдонимы и т.д. Если требуется добавить, необходимо использовать метод addSubview
. Если элементы добавлены, они будут участвовать в выравнивании, которое уже реализовано в методе -setup
родительского класса.
Рекомендуется использовать AutoLayout для размещения элементов. Если вы правильно ограничили self.contentView
, ChatKit автоматически рассчитает высоту ячейки. Если вы не ограничили self.contentView
, вам потребуется дополнительно предоставить размеры ячейки:
-systemLayoutSizeFittingSize:
-sizeThatFits:
Пример:
- (CGSize)sizeThatFits:(CGSize)size {
return CGSizeMake(size.width, A + B + C + D + E + ...);
}
Для более подробной информации обратитесь к документации.
Пример использования в демонстрационном приложении:```Objective-C #pragma mark - #pragma mark - Переопределенные методы
(void)setup { [self.vCardView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.contentView).with.insets(UIEdgeInsetsMake(LCCK_MSG_SPACE_TOP, LCCK_MSG_SPACE_LEFT, LCCK_MSG_SPACE_BTM, LCCK_MSG_SPACE_RIGHT)); }]; [self updateConstraintsIfNeeded]; [super setup]; }
(void)configureCellWithData:(AVIMTypedMessage *)message { [super configureCellWithData:message]; NSString *clientId; NSString *name = nil; NSURL *avatarURL = nil; clientId = [message.attributes valueForKey:@"clientId"]; [[LCChatKit sharedInstance] getCachedProfileIfExists:clientId name:&name avatarURL:&avatarURL error:nil]; if (!name) { name = clientId; } if (!name) { name = @"Неизвестный пользователь"; }
[self.vCardView configureWithAvatarURL:avatarURL title:name clientId:clientId]; }
Для определения нажатия на пользовательский Cell необходимо самостоятельно определить и отреагировать на это в пользовательском Cell. В демо используется добавление тап-геста.
### Пользовательский плагин для ввода
Использование аналогично пользовательскому сообщению и пользовательскому Cell:
Наследуйте `LCCKInputViewPlugin`, следуйте и реализуйте протокол `LCCKInputViewPluginSubclassing`:
```Objective-C
#pragma mark -
#pragma mark - LCCKInputViewPluginSubclassing Method
+ (void)load {
[self registerCustomInputViewPlugin];
}
+ (LCCKInputViewPluginType)classPluginType {
return LCCKInputViewPluginTypeVCard;
}
Для пользовательской настройки интерфейса необходимо реализовать методы LCCKInputViewPluginDelegate
:
#pragma mark -
#pragma mark - LCCKInputViewPluginDelegate Method
/**
* Иконка плагина
*/
- (UIImage *)pluginIconImage {
return [self imageInBundlePathForImageName:@"chat_bar_icons_location"];
}
``````markdown
/**
* Название плагина
*/
- (NSString *)pluginTitle {
return @"Визитка";
}
/**
* Пользовательский интерфейс плагина, который будет загружен на inputView
*/
- (UIView *)pluginContentView {
return nil;
}
/**
* Пользовательский интерфейс плагина был выбран и запущен
*/
- (void)pluginDidClicked {
[super pluginDidClicked];
[self presentSelectMemberViewController];
}
/**
* Обработчик отправки пользовательского сообщения
*/
- (LCCKIdResultBlock)sendCustomMessageHandler {
if (_sendCustomMessageHandler) {
return _sendCustomMessageHandler;
}
LCCKIdResultBlock sendCustomMessageHandler = ^(id object, NSError *error) {
LCCKVCardMessage *vCardMessage = [LCCKVCardMessage vCardMessageWithClientId:object];
[self.conversationViewController sendCustomMessage:vCardMessage progressBlock:^(NSInteger percentDone) {
} success:^(BOOL succeeded, NSError *error) {
[self.conversationViewController sendLocalFeedbackTextMessage:@"Визитка отправлена"];
} failed:^(BOOL succeeded, NSError *error) {
[self.conversationViewController sendLocalFeedbackTextMessage:@"Визитка не отправлена"];
}];
// важно: избегайте циклической ссылки!
_sendCustomMessageHandler = nil;
};
_sendCustomMessageHandler = sendCustomMessageHandler;
return sendCustomMessageHandler;
}
Проблема сортировки плагинов:
Правила приоритета сортировки:
### Удаление персонализированных плагинов, сообщений и ячеек
Если необходимо удалить плагин, например, в демонстрации был создан персонализированный плагин для визитки, чтобы удалить его, достаточно удалить следующий код из класса LCCKInputViewPluginVCard, хотя удаление всего класса также достигнет этой цели:
```Objective-C
+ (void)load {
[self registerCustomInputViewPlugin];
}
И поскольку VCard удалён, то пользовательские типы также будут прерваны и не будут последовательными, например, в демонстрации тип VCard равен 1,
перед удалением: -1, -2, -3, 1, 2, 3, а после удаления: -1, -2, -3, 2, 3, что делает последовательность несуществующей. Вам потребуется перенастроить типы, чтобы они снова стали последовательными, то есть изменить 2 на 1, а 3 на 2, чтобы типы начинались с 1 и увеличивались последовательно. Подробнее см. обсуждение проблемы: программа падает после удаления плагина.Кроме того, поскольку один плагин обычно сопровождается персонализированным Cell и сообщением, эти элементы также следует удалить:
Удаление персонализированных сообщений:
+ (void)load {
[self registerSubclass];
}
из класса LCCKVCardMessage.
Удаление персонализированных Cell:
+ (void)load {
[self registerCustomMessageCell];
}
из класса LCCKVCardMessageCell.
Также можно удалить соответствующие классы, чтобы достичь того же результата.
ChatKit поддерживает интернационализацию в основных процессах (чаты, списки сообщений и связанные страницы), разработчики могут поддерживать локализацию с минимальными усилиями, просто создавая персонализированный Other.bundle (CustomizedChatKit.Other.bundle) и изменяя или добавляя соответствующие локализованные файлы.
Этот файл обновляется постепенно при каждом выпуске ChatKit, новые элементы добавляются в конец файла с временными метками, что позволяет разработчикам быстро находить новые ключи.
Можно использовать интерфейс -[LCChatKit setSendMessageHookBlock:]
, чтобы перехватить поведение отправки сообщений. Это позволяет реализовать черный список, локальное фильтрование чувствительных слов и другие бизнес-функции. Конкретные способы использования:```Objective-C
// См. LCChatKitExample+Setting.m
(void)lcck_setupSendMessageHook { [[LCChatKit sharedInstance] setSendMessageHookBlock:^(LCCKConversationViewController *conversationController, __kindof AVIMTypedMessage *message, LCCKSendMessageHookCompletionHandler completionHandler) { if ([message.clientId isEqualToString:@"Jerry"]) { NSInteger code = 0; NSString *errorReasonText = @"Запрещено отправлять сообщения Jerry"; NSDictionary *errorInfo = @{ @"code":@(code), NSLocalizedDescriptionKey : errorReasonText, }; NSError *error = [NSError errorWithDomain:NSStringFromClass([self class]) code:code userInfo:errorInfo];
completionHandler(NO, error);
[conversationController sendLocalFeedbackTextMessage:errorReasonText];
} else {
completionHandler(YES, nil);
}
}]; }
Используя интерфейс `-[LCChatKit setFilterMessagesBlock:]`, можно перехватить новые сообщения, включая реальные сообщения и сообщения из истории.
В демонстрационном примере показано, как реализовать групповые целевые сообщения:```Objective-C
- (instancetype)initWithClientId:(NSString *)clientId conversationType:(LCCKConversationType)conversationType {
self = [super init];
if (!self) {
return nil;
}
[self lcck_setObject:@"Визитка" forKey:LCCKCustomMessageTypeTitleKey];
[self lcck_setObject:@"Это сообщение визитки, текущая версия слишком старая для отображения, попробуйте обновить приложение для просмотра" forKey:LCCKCustomMessageDegradeKey];
[self lcck_setObject:@"Кто-то отправил вам сообщение визитки, пожалуйста, откройте приложение для просмотра" forKey:LCCKCustomMessageSummaryKey];
[self lcck_setObject:@(conversationType) forKey:LCCKCustomMessageConversationTypeKey];
[self lcck_setObject:clientId forKey:@"clientId"];
//Целевое сообщение для группы, видимо только для части пользователей, необходимо реализовать `-setFilterMessagesBlock:`, подробнее см. LCChatKitExample
[self lcck_setObject:@[ @"Том", @"Джерри"] forKey:LCCKCustomMessageOnlyVisiableForPartClientIds];
return self;
}
``````Objective-C
[[LCChatKit sharedInstance] setFilterMessagesBlock:^(AVIMConversation *conversation, NSArray<AVIMTypedMessage *> *messages, LCCKFilterMessagesCompletionHandler completionHandler) {
if (conversation.lcck_type == LCCKConversationTypeSingle) {
completionHandler(messages ,nil);
return;
}
// групповой чат
NSMutableArray *filterMessages = [NSMutableArray arrayWithCapacity:messages.count];
for (AVIMTypedMessage *typedMessage in messages) {
if ([typedMessage.clientId isEqualToString:[LCChatKit sharedInstance].clientId]) {
[filterMessages addObject:typedMessage];
continue;
}
NSArray *visiableForPartClientIds = [typedMessage.attributes valueForKey:LCCKCustomMessageOnlyVisiableForPartClientIds];
if (!visiableForPartClientIds) {
[filterMessages addObject:typedMessage];
} else if (visiableForPartClientIds.count > 0) {
BOOL visiableForCurrentClientId = [visiableForPartClientIds containsObject:[LCChatKit sharedInstance].clientId];
if (visiableForCurrentClientId) {
[filterMessages addObject:typedMessage];
} else {
typedMessage.text = @"Это групповое сообщение, видимое только некоторым участникам";
typedMessage.mediaType = kAVIMMessageMediaTypeText;
[filterMessages addObject:typedMessage];
}
}
}
completionHandler([filterMessages copy] ,nil);
}];
По умолчанию сообщения отображаются в стиле, подобном WeChat. Если вы хотите настроить это, вы можете использовать следующий метод:
// Замените стиль предварительного просмотра изображений по умолчанию
[[LCChatKit sharedInstance] setPreviewImageMessageBlock:^(NSUInteger index, NSArray *allVisibleImages, NSArray *allVisibleThumbs, NSDictionary *userInfo) {
[self examplePreviewImageMessageWithInitialIndex:index allVisibleImages:allVisibleImages allVisibleThumbs:allVisibleThumbs];
}];
```#### Предварительный просмотр местоположения
Вы можете настроить предварительный просмотр местоположения с помощью метода `[LCChatKit setPreviewLocationMessageBlock:]`:
```Objective-C
[[LCChatKit sharedInstance] setPreviewLocationMessageBlock:^(CLLocation *location, NSString *geolocations, NSDictionary *userInfo) {
[self examplePreViewLocationMessageWithLocation:location geolocations:geolocations];
}];
По умолчанию chatKit устанавливает количество непрочитанных сообщений для стиля TabBar. Если используется другой стиль, необходимо реализовать этот блок для установки значка Badge:
// Если используется другой стиль, необходимо реализовать этот блок для установки значка Badge.
[[LCChatKit sharedInstance] setMarkBadgeWithTotalUnreadCountBlock:^(NSInteger totalUnreadCount, UIViewController *controller) {
[self exampleMarkBadgeWithTotalUnreadCount:totalUnreadCount controller:controller];
}];
Если пользователь был отключен из-за единого входа или нажал на красную полосу в верхней части экрана чата, chatKit выполнит блок ForceReconnectSessionBlock
. Необходимо настроить [LCChatKit setForceReconnectSessionBlock:]
, чтобы chatKit мог выполнить логику повторного подключения.
По умолчанию единственный вход в систему включен. Если его нужно отключить, необходимо настроить [LCChatKit setDisableSingleSignOn:]
.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )