1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the License.html file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
#import "SubscriptionManager.h"
@implementation SubscriptionManager
static SubscriptionManager *sharedInstance = nil;
static NSString *SKU = @"net.mediaarea.mediainfo.mac.nrsubs.inapp1";
static NSString *lifetimeSKU = @"net.mediaarea.mediainfo.mac.purchase.inapp1";
static NSString *_subscriptionStateChangedNotification = @"net.mediaarea.mediainfo.mac.notifications.subscriptioStateChanged";
static NSString *_subscriptionDetailsReadyNotification = @"net.mediaarea.mediainfo.mac.notifications.subscriptionDetailsReady";
static NSString *_subscriptionDetailsUnaviableNotification = @"net.mediaarea.mediainfo.mac.notifications.subscriptionDetailsUnaviable";
static NSString *_subscriptionPurchaseSucceededNotification = @"net.mediaarea.mediainfo.mac.notifications.subscriptionPurchaseSucceededNotification";
static NSString *_subscriptionPurchaseDeferredNotification = @"net.mediaarea.mediainfo.mac.notifications.subscriptionPurchaseDeferredNotification";
static NSString *_subscriptionPurchaseFailedNotification = @"net.mediaarea.mediainfo.mac.notifications.subscriptionPurchaseFailedNotification";
+(NSString *)subscriptionStateChangedNotification {
return _subscriptionStateChangedNotification;
}
+(NSString *)subscriptionDetailsReadyNotification {
return _subscriptionDetailsReadyNotification;
}
+(NSString *)subscriptionDetailsUnaviableNotification {
return _subscriptionDetailsUnaviableNotification;
}
+(NSString *)subscriptionPurchaseSucceededNotification {
return _subscriptionPurchaseSucceededNotification;
}
+(NSString *)subscriptionPurchaseDeferredNotification {
return _subscriptionPurchaseDeferredNotification;
}
+(NSString *)subscriptionPurchaseFailedNotification {
return _subscriptionPurchaseFailedNotification;
}
+(instancetype)shared {
if(!sharedInstance) {
sharedInstance = [[SubscriptionManager alloc] init];
}
return sharedInstance;
}
-(instancetype)init {
self = [super init];
_request = nil;
_subscription = nil;
_lifetimeSubscription = nil;
_subscriptionEndDate = nil;
_subscriptionActive = NO;
_isLifetime = NO;
[self requestSubscriptionDetails];
[self parseSubscriptions];
_shouldNotifyUserForSubscription = NO;
NSInteger launchCount = [[NSUserDefaults standardUserDefaults]integerForKey:@"launchCount"];
if(!_isLifetime && launchCount == 10 && !_subscriptionEndDate) {
_shouldNotifyUserForSubscription = YES;
}
[[NSUserDefaults standardUserDefaults] setInteger:launchCount + 1 forKey:@"launchCount"];
_shouldNotifyUserForSubscriptionEnd = NO;
if(!_isLifetime && _subscriptionEndDate && [_subscriptionEndDate isLessThan:[NSDate date]]) {
NSDate *subscriptionEndNotificationDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"subscriptionEndNotificationDate"];
if(!subscriptionEndNotificationDate || [subscriptionEndNotificationDate isLessThan:_subscriptionEndDate]) {
_shouldNotifyUserForSubscriptionEnd = YES;
}
}
return self;
}
-(void)dealloc {
if(_request) {
[_request release];
}
if(_subscription) {
[_subscription release];
}
if(_lifetimeSubscription) {
[_lifetimeSubscription release];
}
if(_subscriptionEndDate) {
[_subscriptionEndDate release];
}
[super dealloc];
}
-(NSArray *)subscriptions {
NSMutableSet *toReturn = [[[NSMutableSet alloc] init] autorelease];
NSArray *local = [[NSUserDefaults standardUserDefaults] arrayForKey:@"subscriptions"];
if(local) {
[toReturn addObjectsFromArray:local];
}
NSArray *remote = [[NSUbiquitousKeyValueStore defaultStore] arrayForKey:@"subscriptions"];
if(remote) {
[toReturn addObjectsFromArray:remote];
}
if([[toReturn allObjects] isNotEqualTo:local]) {
[[NSUserDefaults standardUserDefaults] setObject:[toReturn allObjects] forKey:@"subscriptions"];
}
if([[toReturn allObjects] isNotEqualTo:remote]) {
[[NSUbiquitousKeyValueStore defaultStore] setObject:[toReturn allObjects] forKey:@"subscriptions"];
}
return [toReturn allObjects];
}
-(void)requestSubscriptionDetails {
if(!_request) {
_request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:SKU, lifetimeSKU, nil]];
_request.delegate = self;
[_request start];
}
}
-(void)purchaseSubscription:(SKProduct *)product {
if(!product) {
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionPurchaseFailedNotification object:self userInfo:nil];
return;
}
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
-(void)restoreSubscriptions {
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
-(void)parseSubscriptions {
NSDate *end = [NSDate dateWithTimeIntervalSince1970:0];
NSArray *descriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"date" ascending:YES]];
for(NSDictionary *subscription in [[self subscriptions] sortedArrayUsingDescriptors:descriptors]) {
if([subscription[@"product"] isEqualToString:SKU]) {
NSDate *new = subscription[@"date"];
NSInteger quantity = [subscription[@"quantity"] integerValue];
if([new isGreaterThan:end]) {
end = [[NSCalendar currentCalendar] dateByAddingUnit:NSCalendarUnitYear value:quantity toDate:new options:0];
}
else {
end = [[NSCalendar currentCalendar] dateByAddingUnit:NSCalendarUnitYear value:quantity toDate:end options:0];
}
}
else if([subscription[@"product"] isEqualToString:lifetimeSKU]) {
end = [NSDate distantFuture];
_isLifetime = YES;
}
}
if([end isGreaterThan:[NSDate dateWithTimeIntervalSince1970:0]]) {
_subscriptionEndDate = end;
if([end isGreaterThanOrEqualTo:[NSDate date]]) {
BOOL oldSubscriptionState = _subscriptionActive;
_subscriptionActive = YES;
if(!oldSubscriptionState) {
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionStateChangedNotification object:self userInfo:nil];
}
}
}
}
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
for(SKProduct* product in response.products) {
if([product.productIdentifier isEqualToString:SKU]) {
if(_subscription) {
[_subscription release];
_subscription = nil;
}
_subscription = [product retain];
}
else if([product.productIdentifier isEqualToString:lifetimeSKU]) {
if(_lifetimeSubscription) {
[_lifetimeSubscription release];
_lifetimeSubscription = nil;
}
_lifetimeSubscription = [product retain];
}
}
if(_subscription && _lifetimeSubscription) {
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionDetailsReadyNotification object:self userInfo:nil];
}
[_request release];
_request = nil;
}
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error {
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionDetailsUnaviableNotification object:self userInfo:nil];
[_request release];
_request = nil;
}
-(void)purchaseSucceeded:(SKPaymentTransaction *)transaction {
if(transaction && ([transaction.payment.productIdentifier isEqualToString:SKU] || [transaction.payment.productIdentifier isEqualToString:lifetimeSKU])) {
NSDictionary *new = [[NSDictionary alloc] initWithObjectsAndKeys:transaction.transactionIdentifier, @"id", transaction.payment.productIdentifier, @"product", [NSNumber numberWithInteger: transaction.payment.quantity], @"quantity", transaction.transactionDate, @"date", nil];
NSMutableSet *saved = [[[NSMutableSet alloc] initWithArray: [self subscriptions]] autorelease];
[saved addObject:new];
[[NSUserDefaults standardUserDefaults] setObject:[saved allObjects] forKey:@"subscriptions"];
[[NSUbiquitousKeyValueStore defaultStore] setObject:[saved allObjects] forKey:@"subscriptions"];
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionPurchaseSucceededNotification object:self userInfo:nil];
[self parseSubscriptions];
}
}
-(void)purchaseDeferred:(SKPaymentTransaction *)transaction {
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionPurchaseDeferredNotification object:self userInfo:nil];
}
-(void)purchaseFailed:(SKPaymentTransaction *)transaction {
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionPurchaseFailedNotification object:self userInfo:nil];
}
-(void)purchaseRestored:(SKPaymentTransaction *)transaction {
SKPaymentTransaction *originalTransaction = transaction.originalTransaction;
if(originalTransaction && ([originalTransaction.payment.productIdentifier isEqualToString:SKU] || [originalTransaction.payment.productIdentifier isEqualToString:lifetimeSKU])) {
NSDictionary *new = [[NSDictionary alloc] initWithObjectsAndKeys:originalTransaction.transactionIdentifier, @"id", originalTransaction.payment.productIdentifier, @"product",[NSNumber numberWithInteger: originalTransaction.payment.quantity], @"quantity", originalTransaction.transactionDate, @"date", nil];
NSMutableSet *saved = [[[NSMutableSet alloc] initWithArray: [self subscriptions]] autorelease];
[saved addObject:new];
[[NSUserDefaults standardUserDefaults] setObject:[saved allObjects] forKey:@"subscriptions"];
[[NSUbiquitousKeyValueStore defaultStore] setObject:[saved allObjects] forKey:@"subscriptions"];
[[NSNotificationCenter defaultCenter] postNotificationName:_subscriptionPurchaseSucceededNotification object:self userInfo:nil];
[self parseSubscriptions];
}
}
- (void)userNotifiedForSubscriptionEnd {
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:@"subscriptionEndNotificationDate"];
}
@end
|