Обновление содержимого при использовании содержимого, размещенного в Apple, для покупки в приложении
Я реализую In-App Purchase, используя размещенный в Apple контент. Ранее я использовал Urban Airship для размещения своего контента и использовал их SDK для обеспечения пользовательского интерфейса магазина и функциональности покупки.
Поскольку в июле этого года Urban Airship прекращает поддержку IAP, мне нужно заменить ее.
В Urban Airship SDK была поддержка обновления приобретенного контента. Я вижу, что StoreKit предоставляет эту функциональность (по крайней мере, в определенной степени), но не уверен, как правильно реализовать само обновление контента.
SKProduct
имеет downloadContentVersion
которая указывает версию содержимого, которое доступно для загрузки с Apple. Я отслеживаю, какая версия в данный момент загружена в приложение, поэтому я знаю, когда доступно обновление.
Часть, с которой я застрял - как на самом деле загрузить обновленный контент?
Моей первой мыслью было сделать восстановление для этой конкретной покупки, но, похоже, нет способа восстановить отдельные продукты (только все продукты). Вторая мысль состояла в том, чтобы просто повторно купить продукт, но это представляет предупреждение пользователю, указывающее, что с них будет взиматься плата снова, однако, они не будут оплачиваться, так как после повторной покупки отображается другое предупреждение, информирующее пользователя о том, что контент уже приобретен и будет повторно загружен бесплатно - но для меня это выглядит как плохой пользовательский опыт, они могут не обязательно знать, что с них не будет взиматься плата, пока вы не согласитесь на покупку.
Документация говорит не создавать SKDownload
Например, я не могу просто создать его и добавить в очередь загрузки.
Как мне реализовать обновления контента для покупки в приложении при использовании контента, размещенного в Apple?
2 ответа
Спасибо Jasarien за то, что связались с Apple по этому вопросу. Вот пример кода для любого, кто находит эту тему, пытающейся решить, как обновить содержимое в приложении.
Во-первых, когда вы получите ответ от SKProductsRequest, проверьте downloadContentVersion относительно версии вашего ранее загруженного контента. Вы можете получить версию контента для существующего контента с помощью кода, подобного следующему:
NSString *pathToYourContent = @""; // Put your path here
NSString *contentInfoPath = [pathToYourContent stringByAppendingPathComponent:@"ContentInfo.plist"];
NSDictionary *contentInfo = [NSDictionary dictionaryWithContentsOfFile:contentInfoPath];
NSString *contentVersion = [contentInfo objectForKey:@"ContentVersion"];
NSString *iapProductIdentifier = [contentInfo objectForKey:@"IAPProductIdentifier"];
Затем, если вы заметите, что версия была изменена, вы можете предложить пользователю обновить. Если они согласны, тогда начните восстановление.
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
Затем, когда начинают поступать транзакции, вам нужно решить, какие из них принять, а какие проигнорировать. В этом примере из моего приложения, которое загружает содержимое песни, у меня есть класс YHSongVersion, который хранит идентификатор и версию для всех песен, которые мы скачали, и они хранятся в массиве self.ownedSongVersions. В этом примере будут приниматься любые операции восстановления, если номера версий отличаются или у нас нет содержимого.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStateFailed:
break;
case SKPaymentTransactionStatePurchased:
[self provideContentForTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStateRestored:
[self restorePurchaseIfRequired:transaction];
break;
}
}
}
/// On a restore download the content if either we don't have the content or the version number has changed.
- (void)restorePurchaseIfRequired:(SKPaymentTransaction *)transaction {
BOOL haveSong = NO;
SKDownload *download = [transaction.downloads objectAtIndex:0];
for (YHSongVersion *ownedSongVersion in self.ownedSongVersions) {
BOOL isSongForThisDownload = [ownedSongVersion.iapProductIdentifier isEqualToString:download.contentIdentifier];
if (isSongForThisDownload) {
haveSong = YES;
BOOL hasDifferentVersionNumber = ![ownedSongVersion.contentVersion isEqualToString:download.contentVersion];
if (hasDifferentVersionNumber) {
[self provideContentForTransaction:transaction];
}
else {
// Do nothing
[self completeTransaction:transaction];
NSLog(@"Ignoring restore for %@", ownedSongVersion.iapProductIdentifier);
}
}
}
if (!haveSong) {
[self provideContentForTransaction:transaction];
}
}
Я поговорил с некоторыми инженерами Store Kit на WWDC и задал им этот вопрос.
Их ответ был не таким положительным, как я надеялся.
Они подтвердили отсутствие API для восстановления одного продукта в качестве ошибки и предложили мне подать две ошибки (одна для запроса на усовершенствование этого API в наборе магазина, а другая для документации, слишком редкой в этой области обновления продуктов),
Что касается насущной проблемы, то они предложили либо реализовать функцию "обновить все", в которой все продукты восстанавливаются для получения их транзакций и их объектов загрузки (вариант, который я в конечном итоге выбрал), либо аналогичным образом восстановить все продукты, но игнорируйте все продукты, кроме того, который вы пытаетесь обновить (в конечном счете, бессмысленно, так как вы восстанавливаете все несколько раз, если применяете этот подход для каждого продукта).
Я обновлю этот ответ номерами радаров для ошибок, которые я регистрирую, как только я это сделаю, чтобы другие могли дублировать их при необходимости (помните, дублирует ошибки!)
редактировать
Я сообщил об ошибке и ее номер rdar://14174034 - не стесняйтесь дублировать.