Authentication Challenge - iphone

i try to access a protected webfolder with the webview. with "hard coded" user and pass it works, but my plan is to pop up an alertview to enter user and pass. here is the part of code:
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge{
NSLog(#"Need Authentication");
UIAlertView *webLogin = [[UIAlertView alloc] initWithTitle:#"Authentication"
message:#"Enter User and Pass"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK"
, nil];
webLogin.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
[webLogin show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
user = [[alertView textFieldAtIndex:0]text];
pass = [[alertView textFieldAtIndex:1]text];
NSLog(#"user is %# and pass is %#",user,pass);
if (buttonIndex == [alertView cancelButtonIndex]) {
[self dismissModalViewControllerAnimated:YES];
}
else if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"OK Pressed");
[self handleAuthentificationOKForChallenge:nil withUser:user password:pass];
}
}
- (void)handleAuthentificationOKForChallenge:(NSURLAuthenticationChallenge *)aChallenge withUser:(NSString *)userName password:(NSString *)password {
NSURLCredential *credential = [[NSURLCredential alloc]
initWithUser:userName password:password
persistence:NSURLCredentialPersistenceForSession];
[[aChallenge sender] useCredential:credential forAuthenticationChallenge:aChallenge];
}
can anybody tell me how to call the handleAuthenticationOKForChallenge
i´m a little bit confused with the NSURLAuthenticationChallenge....

First things first, you shouldn't use two if statements one after the other if they're comparing the same variable. Your second if statement should be an else if statement.
It looks like your handleAuthentificationOKForChallenge method wants to accept an instance of NSURLAuthenticationChallenge, but you're currently just passing it nil.
Why don't you declare an instance of NSURLAuthenticationChallenge in your header file (let's call it myChallenge), and in your first method, allocate and initialize it with challenge. You could also just set it equal to challenge (might work, if you feel like trying this first), but you may lose the pointer at some point.
Then you would change your line in your second method to:
[self handleAuthentificationOKForChallenge:myChallenge withUser:user password:pass];
Let me know if this works...

Related

iOS In app purchase doesn't call restoreTransaction on already purchased item

I am working on in app purchase with ios and i have few doubts, that doubts will be helpful for fresher like me so understand In app purchase.
1)I got problem in my app if user "install my app into new device or same device if he remove my app before" at that time when user try to buy already purchase item my code does not callrestoreTransaction in switch case of updatedTransactions
I get the message that you ve already purchased this tap okay to downlaod it FREE Enviornment sandbox and it call the SKPaymentTransactionStatePurchased case but it does not call the SKPaymentTransactionStateRestored what will the problem in my case..
So i have implementing separate Restore Button to restore all video item already brought by user so just need to know that will it reject my app at apple store?
2) For purchase of item it ask me password only one time and after that it doesn't ask me for password to purchase. it directly display the dialog box with confirm button but my project manager says it should ask for password for every item purchase.
It ask for password every time when i try to restore the Purchase..strange.
3) Currently i am testing in sandbox when i try to purchase with real apple id it display purchase failed(i have to use test account to test purchase as apple document says) but my project manager says that it should ask for new test username if you are testing in sandbox (as document said you have to sign out from setting manually but my project manager want to it should do automatically) ,
So just need to ask that is it possible to sign-out and display sign box by coding ( i know its not possible but for information i ask)
4)Currently my app is working in sandbox environment but do i need to change something for real purchase for my app?..or apple will automatically change sandbox to real purchase when apple validate my app and sign it and available on app store?
5)i am validating transaction on my own server so i am sending sandbox 1 if i am on sandbox environment otherwise i have to send 0 ( currently i hardcode sandbox value to 1)so is there any method to detect environment is sandbox or real?
Here is my purchase code and Restore button code
any help is appreciated
Purchase code
- (IBAction)PaymentButton:(id)sender {
loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.labelText = NSLocalizedString(#"Loading", nil);
[loadingHUD show:YES];
[self startPurchase];// call the restore Purchase method
//[loadingHUD showWhileExecuting:#selector(startPurchase) onTarget:self withObject:nil animated:YES];// call the restore Purchase method
}
- (void)startPurchase {
if([SKPaymentQueue canMakePayments]) {
NSLog(#"IN-APP:can make payments");
[self requestProductData];
}
else {
NSLog(#"IN-APP:can't make payments");
loadingHUD.hidden=YES;
}
}
- (void)requestProductData {
NSLog(#"IN-APP:requestProductData");
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject:myIdentifier]];
request.delegate = self;
[request start];
NSLog(#"IN-APP:requestProductData END");
NSLog(#"Productdata is %#",myIdentifier);
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
#try {
SKProduct *product = [response.products objectAtIndex:0];
SKPayment *newPayment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:newPayment];
NSLog(#"IN-APP:productsRequest END");
}
#catch (NSException *exception) {
// Failed to purchase Hide the progress bar and Display Error Dialog
loadingHUD.hidden=YES;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Alert" message:#"Error in Product id can not purchase" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
- (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(#"Transaction Completed");
// Finally, remove the transaction from the payment queue.
[self verifyReceipt:transaction]; // Call the verifyReceipt method to send transaction.bytes
NSLog(#"Purchase Transaction finish");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
NSLog(#"Transaction Restored %#",transaction.originalTransaction.payment.productIdentifier);
// You can create a method to record the transaction.
// [self recordTransaction: transaction];
loadingHUD.hidden=YES;
// You should make the update to your app based on what was purchased and inform user.
// [self provideContent: transaction.payment.productIdentifier];
// Finally, remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
loadingHUD.hidden=YES;// hide loadingHUD
if (transaction.error.code != SKErrorPaymentCancelled)
{
// Display an error here.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Purchase Unsuccessful"
message:#"Your purchase failed. Please try again."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
For restore it simple
-(void)startRestore
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
if ([queue.transactions count] == 0)
{
HUD.hidden=YES;
UIAlertView *restorealert = [[UIAlertView alloc]
initWithTitle:#"Restore"
message:#"There is no products purchased by you"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[restorealert show];
}
else
{
NSLog(#"received restored transactions: %i", queue.transactions.count);
for (SKPaymentTransaction *transaction in queue.transactions)
{
NSString *temp = transaction.payment.productIdentifier;
NSString *testID = [temp stringByReplacingOccurrencesOfString:projectIdString withString:#""];
NSString *productID = [testID stringByReplacingOccurrencesOfString:#"." withString:#""]; // remove Dot
NSLog(#"cutted string is %#",productID);
[purchasedItemIDs addObject:productID];
NSLog(#"** Purchased item is %#",purchasedItemIDs);
}
HUD.hidden=YES;
HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = NSLocalizedString(#"Restoring", nil);
[HUD showWhileExecuting:#selector(restorePurchasedItem) onTarget:self withObject:nil animated:YES];// call the restore Purchase method
}
}
IMHO you'd better crop this question in some number if different questions.
Anyway, I'll try to answer:
1) That's how it meant to be.
You get transactions with SKPaymentTransactionStateRestored state only if you call restoreCompletedTransactions manually. AFAIK, that's the normal practise to create one button (for example, "Restore purchases") for that.
2) Can't say anything about that. Normally, every time, when your app is going to make a purchase (and take some user's money), it should ask user for password.
3) AFAIK, no. You work with Apple servers through iTunes/AppStore apps. It's their business to remember user's iTunes account. And I don't think they give you any way to make current user logged out. Your project manager should understand it :-)
4), 5) There is no difference in production/sandbox environments until you try to verify the receipt. If you talk about work with server, I hope, you use server to verify receipts.
At device's side, all what you do is working with StoreKit framework. You don't define any URLs to Apple servers, you just use framework's classes and call it's methods. AFAIK, you don't need to make any changes to your code for sandbox and production support at the same time.
But at your server's side, there is difference: when your app is in production already, you should send HTTP POST requests to https://buy.itunes.apple.com/verifyReceipt . At the other hand, when your app is still in the sandbox, use https://sandbox.itunes.apple.com/verifyReceipt .
How to handle that? Watch WWDC 2012 video 308 about Auto-Renewable subscriptions. They suggest 2 ways:
1) Smart server. When your app send receipts to your server, it also passes some parameter, to let server know, which Apple's server to use. As I see, you already use this method.
2) Reactive server. Your server always send receipts to Apple's production server. You check the response, and if the status is 21007 (following the documentation, "This receipt is a sandbox receipt, but it was sent to the production service for verification."), you send the same request to Apple's sandbox server.
Use this code, it might help you....
//To Show Alert of InAppPurchase
- (void)showAlert
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"" message:#"Click buy to
purchase full tracks and other functionalities of the application." delegate:self
cancelButtonTitle:nil otherButtonTitles:nil, nil];
[alert addButtonWithTitle:#"Buy"];
[alert addButtonWithTitle:#"Restore Transaction"];
[alert addButtonWithTitle:#"Cancel"];
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:
(NSInteger)buttonIndex{
if(buttonIndex==0)
{
// For buy an item
[self Declarations];
}
else if(buttonIndex == 1)
{
//For Restore Previous Transaction
[self restorePreviousTransaction:nil];
}
else
{
//Do something here..
}
}
#pragma mark In App Purchase
-(void)Declarations
{
if ([SKPaymentQueue canMakePayments]) {
NSLog(#"parental functions are disabled");
SKProductsRequest *productRequest = [[SKProductsRequest
alloc]initWithProductIdentifiers:[NSSet
setWithObjects:#"com.tapmobi.careerandsuccess.inapp",nil]];
productRequest.delegate=self;
[productRequest start];
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
}
else
{
NSLog(#"parental functions are enabled");
}
}
- (IBAction)restorePreviousTransaction:(id)sender {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:
(SKProductsResponse *)response
{
SKProduct *validProduct=nil;
int count = [response.products count];
NSLog(#"number of prouducts present:%d",count);
if(count==0){
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
return;
}
validProduct = [response.products objectAtIndex:0];
NSLog(#"the product is :%#",validProduct.localizedTitle);
SKPayment *skpayment = [SKPayment paymentWithProduct:validProduct];
[[SKPaymentQueue defaultQueue] addPayment:skpayment];
[[SKPaymentQueue defaultQueue]addTransactionObserver:self];
}
-(void)requestDidFinish:(SKRequest *)request
{
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
}
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
NSLog(#"Failed to connect with error: %#", [error localizedDescription]);
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
NSString *message = [[NSString alloc]init];
BOOL bSuccess = NO;
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
NSLog(#"stuff is getting purchased");
break;
case SKPaymentTransactionStatePurchased:
NSLog(#"purchased properly");
message = #"Thank you.";
[[NSUserDefaults standardUserDefaults] setValue:#"Full Version"
forKey:PURCHASED_KEY];
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
bSuccess = YES;
break;
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"error happened");
message = #"Purchase is not successfull. Try again later";
}
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
default:
break;
}
}
if (bSuccess){
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"" message:message
delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
}
Happy Coding..

XMPPFramework not sending presence

Im developing an app for iPhone, in wich one of the functionalities is an instant message system, using XMPPFramework. By now, im testing it with Google Talk. The delegate is the same class that manages the User Interface. So, I got this code:
In viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupStream];
}
The setupStream method:
- (void) setupStream
{
NSLog(#"Inside setupStream");
xmppStream = [[XMPPStream alloc] init];
[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
[self connect];
}
The connect method:
- (BOOL) connect
{
NSLog(#"Inside connect method");
General *general = [General sharedManager];//this is a singleton to manage settings for every user
NSString *chatid;
NSString *chatpass;
//chatid=[general user];
chatid=#"somegmailaccount#gmail.com";
xmppStream.myJID=[XMPPJID jidWithString:chatid];
if (![xmppStream isDisconnected]) {
return YES;
}
NSError *error = nil;
if (![xmppStream connect:&error])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:[NSString stringWithFormat:#"Can't connect to server %#", [error localizedDescription]]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
return NO;
}
return YES;
}
In xmppStreamDidConnect method:
- (void) xmppStreamDidConnect:(XMPPStream *)sender
{
[xmppStream authenticateWithPassword:#"password" error:NULL];
[self goOnline];
}
And goOnline method:
- (void) goOnline
{
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
NSLog(#"Presence sent");
}
With this, the presence is not sent. I have another google account that I try for testing (say, testing#gmail.com) and in this account the presence of somegmailaccount.gmail.com is not seen. Both accounts are connected and know each other, since I used this same accounts to develop the Android app.
Any idea about what i´m doing wrong? Any help is appreciated.
Thank you very much.
I found it! The presence is not sent this way:
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
Insted, i have done it this way:
NSXMLElement *presence = [NSXMLElement elementWithName:#"presence"];
[xmppStream sendElement:presence];
This way, the presence is sent without any problem :)
With this code, i implement method xmppStreamDidAuthenticate:(XMPPStream *)sender
and the program DO enter that method without any call from my code. But if i put
[xmppStream setHostName:#"talk.google.com"];
[xmppStream setHostPort:5222];
... in method connect, the program DO NOT enter that method, nor xmppStreamDidConnect.
Im getting mad.

how to pass a Parameter from a Method which opens a UIAlertView to the UIAlertViewDelegate-Method?

Given the following code:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if (mainViewController.loggedIn) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"test" message:#"notification received. view now?" delegate:self cancelButtonTitle:#"Later" otherButtonTitles: #"Show"), nil];
NSString *hash = [userInfo objectForKey:#"id"];
[alert setValue:hash forKey:#"hash"];
[alert show];
[alert release];
}
}
Here I try to set a value (hash) for the key #"hash". I'm doing this, because I need this hash value in case the user presses the "Show" button. Then - in the delegate method - I try to read the value again:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
NSString *hash = [alertView valueForKey:#"hash"];
if (hash != nil) {
// send hash to server to show the correct site
}
}
}
But as soon as i call[alert setValue:hash forKey:#"hash"]; my iphone app crashes.
This is what i see in the console:
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key hash.'
Does anybody has an idea what I made wrong. Or how could i pass my "hash" value to the clickedButtonAtIndex method?
Declare hash as NSString class member. While you are showing the alertview, set the hash variable. Also, set a tag to the alertview.
In clickedButtonAtIndex method, check the alertview tag and use the hash value if required.

what GKSession doesn't connect on every attempt?

In application, invitationDidFail is being called, some time it connects properly, but sometime it doesn't...
what can be possible reasons of denying the connection?
// Display an alert sheet indicating a failure to connect to the peer.
- (void) invitationDidFail:(SessionManager *)session fromPeer:(NSString *)participantID
{
NSString *str;
if (alertView.visible) {
// Peer cancelled invitation before it could be accepted/rejected
// Close the invitation dialog before opening an error dialog
[alertView dismissWithClickedButtonIndex:0 animated:NO];
[alertView release];
str = [NSString stringWithFormat:#"%# is busy.\nPlease again", participantID];
//[peerList removeAllObjects];
[self peerListDidChange:nil];
[self.tableData reloadData];
//[self TwoPlayer:self];
} else {
// Peer rejected invitation or exited app.
str = [NSString stringWithFormat:#"%# is busy.\nPlease try again", participantID];
//[peerList removeAllObjects];
[self peerListDidChange:nil];
[self.tableData reloadData];
//[self TwoPlayer:self];
}
}
Even it doesn't call this method, It is sure that device is not paired to any other device, then what are reasons that sometime it do accept and call didReceivedInvitation method, or some time it does deny by calling invitationDidFail.
// Invitation dialog due to peer attempting to connect.
- (void) didReceiveInvitation:(SessionManager *)session fromPeer:(NSString *)participantID;
{
[alertView dismissWithClickedButtonIndex:1 animated:NO];
NSString *str = [NSString stringWithFormat:#"Incoming Invite from %#", participantID];
if (alertView.visible) {
[alertView dismissWithClickedButtonIndex:0 animated:NO];
[alertView release];
}
alertView = [[UIAlertView alloc]
initWithTitle:str
message:#"Do you wish to accept?"
delegate:self
cancelButtonTitle:#"Decline"
otherButtonTitles:nil];
[alertView addButtonWithTitle:#"Accept"];
[alertView show];
}
When I was recently writing an application using connections, I used GKSession. I spent weeks trying to debug connection issues with it and in the end I gave up and stopped using it. There seems to be a number of issues with GKSession when connecting especially if you disconnect and then attempt to reconnect within a short time (a short time could be 1 minute or more). It seems that the connection doesn't properly get dropped and then it doesn't recreate the connection properly.
In the end I took out all the GKSession code and used this instead. Worked a treat - no more connection issues.
GCD Async Socket

How to get a UIAlertView's result?

I implemented the gamekit. All works fine now. But if the user presses on send the data will instantly send to the other iphone/ipod/ipad and it will instantly written.
So now i wanted to implemenr a confirm screen for the receiver.
In my receiveData method (from the gamekit) i have an array. If the user presses yes the array will be written into a file.if not it wont be written into a file.
#pragma mark -
#pragma mark - GKreceiveData
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context
{
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Incoming Set" message:[NSString stringWithFormat:#"%# wants to send you a Set named: \n\n %#",[session displayNameForPeer:peer], [dict valueForKey:#"SetName"]] delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alert show];
[alert release];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if (buttonIndex == 0)
{
//NSLog(#"ok");
//this should happen if the user presses on ok on the alertview.
[dataArray addObject:dict]; //i can't acess "dict"
}
else
{
//NSLog(#"cancel");
}
}
Do you see the problem?? What can I do??
dict is created as autorelease, so it will be deleted during UIAlertView show up.
Your CancelButton's index is == 0;
cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil
Seems, that your OK button index is 1.