forked from mirrors/linphone-iphone
continue
This commit is contained in:
parent
35c5adf02a
commit
0909bb2909
9 changed files with 152 additions and 37 deletions
|
|
@ -292,6 +292,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
LOGE(@"Cannot sent logs: file is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
||||
NSString *filename = [appName stringByAppendingString:@".gz"];
|
||||
NSString *mimeType = @"text/plain";
|
||||
|
|
|
|||
|
|
@ -20,15 +20,28 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <StoreKit/StoreKit.h>
|
||||
|
||||
extern NSString *const kInAppProductsReady;
|
||||
extern NSString *const kLinphoneIAPurchaseNotification;
|
||||
|
||||
@interface InAppProductsManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver> {
|
||||
@interface InAppProductsManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>
|
||||
|
||||
}
|
||||
#define IAPAvailableSucceeded @"IAPAvailableSucceeded"
|
||||
#define IAPAvailableFailed @"IAPAvailableFailed"
|
||||
#define IAPPurchaseFailed @"IAPPurchaseFailed"
|
||||
#define IAPPurchaseSucceeded @"IAPPurchaseSucceeded"
|
||||
#define IAPRestoreFailed @"IAPRestoreFailed"
|
||||
#define IAPRestoreSucceeded @"IAPRestoreSucceeded"
|
||||
typedef NSString* IAPPurchaseNotificationStatus;
|
||||
|
||||
@property (readonly) NSArray *inAppProducts;
|
||||
@property (nonatomic, retain) IAPPurchaseNotificationStatus status;
|
||||
@property (nonatomic, copy) NSString *errlast;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray *productsAvailable;
|
||||
@property (nonatomic, strong) NSMutableArray *productsPurchased;
|
||||
@property (nonatomic, strong) NSMutableArray *productsRestored;
|
||||
|
||||
- (void)loadProducts;
|
||||
- (BOOL)isPurchased:(SKProduct*)product;
|
||||
- (void)purchaseWithID:(NSString*)productId;
|
||||
- (void)restore;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#import "InAppProductsManager.h"
|
||||
#import "Utils.h"
|
||||
|
||||
NSString *const kInAppProductsReady = @"InAppProductsReady";
|
||||
NSString *const kLinphoneIAPurchaseNotification = @"LinphoneIAProductsNotification";
|
||||
|
||||
@implementation InAppProductsManager {
|
||||
bool ready;
|
||||
|
|
@ -39,7 +39,7 @@ NSString *const kInAppProductsReady = @"InAppProductsReady";
|
|||
return;
|
||||
}
|
||||
//TODO: move this list elsewhere
|
||||
NSArray * list = [[NSArray alloc] initWithArray:@[@"test.tunnel"]];
|
||||
NSArray * list = [[[NSArray alloc] initWithArray:@[@"test.tunnel"]] autorelease];
|
||||
|
||||
SKProductsRequest *productsRequest = [[SKProductsRequest alloc]
|
||||
initWithProductIdentifiers:[NSSet setWithArray:list]];
|
||||
|
|
@ -49,39 +49,108 @@ NSString *const kInAppProductsReady = @"InAppProductsReady";
|
|||
|
||||
- (void)productsRequest:(SKProductsRequest *)request
|
||||
didReceiveResponse:(SKProductsResponse *)response {
|
||||
_inAppProducts = [response.products retain];
|
||||
LOGI(@"Found %lu products purchasable", (unsigned long)_inAppProducts.count);
|
||||
_productsAvailable= [[NSMutableArray arrayWithArray: response.products] retain];
|
||||
|
||||
for (NSString *invalidIdentifier in response.invalidProductIdentifiers) {
|
||||
LOGE(@"Product Identifier with invalid ID %@", invalidIdentifier);
|
||||
LOGI(@"Found %lu products available", (unsigned long)_productsAvailable.count);
|
||||
|
||||
if (response.invalidProductIdentifiers.count > 0) {
|
||||
for (NSString *invalidIdentifier in response.invalidProductIdentifiers) {
|
||||
LOGW(@"Found product Identifier with invalid ID '%@'", invalidIdentifier);
|
||||
}
|
||||
[self postNotificationforStatus:IAPAvailableFailed];
|
||||
} else {
|
||||
[self postNotificationforStatus:IAPAvailableSucceeded];
|
||||
}
|
||||
ready = true;
|
||||
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
_inAppProducts, @"products",
|
||||
nil];
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppProductsReady object:self userInfo:dict];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)isPurchased:(SKProduct*)product {
|
||||
for (SKProduct *prod in _inAppProducts) {
|
||||
for (SKProduct *prod in _productsPurchased) {
|
||||
if (prod == product) {
|
||||
LOGE(@"Is %@ bought? assuming NO", product.localizedTitle);
|
||||
return false; //todo
|
||||
bool isBought = true;
|
||||
LOGE(@"%@ is %s bought.", product.localizedTitle, isBought?"":"NOT");
|
||||
return isBought;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
- (void)purchaseWithID:(NSString *)productId {
|
||||
|
||||
for (SKProduct *product in _productsAvailable) {
|
||||
if ([product.productIdentifier compare:productId options:NSLiteralSearch] == NSOrderedSame) {
|
||||
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
|
||||
[[SKPaymentQueue defaultQueue] addPayment:payment];
|
||||
return;
|
||||
}
|
||||
}
|
||||
[self postNotificationforStatus:IAPPurchaseFailed];
|
||||
}
|
||||
|
||||
@end
|
||||
-(void)restore {
|
||||
_productsRestored = [[NSMutableArray alloc] initWithCapacity:0];
|
||||
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
|
||||
for(SKPaymentTransaction * transaction in transactions) {
|
||||
switch (transaction.transactionState) {
|
||||
case SKPaymentTransactionStatePurchasing:
|
||||
break;
|
||||
case SKPaymentTransactionStatePurchased:
|
||||
case SKPaymentTransactionStateRestored:
|
||||
[_productsPurchased addObject:transaction];
|
||||
[self completeTransaction:transaction forStatus:IAPPurchaseSucceeded];
|
||||
break;
|
||||
default:
|
||||
_errlast = [NSString stringWithFormat:@"Purchase of %@ failed.",transaction.payment.productIdentifier];
|
||||
[self completeTransaction:transaction forStatus:IAPPurchaseFailed];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions {
|
||||
for(SKPaymentTransaction * transaction in transactions) {
|
||||
NSLog(@"%@ was removed from the payment queue.", transaction.payment.productIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
|
||||
if (error.code != SKErrorPaymentCancelled) {
|
||||
_errlast = [error localizedDescription];
|
||||
[self postNotificationforStatus:IAPRestoreFailed];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
|
||||
{
|
||||
LOGI(@"All restorable transactions have been processed by the payment queue.");
|
||||
// for (SKPayment *payment in queue) {
|
||||
// [queue transactions]
|
||||
// [_productsRestored addObject:payment.productIdentifier];
|
||||
// }
|
||||
|
||||
for (SKPaymentTransaction *transaction in queue.transactions) {
|
||||
NSString *productID = transaction.payment.productIdentifier;
|
||||
[_productsRestored addObject:productID];
|
||||
NSLog (@"product id is %@" , productID);
|
||||
}
|
||||
}
|
||||
|
||||
-(void)postNotificationforStatus:(IAPPurchaseNotificationStatus)status {
|
||||
_status = status;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneIAPurchaseNotification object:self];
|
||||
LOGI(@"Triggering notification for status %@", status);
|
||||
}
|
||||
|
||||
-(void)completeTransaction:(SKPaymentTransaction *)transaction forStatus:(IAPPurchaseNotificationStatus)status {
|
||||
if (transaction.error.code != SKErrorPaymentCancelled) {
|
||||
[self postNotificationforStatus:status];
|
||||
} else {
|
||||
_status = status;
|
||||
}
|
||||
|
||||
// Remove the transaction from the queue for purchased and restored statuses
|
||||
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,25 @@
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
iapm = [[LinphoneManager instance] iapManager];
|
||||
currentExpanded = -1;
|
||||
[iapm loadProducts];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onIAPPurchaseNotification:)
|
||||
name:kLinphoneIAPurchaseNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:kLinphoneIAPurchaseNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)onIAPPurchaseNotification:(NSNotification*)notif {
|
||||
if ([[iapm status] isEqual: IAPAvailableSucceeded]) {
|
||||
[[self tableView] reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
|
@ -30,7 +48,7 @@
|
|||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return [iapm inAppProducts].count;
|
||||
return [iapm productsAvailable].count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
@ -39,7 +57,7 @@
|
|||
if (cell == nil) {
|
||||
cell = [[[InAppProductsCell alloc] initWithIdentifier:kCellId maximized:(currentExpanded == indexPath.row)] autorelease];
|
||||
}
|
||||
SKProduct *prod = [[[[LinphoneManager instance] iapManager] inAppProducts] objectAtIndex:indexPath.row];
|
||||
SKProduct *prod = [[[[LinphoneManager instance] iapManager] productsAvailable] objectAtIndex:indexPath.row];
|
||||
[cell.ptitle setText: [prod localizedTitle]];
|
||||
[cell.pdescription setText: [prod localizedDescription]];
|
||||
[cell.pprice setText: [NSString stringWithFormat:@"%@", [prod price]]];
|
||||
|
|
@ -75,6 +93,7 @@
|
|||
[alert release];
|
||||
} else {
|
||||
//try to purchase item, and if successfull change the switch
|
||||
LOGI(@"Trying to purchase %@", cell.productID);
|
||||
[[[LinphoneManager instance] iapManager] purchaseWithID: cell.productID];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,5 +14,6 @@
|
|||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet InAppProductsTableViewController* tableController;
|
||||
- (IBAction)onRestoreClicked:(UIButton *)sender;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -67,4 +67,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
return compositeDescription;
|
||||
}
|
||||
|
||||
- (IBAction)onRestoreClicked:(UIButton *)sender {
|
||||
[[[LinphoneManager instance] iapManager] restore];
|
||||
}
|
||||
@end
|
||||
|
|
@ -16,8 +16,8 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="10" sectionFooterHeight="10" id="fwu-cz-Gse" userLabel="productsTable">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="10" id="fwu-cz-Gse" userLabel="productsTable">
|
||||
<rect key="frame" x="0.0" y="38" width="320" height="422"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<connections>
|
||||
|
|
@ -25,6 +25,16 @@
|
|||
<outlet property="delegate" destination="FRQ-Fw-iZ8" id="2Dx-aQ-XVB"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="XrD-Mn-6EM" userLabel="restoreButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" title="Restore">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onRestoreClicked:" destination="-1" eventType="touchUpInside" id="ZYY-WP-1of"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
|
|
|
|||
|
|
@ -271,7 +271,8 @@ struct codec_name_pref_table codec_pref_table[]={
|
|||
[LinphoneLogger logc:LinphoneLoggerError format:"cannot register route change handler [%ld]",lStatus];
|
||||
}
|
||||
|
||||
|
||||
_iapManager = [[InAppProductsManager alloc] init];
|
||||
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"];
|
||||
self.messagePlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil] autorelease];
|
||||
|
||||
|
|
@ -1283,8 +1284,6 @@ static LinphoneCoreVTable linphonec_vtable = {
|
|||
[_contactSipField release];
|
||||
_contactSipField = [[self lpConfigStringForKey:@"contact_im_type_value" withDefault:@"SIP"] retain];
|
||||
|
||||
_iapManager = [[InAppProductsManager alloc] init];
|
||||
|
||||
fastAddressBook = [[FastAddressBook alloc] init];
|
||||
|
||||
linphone_core_set_root_ca(theLinphoneCore, lRootCa);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>2</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIApplicationExitsOnSuspend</key>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue