Статьи

Создание клиента Jabber для iOS: настройка интерфейса

В этом уроке мы создадим Jabber-клиент для iOS. Приложение, разработанное в этой серии, позволит пользователям входить в систему, добавлять друзей и отправлять сообщения. Этот учебник будет посвящен настройке пользовательского интерфейса для примера клиента чата.

Ядро нашего приложения Jabber построено на возможностях XMPP. Мы будем хранить эти функции в главном делегате приложения, который будет реализовывать собственный протокол для отправки событий, таких как вход в систему и отправка сообщений. Приложение, которое мы собираемся создать, основано на трех видах: логин, список друзей и чат.

iOS Client Views

Список друзей — это представление по умолчанию, которое отображается при запуске приложения. Он показывает список онлайн-друзей. Вид входа в систему появится только в том случае, если на устройстве ранее не было сохранено никаких учетных данных. Кнопка с именем «Аккаунт» покажет вид входа в систему из списка друзей, чтобы при необходимости можно было изменить учетные данные для входа. Вид чата отображается при нажатии на собеседника в сети, чтобы начать чат. Мы создадим контроллер представления для каждого из этих представлений. Контроллеры реализуют простой протокол для получения уведомлений, отправляемых делегатом приложения. Для простоты вход в систему и просмотр чата будут отображаться как модальный контроллер просмотра. Если хотите, вы можете переработать приложение, чтобы вместо него использовать навигационный контроллер.

Давайте откроем Xcode и начнем новый проект. Мы выберем приложение на основе простого представления и назовем его «JabberClient». Чтобы взаимодействовать с сервером, мы примем удобную библиотеку для iOS, которая называется фреймворк XMPP . Эта библиотека совместима с приложениями Mac и iOS и поможет нам в реализации низкоуровневых функций для подключения к серверу XMPP и управления обменом сообщениями через сокеты. Поскольку в репозитории нет ссылки на скачивание, вам нужно установить git (см. Здесь для получения дополнительной информации). После того, как вы установили git, вы можете ввести в консоли следующую команду:

git clone https://code.google.com/p/xmppframework/ xmppframework

После завершения загрузки мы должны получить папку, подобную следующей:

Папки XMPP Framework

Нам нужны только папки, выделенные на картинке. После выбора мы перетаскиваем их на проект, чтобы включить их. Просто не забудьте поставить галочку «Копировать элементы в папку целевой группы (при необходимости)».

Импорт XMPP Framework

Нам не нужна интеграция с Facebook, поэтому в группе «Расширения» мы можем удалить папку «X-FACEBOOK-PLATFORM».

Удаление части Facebook

Теперь давайте добавим необходимые рамки. Мы выбираем проект в навигаторе, затем выбираем цель и открываем «Link Binary With Libraries», как показано на рисунке.

Добавление фреймворков для Proejct

Мы должны добавить множество фреймворков, как показано на следующем рисунке:

Список рамок, необходимых для проекта

Наконец, для компиляции проекта нам нужно настроить некоторые параметры сборки. Изменения должны быть добавлены как к проекту, так и к цели. Сначала мы находим «Пути поиска по заголовкам пользователей» и указываем библиотеку, необходимую для разбора xml: ‘/ usr / include / libxml2’

Включая библиотеку xml2

Затем мы выбираем «Другие флаги компоновщика» и добавляем следующий флаг: «-lxml2».

Включая библиотеку xml2

Теперь проект настроен правильно, и вы сможете его построить без ошибок и предупреждений.

Список друзей содержит табличное представление, которое показывает список онлайн-контактов. При нажатии на него отображается соответствующий вид чата. Мастер проекта уже создал контроллер представления, который мы будем переименовывать в BuddyListViewController для большей согласованности. Этот контроллер будет иметь UITableView и массив для хранения онлайн-контактов. Он также будет иметь IBAction для отображения вида входа в систему, если пользователь хочет сменить аккаунт. Кроме того, он будет реализовывать делегаты табличного представления Поэтому мы обновляем файл реализации следующим образом.

01
02
03
04
05
06
07
08
09
10
11
12
@interface JabberClientViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
 
    UITableView *tView;
    NSMutableArray *onlineBuddies;
 
}
 
@property (nonatomic,retain) IBOutlet UITableView *tView;
 
— (IBAction) showLogin;
 
@end

В файле реализации мы синхронизируем свойство и добавляем стандартные методы для управления
вид таблицы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
@implementation JabberClientViewController
 
@synthesize tView;
 
— (void)viewDidLoad {
 
        [super viewDidLoad];
    self.tView.delegate = self;
    self.tView.dataSource = self;
    onlineBuddies = [[NSMutableArray alloc ] init];
 
}
 
— (void) showLogin {
 
    // show login view
 
}
 
#pragma mark —
#pragma mark Table view delegates
 
— (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
        NSString *s = (NSString *) [onlineBuddies objectAtIndex:indexPath.row];
        static NSString *CellIdentifier = @»UserCellIdentifier»;
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        }
 
        cell.textLabel.text = s;
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
 
        return cell;
 
}
 
— (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 
    return [onlineBuddies count];
 
}
 
— (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 
    return 1;
 
}
 
— (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 
    // start a chat
 
}
 
@end

Соответствующий файл xib будет иметь табличное представление и панель инструментов с элементом кнопки панели, как показано на следующем рисунке:

Разработка списка друзей

Мы должны помнить, чтобы связать табличное представление и действие showLogin с их соответствующими выходами, как показано ниже:

Список друзей

Если мы запустим приложение, мы должны увидеть пустую таблицу, как на следующем скриншоте:

Список друзей во время выполнения

Мы можем приостановить реализацию этого класса на некоторое время. Когда мы будем готовы, мы интегрируем функции XMPP. А пока давайте перейдем к логину.

Это представление отображается, когда пользователь еще не ввел учетные данные для входа или когда нажата кнопка «Учетная запись». Он состоит из двух полей ввода и кнопки. Дополнительное действие позволит пользователю скрыть представление без изменений.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@interface SMLoginViewController : UIViewController {
 
    UITextField *loginField;
    UITextField *passwordField;
 
}
 
@property (nonatomic,retain) IBOutlet UITextField *loginField;
@property (nonatomic,retain) IBOutlet UITextField *passwordField;
 
— (IBAction) login;
— (IBAction) hideLogin;
 
@end

Реализация довольно проста. Когда инициируется действие входа в систему, данные в NSUSerDefaults сохраняются в NSUSerDefaults с двумя ключами «userID» и «userPassword». Эти данные будут использованы механизмом XMPP и отправлены на сервер.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
@implementation SMLoginViewController
 
@synthesize loginField, passwordField;
 
— (IBAction) login {
 
    [[NSUserDefaults standardUserDefaults] setObject:self.loginField.text forKey:@»userID»];
    [[NSUserDefaults standardUserDefaults] setObject:self.passwordField.text forKey:@»userPassword»];
    [[NSUserDefaults standardUserDefaults] synchronize];
 
    [self dismissModalViewControllerAnimated:YES];
 
}
 
— (IBAction) hideLogin {
 
    [self dismissModalViewControllerAnimated:YES];
 
}
 
@end

Как и выше, мы не должны связывать текстовые поля и действия в файле XIB.

Проектирование вида входа в систему

Теперь мы можем обновить контроллер BuddyList, чтобы при необходимости отображать вид входа в систему. Мы импортируем соответствующий класс и обновляем действие следующим образом.

1
2
3
4
5
6
— (IBAction) showLogin {
 
    SMLoginViewController *loginController = [[SMLoginViewController alloc] init];
    [self presentModalViewController:loginController animated:YES];
 
}

Мы также реализуем функцию viewDidAppear чтобы она отображала представление входа в систему, когда данные не сохраняются.

01
02
03
04
05
06
07
08
09
10
11
12
— (void)viewDidAppear:(BOOL)animated {
 
    [super viewDidAppear:animated];
 
    NSString *login = [[NSUserDefaults standardUserDefaults] objectForKey:@»userID»];
 
    if (!login) {
 
        [self showLogin];
 
    }
}

Если мы скомпилируем приложение, то увидим, что окно входа в систему выглядит так, как ожидается, или когда пользователь нажимает кнопку.

Представление чата имеет четыре визуальных элемента:

  • панель инструментов с кнопкой, чтобы закрыть вид
  • текстовое поле для ввода сообщений
  • кнопка для отправки сообщений
  • табличное представление для отображения отправленных и полученных сообщений
Проектирование вида чата

Заголовочный файл имеет следующий вид:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@interface SMChatViewController : UIViewController {
 
UITextField *messageField;
NSString *chatWithUser;
UITableView *tView;
NSMutableArray *messages;
 
}
 
@property (nonatomic,retain) IBOutlet UITextField *messageField;
@property (nonatomic,retain) NSString *chatWithUser;
@property (nonatomic,retain) IBOutlet UITableView *tView;
 
— (id) initWithUser:(NSString *) userName;
— (IBAction) sendMessage;
— (IBAction) closeChat;
 
@end

Подобно представлению друзей, этот класс реализует делегаты таблицы. Он отслеживает полученное с помощью строковой переменной chatWithUser и имеет два действия: closeChat и sendMessage . Соответствующая реализация заключается в следующем.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@implementation SMChatViewController
 
@synthesize messageField, chatWithUser, tView;
 
— (void)viewDidLoad {
 
    [super viewDidLoad];
    self.tView.delegate = self;
    self.tView.dataSource = self;
    messages = [[NSMutableArray alloc ] init];
 
    [self.messageField becomeFirstResponder];
 
}
 
#pragma mark —
#pragma mark Actions
 
— (IBAction) closeChat {
 
    [self dismissModalViewControllerAnimated:YES];
 
}
 
— (IBAction)sendMessage {
 
    NSString *messageStr = self.messageField.text;
 
    if([messageStr length] > 0) {
 
        // send message through XMPP
 
       self.messageField.text = @»»;
 
       NSString *m = [NSString stringWithFormat:@»%@:%@», messageStr, @»you»];
 
       NSMutableDictionary *m = [[NSMutableDictionary alloc] init];
       [m setObject:messageStr forKey:@»msg»];
       [m setObject:@»you» forKey:@»sender»];
 
       [messages addObject:m];
       [self.tView reloadData];
       [m release];
 
    }
 
}
 
#pragma mark —
#pragma mark Table view delegates
 
— (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    NSDictionary *s = (NSDictionary *) [messages objectAtIndex:indexPath.row];
    static NSString *CellIdentifier = @»MessageCellIdentifier»;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }
 
    cell.textLabel.text = [s objectForKey:@»msg»];
    cell.detailTextLabel.text = [s objectForKey:@»sender»];
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.userInteractionEnabled = NO;
 
    return cell;
 
}
 
— (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 
    return [messages count];
 
}
 
— (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 
    return 1;
 
}
 
#pragma mark —
#pragma mark Chat delegates
 
// react to the message received
 
— (void)dealloc {
 
    [messageField dealloc];
    [chatWithUser dealloc];
    [tView dealloc];
    [super dealloc];
 
}

Когда представление загружено, мы показываем клавиатуру. Часть таблицы очень похожа на вид друзей. Здесь мы используем немного другой тип ячейки таблицы для отображения как сообщения, так и имени. Ниже приведен предполагаемый результат, когда приложение готово:

Просмотр чата во время выполнения

Не забудьте связать свойства IBAction с соответствующими кнопками как обычно.

Чат Просмотр торговых точек

Визуальная часть нашего приложения готова! Теперь мы остались с основной функциональностью обмена сообщениями, и это будет рассмотрено в следующей части этой серии!

Полный исходный код этого проекта можно найти на GitHub здесь .