iOS XMPP Framework, how to handle wrong credential? - ios

All the codes I use are from https://github.com/robbiehanson/XMPPFramework. Inside the sample code.
In my iOS7 messaging app, I invoke the "connect" function inside XMPP Framework after the user has entered their login credential and clicked the "login" button. The connect function works fine if they entered the correct credentials the first time, but would not work if the user entered the wrong credential. Because this very first line inside connect would simply return TRUE:
if (![_xmppStream isDisconnected]) {
return YES;
}
Which means any further presses on the login button would do nothing.
Should I manually invoke authenticateWithPassword? Is this the right practice assuming a connection between the client and the server has been setup?
Thank you.

You need to use the methods in the delegate to handle authentication. First you need to connect to the server if it's not already connected:
[_xmppStream connectWithTimeout:10 error:&error];
Once the stream is connected to the server the delegate method will be invoked:
- (void)xmppStreamDidConnect:(XMPPStream *)sender;
Inside that method, you can call authenticateWithPassword. If the stream was previously connected (would be the else part of the if you posted) you can just call authenticateWithPassword.
If authentication fails, the following delegate method is called:
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error;
There you can decide to show a message to the user and start over. If authentication succeeds, the following method is called:
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender;

Related

Best way to check if sharing via SLComposeViewController is successful with a limited (or no) Internet connection

Apple's documentation is clear on using SLComposeViewController to provide sharing capabilites with other social networks such as Twitter and Facebook.
Typical code will use isAvailableForServiceType to verify if a particular service is available and then add a completion handler to the view controller where an SLComposeViewControllerResult can be checked for either SLComposeViewControllerResultCancelled or SLComposeViewControllerResultDone, which check if the user tapped on the 'Post' button or on the 'Cancel' button after the sharing view has been displayed.
The issue here is that if you use SLComposeViewControllerResultDone to validate that the user made the request, you don't actually check if it was successful such as when the user has limited or no connectivity.
I have tried with one of my apps to test this and have noticed that the SLComposeViewControllerResultDone constant is still valid even if airplane mode is turned on such that a request is not possible. What this means is that the user fills out the sharing view fields and taps on 'Post' and my success code executes even though I should really be checking to make sure that the post was indeed successful.
Currently, I figure that the best option is to check for an Internet connection using the standard Reachability options (as recommended here) and disable the sharing button if a connection is not available, but I'm not sure if this is the best solution as it doesn't account for a limited connection where the user can tap on 'Post' but the actual request is unsuccessful.
My question is what is the best method of detecting if a sharing request has successfully completed?
then you need to make sure that you do not write below line in didSelectPost
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
and once you get success or fail based on that in the your request handler you can write above line, so your didSelectPost should be like :
- (void)didSelectPost {
NSExtensionItem *inputItem = self.extensionContext.inputItems.firstObject;
NSItemProvider *attachment = inputItem.attachments.firstObject;
if ([attachment hasItemConformingToTypeIdentifier:#"public.url"])
{
//NSString *strLink = [attachement loadItemForTypeIdentifier:#"public.url" options:nil completionHandler:nil];
[attachment loadItemForTypeIdentifier: #"public.url"
options: nil
// make your request here
}];
}
}

Objective C - DropboxSDK: (401) Authentication failed -

I'm using the dropbox SDK to save file to a user's dropbox account.
When the user taps 'save to dropbox' button for the first time, a popup window pops up and the user is required to login onto their dropbox account. I then upload a file to their dropbox account using uploadFile method provided by the SDK. However, the first time, it gives me the error:
DropboxSDK: error making request to /1/files_put/dropbox/sampleFile.pdf - (401) Authentication failed
When I close the app and try again, it successfully uploads the file.
What may be causing the app to behave so strangely?
I had the same issue and it turned out that I initialized my DBRestClient from viewDidLoad like the Dropbox docs say, but since that happens before the dropbox account is linked the restClient is not properly set.
This can be easily fixed re-initializing your restClient or even better by using the following way to access your restClient.
-(DBRestClient*)restClient{
if(_restClient == nil){
_restClient = [[DBRestClient alloc] initWithSession:[DBSession sharedSession]];
[_restClient setDelegate:self];
}
return _restClient;
}
I got same error, use this code in your app hope this will help you.
if([[DBSession sharedSession] isLinked])
{
//Do your drop box work here...
}
else
{
//If not linked then start linking here..
[[DBSession sharedSession] linkFromController:self];
}

XMPPFramework - Auto Accept of Presence Subscription Requests

I think the title is illustrating enough, but here's the story:
I'm new to XMPPFramework for iOS, and I want to set my client to automatically accept any subscription request it receives. So that other clients can see this client's presence status, when they request it.
According to developer comments In XMPPRoster.h file, there's this method which is called when a subscription request is received:
/**
* Sent when a presence subscription request is received.
* That is, another user has added you to their roster,
* and is requesting permission to receive presence broadcasts that you send.
*
* The entire presence packet is provided for proper extensibility.
* You can use [presence from] to get the JID of the user who sent the request.
*
* The methods acceptPresenceSubscriptionRequestFrom: and rejectPresenceSubscriptionRequestFrom: can
* be used to respond to the request.
**/
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
But it is not implemented in XMPPRoster.m. So I implemented it as following :
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
[self acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Since I'm new to XMPPFramework I dunno if I have done anything wrong, but I still cannot get this client's presence in other clients.
I also have seen similar topics like Accept buddy request in xmpp client iphone or Xmpp Accepting buddy request but the solution does not seem to be even related !
Any suggestions is really appreciated.
Thanks.
You did it wrong. You do not have to implement something in XMPPRoster.m or other library files.
This function
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
is a callback fired when your xmpp client receives presence subscription request. If you want to execute some code when this callback fired you have to implement a protocol called XMPPRosterDelegate. Protocol is a feature like interface in Java and C# or like abstract class in C++. You have to have a class that inherits from this XMPPRosterDelegate and finally implements this function (and other functions if you want so).
If you want to autoaccept all requests you have to implement your protocol function implementation like this:
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Also roster object got to know who is its delegate (an object who implements XMPPRosterDelegate), cause if you want to send someone a message you have to know two things: target and selector. Selector is specified in protocol. Target is a delegate property. You have to set roster's delegate during its initialization. In my code I added line
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
before line
[xmppRoster activate:xmppStream];
Of course self implements XMPPRosterDelegate and especially has this piece of code
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Good luck and sorry for long post.

Kill all views/controllers and default to Login page on home button not working for web service calls

I have a LOGIN view which is the root view controller. After the user is logged in and anytime during the app if he clicks on home button, I remove all the possible subviews using: [view removeFromSuperview] recursively so I can kill all views. I even use [controller removeFromParentViewController]. However, if any web service calls were running when we click on iphone home button, even though all views & controllers were removed, the response from the web service is processed by the app and it crashes due to Push segue being called. How can I kill any existing web service calls in the app in the AppDelegate? Error " Could not find a navigation controller for segue "XXsearch". This error is obviously because I remove all the controllers and views. But why does the web service response still get processed? Is there another way I can kill the web service calls?
The web service calls are asynchronous. But why do the controllers still exists to deal with the response?
This is the web service call:
[NSURLConnection connectionWithRequest:NSMutableURLRequestObject delegate:self];
This is the code in the controller which is a delegate to the web service:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
// do something with response object
[self performSegueWithIdentifier:#"XXsearch" sender:self];
}
According to the documentation for connectionWithRequest:delegate:
During the download the connection maintains a strong reference to the delegate. It releases that strong reference when the connection finishes loading, fails, or is canceled.
This means that even though you are removing the view controller, the NSURLConnection is forcing it to stay around. First of all, you'll want to save the connection in property in your view controller.
self.connection = [NSURLConnection connectionWithRequest:NSMutableURLRequestObject delegate:self];
Then you'll need to make sure you cancel the connection and set it to nil when your view controller is removed from its parent view controller.
- (void)didMoveToParentViewController:(UIViewController *)parent
{
[super didMoveToParentViewController:parent];
if (!parent && self.connection) {
[self.connection cancel];
[self setConnection:nil];
}
}
Also, you'll want to make sure you set the connection to nil when the connection finished or fails.

How does google plus call back function work after authentication in IOS

I've done a google plus integration and i've done a simple login and displaying google friends on table. But the problem is before I load the friends I want to check if the user is logged in, so in my friendsdisplayViewController i've done something like this
if ([GPPSignIn sharedInstance].authentication)
{
NSLog(#"Status is authenticated, fetching friends!!");
[self fetchGooglePlusFriends:kGTLPlusCollectionVisible];
}
else
{
[[GPPSignIn sharedInstance]authenticate];
}
I've defined the callback function one on initial signupviewcontroller and one under this one
-(void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error
{
//code
}
But whenever the else case executes it always calls the call back function defined on signupviewcontroller not the one I defined on friendsdisplayViewController hence I'm unable to display the list and but able to validate the authentication.
I'm just curious how the call to this google call back function (finishedWithAuth) is made. Why did it call the one in signup and not in friendsdisplay eventhough the authentication was triggered from friendsdisplay.
I figured out the issue was because of the delegate which needs to be put on every view controller which you are calling, the GPPSignInDelegate. And the finishedWithAuth will then get triggered from the ViewController which you are trying to call it else it will trigger the finishedWithAuth in the ViewController which is standing in top of stack.

Resources