Skip to content

Commit

Permalink
Refresh receipts & Add info about app
Browse files Browse the repository at this point in the history
  • Loading branch information
j3k0 committed Nov 12, 2014
1 parent d4e59c0 commit df492ae
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 112 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
/node_modules/
/coverage/
/test/tmp/
/www/.store-android.js
/www/.store-ios.js
*~
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ build: sync-android test-js
@echo "- Preprocess"
@node_modules/.bin/preprocess src/js/store-ios.js src/js | node_modules/.bin/uglifyjs -b > www/store-ios.js
@node_modules/.bin/preprocess src/js/store-android.js src/js | node_modules/.bin/uglifyjs -b > www/store-android.js
@echo "- DONE"
@echo "- Done"
@echo ""

prepare-test-js:
Expand All @@ -44,6 +44,7 @@ eslint: jshint
test-js: jshint eslint prepare-test-js
@echo "- Mocha"
@node_modules/.bin/istanbul test --root test/tmp test/js/run.js
@echo

test-js-coverage: jshint eslint prepare-test-js
@echo "- Mocha / Instanbul"
Expand Down
11 changes: 10 additions & 1 deletion src/ios/InAppPurchase.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- (void) load: (CDVInvokedUrlCommand*)command;
- (void) purchase: (CDVInvokedUrlCommand*)command;
- (void) appStoreReceipt: (CDVInvokedUrlCommand*)command;
- (void) appStoreRefreshReceipt: (CDVInvokedUrlCommand*)command;

- (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
- (void) paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error;
Expand All @@ -44,5 +45,13 @@

@property (nonatomic,retain) InAppPurchase* plugin;
@property (nonatomic,retain) CDVInvokedUrlCommand* command;

@end;

@interface RefreshReceiptDelegate : NSObject <SKRequestDelegate> {
InAppPurchase* plugin;
CDVInvokedUrlCommand* command;
}

@property (nonatomic,retain) InAppPurchase* plugin;
@property (nonatomic,retain) CDVInvokedUrlCommand* command;
@end
129 changes: 103 additions & 26 deletions src/ios/InAppPurchase.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#define ERR_PAYMENT_INVALID (ERROR_CODES_BASE + 7)
#define ERR_PAYMENT_NOT_ALLOWED (ERROR_CODES_BASE + 8)
#define ERR_UNKNOWN (ERROR_CODES_BASE + 10)
#define ERR_REFRESH_RECEIPTS (ERROR_CODES_BASE + 11)

static NSInteger jsErrorCode(NSInteger storeKitErrorCode)
{
Expand All @@ -56,6 +57,7 @@ static NSInteger jsErrorCode(NSInteger storeKitErrorCode)
case ERR_LOAD: return @"ERR_LOAD";
case ERR_PURCHASE: return @"ERR_PURCHASE";
case ERR_LOAD_RECEIPTS: return @"ERR_LOAD_RECEIPTS";
case ERR_REFRESH_RECEIPTS: return @"ERR_REFRESH_RECEIPTS";
case ERR_CLIENT_INVALID: return @"ERR_CLIENT_INVALID";
case ERR_PAYMENT_CANCELLED: return @"ERR_PAYMENT_CANCELLED";
case ERR_PAYMENT_INVALID: return @"ERR_PAYMENT_INVALID";
Expand All @@ -71,32 +73,32 @@ static NSInteger jsErrorCode(NSInteger storeKitErrorCode)
// maps A=>0,B=>1..
const static unsigned char unb64[]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40
0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50
54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90
25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120
49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250
0, 0, 0, 0, 0, 0,
}; // This array has 255 elements
// Converts binary data of length=len to base64 characters.
Expand Down Expand Up @@ -595,6 +597,26 @@ - (void) appStoreReceipt: (CDVInvokedUrlCommand*)command {
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

- (void) appStoreRefreshReceipt: (CDVInvokedUrlCommand*)command {
DLog(@"Request to refresh app receipt");
RefreshReceiptDelegate* delegate = [[RefreshReceiptDelegate alloc] init];
SKReceiptRefreshRequest* recreq = [[SKReceiptRefreshRequest alloc] init];
recreq.delegate = delegate;
delegate.plugin = self;
delegate.command = command;

#if ARC_ENABLED
self.retainer[@"receiptRefreshRequest"] = recreq;
self.retainer[@"receiptRefreshRequestDelegate"] = delegate;
#else
[delegate retain];
#endif

DLog(@"Starting receipt refresh request...");
[recreq start];
DLog(@"Receipt refresh request started");
}

- (void) dispose {
self.retainer = nil;
self.list = nil;
Expand All @@ -605,6 +627,61 @@ - (void) dispose {
[super dispose];
}

@end
/**
* Receive refreshed app receipt
*/
@implementation RefreshReceiptDelegate

@synthesize plugin, command;

- (void) requestDidFinish:(SKRequest *)request {
DLog(@"Got refreshed receipt");
NSString *base64 = nil;
NSData *receiptData = [self.plugin appStoreReceipt];
if (receiptData != nil) {
base64 = [receiptData convertToBase64];
// DLog(@"base64 receipt: %@", base64);
}
NSBundle *bundle = [NSBundle mainBundle];
NSArray *callbackArgs = [NSArray arrayWithObjects:
NILABLE(base64),
NILABLE([bundle.infoDictionary objectForKey:@"CFBundleIdentifier"]),
NILABLE([bundle.infoDictionary objectForKey:@"CFBundleShortVersionString"]),
NILABLE([bundle.infoDictionary objectForKey:@"CFBundleNumericVersion"]),
NILABLE([bundle.infoDictionary objectForKey:@"CFBundleSignature"]),
nil];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:callbackArgs];
DLog(@"Send new receipt data");
[self.plugin.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

#if ARC_ENABLED
[self.plugin.retainer removeObjectForKey:@"receiptRefreshRequest"];
[self.plugin.retainer removeObjectForKey:@"receiptRefreshRequestDelegate"];
#else
[request release];
[self release];
#endif
}

- (void):(SKRequest *)request didFailWithError:(NSError*) error {
DLog(@"In-App Store unavailable (ERROR %li)", (unsigned long)error.code);
DLog(@"%@", [error localizedDescription]);

CDVPluginResult* pluginResult =
[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]];
[self.plugin.commandDelegate sendPluginResult:pluginResult callbackId:self.command.callbackId];
}

#if ARC_DISABLED
- (void) dealloc {
[plugin release];
[command release];
[super dealloc];
}
#endif

@end

/**
Expand Down
98 changes: 85 additions & 13 deletions src/js/platforms/ios-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ function storekitLoaded(validProducts, invalidProductIds) {
//! Note: the execution of "ready" is deferred to make sure state
//! changes have been processed.
setTimeout(function() {
storekit.loading = false;
storekit.loaded = true;
loading = false;
loaded = true;
store.ready(true);
}, 1);
}
Expand All @@ -224,6 +224,38 @@ function storekitLoadFailed() {
retry(storekitLoad);
}

var refreshCallbacks = [];
var refreshing = false;
function storekitRefreshReceipts(callback) {
if (callback)
refreshCallbacks.push(callback);
if (refreshing)
return;
refreshing = true;

function callCallbacks() {
var callbacks = refreshCallbacks;
refreshCallbacks = [];
for (var i = 0; i < callbacks.length; ++i)
callbacks[i]();
}

storekit.refreshReceipts(function() {
// success
refreshing = false;
callCallbacks();
},
function() {
// error
refreshing = false;
callCallbacks();
});
}

store.when("expired", function() {
storekitRefreshReceipts();
});

//! ### <a name="storekitPurchasing"></a> *storekitPurchasing()*
//!
//! Called by `storekit` when a purchase is in progress.
Expand Down Expand Up @@ -336,6 +368,27 @@ function storekitError(errorCode, errorText, options) {
// };
store.when("re-refreshed", function() {
storekit.restore();
storekit.refreshReceipts(function(data) {
if (data) {
var p = data.bundleIdentifier ? store.get(data.bundleIdentifier) : null;
if (!p) {
p = new store.Product({
id: data.bundleIdentifier || "application data",
alias: "application data",
type: store.NON_CONSUMABLE
});
store.register(p);
}
p.version = data.bundleShortVersion;
p.transaction = {
type: 'ios-appstore',
appStoreReceipt: data.appStoreReceipt,
signature: data.signature
};
p.trigger("loaded");
p.set('state', store.APPROVED);
}
});
});

function storekitRestored(originalTransactionId, productId) {
Expand All @@ -355,19 +408,38 @@ function storekitRestoreFailed(/*errorCode*/) {
});
}

store._refreshForValidation = function(callback) {
storekitRefreshReceipts(callback);
};

// Load receipts required by server-side validation of purchases.
store._prepareForValidation = function(product, callback) {
storekit.loadReceipts(function(r) {
if (!product.transaction) {
product.transaction = {
type: 'ios-appstore'
};
}
product.transaction.appStoreReceipt = r.appStoreReceipt;
if (product.transaction.id)
product.transaction.transactionReceipt = r.forTransaction(product.transaction.id);
callback();
});
var nRetry = 0;
function loadReceipts() {
storekit.loadReceipts(function(r) {
if (!product.transaction) {
product.transaction = {
type: 'ios-appstore'
};
}
product.transaction.appStoreReceipt = r.appStoreReceipt;
if (product.transaction.id)
product.transaction.transactionReceipt = r.forTransaction(product.transaction.id);
if (!product.transaction.appStoreReceipt && !product.transaction.transactionReceipt) {
nRetry ++;
if (nRetry < 2) {
setTimeout(loadReceipts, 500);
return;
}
else if (nRetry === 2) {
storekit.refreshReceipts(loadReceipts);
return;
}
}
callback();
});
}
loadReceipts();
};

//!
Expand Down
Loading

0 comments on commit df492ae

Please sign in to comment.