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

Не яйца красят человека, а человек красит яйца Лучок, свекла, старый гастук, цветные нитки — сколько способов раскраски яиц знаете вы? Сегодня мы расскажем еще об одном, придуманном нами.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Добавить приложение можно зарегистрировав бесплатный аккаунт, бесплатно доступно множество настроек отображения и встраивания такого интерактивного демо через параметры ссылки. С недавнего времени такое демо своего приложения можно встраивать в виде полноэкранной интерактивной рекламы.

[embedded content]

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

И на будущее: берегите яйца! Христос Воскресе!

© Habrahabr.ru