Code Monkey home page Code Monkey logo

rmstore's Introduction

#RMStore

CocoaPods Version Platform Build Status Join the chat at https://gitter.im/robotmedia/RMStore

A lightweight iOS library for In-App Purchases.

RMStore adds blocks and notifications to StoreKit, plus receipt verification, content downloads and transaction persistence. All in one class without external dependencies. Purchasing a product is as simple as:

[[RMStore defaultStore] addPayment:productID success:^(SKPaymentTransaction *transaction) {
    NSLog(@"Purchased!");
} failure:^(SKPaymentTransaction *transaction, NSError *error) {
    NSLog(@"Something went wrong");
}];

##Installation

Using CocoaPods:

pod 'RMStore', '~> 0.7'

Or add the files from the RMStore directory if you're doing it manually.

Check out the wiki for more options.

##StoreKit with blocks

RMStore adds blocks to all asynchronous StoreKit operations.

###Requesting products

NSSet *products = [NSSet setWithArray:@[@"fabulousIdol", @"rootBeer", @"rubberChicken"]];
[[RMStore defaultStore] requestProducts:products success:^(NSArray *products, NSArray *invalidProductIdentifiers) {
    NSLog(@"Products loaded");
} failure:^(NSError *error) {
    NSLog(@"Something went wrong");
}];

###Add payment

[[RMStore defaultStore] addPayment:@"waxLips" success:^(SKPaymentTransaction *transaction) {
    NSLog(@"Product purchased");
} failure:^(SKPaymentTransaction *transaction, NSError *error) {
    NSLog(@"Something went wrong");
}];

###Restore transactions

[[RMStore defaultStore] restoreTransactionsOnSuccess:^(NSArray *transactions){
    NSLog(@"Transactions restored");
} failure:^(NSError *error) {
    NSLog(@"Something went wrong");
}];

###Refresh receipt (iOS 7+ only)

[[RMStore defaultStore] refreshReceiptOnSuccess:^{
    NSLog(@"Receipt refreshed");
} failure:^(NSError *error) {
    NSLog(@"Something went wrong");
}];

##Notifications

RMStore sends notifications of StoreKit related events and extends NSNotification to provide relevant information. To receive them, implement the desired methods of the RMStoreObserver protocol and add the observer to RMStore.

###Adding and removing the observer

[[RMStore defaultStore] addStoreObserver:self];
...
[[RMStore defaultStore] removeStoreObserver:self];

###Products request notifications

- (void)storeProductsRequestFailed:(NSNotification*)notification
{
    NSError *error = notification.rm_storeError;
}

- (void)storeProductsRequestFinished:(NSNotification*)notification
{
    NSArray *products = notification.rm_products;
    NSArray *invalidProductIdentifiers = notification.rm_invalidProductIdentififers;
}

###Payment transaction notifications

Payment transaction notifications are sent after a payment has been requested or for each restored transaction.

- (void)storePaymentTransactionFinished:(NSNotification*)notification
{
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
}

- (void)storePaymentTransactionFailed:(NSNotification*)notification
{
    NSError *error = notification.rm_storeError;
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
}

// iOS 8+ only

- (void)storePaymentTransactionDeferred:(NSNotification*)notification
{
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
}

###Restore transactions notifications

- (void)storeRestoreTransactionsFailed:(NSNotification*)notification;
{
    NSError *error = notification.rm_storeError;
}

- (void)storeRestoreTransactionsFinished:(NSNotification*)notification
{
	NSArray *transactions = notification.rm_transactions;
}

###Download notifications (iOS 6+ only)

For Apple-hosted and self-hosted downloads:

- (void)storeDownloadFailed:(NSNotification*)notification
{
    SKDownload *download = notification.rm_storeDownload; // Apple-hosted only
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
    NSError *error = notification.rm_storeError;
}

- (void)storeDownloadFinished:(NSNotification*)notification;
{
    SKDownload *download = notification.rm_storeDownload; // Apple-hosted only
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
}

- (void)storeDownloadUpdated:(NSNotification*)notification
{
    SKDownload *download = notification.rm_storeDownload; // Apple-hosted only
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
    float progress = notification.rm_downloadProgress;
}

Only for Apple-hosted downloads:

- (void)storeDownloadCanceled:(NSNotification*)notification
{
	SKDownload *download = notification.rm_storeDownload;
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
}

- (void)storeDownloadPaused:(NSNotification*)notification
{
	SKDownload *download = notification.rm_storeDownload;
    NSString *productIdentifier = notification.rm_productIdentifier;
    SKPaymentTransaction *transaction = notification.rm_transaction;
}

###Refresh receipt notifications (iOS 7+ only)

- (void)storeRefreshReceiptFailed:(NSNotification*)notification;
{
    NSError *error = notification.rm_storeError;
}

- (void)storeRefreshReceiptFinished:(NSNotification*)notification { }

##Receipt verification

RMStore doesn't perform receipt verification by default but provides reference implementations. You can implement your own custom verification or use the reference verifiers provided by the library.

Both options are outlined below. For more info, check out the wiki.

###Reference verifiers

RMStore provides receipt verification via RMStoreAppReceiptVerifier (for iOS 7 or higher) and RMStoreTransactionReceiptVerifier (for iOS 6 or lower). To use any of them, add the corresponding files from RMStore/Optional into your project and set the verifier delegate (receiptVerifier) at startup. For example:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    const BOOL iOS7OrHigher = floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1;
    _receiptVerifier = iOS7OrHigher ? [[RMStoreAppReceiptVerifier alloc] init] : [[RMStoreTransactionReceiptVerifier alloc] init];
    [RMStore defaultStore].receiptVerifier = _receiptVerifier;
    // Your code
    return YES;
}

If security is a concern you might want to avoid using an open source verification logic, and provide your own custom verifier instead.

###Custom verifier

RMStore delegates receipt verification, enabling you to provide your own implementation using the RMStoreReceiptVerifier protocol:

- (void)verifyTransaction:(SKPaymentTransaction*)transaction
                           success:(void (^)())successBlock
                           failure:(void (^)(NSError *error))failureBlock;

Call successBlock if the receipt passes verification, and failureBlock if it doesn't. If verification could not be completed (e.g., due to connection issues), then error must be of code RMStoreErrorCodeUnableToCompleteVerification to prevent RMStore to finish the transaction.

You will also need to set the receiptVerifier delegate at startup, as indicated above.

##Downloading content

RMStore automatically downloads Apple-hosted content and provides a delegate for a self-hosted content.

###Apple-hosted content

Downloadable content hosted by Apple (SKDownload) will be automatically downloaded when purchasing o restoring a product. RMStore will notify observers of the download progress by calling storeDownloadUpdate: and finally storeDownloadFinished:. Additionally, RMStore notifies when downloads are paused, cancelled or have failed.

RMStore will notify that a transaction finished or failed only after all of its downloads have been processed. If you use blocks, they will called afterwards as well. The same applies to restoring transactions.

###Self-hosted content

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.

##Transaction persistence

RMStore delegates transaction persistence and provides two optional reference implementations for storing transactions in the Keychain or in NSUserDefaults. You can implement your transaction, use the reference implementations provided by the library or, in the case of non-consumables and auto-renewable subscriptions, get the transactions directly from the receipt.

For more info, check out the wiki.

##Requirements

RMStore requires iOS 5.0 or above and ARC.

##Roadmap

RMStore is in initial development and its public API should not be considered stable. Future enhancements will include:

##License

Copyright 2013-2014 Robot Media SL

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

rmstore's People

Contributors

alexchugunov avatar chaoscoder avatar gitter-badger avatar gnatok avatar hpique avatar jcaille avatar joeltay17 avatar karolus avatar kommen avatar mckaskle avatar pjata avatar ricsantos avatar rodericj avatar streeter avatar xavigil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rmstore's Issues

RMKeychainSetValue warnings

3 warnings during Analyze in
void RMKeychainSetValue(NSData *value, NSString *key)

all three are 'value stored to status is never read'

Add support for 64bit CPUs

When I build my app for 64-bit CPUs, I get the following warnings from Xcode:

  • RMStoreTransactionReceiptVerificator.m:64:21: Implicit conversion loses integer precision: 'NSUInteger' (aka 'unsigned long') to 'int'
  • RMStoreTransactionReceiptVerificator.m:208:65: Values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead
  • RMStoreKeychainPersistence.m:81:89: Values of type 'OSStatus' should not be used as format arguments; add an explicit cast to 'int' instead
  • RMStoreKeychainPersistence.m:67:89: Values of type 'OSStatus' should not be used as format arguments; add an explicit cast to 'int' instead

I tried fixing these errors, but it looks like the changing line 64 in RMStoreTransactionReceiptVerificator.m from:

int intLength

to:

NSUInteger intLength

Breaks the unit tests on iOS 6 (which is obviously unacceptable).

Add method to add a transaction to the Keychain without going through the payment process

In my app, which is currently using MKStoreKit but which I am transitioning to RMStore, I need to record transactions in the keychain without going through the payment process for certain product identifiers. My app changed from paid to free, so although the paid clients did not purchase the in-app purchase, I have an indicator to tell that they did, in fact, pay for the app. So, for these clients, I 'remember' or add the product to the keychain as if it has been purchased through the in-app purchase process.

podspec: add OpenSSL to AppReceiptVerificator subspec

The podspec has a known bug which is that the AppReceiptVerificator subspec is missing the OpenSSL static library.

I don't have a lot of experience with CocoaPods so I asked how to do this in Stack Overflow. Does anyone know the answer or can submit a pull request with a fix?

Thanks!

Build fails unless you link libssl and libcrypto libraries with the Pods-RMStore target

When running pod install for the first time on a project with RMStore the project will not build. You have to link the Pods-RMStore target in the Pods project with the libssl and libcrypto libraries.

Relevant portion of build log:

(null): "_d2i_PKCS7_fp", referenced from:
(null): +[RMAppReceipt dataFromPCKS7Path:] in libPods.a(RMAppReceipt.o)
(null): "_SHA1", referenced from:
(null): -[RMAppReceipt verifyReceiptHash] in libPods.a(RMAppReceipt.o)
(null): "_PKCS7_free", referenced from:
(null): +[RMAppReceipt dataFromPCKS7Path:] in libPods.a(RMAppReceipt.o)
(null): "_ASN1_get_object", referenced from:
(null): _RMASN1ReadInteger in libPods.a(RMAppReceipt.o)
(null): _RMASN1ReadOctectString in libPods.a(RMAppReceipt.o)
(null): _RMASN1ReadString in libPods.a(RMAppReceipt.o)
(null): +[RMAppReceipt enumerateASN1Attributes:length:usingBlock:] in libPods.a(RMAppReceipt.o)
(null): Symbol(s) not found for architecture armv7s
(null): Linker command failed with exit code 1 (use -v to see invocation)

Podfile:

platform :ios, '7.0'
pod 'RMStore', '~> 0.4.2'

originalAppVersion is empty in RMAppReceipt

I'm trying to implement a transition from paid to freemium model for my app, but for some reason originalAppVersion is always empty for me. I was going to use this field to decide whether a person purchased my paid app, so that I can unlock all IAPs for them.

Apple's docs say that: "In the sandbox environment, the value of this field is always “1.0”.". But even if I renew the receipt and then read it using RMAppReceipt, this field is always nil.

If I try to trace it, I see that length is zero after evaluating

ASN1_get_object(pp, &length, &tag, &class, omax);

Is that the behaviour everyone is getting and do you think I can rely that originalAppVersion will be filled correctly in production?

Restoring Transactions are never persisted

When I successfully restore a transactions with the following code:

 [[RMStore defaultStore] restoreTransactionsOnSuccess:^{
        // success handler
    } failure:^(NSError *error) {
        // failure handler
    }
 ]

And later call the following code to verify that the purchase restoration has been completed:

RMStore *store =[RMStore defaultStore];
RMStoreKeychainPersistence *transactionStore = store.transactionPersistor;

return [transactionStore isPurchasedProductOfIdentifier:@"myProductId"];

I get a result of "false" when I expect it to be "true" after restoring my purchase.

When I look at the RMStore.m code, it looks like there is no call to persist the transaction during the restore process.

Note: I am using RMStoreKeychainPersistence method to persist my IAP transactions.

Better subscriptions support

RMStore kinda supports subscriptions already. Auto-renewable subscriptions require minor changes to the receipt validation code. Also, a few convenience subscription management methods might be helpful.

iOS 7 support

RMStore already supports iOS 7. However, there are non-breaking API changes in StoreKit that it would be nice to contemplate.

Question: Handling Return from Account Verification in App Store

I have a problem now with my current live app (using MKStoreKit) where, if a user tries to upgrade the app, and they are on a new device (iPhone 5S for example), they are taken to an account verification screen in the actual App Store. Then, once they verify their account, they are returned to my app. Apparently, wherever they are returned to is a place where I do not know, because my app does not deliver the content, and then crashes, and then somehow crashes every time thereafter when they return to the app to try to upgrade or restore their purchase (with a SIGTRAP error?!?), which is unrecognizable to the app at this point. I have not gotten to the bottom of this problem yet, but I was wanting to alert you to the error so that you are aware of it, and can make sure that RMStore handles this situation if it is one that you think is important. Also, if you have any thoughts at all on how this should be handled, I would love to hear them, as I am about at my wits end with this.

original App version

I'm using the following code to get the version number:

RMAppReceipt* appReceipt;
appReceipt = [RMAppReceipt bundleReceipt];
if (appReceipt == nil) {
NSLog(@"ERROR! NO APP RECEIPT FOUND");
return nil;
}
else {
return appReceipt.originalAppVersion;
}

Then I want to verify the version. All versions below 1.1 (it's version 1.0 and 1.0.1) should be return TRUE:
if([originalVersionStr isEqualToString:@"1"] || [originalVersionStr isEqualToString:@"1.0"] || [originalVersionStr isEqualToString:@"1.0.1"])

The problem is, that the users from version 1.0 are fine - but 1.0.1 users get a false here. Now I created a new apple id and downloaded the actual version. The appReceipt.originalAppVersion return version 6. I think this is the build number?

Can you offer me a fast fix for my issue?

24-hour time problem in Parsing receipt date

In RMAppReceipt.m file, the +(NSDate)formatRFC3339String:(NSString)string method

the dateFormat is incompatible with certain settings, example:

If the phone region format setting (General > International > Region Format) is changed to United Kingdom, and the 24-Hour Time Switch is turned off (General > Date & Time).

Because of this, I'm able to get my purchased products' bundle ID, but I cannot get the proper return of NSDate values from [RMAppReceiptIAP originalPurchaseDate], [RMAppReceiptIAP subscriptionExpirationDate], and basically anything that returns a date. It will return me a null value (basically dateformatter failed).

The string before parsing the date looks like this: "2014-02-20T04:27:04Z" without quotes.
And the dateFormat is this: "yyyy-MM-dd'T'HH:mm:ssZ" without quotes.
Changing HH to hh fixes the specfic setting described above (Region Format and 24 hour switch), but I'm not sure if it breaks the other combinations of settings (Different region formats with different 24 hour settings).

Hope you guys can fix this asap :)

Cannot connect to store?

Error Domain=SKErrorDomain Code=0 "Cannot connect to iTunes Store" UserInfo=0x14eabc00 {NSLocalizedDescription=Cannot connect to iTunes Store}

Any ideas?

Can RMStore defence iAPFree?

Thanks Hermes for creating such a great project.

I would like to ask RMStore can defence iAPFree? iAPFree can intercept iAP receipt request and fake the answer, so it is more powerful than iAP Cracker.

Crash with nil error

I'm running into following issue when testing on the device with airplane mode on (so without the internet).

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    RMProductsRequestWrapper *wrapper = [self popWrapperForRequest:request];
    RMStoreLog(@"products request failed with error %@", error.debugDescription);
    if (wrapper.failureBlock)
    {
        wrapper.failureBlock(error);
    }
    // here it creates dict with nil error what leads to crash
    NSDictionary *userInfo = @{RMStoreNotificationStoreError: error};
    [[NSNotificationCenter defaultCenter] postNotificationName:RMSKProductsRequestFailed object:self userInfo:userInfo];
}

The error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]'

screen shot 2013-10-03 at 13 25 31

Great work with the library btw :)

Consumable products.

Hi Hermes, thanks for sharing this fantastic class. I really like that you added support for local transaction verification on iOS7. I guess this would be a pain to figure out if it wasn't for your class.
I have a couple of questions. I am looking at the class for purchasing consumable products. When an user buys a product I store the product along with the receipt and other data on a server in the cloud. Purchases are in fact liked to activation codes for projects that users develop in the app, so persistence of purchased activations for users is given through the server. I also use the server for receipt validation, so when a purchase is made the server validates it and creates an activation. The first question I have is what happens if the server fails to validate the receipt or to create a code. Since this is a consumable product I assume there is no way to restore purchases, and the user may end having paid for no content, is this right?. In such case, is there a way to prevent users from paying until the app received confirmation from the server? Thanks.

payment.applicationUsername for iOS 7 Store Kit

In the WWDC video "Using Store Kit for In-App Purchases", the speaker describes adding a payment.applicationUsername as a hash of the customer account name.

payment.applicationUsername = hash(customerAccountName);

I cannot find any documentation on this but thought that you might like to add it if you can find more information on it.

[RMStore defaultStore].transactionPersistor returns null

After I call restoreSuccess the persistence returns null

[[RMStore defaultStore]restoreTransactionsOnSuccess:^{
    RMStoreUserDefaultsPersistence *persistence = (RMStoreUserDefaultsPersistence *)([RMStore defaultStore].transactionPersistor); // nil here!!!
    BOOL purchased = [persistence isPurchasedProductOfIdentifier:@"pro_version"];
    log4Debug(@"restore success?: %@", purchased ? @"YES" : @"NO");
} failure:^(NSError *error) {
}];

What's the possible cause please? Thank you.

Add documentation to explain how to check if a product has already been purchased

I just updated my codebase to adopt version 0.4.2 of RMStore and I saw that the way to verify purchases has changed with the introduction of RMStoreKeychainPersistence alongside the old user defaults implementation.

It would be helpful if the wiki or README included a note to explain how to check that a product has already been purchased with the "isPurchasedProductOfIdentifier" API. This doc should include how one needs to configure the [RMStore defaultStore] object needs to have its receiptVerificator and/or transactionPersistor attributes be configured in order for the purchase verification to work.

What should I do after restore transactions finished?

Hi;

I have a question. I couldn't find my answer in the tutorial.

I want to restore purchased products. Before last update, I had the product identifiers of the restored products so that I could download the content.

But in the latest version, using blocks, I don't have the product identifiers. So how will I know which product to restore?

Thank you.

Restore Purchase is always successful, even when product has not been purchased

I am testing on a device in iOS 7 in the sandbox. I logged out of my iTunes account and cleared the keychain data. I downloaded a fresh version of the app and used a brand new test account. I hit the Restore button for my non-consumable product. I was asked to enter my iTunes ID and password twice, even though I am positive I entered it correctly the first time. The product was then restored successfully, even though it had not yet been purchased by this test account user. I tried this with multiple test accounts and it is reproducible every time.

Possible bug in RMStoreTransactionReceiptVerificator

Hi,

Just looking at your code I found this pattern on several places

NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (error != nil)
{
// do stuff

I read somewhere that errors returned by reference are not guaranteed to be initialized unless the condition returned by the method is false. If this is the case you should check for data being nil instead of the error being not nil. If the error was indeed not set by the method then it may contain garbage on success. I suppose you actually tested this and it worked for this particular method call but you can not assume that it will always work as per the general rule.

Thanks,

User tapping "cancel" on purchase throws error

When the user taps to purchase a product in my app, I run:

        NSString *productId = @"myProductId";
        [[RMStore defaultStore] addPayment:productId success:^(SKPaymentTransaction *transaction) {
            NSLog(@"Product purchased: %@", productId);
            // ... do stuff here
        } failure:^(SKPaymentTransaction *transaction, NSError *error) {
            NSLog(@"Purchase failed: %@", error);
            // ... throw an error here
        }];

This works great under most circumstances. However when the user is prompted for the password, and then taps the 'cancel' button, the failure block is called. Is it possible to determine that it was not a system failure, but rather that the user simply decided to cancel?

Use system frameworks instead of OpenSSL

RMAppReceipt uses OpenSSL to extract the app receipt as ASN1 data from the PKCS7 container and then parse the ASN1 data into an object.

In order to avoid external dependencies it would be better to use system frameworks instead. Sadly, my cryptography-fu is not strong enough to do it. Any takers?

According to the this app, it appears to be possible.

Problem with AppReceiptVerificator with cocoapods

I was using RMStore from a downloaded file, but I'v changed to pods now and it can't find RMStoreAppReceiptVerificator.h/.m. The problem is at the .podspec it states that the subspec 'AppReceiptVerificator' be available only for iOS 7.0, but my app deployment target is 5.0. What should I do? Change my pod file to 7.0 only for RMStore? Or what? I have configured RMStore just like the demo Proyect with this line:

_receiptVerificator = iOS7OrHigher ? [[RMStoreAppReceiptVerificator alloc] init] : [[RMStoreTransactionReceiptVerificator alloc] init];
[RMStore defaultStore].receiptVerificator = _receiptVerificator;

Thanks

How to get the receipt after "receipt validation locally"

In my applications I am using RMStore library. After calling addPayment:success:failure method of RMStore class, I am doing receipt validation locally. But after validation where I will get the transaction receipt. Sample receipt after verification is below.

{
environment = Sandbox;
receipt = {
"adam_id" = 0;
"application_version" = "1.6";
"bundle_id" = "Some bundle id";
"download_id" = 0;
"in_app" = (
{
"is_trial_period" = false;
"original_purchase_date" = "2013-10-10 06:43:45 Etc/GMT";
"original_purchase_date_ms" = 1381387425000;
"original_purchase_date_pst" = "2013-10-09 23:43:45 America/Los_Angeles";
"original_transaction_id" = 1000000089656289;
"product_id" = "product_id";
"purchase_date" = "2013-12-03 08:24:49 Etc/GMT";
"purchase_date_ms" = 1386059089000;
"purchase_date_pst" = "2013-12-03 00:24:49 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000089656289;
},
{
"is_trial_period" = false;
"original_purchase_date" = "2013-12-03 08:24:49 Etc/GMT";
"original_purchase_date_ms" = 1386059089000;
"original_purchase_date_pst" = "2013-12-03 00:24:49 America/Los_Angeles";
"original_transaction_id" = 1000000095357076;
"product_id" = "product_id";
"purchase_date" = "2013-12-03 08:24:49 Etc/GMT";
"purchase_date_ms" = 1386059089000;
"purchase_date_pst" = "2013-12-03 00:24:49 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000095357076;
}
);
"receipt_type" = ProductionSandbox;
"request_date" = "2013-12-03 08:24:56 Etc/GMT";
"request_date_ms" = 1386059096603;
"request_date_pst" = "2013-12-03 00:24:56 America/Los_Angeles";
};
status = 0;
}

It takes too much time to verify all of the receipts when restore purchases

Hi;

I have 10 products purchased. When I want to restore it, code is waiting tooo much because for every product, it goes to server again to make receipt verification because of the code:

- (void)restoreTransaction:(SKPaymentTransaction *)transaction

{
SKPaymentTransaction *originalTransaction = transaction.originalTransaction;
SKPayment *payment = originalTransaction.payment;
RMStoreLog(@"transaction restored with product %@", payment.productIdentifier);

_pendingRestoredTransactionsCount++;
/*if (self.receiptVerificator != nil)
{
    [self.receiptVerificator verifyReceiptOfTransaction:transaction success:^{
        [self verifiedTransaction:transaction];
        [self notifyRestoreTransactionFinishedIfApplicableAfterTransaction:transaction];
    } failure:^(NSError *error) {
        [self failedTransaction:transaction error:error];
        [self notifyRestoreTransactionFinishedIfApplicableAfterTransaction:transaction];
    }];
}
else
{*/
    RMStoreLog(@"WARNING: no receipt verification");
    [self verifiedTransaction:transaction];
    [self notifyRestoreTransactionFinishedIfApplicableAfterTransaction:transaction];
//}

}

I commented out the verification part. But I still want to verify when user wants to buy a product. So I cannot make receiptVerificator nil.

[[RMAppReceipt bundleReceipt] originalAppVersion] returns no value (on sandbox)

although this is stated in RMAppReceipt.h

/** The version of the app that was originally purchased. This corresponds to the value of CFBundleVersion (in iOS) or CFBundleShortVersionString (in OS X) in the Info.plist file when the purchase was originally made. In the sandbox environment, the value of this field is always “1.0”.
*/
@Property (nonatomic, strong, readonly) NSString *originalAppVersion;

when i use it on test environment (sandbox) i get no value returned, no "1.0" string as state, is this normal? can i trust it to work properly on production code ?

Payment fail

Hi,

First of all thank you for this great component, I was wondering if it was normal that when I add the payment I get payment failed when (The in app purchase has been approved by Apple) ? I don't even get to sign in? Or something wrong in my code

In the simulator I get to sign in but not in the device

Thank You

Successfully request product details but can't make purchase

I'm not sure if this is a bug or just something I'm doing wrong. I can successfully get the product details for my items when I submit the product ID's (i.e. I can get price etc.).

When I use the same product ID's to attempt a purchase I get an invalid ID error. This doesn't seem to make sense as they are valid and able to request product details.

Feature Requst: Download Product automatically if not available

Now when I try to make an In-App Purchase and the product hasn't been requested yet it returns with an error.
I believe it would be really nice if it doesn't have the product yet it automatically requests it first and then proceeds to the purchase automatically.

Otherwise I have to always check if the product is available or not in RMStore before trying the addPayment...

Storing purchases in NSUserDefaults doesn't work

First of all, thanks for the great framework!

Unfortunately I have a problem with checking if purchases were made or not.

[[RMStore defaultStore] isPurchasedForIdentifier:@"..."] fails for me as nothing is ever stored in NSUserDefaults.

Manually calling
[[RMStore defaultStore] addPurchaseForProductIdentifier:@"..."]
before does not help either.

Am I the only one?

Non-renewing subscriptions

Can RMStore be used for non-renewing subscriptions?
And does it help out with persisting purchases in iCloud like the Storekit guide suggests?

Thanks in advance

Svend

Add "Restored" flag into RMSKPaymentTransactionFinished notification

This kind of notification is equal both for first purchasing and restoring of transaction. Is it possible to add some flag into userInfo as follows:
NSDictionary *userInfo = @{RMStoreNotificationTransaction: transaction, RMStoreNotificationProductIdentifier: productIdentifier, RMStoreNotificationRestoreState:@(YES)};

What happens if the verificator is not able to complete the verification?

As discovered by @John-Lluch in #30, RMStore does not provide a way for verificators to indicate that they couldn't complete the verification (e.g., due to connectivity problems).

Also, RMStoreTransactionReceiptVerificator is calling the failure block when the connection with Apple fails. This finishes the transaction but reports the payment or restoration as a failure, when it might not be.

Doesn't build on iOS 5 or 6 due to `SKReceiptRefreshRequest`

You are referencing SKReceiptRefreshRequest which is iOS 7+ so this pod fails to build in any earlier versions even though the pod spec says it's good for iOS 5 and above.

/Users/rob/App/Pods/RMStore/RMStore/RMStore.m:116:5: Unknown type name 'SKReceiptRefreshRequest'

"The app receipt failed verification" when app is in production.

In my entire testing phase for my new app, I never saw this error message before (using one of the included verificators). My app got approved a few hours ago, and I'm trying to buy my own IAP, but I receive the error message in the title when I do it.

But it looks like my IAPs have been unlocked anyway. I check if the purchase was valid by using the receipt itself so it does look like the purchase was successful and that the receipt should be valid.

Am I doing something wrong, or does the app need to refresh something related to IAP, since the app was approved less than 5 hours ago?

Feature Request: In completionblock of restore, provide array of productID's

The completion block of restoreOnSuccess does not provide and productID's of IAP's, so I have to manually add/remove the observe and implement an extra method that gets notifications when products have been purchased/restored. It would simply save some time/code if the completion block returns restored product ID's.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.