Подпишись на новости Times kz!
USD 335.71 RUB 5.23 EUR 357.36

Как собрать WhatsApp за сутки. Часть 1

В этой серии статей я расскажу, как быстро и почти безболезненно поднять свой собственный WhatsApp под iOS. Статью делю на две части для вашего удобства:

1.Создание проекта, простой UI, привязка к сервису мгновенных сообщений
2.Делаем красивый UI, добавляем видео и аудио звонки, передачу фото и документов


К сожалению, пособие о том, как набрать 400 000 000 пользователей и продать сервис за 19 Инстаграмов, затерялось где-то на книжной полке. Постараюсь его найти, если кому интересно.

Заинтересовавшихся прошу под кат.

Создание проекта

Открываем Xcode и создаем новый проект.
Как собрать WhatsApp за сутки. Часть 1
Берем Single View Application за основу.
Как собрать WhatsApp за сутки. Часть 1
Вводим все данные для приложения и жмем «Next». Я выбрал наименее претенциозные регалии.
Как собрать WhatsApp за сутки. Часть 1
И проект готов.
Как собрать WhatsApp за сутки. Часть 1
Но, что это такое? Какая ужасная сортировка файлов по группам! Давайте это поправим.
Как собрать WhatsApp за сутки. Часть 1
Так-то лучше! Вы можете использовать свой способ сортировки файлов, но в этом руководстве я буду придерживаться модели выше. Кстати говоря, комбинация клавиш для создания новой группы — это Command + Alt + N.

Простой UI

Тем временем, я позволил себе создать новый класс NKLoginViewController и привязать его к UIViewController объекту в Interface Builder. Этот View Controller будет первым, что увидит пользователь. Это и логично — никакого чата без регистрации!
Как собрать WhatsApp за сутки. Часть 1
Продолжая развлекаться, я прикрутил текстовые поля, как Outlet, и Action кнопки «Войти» к нашему NKLoginViewController. Считаю это хорошим тоном, прикручивать IB объекты в .m файлах, дабы они были недоступны извне. Более того, мне нравится, когда код поделен на «Прагмы».
Как собрать WhatsApp за сутки. Часть 1
Создаем еще один контроллер (как представление в IB, так и новый класс) — список чатов. Используем стандартный код UITableViewController — нам никакого сверхъестественного функционала тут не нужно, пока что.
Как собрать WhatsApp за сутки. Часть 1
Слегка изменим код NKChatListTableViewController.m, чтобы в таблице хоть что-то отображалось:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = @"Vasiliy Pupkin";
return cell;
}


Теперь подумаем над навигацией. Все приложение у нас будет встроено в один UINavigationController и контроллеры мы будем «пушить» и «попать» в зависимости от ситуации. Встроим же приложение в UINavigationController! Let the magic time begin!
Как собрать WhatsApp за сутки. Часть 1
Добавляем названия контроллеров и Segue от Login View Controller до Chat List Table View Controller. Назовем ее «SegueToChatList». Вот так выглядит наше приложение сейчас.
Как собрать WhatsApp за сутки. Часть 1
Слегка поработаем над кодом Login View Controller. Дадим пользователю возможность убирать клавиатуру. Для этого мы сделаем контроллер делегатом текстовых полей.
Как собрать WhatsApp за сутки. Часть 1
А сам код контроллера поправим следующим образом:

NKLoginViewController.h
#import <UIKit/UIKit.h>

// Добавим нужный протокол к интерфейсу
@interface NKLoginViewController : UIViewController <UITextFieldDelegate>
@end

NKLoginViewController.m
#import "NKLoginViewController.h"

@interface NKLoginViewController ()

@property (weak, nonatomic) IBOutlet UITextField *emailTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;

- (IBAction)loginTouched:(UIButton *)sender;

@end

@implementation NKLoginViewController

#pragma mark - UITextFieldDelegate -

// Сделаем так, чтобы по нажатию "Done" клавиатура пряталась
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}

#pragma mark - Button methods -

// Пока что просто переместимся на следующий экран по нажатию кнопки "Войти".
- (IBAction)loginTouched:(UIButton *)sender
{
[self performSegueWithIdentifier:@"SegueToChatList" sender:self];
}

На время перенесем все элементы на контроллере логина вверх — это ведь простой UI. О том, как интерактивно перемещать элементы интерфейса вверх при появлении клавиатуры, я расскажу в следующей части.

Наше приложение уже можно потыкать!
Как собрать WhatsApp за сутки. Часть 1
Создаем третий — и последний — контроллер. Попадать в него мы будем при помощи нажатия на ячейку предыдущего контроллера. Сам контроллер состоит из UITableView, источником данных которого назначен контроллер, текстового поля и кнопки «Отправить». Полагаю, этот экран интуитивно понятен.
Как собрать WhatsApp за сутки. Часть 1
Код NKChatViewController.m ниже:
#import "NKChatViewController.h"
@interface NKChatViewController ()
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UITextField *messageTextField;
- (IBAction)sendTouched:(UIButton *)sender;
@end
@implementation NKChatViewController
#pragma mark - View Controller life cycle -

- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Показываем клавиатуру, как только попадаем на контроллер
[_messageTextField becomeFirstResponder];
}
#pragma mark - UITableViewDataSource -

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
cell.textLabel.text = @"Вася Пупкен";
cell.detailTextLabel.text = @"Привет, как дела?";
return cell;
}
#pragma mark - Button methods -

- (IBAction)sendTouched:(UIButton *)sender
{
}
@end

ростенький UI для нашего мессенджера готов. Приступаем к самому интересному — начинке приложения!

Привязка к сервису мгновенных сообщений

В качестве сервиса мгновенных сообщений у нас будет выступать C2Call. Конечно, никто не мешает вам написать свою серверную часть, но это может занять чуть больше 24х часов.

Все, что вам нужно сделать — это зарегистрировать на c2call.com и купить учетку за $100. К сожалению, в бесплатной версии не работает регистрация через low-language API. Возможно, что-то изменится на момент прочтения вами этой статьи. Однако вместо помесячной оплаты C2Call сняли с меня $100 и, похоже, забыли про меня. Больше денег не списывали. Я не призываю вас ни покупать продукт, ни пытать удачу с месячной подпиской. Полагаю, мне просто повезло.

После регистрации, покупки учетки и регистрации приложения на сервисе — это довольно тривиальная задача — качаем SDK. В архиве пара-тройка примеров, как собирать приложения. Нам понадобятся следующие два объекта:
Как собрать WhatsApp за сутки. Часть 1
Переносим их в наш проект.
Как собрать WhatsApp за сутки. Часть 1


И прописываем следующее в Build Settings:

HEADER_SEARCH_PATHS = /usr/include/libxml2
OTHER_LDFLAGS = -lxml2 -lstdc++
ARCHS = armv7
VALID_ARCHS = armv7

Теперь немного поменяем App Delegate:

NKAppDelegate.h
#import <UIKit/UIKit.h>
#import <SocialCommunication/SocialCommunication.h>
@interface NKAppDelegate : C2CallAppDelegate <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

NKAppDelegate.m
@implementation NKAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.affiliateid = @"6B9DF5671444320162B";
self.secret = @"2fd9cd18aa4d957a4030c0455101646d";
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

Мы засабклассили элемент от C2Call, да рассказали ему о наших данных. Ваши Affiliate ID и Secret вы можете посмотреть в админке сервиса.

Закончили с настройкой фреймворка, пора его использовать.

Создадим подкласс NSObject под названием NKChat, в котором мы инкапсулируем всю логику чата. Думаю, будет правильным дать вам примерный листинг кода NKChat.m, а после объяснить его.

NKChat.m


Пойдем по-порядку:

1.Стандартный шаблон — синглтон. Ничего необычного для вас здесь быть не должно. У нас один объект, который отвечает за чат — больше не надо.
2.Метод-аксессор, который возвращает массив истории чата в нужной нам форме.
3.Метод для регистрации и логина. Фишка C2Call в том, что, когда вы входите с одними данными в первый раз, вы регистрируетесь. Когда вы входите с 4.теми же данными второй раз, вы просто входите. Этот метод как-раз и недоступен бесплатным подписчикам, к сожалению. Вы можете обойти этот 5.метод добавив нативное окно регистрации от C2Call, дабы сэкономить.
6.Метод для логаута. Дешево и сердито.
7.Метод для посылки сообщения — тоже довольно прост.
8.Ужасный и монструозный метод-скатерть, который возвращает в нужном формате историю чата. Здесь собраны все камни, о которые можно столкнуться, используя C2Call. Во-первых, данные хранятся в Core Data. Во-вторых, имена контактов постоянно разные — то id придет, то имя и фамилия. В-третьих, забудьте пока что про этот метод. Он работает и для этого туториала сойдет :)

Ну, когда все готово для работы, пора использовать магию кода!

Добавьте в NKAppDelegate.m инициализацию NKChat, если еще не сделали этого.
#import "NKAppDelegate.h"
@implementation NKAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.affiliateid = @"6B9DF5671444320162B";
self.secret = @"2fd9cd18aa4d957a4030c0455101646d";
[NKChat sharedManager];
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end


Теперь слегка изменим метод loginTouched у класса NKLoginViewController. Не забудьте сделать импорт NKChat!
- (IBAction)loginTouched:(UIButton *)sender
{
sender.enabled = NO;
[[NKChat sharedManager] login:_emailTextField.text
password:_passwordTextField.text
success:^{
[self performSegueWithIdentifier:@"SegueToChatList" sender:self];
sender.enabled = YES;
}
failure:^{
sender.enabled = YES;
}];
}


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

В этой части туториала мы будем работать с двумя учетными записями: nikita@borodutch.com и luke@borodutch.com. Мы просто захардкодим возможность отправлять сообщения этим двум контактам, временно.

Слегка изменим NKChatListTableViewController.m таким образом, чтобы можно было отправлять сообщения только этим двум контактам.

#import "NKChatListTableViewController.h"
@interface NKChatListTableViewController ()
@end
@implementation NKChatListTableViewController
#pragma mark - UITableViewDataSource -
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.textLabel.text = (indexPath.row) ? @"nikita@borodutch.com" : @"luke@borodutch.com";
return cell;
}
@end


Результат манипуляций:
Как собрать WhatsApp за сутки. Часть 1
Добавим метод передачи информации в следующий контроллер в NKChatListTableViewController.m.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender
{
UIViewController *dest = segue.destinationViewController;
dest.title = sender.textLabel.text;
}

Нам осталось только получать нужную историю чата и отправлять сообщения нужным контактам! Дело в шляпе, сударь.
Как в старые добрые времена, приведу листинг NKChatViewController.m вместе с объяснениями чуть ниже.


По-порядку:
Как только контроллер загрузился, мы заполняем его нужными данными
kC2CallPhoneReceivedMessage — это дефиниция названия нотификации о том, что пришло новое сообщение; подписываемся на это событие
Нам нужно столько ячеек, сколько всего сообщений есть в истории этого чата
Каждой ячейке даем нужное имя контакта и сообщение
Отправляем сообщение при помощи метода из NKChat; добавляем сообщение в локальные данные контроллера, потому что сообщению нужно время для того, чтобы оно добавилось в историю C2Call; очищаем поле отправки
Метод добавления сообщения в локальные данные контроллера. Полагаю, интуитивно понятен
При получении сообщения нужно перезагрузить историю в контроллере и заставить таблицу обновить свои данные
Просто проходимся по всей истории и возвращаем историю нужного нам контакта

Вот, что у нас получилось (большая гифка):
Как собрать WhatsApp за сутки. Часть 1

Заключение

Огромное спасибо, что дошли до конца первой части этого руководства. В скором времени, как появится пара свободных деньков, напишу вторую часть. Исходный код первой части тут.

Во второй части мы решим несколько щепетильных вопросов по UI, обойдем пару багов C2Call (например, тот, что виден на последней гифке с получением сообщений), добавим функционала приложению и влепим пару-тройку котиков.

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

В случае обнаружения вами опечаток или неточностей в статье, прошу обращаться в мой хабрацентр.

До скорой встречи.

Нашли ошибку? Выделите слово и нажмите Ctrl+Enter

Комментарии

Читайте также

Швейцарец Ив Росси предпочитает перемещаться при помощи реактивного ранца

10:11

«Русская Ким Кардашьян» заверила поклонников в натуральности своих форм

15:58

Появилась первая фотография нового седана Toyota Camry

13:28

Создатели фильма «Менорка» опубликовали провокационные постеры

17:13

В Лос-Анджелесе вручили игровые «Оскары»

13:29

Женщина прогнала "гигантский сперматозоид" с площади

16:08
Азпп
Наверх