Pull to refresh

История одного пасхального приложения

Reading time6 min
Views6K

Не яйца красят человека, а человек красит яйца


Лучок, свекла, старый галстук, цветные нитки — сколько способов раскраски яиц знаете вы? Сегодня мы расскажем еще об одном, придуманном нами.

image

Набить морду павлину


Яйца раскрасить — не картошки пожарить.

Для каждой палитры есть подходящий материал, а когда речь идет о продукте, который потом еще и съедается — не хочется делать это как попало.

image

Можно!

Все, что вам понадобится — это iPhone, хотя на первых порах можно обойтись и без него. Главное — припасите яиц.

Нарисовав первые прототипы интерфейса мы прикинули, сколько у нас будет разметок, орнаментов, как они будут выглядеть и, наконец, отправились готовить контент для приложения. Спустя несколько дней у нас получилось немного-немало 350 разных орнаментов для 5 цветов и 5 разметок.

“Мотор, камера… Экшн!”


Тут же были нарисованы первые прототипы, на которых были распределены основные экраны приложения, доступный функционал и основная механика расраски. Естественно, все тестировалось на яйцах.

image

Казалось, что при такой простой задаче должно найтись множество способов оформить идею в интерфейсе, однако, оставалось противоречивое мнение по разным мелочам, вроде “нужно ли переключаться на следующий этап редактирования при выборе какой-то зоны, или нет?” и так далее

image

Каждое яйцо было заботливо отрендерено вручную — на это ушло немало времени.
“Почему бы не рендерить в самом приложении по модели?” — спросите вы. Отвечаем: каждый орнамент натягивался на яйцо по-своему — такую работу нельзя доверить роботам.

Подводные яйца


Первую версию мы сделали на Кокосе, и основные сложности были только со скрещиванием объектов сцены с наследниками UIView, но и это можно решить, разбив объекты по разным сценам.

image

Задача, которая появилась на горизонте: слишком много картинок, нужно уложиться в 50 мегабайт (на дворе был 2013, в iOS 7 лимит увеличился вдвое), иначе приложение не получится скачать через сотовую сеть. Пожали все в джипеги, для каждой зоны нарисовали маску, по которой фильтровали слой с каждой зоной. Уложились!

В синий — прищемите дверью


Проверяйте дважды все, прежде чем отправляете приложение с In-App Purchase внутри. Особенно — не забудьте кнопку восстановления для non-consumable покупок. Мы получили свой заслуженный reject и отправились на доработку к следующему году.

Огромного внимания заслуживает тестирование In-App Purchase. Тестирование при помощи тестовых iTunes аккаунтов очень своеобразное — лучше один раз попробовать. И да, если вы публикуете новую версию, и определенные In-App’ы доступны только в ней — не забудьте, что это нужно указать перед отправкой приложения на review.

Те же яйца — вид сбоку


Быстро перевели проект на SpriteKit — логика осталась той же, но стало значительно проще работать с внутренней структурой объектов для отрисовки, для этого даже не пришлось лезть CoreGraphics:

SKSpriteNode *patternNode = [SKSpriteNode spriteNodeWithImageNamed:spriteImageName];
SKSpriteNode *maskNode  = [SKSpriteNode spriteNodeWithImageNamed:maskImageName];
SKCropNode *zoneNode = [SKCropNode node];
[zoneNodeaddChild:patternNode];
[zoneNode setMaskNode:maskNode];

Зачем изобретать велосипед? Вернулись к стандартной навигации UINavigationController, сейчас кастомизируй — не хочу.

image

Симулировать поведение UIScrollView для наследника SKNode можно положив его в один контейнер с UIScrollView, а сам контейнер положить поверх SKView который отрисовывает SKScene, и реализовать для такого контейнера протокол UIScrollViewDelegate и далее изменять положение SKNode внутри контейнера в зависимости от параметра contentOffset:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
  // See also: http://stackoverflow.com/a/19197965/429253
  _selectorNode.position = CGPointMake(- scrollView.contentOffset.x + 160.0f,
                                       _selectorNode.position.y);
}


Анатомия яйца



В качестве счетчика был подключен Google Analytics, это потребовало минимального количества времени на интеграцию, и предоставило кучу рычагов прямо из коробки. Экраны, события, модель поведения пользователей — все добавляется в пару строчек.

Отслеживание событий:

[[[GAI sharedInstance] defaultTracker] send:
 [[GAIDictionaryBuilder createEventWithCategory:@"Share"
                                         action:@"Facebook"
                                          label:nil
                                          value:nil] build]];

Отслеживание экранов:

id tracker = [[GAI sharedInstance] defaultTracker];
[tracker set:kGAIScreenName value:@"Store: Super Eggs"];
[tracker send:[[GAIDictionaryBuilder createAppView] build]];

Особо доставляет раздел Real-Time:

image

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

#if TARGET_IPHONE_SIMULATOR || DEBUG
  [[GAI sharedInstance] setOptOut:YES];
#endif

Сетевые яйца


image

Создание «приложение» для Facebook — это стотыщ баннеров разного размера. Вам все равно придется их сделать. Здесь тоже придется какое-то время подождать (говорят про три рабочих дня, обычно делают за день), прежде чем фейсбучное приложение появится в App Center.

Также, логин при помощи Facebook SDK очень чувствителен к разным условиям: у зависимости от того, установлено на телефоне приложение Facebook или нет, залогинены вы в социальных сетях в настройках iOS, или нет — результат будет разный. Для SSO авторизации не забудьте правильно прописать URL types в настройках приложения в XCode (заменив девятки на идентификатор вашего приложения в Facebook‘е):

image

Фотографию заливаем с помощью FBRequestConnection и указываем, кого мы на этой фотографии отмечаем:

FBRequestConnection *photoUploadConnection = [[FBRequestConnection alloc] init];
FBRequest *request = [FBRequest requestForUploadPhoto:_image];
[request.parameters setObject:[NSString stringWithFormat:@"[{\"tag_uid\":\"%@\"}]", friendId] forKey:@"tags"];
[request.parameters setObject:K_APP_PROMO_TEXT forKey:@"name"];

[photoUploadConnection addRequest:request
                completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
                  if (!error){
                    // handle success
                  }
                } batchEntryName:@"photopost"];

[photoUploadConnection start];

Заливать картинки ВКонтакт немного сложнее, придется сначала запросить адрес сервера для загрузки картинки, и только после этого запостить ее другу на стену (в отличие от Facebook, где мы добавляем фотку в альбом и отмечаем на ней кого-то:

 // 1. Get upload server
  NSDictionary *result = [self sendVkRequestForMethod:@"photos.getWallUploadServer"
                                               params:[NSDictionary dictionaryWithObjectsAndKeys:
                                                       friendId, @"uid",
                                                       K_ACCESS_TOKEN, @"access_token", nil]
                                                error:&error];

  // 2. Upload image
  if (!error) {
    result = [self sendPOSTRequest:[[result objectForKey:@"response"] objectForKey:@"upload_url"]
                     withImageData:UIImageJPEGRepresentation(_image, 75)];
  }

  // 3. Save image
  if (!error) {
    result = [self sendVkRequestForMethod:@"photos.saveWallPhoto"
                                   params:[NSDictionary dictionaryWithObjectsAndKeys:
                                           friendId, @"uid",
                                           K_ACCESS_TOKEN, @"access_token",
                                           [result objectForKey:@"hash"], @"hash",
                                           [result objectForKey:@"photo"], @"photo",
                                           [result objectForKey:@"server"], @"server", nil]
                                    error:&error];
  }

  // 4. Post on wall
  if (!error) {
    result = [self sendVkRequestForMethod:@"wall.post"
                                   params:[NSDictionary dictionaryWithObjectsAndKeys:
                                           friendId, @"owner_id",
                                           K_ACCESS_TOKEN, @"access_token",
                                           K_APP_PROMO_TEXT, @"message",
                                           [[[result objectForKey:@"response"] lastObject]objectForKey:@"id"], @"attachment",
                                           nil]
                                    error:&error];
  }

C Instagram‘ом проще, сначала сохраняем картинку с расширением *.igo, потом открываем ссылку через UIDocumentInteractionController.

// 1. Save file with *.igo extension
NSString *path = [[self applicationDocumentsDirectory].path
                  stringByAppendingPathComponent:@"EggMaker.igo"];
NSError *error = nil;
[UIImagePNGRepresentation(postcardImage) writeToFile:path
                                             options:0

// 2. Open with UIDocumentInteractionController
if (!error) {
  NSURL *instagramURL = [NSURL URLWithString:@"instagram://app"];
  if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
    self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:
                                          [NSURL fileURLWithPath:path]];
    self.documentInteractionController.UTI = @"com.instagram.exclusivegram";
    self.documentInteractionController.annotation = [NSDictionary dictionaryWithObject:K_SHARE_TEXT
                                                                                forKey:@"InstagramCaption"];
    [self.documentInteractionController presentOpenInMenuFromRect:self.view.frame inView:self.view animated:YES];
  }
}

Интерактивные яйца


Всегда не хватало возможности сделать интерактивную перезентацию своего приложения, особенно если приложение платное, а правилами App Store демо версии запрещены? С этой задачей справился App.io:
image

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



Скачай Яйцедел в App Store: http://appstore.com/Яйцедел (кто спрашивал про короткие ссылки?)
Спасибо что вы с нами, обязательно попробуйте Super Eggs — там есть с котиками и пингвинятами!
Наши страницы в Фейсбуке и ВКонтакте

И на будущее: берегите яйца!
Христос Воскресе!
Tags:
Hubs:
Total votes 55: ↑38 and ↓17+21
Comments18

Articles