如何下载In-App托管内容?

Sma*_*ess 21 iphone ios

我按照http://www.raywenderlich.com/21081/introduction-to-in-app-purchases-in-ios-6-tutorial 设置Apple托管的应用内购买.它列出了产品.当我想从Apple下载产品时,我会做这样的事情

-(void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction * transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
            {
                [[SKPaymentQueue defaultQueue] startDownloads:transaction.downloads];

    ....

}

-(void) paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads
{
    NSLog(@"paymentQues");

    for (SKDownload *download in downloads)
    {
        switch (download.downloadState)
        {
            case SKDownloadStateActive:
            {
                NSLog(@"%f", download.progress); break;
             }
    ...

}

-(void) paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{

}
Run Code Online (Sandbox Code Playgroud)

我在updatedTransactions中开始下载,然后Apple使用downloadState == Active调用updatedDownloads.然后,Apple调用removedTransaction而不实际开始下载.下载进度始终为0%,并且从不使用downloadState == Finished调用updatedDownloads.

我不知道为什么我的下载从未开始,以及为什么我的交易在下载完成之前被删除.有人有工作样品吗?

Sma*_*ess 35

问题是我忘了明确关闭交易.作为参考,我的完整代码如下.它有其他的东西,比如在下载时显示进度条,但它是100%正常工作.不要担心Utility.h,它只定义了一些宏,如SAFE_RELEASE_VIEW.

基本上我通过定义两个购买和下载方法扩展了raywenderlich中的样本.

密切关注updatedDownloads.下载完成后,我将内容复制到用户的文档目录.从Apple下载时,您拥有的目录如下所示:

    • ContentInfo.plist
      • 内容
        • 你的档案

Apple仅为您提供下载文件夹的路径.您使用该路径来读取ContentInfo.plist.在我的应用程序中,我在ContentInfo.plist中有一个属性"Files",它在Contents文件夹中列出了我的文件.然后我将文件复制到Documents文件夹.如果您不这样做,您必须猜测您在Contents文件夹中有哪些文件,或者只是复制内部的所有文件.

这是SmallChess(http://www.smallchess.com)的实际应用内购买代码.

#import <StoreKit/StoreKit.h>
#import "MBProgressHUD/MBProgressHUD.h"
#import "Others/Utility.h"
#import "Store/OnlineStore.h"

NSString *const ProductPurchasedNotification = @"ProductPurchasedNotification";

@implementation StoreTransaction
@synthesize productID, payment;
@end

@interface OnlineStore () <SKProductsRequestDelegate, SKPaymentTransactionObserver, MBProgressHUDDelegate>
@end

@implementation OnlineStore
{
    NSSet *_productIDs;
    MBProgressHUD *_progress;
    NSMutableSet * _purchasedIDs;
    SKProductsRequest * _productsRequest;
    RequestProductsCompletionHandler _completionHandler;
}

-(id) init
{
    if ([SKPaymentQueue canMakePayments] && (self = [super init]))
    {
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }

    return self;
}

#pragma mark MBProgressHUDDelegate

-(void) hudWasHidden:(MBProgressHUD *)hud
{
    NSAssert(_progress, @"ddd");

    [_progress removeFromSuperview];

        SAFE_RELEASE_VIEW(_progress);
}

#pragma end

#pragma mark SKProductsRequestDelegate

-(void) request:(NSSet *)productIDs handler:(RequestProductsCompletionHandler)handler
{    
    _completionHandler = [handler copy];

    _productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIDs];
    _productsRequest.delegate = self;
    [_productsRequest start];    
}

-(void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    _productsRequest = nil;
    _completionHandler(YES, response.products);
    _completionHandler = nil;
}

-(void) request:(SKRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"Failed to load list of products.");
    _productsRequest = nil;

    _completionHandler(NO, nil);
    _completionHandler = nil;
}

#pragma end

#pragma mark Transaction

-(void) provideContentForProduct:(SKPaymentTransaction *)payment productID:(NSString *)productID
{
    [_purchasedIDs addObject:productID];

    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:productID];
    [[NSUserDefaults standardUserDefaults] synchronize];

    StoreTransaction *transaction = [[StoreTransaction alloc] init];

    [transaction setPayment:payment];
    [transaction setProductID:productID];

    [[NSNotificationCenter defaultCenter] postNotificationName:ProductPurchasedNotification object:transaction userInfo:nil];
}

-(void) completeTransaction:(SKPaymentTransaction *)transaction
{
#ifdef DEBUG
    NSLog(@"completeTransaction");
#endif

    [self provideContentForProduct:transaction productID:transaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

-(void) restoreTransaction:(SKPaymentTransaction *)transaction
{
#ifdef DEBUG
    NSLog(@"restoreTransaction");
#endif

    [self provideContentForProduct:transaction productID:transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

-(void) failedTransaction:(SKPaymentTransaction *)transaction
{
#ifdef DEBUG
    NSLog(@"failedTransaction");
#endif

    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    }

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

-(void) restoreCompletedTransactions
{
#ifdef DEBUG
    NSLog(@"restoreCompletedTransactions");
#endif

    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

#pragma end

#pragma mark Buy & Download

-(BOOL) purchased:(NSString *)productID
{
    return [_purchasedIDs containsObject:productID];
}

-(void) buy:(SKProduct *)product
{
    SKPayment * payment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

-(void) download:(StoreTransaction *)transaction
{
    NSAssert(transaction.payment.transactionState == SKPaymentTransactionStatePurchased ||
             transaction.payment.transactionState == SKPaymentTransactionStateRestored, @"The payment transaction must be completed");

    if ([transaction.payment.downloads count])
    {
        [[SKPaymentQueue defaultQueue] startDownloads:transaction.payment.downloads];
    }
}

#pragma end

#pragma mark SKPaymentTransactionObserver

-(void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"RestoreCompletedTransactions");
}

-(void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction * transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
            {
#ifdef DEBUG
                NSLog(@"SKPaymentTransactionStatePurchased");
#endif

                [[SKPaymentQueue defaultQueue] startDownloads:transaction.downloads];
                break;
            }

            case SKPaymentTransactionStateFailed:
            {
                NSLog(@"Failed");
                [self failedTransaction:transaction];
                break;
            }

            case SKPaymentTransactionStateRestored:
            {

                NSLog(@"Restored");
                [self restoreTransaction:transaction]; break;
            }

            case SKPaymentTransactionStatePurchasing:
            {
#ifdef DEBUG
                NSLog(@"SKPaymentTransactionStatePurchasing");
#endif

                break;
            }
        }
    }
}

-(void) paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
#ifdef DEBUG
    NSLog(@"restoreCompletedTransactionsFailedWithError");
#endif
}

-(void) paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
#ifdef DEBUG
    NSLog(@"removedTransactions");
#endif
}

-(void) paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads
{
    for (SKDownload *download in downloads)
    {
        switch (download.downloadState)
        {
            case SKDownloadStateActive:
            {
#ifdef DEBUG
                NSLog(@"%f", download.progress);
                NSLog(@"%f remaining", download.timeRemaining);
#endif

                if (download.progress == 0.0 && !_progress)
                {
                    #define WAIT_TOO_LONG_SECONDS 60
                    #define TOO_LARGE_DOWNLOAD_BYTES 4194304

                    const BOOL instantDownload = (download.timeRemaining != SKDownloadTimeRemainingUnknown && download.timeRemaining < WAIT_TOO_LONG_SECONDS) ||
                                                 (download.contentLength < TOO_LARGE_DOWNLOAD_BYTES);

                    if (instantDownload)
                    {
                        UIView *window= [[UIApplication sharedApplication] keyWindow];

                        _progress = [[MBProgressHUD alloc] initWithView:[[UIApplication sharedApplication] keyWindow]];
                        [window addSubview:_progress];

                        [_progress show:YES];
                        [_progress setDelegate:self];
                        [_progress setDimBackground:YES];
                        [_progress setLabelText:@"Downloading"];
                        [_progress setMode:MBProgressHUDModeAnnularDeterminate];
                    }
                    else
                    {
                        NSLog(@"Implement me!");
                    }
                }

                [_progress setProgress:download.progress];

                break;
            }

            case SKDownloadStateCancelled: { break; }
            case SKDownloadStateFailed:
            {
                [Utility showAlert:@"Download Failed"
                           message:@"Failed to download. Please retry later"
                       cancelTitle:@"OK"
                        otherTitle:nil
                          delegate:nil];
                break;
            }

            case SKDownloadStateFinished:
            {
                NSString *source = [download.contentURL relativePath];
                NSDictionary *dict = [[NSMutableDictionary alloc] initWithContentsOfFile:[source stringByAppendingPathComponent:@"ContentInfo.plist"]];

                if (![dict objectForKey:@"Files"])
                {
                    [[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
                    return;
                }

                NSAssert([dict objectForKey:@"Files"], @"The Files property must be valid");

                for (NSString *file in [dict objectForKey:@"Files"])
                {
                    NSString *content = [[source stringByAppendingPathComponent:@"Contents"] stringByAppendingPathComponent:file];

                    NSAssert([Utility isFileExist:content], @"Content path must be valid");

                    // Copy the content to the Documents folder, don't bother with creating a directory for it
                    DEFINE_BOOL(succeed, [Utility copy:content dst:[[Utility getDocPath] stringByAppendingPathComponent:file]]);

                    NSAssert(succeed, @"Failed to copy the content");

#ifdef DEBUG
                    NSLog(@"Copied %@ to %@", content, [[Utility getDocPath] stringByAppendingPathComponent:file]);
#endif
                }

                if (download.transaction.transactionState == SKPaymentTransactionStatePurchased && _progress)
                {
                    [Utility showAlert:@"Purchased Complete"
                               message:@"Your purchase has been completed. Please refer to the FAQ if you have any questions"
                           cancelTitle:@"OK"
                            otherTitle:nil
                              delegate:nil];
                }

                [_progress setDimBackground:NO];
                [_progress hide:YES];

                [[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
                break;
            }

            case SKDownloadStatePaused:
            {
#ifdef DEBUG
                NSLog(@"SKDownloadStatePaused");
#endif
                break;
            }

            case SKDownloadStateWaiting:
            {
#ifdef DEBUG
                NSLog(@"SKDownloadStateWaiting");
#endif
                break;
            }
        }
    }
}

#pragma end

@end
Run Code Online (Sandbox Code Playgroud)

  • 它超过了75%,但从未达到100%.也从未到过SKDownloadStateFinished但最终失败了.是的,我在SKDownloadStateFinished之后完成了交易,但正如我所说,它永远不会被击中. (3认同)