Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Mac Compatibility warning fixed, receipt validation pending

  • Loading branch information...
commit 22347ae04efd6bc45cfc16fafdd70926ed651192 1 parent bd40370
Mugunth Kumar authored
3  Externals/SFHFKeychainUtils.h
View
@@ -27,9 +27,6 @@
// OTHER DEALINGS IN THE SOFTWARE.
//
-#import <UIKit/UIKit.h>
-
-
@interface SFHFKeychainUtils : NSObject {
}
89 MKSKProduct.m
View
@@ -44,6 +44,75 @@ @implementation MKSKProduct
@synthesize theConnection;
@synthesize dataFromConnection;
++(NSString*) deviceId {
+
+#if TARGET_OS_IPHONE
+ UIDevice *dev = [UIDevice currentDevice];
+ NSString *uniqueID;
+ if ([dev respondsToSelector:@selector(uniqueIdentifier)])
+ uniqueID = [dev valueForKey:@"uniqueIdentifier"];
+ else {
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ id uuid = [defaults objectForKey:@"uniqueID"];
+ if (uuid)
+ uniqueID = (NSString *)uuid;
+ else {
+ CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
+ uniqueID = (__bridge NSString *)cfUuid;
+ CFRelease(cfUuid);
+ [defaults setObject:uniqueID forKey:@"uniqueID"];
+ }
+ }
+#elif TARGET_OS_MAC
+
+ kern_return_t kernResult;
+ mach_port_t master_port;
+ CFMutableDictionaryRef matchingDict;
+ io_iterator_t iterator;
+ io_object_t service;
+ CFDataRef macAddress = nil;
+
+ kernResult = IOMasterPort(MACH_PORT_NULL, &master_port);
+ if (kernResult != KERN_SUCCESS) {
+ printf("IOMasterPort returned %d\n", kernResult);
+ return nil;
+ }
+
+ matchingDict = IOBSDNameMatching(master_port, 0, "en0");
+ if(!matchingDict) {
+ printf("IOBSDNameMatching returned empty dictionary\n");
+ return nil;
+ }
+
+ kernResult = IOServiceGetMatchingServices(master_port, matchingDict, &iterator);
+ if (kernResult != KERN_SUCCESS) {
+ printf("IOServiceGetMatchingServices returned %d\n", kernResult);
+ return nil;
+ }
+
+ while((service = IOIteratorNext(iterator)) != 0)
+ {
+ io_object_t parentService;
+
+ kernResult = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parentService);
+ if(kernResult == KERN_SUCCESS)
+ {
+ if(macAddress)
+ CFRelease(macAddress);
+ macAddress = IORegistryEntryCreateCFProperty(parentService, CFSTR("IOMACAddress"), kCFAllocatorDefault, 0);
+ IOObjectRelease(parentService);
+ }
+ else {
+ printf("IORegistryEntryGetParentEntry returned %d\n", kernResult);
+ }
+
+ IOObjectRelease(service);
+ }
+
+ return [[NSString alloc] initWithData:(__bridge NSData*) macAddress encoding:NSASCIIStringEncoding];
+#endif
+}
+
-(id) initWithProductId:(NSString*) aProductId receiptData:(NSData*) aReceipt
{
if((self = [super init]))
@@ -54,7 +123,6 @@ -(id) initWithProductId:(NSString*) aProductId receiptData:(NSData*) aReceipt
return self;
}
-
#pragma mark -
#pragma mark In-App purchases promo codes support
// This function is only used if you want to enable in-app purchases for free for reviewers
@@ -68,23 +136,8 @@ +(void) verifyProductForReviewAccess:(NSString*) productId
{
onReviewRequestVerificationSucceeded = [completionBlock copy];
onReviewRequestVerificationFailed = [errorBlock copy];
-
- UIDevice *dev = [UIDevice currentDevice];
- NSString *uniqueID;
- if ([dev respondsToSelector:@selector(uniqueIdentifier)])
- uniqueID = [dev valueForKey:@"uniqueIdentifier"];
- else {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- id uuid = [defaults objectForKey:@"uniqueID"];
- if (uuid)
- uniqueID = (NSString *)uuid;
- else {
- CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
- uniqueID = (__bridge NSString *)cfUuid;
- CFRelease(cfUuid);
- [defaults setObject:uniqueID forKey:@"uniqueID"];
- }
- }
+
+ NSString *uniqueID = [self deviceId];
// check udid and featureid with developer's server
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", OWN_SERVER, @"featureCheck.php"]];
72 MKStoreManager.m
View
@@ -383,6 +383,28 @@ - (NSMutableDictionary *)pricesDictionary {
return priceDict;
}
+-(void) showAlertWithTitle:(NSString*) title message:(NSString*) message {
+
+#if TARGET_OS_IPHONE
+ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
+ message:message
+ delegate:nil
+ cancelButtonTitle:NSLocalizedString(@"Dismiss", @"")
+ otherButtonTitles:nil];
+ [alert show];
+#elif TARGET_OS_MAC
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert addButtonWithTitle:NSLocalizedString(@"Dismiss", @"")];
+
+ [alert setMessageText:title];
+ [alert setInformativeText:message];
+ [alert setAlertStyle:NSInformationalAlertStyle];
+
+ [alert runModal];
+
+#endif
+}
+
- (void) buyFeature:(NSString*) featureId
onComplete:(void (^)(NSString*)) completionBlock
onCancelled:(void (^)(void)) cancelBlock
@@ -395,12 +417,8 @@ - (void) buyFeature:(NSString*) featureId
{
if([isAllowed boolValue])
{
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Review request approved", @"")
- message:NSLocalizedString(@"You can use this feature for reviewing the app.", @"")
- delegate:self
- cancelButtonTitle:NSLocalizedString(@"Dismiss", @"")
- otherButtonTitles:nil];
- [alert show];
+ [self showAlertWithTitle:NSLocalizedString(@"Review request approved", @"")
+ message:NSLocalizedString(@"You can use this feature for reviewing the app.", @"")];
if(self.onTransactionCompleted)
self.onTransactionCompleted(featureId);
@@ -433,12 +451,8 @@ -(void) addToQueue:(NSString*) productId
}
else
{
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"In-App Purchasing disabled", @"")
- message:NSLocalizedString(@"Check your parental control settings and try again later", @"")
- delegate:self
- cancelButtonTitle:NSLocalizedString(@"Dismiss", @"")
- otherButtonTitles: nil];
- [alert show];
+ [self showAlertWithTitle:NSLocalizedString(@"In-App Purchasing disabled", @"")
+ message:NSLocalizedString(@"Check your parental control settings and try again later", @"")];
}
}
@@ -507,6 +521,11 @@ - (void) startVerifyingSubscriptionReceipts
}
}
+-(NSData*) receiptFromBundle {
+
+ return nil;
+}
+
#pragma mark In-App purchases callbacks
// In most cases you don't have to touch these methods
-(void) provideContent: (NSString*) productIdentifier
@@ -515,6 +534,9 @@ -(void) provideContent: (NSString*) productIdentifier
MKSKSubscriptionProduct *subscriptionProduct = [self.subscriptionProducts objectForKey:productIdentifier];
if(subscriptionProduct)
{
+ // MAC In App Purchases can never be a subscription product (at least as on Dec 2011)
+ // so this can be safely ignored.
+
subscriptionProduct.receipt = receiptData;
[subscriptionProduct verifyReceiptOnComplete:^(NSNumber* isActive)
{
@@ -530,6 +552,23 @@ -(void) provideContent: (NSString*) productIdentifier
}
else
{
+ if(!receiptData) {
+
+ // could be a mac in app receipt.
+ // read from receipts and verify here
+ receiptData = [self receiptFromBundle];
+ if(!receiptData) {
+ if(self.onTransactionCancelled)
+ {
+ self.onTransactionCancelled(productIdentifier);
+ }
+ else
+ {
+ NSLog(@"Receipt invalid");
+ }
+ }
+ }
+
if(OWN_SERVER && SERVER_PRODUCT_MODEL)
{
// ping server and get response before serializing the product
@@ -603,13 +642,8 @@ - (void) failedTransaction: (SKPaymentTransaction *)transaction
NSLog(@"error: %@", transaction.error);
#endif
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[transaction.error localizedFailureReason]
- message:[transaction.error localizedRecoverySuggestion]
- delegate:self
- cancelButtonTitle:NSLocalizedString(@"Dismiss", @"")
- otherButtonTitles: nil];
- [alert show];
-
+ [self showAlertWithTitle:[transaction.error localizedFailureReason] message:[transaction.error localizedRecoverySuggestion]];
+
if(self.onTransactionCancelled)
self.onTransactionCancelled();
}
15 MKStoreObserver.m
View
@@ -79,18 +79,27 @@ - (void) failedTransaction: (SKPaymentTransaction *)transaction
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction
-{
-
+{
+#if TARGET_OS_IPHONE
[[MKStoreManager sharedManager] provideContent:transaction.payment.productIdentifier
forReceipt:transaction.transactionReceipt];
+#elif TARGET_OS_MAC
+ [[MKStoreManager sharedManager] provideContent:transaction.payment.productIdentifier
+ forReceipt:nil];
+#endif
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
+#if TARGET_OS_IPHONE
+ [[MKStoreManager sharedManager] provideContent: transaction.originalTransaction.payment.productIdentifier
+ forReceipt:transaction.transactionReceipt];
+#elif TARGET_OS_MAC
[[MKStoreManager sharedManager] provideContent: transaction.originalTransaction.payment.productIdentifier
- forReceipt:transaction.transactionReceipt];
+ forReceipt:nil];
+#endif
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
51 README.mdown
View
@@ -1,46 +1,36 @@
-This is version 4.1 of MKStoreKit. It's for ARC enabled projects only.
-The latest NonARC version can be obtained from a tagged branch <a href="https://github.com/MugunthKumar/MKStoreKit/zipball/NonARC">here</a>
+This is version 4.1 of MKStoreKit.
+Few minor bugs reported in the past two months are fixed and iCloud syncing is implemented.
----
-###Todo
-I'm currently working on supporting Lion. Once this is done, I guess, MKStoreKit will not have any more major updates hopefully (till Apple introduces new IAP mechanisms).
+I'm working on supporting Lion. Not sure if the current version already works. (I guess it should).
+Once this is done, I guess, MKStoreKit will not have any more major updates (till Apple introduces new IAP mechanisms).
Read the <a href="http://mk.sg/8j"> blog post</a> for more.
+The source code, MKStoreKit, contains several new objective c files notably MKStoreKitConfigs.h among others like, MKStoreManager.h/m and MKStoreObserver.h/m and five server side files. The MKStoreManager is a singleton class that takes care of *everything*. Just include StoreKit.Framework and Security.Framework into your product and drag these four files into the project. You then have to initialize it by calling [MKStoreManager sharedManager] in your applicationDidFinishLaunching. From then on, it does the magic. The MKStoreKit automatically activates/deactivates features using your userDefaults. When a feature is purchased, it automagically records it into NSUserDefaults. For checking whether the user has purchased the feature, you can call a function like,
----
-
-The source code, MKStoreKit, contains a config file, MKStoreKitConfigs.h and several other Objective-C code file like, MKStoreManager.h/m and MKStoreObserver.h/m and five server side files. The MKStoreManager is a singleton class that takes care of *everything*. Just include StoreKit.Framework and Security.Framework into your product and drag all these files into the project. You then have to initialize it by calling [MKStoreManager sharedManager] in your applicationDidFinishLaunching. From then on, it does the magic. The MKStoreKit automatically activates/deactivates features using your Keychain. When a feature is purchased, it automagically records it into Keychain. The Keychain is automatically synced with iCloud if you have enabled iCloud entitlements for your project.
-
----
-For checking whether the user has purchased the feature, you can call a function like,
-
-
- if([MKStoreManager isFeaturePurchased:kFeatureID])
- {
- //unlock it
- }
+if([MKStoreManager isFeaturePurchased:kFeatureID])
+{
+//unlock it
+}
To purchase a feature, just call
- [[MKStoreManager sharedManager] buyFeature:kFeatureAId
- onComplete:^(NSString* purchasedFeature)
- {
- NSLog(@"Purchased: %@", purchasedFeature);
- }
- onCancelled:^
- {
- NSLog(@"User Cancelled Transaction");
- }];
+[[MKStoreManager sharedManager] buyFeature:kFeatureAId
+ onComplete:^(NSString* purchasedFeature)
+ {
+ NSLog(@"Purchased: %@", purchasedFeature);
+ }
+ onCancelled:^
+ {
+ NSLog(@"User Cancelled Transaction");
+ }];
It’s that simple with my MKStoreKit.
----
-###Licensing
+MKStoreKit uses zLib licensing
And so all of my source code can be used royalty-free into your app. Just make sure that you don’t remove the copyright notice from the source code if you make your app open source. You don’t have to attribute me in your app, although I would be glad if you do so.
----
-###Server Setup
The database required can be created from the sql file attached.
+
The code that you need for setting up your server is present in the ServerCode folder.
Copy all the files to some location like
@@ -49,3 +39,4 @@ http://api.mycompany.com/inapp/
The URL which you should copy to "ownServer" variable in MKStoreManager.m is http://api.mycompany.com/inapp/featureCheck.php
Copy this URL to ownServer parameter in MKStoreManager.m
+
Please sign in to comment.
Something went wrong with that request. Please try again.