Feb
16

iPhone разработка: Интегрируем In-App Purchases

Сегодня у нас статья Якова Ильина об In-App Purchases для iPhone-приложений.

Введение

In-App Purchases — это простой и удобный механизм для организации продаж своих приложений или дополнительных фич непосредственно из своего приложения. In-App Purchases легко встраивается и открывает для Вас новый канал продаж. Взаимодействие с App Store осуществляется с помощью StoreKit.framework, который поставляется вместе с SDK, начиная с версии 3.0.

Общая информация

In-App Purchases бывает трех типов:

  • Consumables
  • Non-Consumables
  • Subscriptions

Consumable – потребляемый тип. Purchase такого типа может покупаться несколько раз. Например, в игре Eliminate игрок покупает себе энергию, которая со временем растрачивается и приходится покупать ее заново, либо ждать три часа, пока энергия востановится.

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

Subscription— подписка на что-либо. Например, Вы можете написать iPhone-приложение для Web-сервиса, в котором есть Premium аккаунт, открывающий дополнительные возможности. С помощью Subscription Вы сможете аккаунт активировать, скажем, на месяц или на год.

Реализовать In-App Purchases можно с помощью двух моделей:

  • Встроенная модель
  • Серверная модель

Встроенная модель позволяет разблокировать фичи. Как правило, использование данной модели побуждает разработчиков встраивать их в приложение зарание. При такой реализации, StoreKit отвечает только за оплату фичи. В общем случае, с помощью StoreKit мы можем узнать прошла ли покупка или не прошла.

Серверная модель является более гибкой. В модели принимают участие три сущности: iPhone-приложение, сервер Apple и наш сервер. Все новые фичи хранятся на нашем сервере, поэтому нет необходимости обновлять приложение при добавлении новых фич или продуктов. Работает модель следующим образом:

  1. iPhone-приложение запрашивает список продуктов у своего сервера,
  2. iPhone-приложение отображает новые продукты пользователю,
  3. Пользователь покупает (или не покупает :) )
  4. iPhone-приложение запрашивает покупку у сервера Apple через StoreKit,
  5. StoreKit возвращает ответ,
  6. iPhone-приложение отсылает ответ на свой сервер
  7. Еще раз проверяется ответ (обязательно проверяется, что ответ пришел от Apple),
  8. После этого iPhone-приложение скачивает со своего сервера новый продукт.

В данном посте рассматривается встроенная модель.

Реализация

Работу встроенной модели In-App Purchases я продемонстрирую на тестовом примере AppPurchasesExample. Это небольшое iPhone-приложение с 3 окнами. Первое (оно же главное) окно будет доступно пользователю по-умолчанию. Это окно будет содержать информацию о двух других окнах, разблокировать которые можно только за деньги.

Шаг 1. Создание App ID

Заходим на iPhone Developer Program Portal и открываем вкладку App IDs:

В правом верхнем углу экрана нажимаем New App ID. Затем вводим информацию о приложении. Для своего примера я заполнил форму так:

Для создания Bundle Identifier Apple рекомендует использовать нотацию Reverse DNS, что гарантирует уникальность Вашего Identifier и избавит Вас от дальнейших проблем при публикации приложения.Очень Важно не использовать символ ‘*’ в Bundle Identifier. Если ввести ‘com.wordpress.indiedevelop.*’, то In-App Purchases работать не будет.

Далее необходимо включить In App Purchases для App ID. В списке App IDs, напротив нужного Bundle Identifier в графе Action следует нажать Configure. Появится форма Configure App ID, на которой необходимо включить checkBox ‘Enable In App Purchase’.

Шаг 2. Создание Development профиля
  1. В левом столбце нужно нажать на ‘Provisioning’ и перейти на вкладку ‘Development’.
  2. Нажать ‘New Profile’ и заполнить всю необходимую информацию. Поле Profile Name может быть любое (я записал ‘InAppPurchasesExample Dev’).
  3. В появившемся списке созданный профиль имеет статус pending. Нужно обновить страницу, либо перейти на другую вкладку и обратно, тогда профиль станет доступен для скачивания.
  4. Профиль можно скачивать и устанавливать в xCode. Для установки достаточно просто нажать на профиль двойным кликом, либо перетащить профайл на иконку xCode.

Если профиль установился правильно, тогда в xCode откроется Organizer и вы увидите примерно следующее:

Шаг 3. Создание приложения в iTunes Connect

Для того, чтобы протестировать наше In-App Purchase приложение, его нужно обязательно создать в iTunes Connect. Чтобы это сделать:

  1. Необходимо перейти в iTunes Connect и нажать ‘Manage Your Applications->Add New Application’.
  2. На вопрос ‘Does your product contain encryption?’ ответить отрицательно.
  3. Заполнить форму, где нужно указать имя приложения, описание, номер версии, категорию и т.д. Все достаточно тривиально. Затруднения может вызвать разве что поле ‘SKU Number’. Это поле должно быть уникальным, я ввел в нем ‘IAPEX’ (сокращение от In-App Purchases Example).
  4. На форме ‘Upload’ необходимо выставить флаг ‘Upload application binary later’. Все остальные параметры и формы для тестого примера никакого значения не имеют.
Шаг 4. Создание In-App Purchases в iTunes Connect
  1. В iTunes Connect необходимо нажать ‘Manage Your In App Purchases->Create New’ и выбрать необходимое приложение.
  2. Выбрать Bundle ID и заполнить инфрормацию о Purchase (тип, название, цену и т.д.) Также нужно ввести ‘Product ID’, который может быть произвольным, но я советую использовать Reverse DNS. Лучше всего Product ID формировать из Bundle ID вашего приложения и имени фичи. Для моего примера это выглядит так:

Для тестового приложения я создал два In-App продукта с Product Id ‘com.wordpress.indiedevelop.InAppPurchasesExample.f1’ и ‘com.wordpress.indiedevelop.InAppPurchasesExample.f2’. Обе фичи с типом Non-Consumables.

Шаг 5. Создание тестового пользователя

Для тестирования In-App Purchases необходимо создать хотя бы одного тестового пользователя. Делается это просто:

  1. В iTunes Connect необходимо перейти на ‘Manage Users->In App Purchase Test User’
  2. Нажать ‘Add New User’
  3. Ввести информацию о пользователе

E-mail пользователя не обязательно должен быть реальным. Для своего примера я создал одного тестового пользователя:

Важный момент. Если у Вас не закончен контракт с Apple, тогда In-App Purchase работать у Вас не будет. Для того, чтобы закончить контракт, необходимо указать Contact Info, Bank Info и Tax Info.

Шаг 6. Программирование

Для своего тестового примера я создал каркас проекта и User Interface:

Для работы с App Store я рекомендую использовать MKStoreKit, разработанный в 2009 году разработчиком Кумаром (Mugunth Kumar). Данный набор классов значительно облегчит работу со StoreKit. Кроме MKStoreKit, в проект необходимо добавить StoreKit.framework.

В своем примере я использую слегка модернизированную первую весрию MKStoreKit. Для удобства я добавил к классу MKStoreManager делегат следующего вида:

@protocol MKStoreKitDelegate @optional
- (void)productAPurchased;
- (void)productBPurchased;
- (void)failed;
@end

Делегату посылается сообщение productAPurchased когда куплена фича 1, productBPurchased — когда куплена фича 2 и failed — когда пользователь либо отменил покупку, либо покупка не прошла.

Класс-Singleton MKStoreManager является основным в MKStoreKit. Так выглядит его объявление:

@interface MKStoreManager : NSObject<SKProductsRequestDelegate> {
    ...
}

// делегат
@property (nonatomic, retain) id<MKStoreKitDelegate> delegate;
// продукты, доступные для покупки
@property (nonatomic, retain) NSMutableArray *purchasableObjects;

// фабричный метод для Singleton
+ (MKStoreManager*)sharedManager;

// методы для покупки фич
- (void) buyFeatureA;
- (void) buyFeatureB;

// методы позволяют узнать куплена ли фича
+ (BOOL) featureAPurchased;
+ (BOOL) featureBPurchased;
...
@end

Рассмотрим использование класса на моем тестовом примере.

Сначала в файле MKStoreManager.m я прописал Product ID своих фич:

static NSString *featureAId = @"com.wordpress.indiedevelop.InAppPurchasesExample.f1";
static NSString *featureBId = @"com.wordpress.indiedevelop.InAppPurchasesExample.f2";

Также нужно проверить были ли куплены фичи программы. Основной класс примера унаследован от UIViewController, поэтому код проверки целесообразно встроить в метод viewDidLoad:

- (void)viewDidLoad {
  [super viewDidLoad];

  [MKStoreManager sharedManager].delegate = self; // назначаем делагата для объекта MKStoreManager

  if ([MKStoreManager featureAPurchased]) // если куплена фича 1
  {
    feature1Button.hidden = YES; // скрываем кнопку 'Купить фичу 1'
    seeFeature1Button.hidden = NO; // показываем кнопку 'Перейти на фичу 1'
  }

  if ([MKStoreManager featureBPurchased]) // если куплена фича 2
  {
    feature2Button.hidden = YES; // скрываем кнопку 'Купить фичу 2'
    seeFeature2Button.hidden = NO; // показываем кнопку 'Перейти на фичу 2'
  }
}

Внутри MKStoreKit информация о том, куплен ли продукт сохраняется через NSUserDefaults, поэтому при удалении приложения информация сбрасывается. Однако, пользователь не будет покупать фичи два раза, поскольку StoreKit откроет доступ к фиче бесплатно.

Дальше нужно реализовать методы ‘Купить’. Они привязаны к событию TouchUpInside соотвествующих кнопок:

-(IBAction)feature1ButtonPressed
{
  [self showLockView]; // показываем пользователю, что происходит загрузка
  [[MKStoreManager sharedManager] buyFeatureA]; // посылаем сообщение магазину 'Купить фичу 1'
}

-(IBAction)feature2ButtonPressed
{
  [self showLockView]; // показываем пользователю, что происходит загрузка
  [[MKStoreManager sharedManager] buyFeatureB]; // посылаем сообщение магазину 'Купить фичу 2'
}

Далее я реализовал методы делегата MKStoreKitDelegate:

// фича 1 куплена
- (void)productAPurchased
{
  [self hideLockView]; // скрываем отображение загрузки
  feature1Button.hidden = YES; // скрываем кнопку 'Купить'
  seeFeature1Button.hidden = NO; // показываем кнопку 'Перейти'
}

// фича 2 куплена
- (void)productBPurchased
{
  [self hideLockView]; // скрываем отображение загрузки
  feature2Button.hidden = YES; // скрываем кнопку 'Купить'
  seeFeature2Button.hidden = NO; // показываем кнопку 'Перейти'
}

// покупка не прошла, либо была отменена
- (void)failed
{
  [self hideLockView]; // скрываем отображение загрузки
}

Новые фичи реализованы в виде отдельных UIView под управлением UIViewController. Переход на новые фичи я реализовал с помощь UINavigationController:

// перейти на фичу 1
-(IBAction)seeFeature1
{
  [self.navigationController pushViewController:feature1ViewController animated:YES];
}

// перейти на фичу 2
-(IBAction)seeFeature2
{
  [self.navigationController pushViewController:feature2ViewController animated:YES];
}

Также при манипуляции с магазином можно добавить проверку на его доступность. Это делается так:

if ([SKPaymentQueue canMakePayments])
{
... // Отобразить магазин пользователю
}
else
{
... // Уведомить пользователя, что Purchases недоступны
}

Как видите все достаточно просто. Остается скопилировать и тестировать :)

Шаг 7. Тестирование

Чтобы протестировать In-App Purchases нужно скомпилировать, установить и запустить приложение. При тестировании следует помнить следующее:

  1. Тестировать Purchases можно только на устройстве.
  2. Перед тестированием необходимо выйти из iTunes на своем iPhone. Это делается через ‘Settings->Store->Sign Out’.
  3. При тестировании, в сообщениях с предложением купить фичу, будет появляться [Environment: sandbox] — это признак тестового режима.
  4. Тестировать можно только тест-аккаунтами (см. Шаг 5)
Тестовый пример InAppPurchasesExample

В результате у меня получилось приложение, которое может разблокировать два дополнительных окна. Это приложение можно использовать в качестве примера для создания своих In-App Purchase проектов.

Исходный код

Оригинал статьи в блоге автора.

Скриншоты:

Еще интересные посты о программировании для мобильных устройств:

1 Comment

Make A Comment

Comments RSS Feed   TrackBack URL

Leave a comment

Please leave these two fields as-is:

top