4

I'm trying to add in-app purchase feature to my application and I want to download contents that I host in my own server. RMStore provides an API to do this, however I couldn't figure out how to do it.

Documentation says:

RMStore delegates the downloading of self-hosted content via the optional contentDownloader delegate. You can provide your own implementation using the RMStoreContentDownloader protocol:

- (void)downloadContentForTransaction:(SKPaymentTransaction*)transaction
                              success:(void (^)())successBlock
                             progress:(void (^)(float progress))progressBlock
                              failure:(void (^)(NSError *error))failureBlock;

Call successBlock if the download is successful, failureBlock if it isn't and progressBlock to notify the download progress. RMStore will consider that a transaction has finished or failed only after the content downloader delegate has successfully or unsuccessfully downloaded its content.

And here is the protocol (from RMStore.h):

@protocol RMStoreContentDownloader <NSObject>

/**
 Downloads the self-hosted content associated to the given transaction and calls the given success or failure block accordingly. Can also call the given progress block to notify progress.
 @param transaction The transaction whose associated content will be downloaded.
 @param successBlock Called if the download was successful. Must be called in the main queue.
 @param progressBlock Called to notify progress. Provides a number between 0.0 and 1.0, inclusive, where 0.0 means no data has been downloaded and 1.0 means all the data has been downloaded. Must be called in the main queue.
 @param failureBlock Called if the download failed. Must be called in the main queue.
 @discussion Hosted content from Apple’s server (@c SKDownload) is handled automatically by RMStore.
 */
- (void)downloadContentForTransaction:(SKPaymentTransaction*)transaction
                              success:(void (^)())successBlock
                             progress:(void (^)(float progress))progressBlock
                              failure:(void (^)(NSError *error))failureBlock;

@end

Simply it says, downloads the self-hosted content associated to the given transaction. How do I associate the self-hosted to transaction?

guneykayim
  • 5,210
  • 2
  • 29
  • 61

2 Answers2

2

Here what I did. Obviously you need to add RMStore.h and the protocol RMStoreContentDownloader in the class where you run this method. It works, although I did not understand how it is managed the progressBlock (maybe my download is too short?)...

- (void)downloadContentForTransaction:(SKPaymentTransaction*)transaction
                          success:(void (^)())successBlock
                         progress:(void (^)(float progress))progressBlock
                          failure:(void (^)(NSError *error))failureBlock
{
    //the product purchased
    NSString *productID = transaction.payment.productIdentifier;


    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];

    //HERE IS WHERE TO INSERT THE URL
    NSURL *URL = [NSURL URLWithString:@"http://example.com/download.zip"];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
    return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
    } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
    if (error == nil)
        NSLog(@"File downloaded to: %@", filePath);
        successBlock();
    else
        NSLog(@"Error in download: %@", error.localizedDescription);
        failureBlock();
    }];
    [downloadTask resume];
    [manager setDownloadTaskDidWriteDataBlock:^(NSURLSession *session,    NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite)
    {
        float percentDone = (((float)((int)totalBytesWritten) / (float)((int)totalBytesExpectedToWrite))*100);
        progressBlock(percentDone);
    }];

}

Then the method will be called by RMStore at the right moment!

Hope it helps!

Zanzi
  • 40
  • 1
  • 5
  • Your answer doesn't provide any solution to associating self-hosted content to transaction. – guneykayim Dec 18 '15 at 11:08
  • I just update my answer: the `productIdentifier` is inside the `SKPaymentTransaction`! – Zanzi Dec 18 '15 at 11:48
  • How do I initiate the download? For example, this is my download link http://stackoverflow.com/users/flair/1249328.png where and how should I start the download process and associate this to transaction? – guneykayim Dec 18 '15 at 11:53
  • The download start automatically after RMStore verify the receipt of the purchase, you just have to implement the delegate method, RMStore will call it at the right moment. For downloading content from my server I'm using AFNetworking. – Zanzi Dec 18 '15 at 11:57
  • OK I understand that, but I don't know where to put that link in the implementation of delegate method. – guneykayim Dec 18 '15 at 11:59
  • In my example I have `myMethodToDownload` where I use `AFNetworking` with the syntax you can find at this link [link](https://github.com/AFNetworking/AFNetworking#creating-a-download-task). You can use that syntax directly in the `downloadContentForTransaction` delegate method and call the `succesBlock()` if there are no error during download, otherwise call `failureBlock()`. – Zanzi Dec 18 '15 at 12:07
  • My problem is not about usage of `AFNetworking`, it is about where to put it. So if you could update your answer with a complete code instead of telling me where to put it would be much much more clarifying for me I would be very glad. – guneykayim Dec 18 '15 at 12:11
  • I won't be able to test it right now, but I trust you :) Thanks. – guneykayim Dec 18 '15 at 12:39
-1

Does the content you are trying to provide via in-app purchase unique for each transaction? If it is unique for every transaction, you should pass transaction id to your server and download the content generated for only this transaction id. Otherwise, for each transaction download the content without passing transaction id. For both cases, you should call successBlock or failureBlock at the end of download process. Optionally, you can call progressBlock each time you want to update progress.

furkan3ayraktar
  • 543
  • 10
  • 18
  • The content is unique for each in-app product, not each transaction. My problem is that I'm not sure how to initiate the download process and relate it with the `SKPaymentTransaction`. In which step should I send transaction id? Why should I send transaction id? How should I send transaction id (via web service)? – guneykayim Apr 06 '15 at 14:05
  • If you have content that is unique for in-app product, you can place your content into a simple web hosting and name your files according to in-app purchase identifiers. When user purchases the product, SKPaymentTransaction has the identifier. When you implement the downloadContentForTransaction method, you will have that object. You will start your download process inside that method, too. You can use 3rd party http libraries or simply NSUrlConnection to download your file. – furkan3ayraktar Apr 06 '15 at 14:14