I have an iPhone game in Appstore, I recently tried to upload an updated build with latest Xcode but it was rejected because the inApp-purchases were not working on ipv6 only network. It's working fine with ipv4 network.
//
// ViewController.m
//
NSMutableArray * arrayOfSection;
NSMutableArray * sectionHeaders;
NSString *error;
#import "CoinsController.h"
#import "NSString+SBJSON.h"
#import <CommonCrypto/CommonDigest.h>
#implementation CoinsController
#synthesize bkg;
-(void) callPurchaseId:(NSString*)iapId amount:(NSUInteger)ncoins{
SKPayment *payment = [SKPayment paymentWithProductIdentifier:iapId];
//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.9;
[UIView commitAnimations];
loadingtext.text = #"Processing Purchase";
NSLog(#"Processing Purhcase");
// currentGem = [NSString stringWithFormat:#"vegas%#", #"80k"];
[CommonUtilities encryptString:[NSString stringWithFormat:#"%lu", (unsigned long)ncoins]:#"c"];
NSLog(#"Processing");
}
- (IBAction)purchaseCoins:(id)sender{
UIButton *button = (UIButton *)sender;
NSLog(#"%li", (long)button.tag);
switch (button.tag) {
case 1001:
[self callPurchaseId:IAP1 amount:IAP_AMT_1];
break;
case 1002:
[self callPurchaseId:IAP2 amount:IAP_AMT_2];
break;
case 1003:
[self callPurchaseId:IAP3 amount:IAP_AMT_3];
break;
case 1004:
[self callPurchaseId:IAP4 amount:IAP_AMT_4];
break;
case 1005:
[self callPurchaseId:IAP5 amount:IAP_AMT_5];
break;
case 1006:
[self callPurchaseId:IAP6 amount:IAP_AMT_6];
break;
default:
break;
}
}
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSNumberFormatter* nf = [[NSNumberFormatter alloc] init];
nf.usesGroupingSeparator = YES;
nf.groupingSize = 3;
((UILabel*)[self.view viewWithTag:2001]).text = [NSString stringWithFormat:#"%# Coins", [nf stringFromNumber:[NSNumber numberWithInteger:IAP_AMT_1]]];
((UILabel*)[self.view viewWithTag:2002]).text = [NSString stringWithFormat:#"%# Coins", [nf stringFromNumber:[NSNumber numberWithInteger:IAP_AMT_2]]];
((UILabel*)[self.view viewWithTag:2003]).text = [NSString stringWithFormat:#"%# Coins", [nf stringFromNumber:[NSNumber numberWithInteger:IAP_AMT_3]]];
((UILabel*)[self.view viewWithTag:2004]).text = [NSString stringWithFormat:#"%# Coins", [nf stringFromNumber:[NSNumber numberWithInteger:IAP_AMT_4]]];
((UILabel*)[self.view viewWithTag:2005]).text = [NSString stringWithFormat:#"%# Coins", [nf stringFromNumber:[NSNumber numberWithInteger:IAP_AMT_5]]];
((UILabel*)[self.view viewWithTag:2006]).text = [NSString stringWithFormat:#"%# Coins", [nf stringFromNumber:[NSNumber numberWithInteger:IAP_AMT_6]]];
[nf release];
}
- (void)requestProUpgradeProductData
{
NSLog(#"called productsRequest");
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.9;
[UIView commitAnimations];
loadingtext.text = #"Connecting to Store";
if([cost1000.text isEqual:#"0.00"]){
NSSet *productIdentifiers = [NSSet setWithObjects:IAP1, IAP2, IAP3, IAP4, IAP5, IAP6, nil];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}else{
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
}
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSString *sym = #"";
NSArray *items = response.products;
for(SKProduct *itemproduct in items)
{
NSLog(#"Product title: %# - %#" , itemproduct.localizedTitle, itemproduct.priceAsString);
//NSLog(#"Product description: %#" , item.localizedDescription);
//NSLog(#"Product price: " , ;
NSLog(#"Product id: %#" , itemproduct.productIdentifier);
if([itemproduct.productIdentifier isEqual:IAP1]){
cost1000.text = [sym stringByAppendingString:[NSString stringWithFormat:#"%#", itemproduct.priceAsString]];
}else if([itemproduct.productIdentifier isEqual:IAP2]){
cost3200.text = [sym stringByAppendingString:[NSString stringWithFormat:#"%#", itemproduct.priceAsString]];
}else if([itemproduct.productIdentifier isEqual:IAP3]){
cost8000.text = [sym stringByAppendingString:[NSString stringWithFormat:#"%#", itemproduct.priceAsString]];
}else if([itemproduct.productIdentifier isEqual:IAP4]){
cost20000.text = [sym stringByAppendingString:[NSString stringWithFormat:#"%#", itemproduct.priceAsString]];
}else if([itemproduct.productIdentifier isEqual:IAP5]){
cost80000.text = [sym stringByAppendingString:[NSString stringWithFormat:#"%#", itemproduct.priceAsString]];
}else if([itemproduct.productIdentifier isEqual:IAP6]){
cost200000.text = [sym stringByAppendingString:[NSString stringWithFormat:#"%#", itemproduct.priceAsString]];
}
}
for (NSString *invalidProductId in response.invalidProductIdentifiers)
{
NSLog(#"Invalid product id: %#" , invalidProductId);
error = #"YES";
}
if([error isEqual:#"YES"]){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Payments Error Occured" message:#"Could not read payment information from Apple In-App Servers. Please try again later" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
[self dismissViewControllerAnimated:YES completion:nil];
error = #"NO";
}
// finally release the reqest we alloc/init’ed in requestProUpgradeProductData
//[productsRequest release];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
}
//
// removes the transaction from the queue and posts a notification with the transaction result
//
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
// remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
if (wasSuccessful)
{
#ifdef kURL_VERIFY_PURCHASE_RECEIPT
NSString *jsonObjectString = [CommonUtilities encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
////NSLog(jsonObjectString);
[CommonUtilities encryptString:[CommonUtilities md5:jsonObjectString]:#"b"];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.9;
[UIView commitAnimations];
//loadingtext.text = #"Purchase Completing";
loadingtext.text = #"Completing Transaction";
NSString *httpBodyString=[[NSString alloc] initWithFormat:#"receipt=%#&userid=%#",jsonObjectString, [CommonUtilities decryptString:#"username"]];
NSString *urlString=kURL_VERIFY_PURCHASE_RECEIPT;
NSURL *url=[[NSURL alloc] initWithString:urlString];
[urlString release];
NSMutableURLRequest *urlRequest=[NSMutableURLRequest requestWithURL:url];
[url release];
NSString *postLength = [NSString stringWithFormat:#"%d", [httpBodyString length]];
[urlRequest setValue:postLength forHTTPHeaderField:#"Content-Length"];
[urlRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[httpBodyString dataUsingEncoding:NSISOLatin1StringEncoding]];
[httpBodyString release];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
connection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
responseData=[[NSMutableData data] retain];
#else
int addCoins = [[CommonUtilities decryptString:#"c"] intValue];
int currentCoins = [[CommonUtilities decryptString:#"coins"] intValue];
int newCoins = addCoins + currentCoins;
[CommonUtilities encryptString:[NSString stringWithFormat:#"%i", newCoins]:#"coins"];
// due to sync issues we add + 1 to xp so sync to server completes
NSLog(#"transaction complete");
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
#endif
}
else
{
NSLog(#"Purchase failed");
// send out a notification for the failed transaction
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, #"transaction" , nil];
//[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
}
}
//
// called when the transaction was successful
//
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
[self finishTransaction:transaction wasSuccessful:YES];
}
//
// called when a transaction has failed
//
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
// error!
[self finishTransaction:transaction wasSuccessful:NO];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
NSLog(#"error transaction");
}
else
{
// this is fine, the user just cancelled, so don’t notify
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
NSLog(#"cancelled transaction");
}
}
//
// called when the transaction status is updated
//
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
default:
break;
}
}
}
#pragma mark -
- (IBAction)closeCoins:(id)sender{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
webView.opaque = NO;
webView.backgroundColor = [UIColor clearColor];
webView.dataDetectorTypes = UIDataDetectorTypeLink;
jackpotView.opaque = NO;
jackpotView.backgroundColor = [UIColor clearColor];
//[self didLoad];
NSString *filename = #"store.jpg";
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.width == 568.0f) {
filename = [filename stringByReplacingOccurrencesOfString:#".jpg" withString:#"-568h#2x.jpg"];
[self.bkg setBounds:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
NSLog(#"YAGO - changing background: %#", filename);
}
if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) {
filename = #"store-ipad.jpg";
}
self.bkg.image = [UIImage imageNamed:filename];
viewLoading.alpha = 0.0;
viewNoInternet.alpha = 0.0;
// reachability
[self tryConnect:nil];
if([SKPaymentQueue canMakePayments]){
////NSLog(#"can make payments");
[self requestProUpgradeProductData];
}else{
////NSLog(#"cannot make payments");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Payments Disabled" message:#"In-App Purchases are disabled on this device." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
[self dismissViewControllerAnimated: YES completion:nil];
}
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width * scale, result.height * scale);
if(result.height == 960){
bar.frame = CGRectMake(0,0,(result.height / 2),32);
}else if(result.height == 1136){
bar.frame = CGRectMake(0,0,(result.height / 2),32);
}else if(result.height == 1024){
bar.frame = CGRectMake(0,0,result.height,44);
}else if (result.height == 2048){
bar.frame = CGRectMake(0,0,result.height/2,44);
}
else{
bar.frame = CGRectMake(0,0,(result.height),32);
}
int fontSize = 16;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
//[[UILabel appearance] setFont:[UIFont fontWithName:#"Myriad Web Pro" size:28.0]];
}else{
//[[UILabel appearance] setFont:[UIFont fontWithName:#"Myriad Web Pro" size:12.0]];
fontSize = 12;
}
UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithTitle:#"Close" style:UIBarButtonItemStyleBordered target:nil action:nil] autorelease];
UIImage *buttonBack32 = [[UIImage imageNamed:#"NavigationBackButton"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 5)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:buttonBack32 forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor whiteColor],
UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8],
UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, -1)],
UITextAttributeTextShadowOffset,
[UIFont fontWithName:#"Helvetica-Bold" size:fontSize],
UITextAttributeFont,
nil]
forState:UIControlStateNormal];
self.navigationItem.backBarButtonItem = backButton;
}
-(void)viewWillDisappear:(BOOL)animated{
NSLog(#"coins has gone");
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateCoins" object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:#"sortCoins" object:self];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
//[[UILabel appearance] setFont:[UIFont fontWithName:#"Myriad Web Pro" size:20.0]];
}else{
//[[UILabel appearance] setFont:[UIFont fontWithName:#"Myriad Web Pro" size:10.0]];
}
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
- (BOOL) shouldAutorotate {
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight){
return YES;
}else{
return NO;
}
}
- (void)dealloc {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[self.bkg release];
[super dealloc];
}
#pragma mark for server side validation (no customer support)
// these connection-related methods are only here to help in case you ever decide to implement
// server-side validation of purchase receipts
// - in this case, you'll also need to define your own kURL_VERIFY_PURCHASE_RECEIPT and figure out the existing validation protocol (I can't provide you with support on this one, it's code written by someone else)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
//NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
if ([response respondsToSelector:#selector(allHeaderFields)]) {
//NSDictionary *dictionary = [httpResponse allHeaderFields];
//NSLog([dictionary description]);
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
//NSString *a = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(#"Data: %#", a);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Connection" message:#"You are not connected to the internet or data. Please connect and try again." delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
//////NSLog(responseString);
NSString *gKey = [CommonUtilities decryptString:#"b"];
NSString *result = [CommonUtilities base64Decrypt:responseString:gKey];
NSLog(#"%#",result);
int r = [result intValue];
////NSLog(#"r int: %i", r);
if(r == 1){
int addCoins = [[CommonUtilities decryptString:#"c"] intValue];
int currentCoins = [[CommonUtilities decryptString:#"coins"] intValue];
int newCoins = addCoins + currentCoins;
[CommonUtilities encryptString:[NSString stringWithFormat:#"%i", newCoins]:#"coins"];
// due to sync issues we add + 1 to xp so sync to server completes
NSLog(#"transaction complete");
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Receipt Failed" message:#"Please make the purchase again using a vaild iTunes account" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
[self dismissViewControllerAnimated:YES completion:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(fadeOut:finished:context:)];
viewLoading.alpha = 0.0;
[UIView commitAnimations];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
#end
I don't know whats wrong with this code. The only thing I get in the xcode debug log is "Purchase failed" .
Any help will be highly appreciated.
Turns out the problem wasn't on my side . Since sandbox.itunes.apple.com does not have an ipv6 address so it works with DNS64 (or NAT64 or whatever this thing is :D .I don't know much about this stuff) and not on a real ipv6 only network.
Not sure why they rejected my app the first time but it was approved after I resubmitted it .
Related
Any one know how to reload collectionView in parentViewController when removing childViewController.
Here, I am processing on click of button adding childViewController and on click of that childViewController I am getting data and that data will transferred to parentViewController after that child view get's remove from parentViewController.
I am getting data from childViewController, also reloading collection view.
dispatch_async(dispatch_get_main_queue(),^{
[self.view layoutIfNeeded];
[self.collectionViewcellItem layoutIfNeeded];
[self.collectionViewcellItem reloadData];
});
but, no effect of reloading here seen.
means not able to change parentviewconroller view after removal of childViewController.
Thank you
Waiting for the answer and yes I am doing it in objective c.
parentViewController file.
[self.view addSubview:filterMenuVC.view];
filterMenuVC.view.backgroundColor = [UIColor clearColor];
[self addChildViewController:filterMenuVC];
[self.view addSubview:filterMenuVC.view];
[self animationSideFilterMenuBarOpen];
[filterMenuVC didMoveToParentViewController:self];
childViewController file
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"%#",[NSString stringWithFormat:#"%ld",(long)indexPath.row]);
// // [wel animationSideFilterMenuBarClose];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
int categoryId = (int)cell.textLabel.tag;
[self animationSideMainMenuBarClose:categoryId];
}
-(void)animationSideMainMenuBarClose:(int)categoryId{
CGFloat width = [UIScreen mainScreen].bounds.size.width;
self.view.frame = CGRectMake(width - self.view.frame.size.width, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
[UIView animateWithDuration:0.5 animations:^{
self.view.frame = CGRectMake(width, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);
}
completion:^(BOOL finished){
[self.view removeFromSuperview];
self.view = nil;
NSLog(#"category id Filter: %d",categoryId);
BOOL boolresponse = [wel getUserWork:categoryId];
if (boolresponse == NO) {
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:#""
message:#"No internet connection"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
}
}];
}
here, BOOL boolresponse = [wel getUserWork:categoryId]; getUserWork is the function in parentViewController, I call that and removing the childViewController. get correct data but not able to reload collectionView.
parentViewFunction which I am calling.
-(BOOL)getUserWork:(int)catergoryId{
appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
[self dismissViewControllerAnimated:true completion:^{
//do whatever you do here
[self.collectionViewcellItem reloadData];
}];
categoryIdStart = catergoryId;
Reachability *r = [[Reachability alloc]init];
if(r.currentReachabilityStatus != NotReachable) {
return NO;
}
else
{
[SVProgressHUD show];
[SVProgressHUD setStatus:#"Loading..."];
[SVProgressHUD setRingRadius:20];
[SVProgressHUD setRingThickness:10];
[SVProgressHUD setBorderColor:[UIColor orangeColor]];
[SVProgressHUD setBorderWidth:0.5];
[SVProgressHUD setForegroundColor:[UIColor orangeColor]];
NSLog(#"id category: %d",categoryIdStart);
NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:[appDelegate.UserDic valueForKey:#"token"],#"token",[appDelegate.UserDic valueForKey:#"id"],#"id_user",[NSString stringWithFormat:#"%d",categoryIdStart],#"id_category",nil];
NSMutableArray *postArray = [NSMutableArray array];
[params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
[postArray addObject:[NSString stringWithFormat:#"%#=%#", key, [apiCall percentEscapeString:obj]]];
}];
NSString *postString = [postArray componentsJoinedByString:#"&"];
[apiCall apiType:#"xyzzy" pD:postString dataRetrive:^(NSDictionary *dictionary){
int status = [[dictionary valueForKey:#"status"] intValue];
if (status == 0) {
[SVProgressHUD dismiss];
dispatch_async(dispatch_get_main_queue(),^{
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:#""
message:[dictionary valueForKey:#"msg"]
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okButton = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
});
}
else{
[SVProgressHUD dismiss];
[cacheImage removeAllObjects];
dic = [dictionary valueForKey:#"data"];
NSLog(#"Category detail: %# %lu",dic,(unsigned long)dic.count);
NSLog(#"image category %# :",[dic valueForKey:#"category_name"]);
dispatch_async(dispatch_get_main_queue(),^{
[self.view layoutIfNeeded];
[self.collectionViewcellItem layoutIfNeeded];
[self.collectionViewcellItem reloadData];
[self viewWillAppear:true];
});
}
}];
return YES;
}
}
I have used a UIWebView to show an url over that. It works fine but client said to download video and save it into photo gallery.i have written code for downloading video from UIWebView and saving it to photo gallery. But i have written a condition, if user clicked on a video that is already downloaded and saved to photo gallery,to show an alert that file is already saved.then i see on that when this message is shown in the same time there is black screen appears on the view same as media player . so my question is that- How to Control or remove that black screen from web view i have removed black screen by reloading same UIWebView but this is not fulfilling my requirement so please help me... Please.. Please
Here is my code for showing url on UIWebView and saving video file
#import "WebViewController.h"
#import "AppDelegate.h"
#interface WebViewController ()
{
NSURL *theRessourcesURL;
}
#property (nonatomic, strong) NSString *lastURL;
#property(nonatomic,strong)MBProgressHUD *hud;
#end
#implementation WebViewController
#synthesize webView;
- (void)viewDidLoad
{
[super viewDidLoad];
BOOL isLandscape = UIDeviceOrientationIsLandscape(self.interfaceOrientation);
BOOL isPortrait = UIDeviceOrientationIsPortrait(self.interfaceOrientation);
if(isLandscape)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 568, 300)];
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 480, 300)];
}
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 1004, 748)];
}
NSLog(#"isLandscape");
}
else if (isPortrait)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 320, 548)];
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 320, 460)];
}
}
else
{
webView= [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, 768, 984)];
}
}
[webView setDelegate:self];
webView.tag = 999;
for (UIView* subView in webView.subviews) {
if ([subView isKindOfClass:[UIScrollView class]]) {
currentScrollView = (UIScrollView *)subView;
currentScrollView.delegate = (id) self;
}
}
//demo url
NSString *fullURL = #"http://demo.php.anuj.com/videoapp-t/home";
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
pull = [[PullToRefreshView alloc] initWithScrollView:currentScrollView];
[pull setDelegate:self];
pull.tag = 998;
[currentScrollView addSubview:pull];
[self.view addSubview:webView];
}
-(void)pullToRefreshViewShouldRefresh:(PullToRefreshView *)view {
[(UIWebView *)[self.view viewWithTag:999] reload];
}
- (void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
BOOL isLandscape = UIDeviceOrientationIsLandscape(self.interfaceOrientation);
BOOL isPortrait = UIDeviceOrientationIsPortrait(self.interfaceOrientation);
if(isLandscape)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView.frame =CGRectMake(0, 20, 568, 300);
}
else
{
webView.frame =CGRectMake(0, 20, 480, 300);
}
}
else
{
webView.frame =CGRectMake(0, 20, 1004, 748);
}
NSLog(#"isLandscape");
}
else if (isPortrait)
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
if (screenRect.size.height > 500)
{
webView.frame = CGRectMake(0, 20, 320, 548);
}
else
{
webView.frame =CGRectMake(0, 20, 320, 460);
}
}
else
{
webView.frame =CGRectMake(0, 20, 768, 984);
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - webview
- (void)webViewDidStartLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = #"Loading...";
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES];
[(PullToRefreshView *)[self.view viewWithTag:998] finishedLoading];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
AppDelegate *appdel=[[UIApplication sharedApplication]delegate];
NetworkStatus remoteHostStatus = [appdel.reachability currentReachabilityStatus];
if (remoteHostStatus == NotReachable)
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Anuj Demo" message:#"Internet connection required. Please check connectivity to internet." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
else
{
// UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Anuj Demo" message:#"Internet connection required. Please pull to refresh." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
// [alert show];
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES];
[(PullToRefreshView *)[self.view viewWithTag:998] finishedLoading];
}
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType
{
if ( inType == UIWebViewNavigationTypeLinkClicked )
{
theRessourcesURL = [inRequest URL];
NSString *fileExtension = [theRessourcesURL pathExtension];
if ([fileExtension isEqualToString:#"mp4"] || [fileExtension isEqualToString:#"mov"] || [fileExtension isEqualToString:#"m4v"])
{
// Get the filename of the loaded ressource form the UIWebView's request URL
NSString *filename = [theRessourcesURL lastPathComponent];
NSLog(#"Filename: %#", filename);
NSFileManager *filemanager=[NSFileManager defaultManager];
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:filename];
BOOL success =[filemanager fileExistsAtPath:path];
if (success ==TRUE) {
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"Reel Africa" message:[NSString stringWithFormat:#"The file %# already exists.", filename] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
// Here if i reload webview then it works otherwise giving black screen on webview like media player( [webview reload])
}
else
{
[self performSelector:#selector(saveVideoTOPhotoAlbum) withObject:nil afterDelay:0.2];
}
}
else if([fileExtension isEqualToString:#"wmv"] || [fileExtension isEqualToString:#"3gp"] || [fileExtension isEqualToString:#"3G2"])
{
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"Anuj Demo" message:#"iPhone does not support this vedio format." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
}
NSString *tempString = [NSString stringWithFormat:#"%#",[inRequest URL]];
if ([tempString rangeOfString:#"?ultima"].location != NSNotFound) {
[[UIApplication sharedApplication] openURL:[inRequest URL]];
return NO;
}
}
return YES;
}
-(void)saveVideoTOPhotoAlbum
{
NSString *filename = [theRessourcesURL lastPathComponent];
NSLog(#"Filename: %#", filename);
// Get the path to the App's Documents directory
NSString *docPath = [self documentsDirectoryPath];
// Combine the filename and the path to the documents dir into the full path
NSString *pathToDownloadTo = [NSString stringWithFormat:#"%#/%#", docPath, filename];
// Load the file from the remote server
NSData *tmp = [NSData dataWithContentsOfURL:theRessourcesURL];
// Save the loaded data if loaded successfully
if (tmp != nil) {
NSError *error = nil;
[tmp writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];
// Write the contents of our tmp object into a file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *getImagePath = [basePath stringByAppendingPathComponent:filename];
printf(" \n\n\n-Video file == %s",[getImagePath UTF8String]);
UISaveVideoAtPathToSavedPhotosAlbum ( getImagePath,self, #selector(video:didFinishSavingWithError: contextInfo:), nil);
if (error != nil) {
NSLog(#"Failed to save the file: %#", [error description]);
} else {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[MBProgressHUD hideHUDForView:self.view animated:YES];
// Display an UIAlertView that shows the users we saved the file :)
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"Anuj Demo" message:[NSString stringWithFormat:#"The file %# has been saved.", filename] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
}
}
}
- (void) video: (NSString *) videoPath didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo
{
NSLog(#"Finished saving video with error: %#", error);
//Anuj here ****
}
- (NSString *)documentsDirectoryPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [paths objectAtIndex:0];
return documentsDirectoryPath;
}
#end
If file exist, you should return NO. try it.
I am trying to remove ads with In App Purchase but It does not work. When I open my app the banner comes up and when I tap the banner it says it is working correctly. However after a few seconds it disappears and then appears again after a few minutes. Just keeping on the same screen. Is my code correct for this?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSUserDefaults *saveapp = [NSUserDefaults standardUserDefaults];
bool saved = [saveapp boolForKey:k_Save];
if (!saved) {
/// not save code here
} else {
///saved code here
Label.text = #"item has been purchased";
}
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
NSUserDefaults *saveapp = [NSUserDefaults standardUserDefaults];
bool saved = [saveapp boolForKey:k_Save];
if (!saved) {
/// not save code here
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];
} else {
///saved code here
}
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[banner setAlpha:0];
[UIView commitAnimations];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
This is for saving
- (IBAction)PurchaseItem:(id)sender {
_purchaseController = [[PurchasedViewController alloc] initWithNibName:nil bundle:nil];
_purchaseController.productID = #"com.myname.test.iap1";
[[SKPaymentQueue defaultQueue] addTransactionObserver:_purchaseController];
[self presentViewController:_purchaseController animated:YES completion:NULL];
[_purchaseController getProductID:self];
}
-(void)Purchased {
Label.text = #"item has been purchased";
iadBanner.hidden = YES;
NSUserDefaults *saveapp = [NSUserDefaults standardUserDefaults];
[saveapp setBool:TRUE forKey:k_Save];
[saveapp synchronize];
}
- (IBAction)BuyProduct:(id)sender {
SKPayment *payment = [SKPayment paymentWithProduct:_product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (IBAction)Restore:(id)sender {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
[self UnlockPurchase];
}
-(void)getProductID:(ViewController *)viewController {
_homeViewController = viewController;
if ([SKPaymentQueue canMakePayments]) {
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:self.productID]];
request.delegate = self;
[request start];
} else
_productDescription.text = #"Please enable in app purchase in your settings";
}
#pragma mark _
#pragma mark SKProductsRequestDelegate
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSArray *products = response.products;
if (products.count != 0) {
_product = products[0];
_buyButton.enabled = YES;
_productTitle.text = _product.localizedTitle;
_productDescription.text = _product.localizedDescription;
} else {
_productTitle.text = #"Product Not Found";
}
products = response.invalidProductIdentifiers;
for (SKProduct *product in products) {
NSLog(#"Product not Found: %#", product);
}
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:[self UnlockPurchase];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:NSLog(#"Transaction Failed");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
default:
break;
}
}
}
-(void)UnlockPurchase {
_buyButton.enabled = NO;
[_buyButton setTitle:#"Purchased" forState:UIControlStateDisabled];
[_homeViewController Purchased];
}
Well, at least one potential issue I see is that you try to hide with:
iadBanner.hidden = YES;
But I don't see that property referred to anywhere else. Is it synthesized? Hooked up in IB?
With ios7 use self.canDisplayBannerAds instead , its easier and more straight forward
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
bool adsRemoved = [userDefaults boolForKey:#"removeAds"];
self.canDisplayBannerAds=!adsRemoved;
}
I am trying to make it so that if I buy an item on my app it would allow me to hide the iAd that I have put.
However, when I test it out only my restore button is tappable and I cannot tap the buy button.
Did I miss something with my app?
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSUserDefaults *saveapp = [NSUserDefaults standardUserDefaults];
bool saved = [saveapp boolForKey:k_Save];
if (!saved) {
/// not save code here
} else {
///saved code here
Label.text = #"item has been purchased";
}
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
NSUserDefaults *saveapp = [NSUserDefaults standardUserDefaults];
bool saved = [saveapp boolForKey:k_Save];
if (!saved) {
/// not save code here
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];
} else {
///saved code here
}
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[banner setAlpha:0];
[UIView commitAnimations];
}
- (IBAction)PurchaseItem:(id)sender {
_purchaseController = [[PurchasedViewController alloc] initWithNibName:nil bundle:nil];
_purchaseController.productID = #"com.myname.appname.iap1";
[[SKPaymentQueue defaultQueue] addTransactionObserver:_purchaseController];
[self presentViewController:_purchaseController animated:YES completion:NULL];
[_purchaseController getProductID:self];
}
-(void)Purchased {
Label.text = #"item has been purchased";
iadBanner.hidden = YES;
NSUserDefaults *saveapp = [NSUserDefaults standardUserDefaults];
[saveapp setBool:TRUE forKey:k_Save];
[saveapp synchronize];
}
Purchase View
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
_buyButton.enabled = NO;
}
- (IBAction)BuyProduct:(id)sender {
SKPayment *payment = [SKPayment paymentWithProduct:_product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (IBAction)Restore:(id)sender {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
[self UnlockPurchase];
}
-(void)getProductID:(ViewController *)viewController {
_homeViewController = viewController;
if ([SKPaymentQueue canMakePayments]) {
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:self.productID]];
request.delegate = self;
[request start];
} else
_productDescription.text = #"Please enable in app purchase in your settings";
}
#pragma mark _
#pragma mark SKProductsRequestDelegate
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSArray *products = response.products;
if (products.count != 0) {
_product = products[0];
_buyButton.enabled = YES;
_productTitle.text = _product.localizedTitle;
_productDescription.text = _product.localizedDescription;
} else {
_productTitle.text = #"Product Not Found";
}
products = response.invalidProductIdentifiers;
for (SKProduct *product in products) {
NSLog(#"Product not Found: %#", product);
}
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:[self UnlockPurchase];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:NSLog(#"Transaction Failed");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
default:
break;
}
}
}
-(void)UnlockPurchase {
_buyButton.enabled = NO;
[_buyButton setTitle:#"Purchased" forState:UIControlStateDisabled];
[_homeViewController Purchased];
}
You are explicitly disabling it with: _buyButton.enabled = NO; on viewDidLoad and are only setting it enabled when you receive products.. which you can only do by tapping the button in the first place.
I am confused about how to and when to tell the user that they completed the purchase successfully. I got my application rejected during the app review process for this reason:
1. Launch app
2. Tap on learn about the benefits of subscription
3. Tap on Subscribe
4. Tap on Confirm and enter iTunes password
5. No further action occurs
And I am not sure when and how to tell the user they entered their info correctly since that is confirmed on the iTunes server.
I have an IAPHelper class which looks like this:
//
// IAPHelper.m
// BusinessPlan
//
// Created by MacOSLion on 8/12/13.
//
//
// 1
#import "IAPHelper.h"
#import <StoreKit/StoreKit.h>
// 2
//#interface IAPHelper () <SKProductsRequestDelegate>
#interface IAPHelper () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
#end
#implementation IAPHelper
{
// 3
SKProductsRequest * _productsRequest;
// 4
RequestProductsCompletionHandler _completionHandler;
NSSet * _productIdentifiers;
NSMutableSet * _purchasedProductIdentifiers;
}
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers
{
if ((self = [super init]))
{
// Store product identifiers
_productIdentifiers = productIdentifiers;
// Check for previously purchased products
_purchasedProductIdentifiers = [NSMutableSet set];
for (NSString * productIdentifier in _productIdentifiers)
{
BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productIdentifier];
if (productPurchased)
{
[_purchasedProductIdentifiers addObject:productIdentifier];
NSLog(#"Previously purchased: %#", productIdentifier);
// SET memory to yes and then use that later.
// Get user data.
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
// First time on the app, so set the user cookie.
[standardUserDefaults setBool:YES forKey:#"subscriber"];
// Saving
[[NSUserDefaults standardUserDefaults] synchronize];
}
else
{
NSLog(#"Not purchased: %#", productIdentifier);
}
}
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
// retrieve the product information from iTunes Connect
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler
{
// 1
_completionHandler = [completionHandler copy];
// 2
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_productsRequest.delegate = self;
[_productsRequest start];
}
#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"Loaded list of products...");
_productsRequest = nil;
NSArray * skProducts = response.products;
for (SKProduct * skProduct in skProducts)
{
NSLog(#"Found product: %# %# %0.2f",
skProduct.productIdentifier,
skProduct.localizedTitle,
skProduct.price.floatValue);
}
_completionHandler(YES, skProducts);
_completionHandler = nil;
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
NSLog(#"Failed to load list of products.");
_productsRequest = nil;
_completionHandler(NO, nil);
_completionHandler = nil;
}
- (BOOL)productPurchased:(NSString *)productIdentifier
{
return [_purchasedProductIdentifiers containsObject:productIdentifier];
}
- (void)buyProduct:(SKProduct *)product
{
NSLog(#"Buying %#...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction * transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
};
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
NSLog(#"completeTransaction...");
[self provideContentForProductIdentifier:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// SET memory to yes and then use that later.
// Get user data.
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
// First time on the app, so set the user cookie.
[standardUserDefaults setBool:YES forKey:#"subscriber"];
// Saving
[[NSUserDefaults standardUserDefaults] synchronize];
// Tell user that things are purchased.
// MESSAGE PERSON THAT CAN'T CONNECT TO SERVER
// UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Success sending purchase request."
// message:#"Just press OK and wait a few moments while iTunes processes the request." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
//
// [message show];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
NSLog(#"restoreTransaction...");
[self provideContentForProductIdentifier:transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
NSLog(#"failedTransaction...");
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
// MESSAGE PERSON THAT CAN'T CONNECT TO SERVER
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Could not complete your transaction"
message:#"Please try again. If the error persists, please email support at: alex#problemio.com" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
// Add to top of file
NSString *const IAPHelperProductPurchasedNotification = #"IAPHelperProductPurchasedNotification";
// Add new method
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier
{
//NSLog(#"Provifing content for subsciber: ");
// MESSAGE PERSON THAT CAN'T CONNECT TO SERVER
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Subscribed successfully!"
message:#"Now you can ask questions right on the app, and get our monthly business content." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
[_purchasedProductIdentifiers addObject:productIdentifier];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];
}
#end
And my class from which I start the transaction process:
#import "SubscriptionController.h"
// 1
#import "RageIAPHelper.h"
#import <StoreKit/StoreKit.h>
// 2
#interface SubscriptionController ()
{
NSArray *_products;
// Add new instance variable to class extension
NSNumberFormatter * _priceFormatter;
}
#end
#implementation SubscriptionController
// 3
- (void)viewDidLoad
{
[super viewDidLoad];
//self.refreshControl = [[UIRefreshControl alloc] init];
//[self.refreshControl addTarget:self action:#selector(reload) forControlEvents:UIControlEventValueChanged];
[self reload];
//[self.refreshControl beginRefreshing];
// Add to end of viewDidLoad
_priceFormatter = [[NSNumberFormatter alloc] init];
[_priceFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[_priceFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
self.view.backgroundColor = [UIColor colorWithWhite:0.859 alpha:1.000];
}
// 4
- (void)reload
{
_products = nil;
//[self.tableView reloadData];
[[RageIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products)
{
if (success)
{
_products = products;
//[self.tableView reloadData];
}
//[self.refreshControl endRefreshing];
}];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// 5
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _products.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"a");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
SKProduct * product = (SKProduct *) _products[indexPath.row];
cell.textLabel.text = product.localizedTitle;
// Add to bottom of tableView:cellForRowAtIndexPath (before return cell)
[_priceFormatter setLocale:product.priceLocale];
cell.detailTextLabel.text = [_priceFormatter stringFromNumber:product.price];
if ([[RageIAPHelper sharedInstance] productPurchased:product.productIdentifier])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.accessoryView = nil;
}
else
{
UIButton *buyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buyButton.frame = CGRectMake(0, 0, 72, 37);
[buyButton setTitle:#"Buy" forState:UIControlStateNormal];
buyButton.tag = indexPath.row;
[buyButton addTarget:self action:#selector(buyButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryView = buyButton;
}
return cell;
}
//- (IBAction)subscribe:(id)sender
//{
// UIButton *buyButton = (UIButton *)sender;
// SKProduct *product = _products[buyButton.tag];
//
// NSLog(#"Buying %#...", product.productIdentifier);
// [[RageIAPHelper sharedInstance] buyProduct:product];
//}
- (void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(productPurchased:) name:IAPHelperProductPurchasedNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)productPurchased:(NSNotification *)notification
{
NSLog(#"PURCHASEDDDDDDDDD");
// NSString * productIdentifier = notification.object;
// [_products enumerateObjectsUsingBlock:^(SKProduct * product, NSUInteger idx, BOOL *stop)
// {
// if ([product.productIdentifier isEqualToString:productIdentifier])
// {
// // TODO:
// // Update how the button appears.
//
//
//// [self.table reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:idx inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
// *stop = YES;
// }
// }];
// MESSAGE PERSON THAT CAN'T CONNECT TO SERVER
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Purchased successfully"
message:#":)" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
// PUSH TO CONFIRMATION
}
//- (IBAction)subscribe:(id)sender
//{
//
//}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (IBAction)createSub:(id)sender
{
UIButton *buyButton = (UIButton *)sender;
SKProduct *product = _products[buyButton.tag];
if ( product == nil)
{
// MESSAGE PERSON THAT CAN'T CONNECT TO SERVER
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Pulling product data from iTunes..."
message:#"Please try again in a few moments." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
}
else
{
// MESSAGE PERSON THAT CAN'T CONNECT TO SERVER
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Success sending purchase request."
message:#"Just press OK and wait a few moments while iTunes processes the request." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
NSLog(#"Buying %#...", product.productIdentifier);
[[RageIAPHelper sharedInstance] buyProduct:product];
}
}
#end
Thank you for your help!
You should have some sort of UI update to tell the user that the payment was successful and the feature is now available/unlocked. Typically, this is done either with an update in your views to correspond to the new content, or a UIAlertView if there are no visual changes made.