When user grant geo location permission for "once", the authorization requesting pop up will show again when user open the app again some minutes later.
But we only need that authorization once, so we don't wish it to pop up ever again until we want it for another time.
As shown here, the pop up will show again if the app request such an authorization again. But I checked the code and nothing was triggered when the pop up shows for the second time.
https://support.apple.com/en-au/HT203033#:~:text=With%20iOS%2013%20and%20iPadOS,ask%20for%20your%20permission%20again.
Is there a way to prevent it from popping up in such case?
Related
Here's the logic flow I'm trying to code into my iPhone app:
I think I understand the technicalities to achieve this (using AFNetworking, connecting to a Rails API using Devise as authentication). The auth_token will be stored in the keychain once the login is successful. What I can't figure out is the best way to go about setting up my app to behave like above.
I want the experience to be good for the user of course, so maybe while it's checking for the token and attempting to login it shows a "loading" screen of some sort.
How would I go about achieving this? I don't know which view controller I should set as the rootviewcontroller in the AppDelegate or how I should set it after the user has logged in. I've tried this in the Facebook app and when I open it I see a blank navigation controller it seems, then my profile view is loaded. What are they doing behind the scenes and is this the best way to go?
I am not using Storyboards.
I have implemented a similar one, the RootViewController was a "SplashViewController" in a navigationController, showing a nice logo, activity indicator and gives user info about authentication status. It holds the logic for checking stored token there and authentication implementation. If authentication is successfull, ShowUserController is shown by pushing to navigationController stack.
If authentication is failure a LoginViewController is presented modally. SplashViewController implements the delegate of LoginViewController, which does nothing but passing the username and password to SplashViewController. On successfull login, LoginViewController is dismissed and user is directed to ShowUserController.
Start your app with the root controller as the one that the user will see after they have logged in successfully, then layer the login views/controllers on top, with modal calls. If the authentication is successful, your user will already be where they want to be, else you call the login layers modally on top. Once they're authenticated, you won't need the login views anymore.
To elaborate on #Owen Hartnett's answer since this text won't fit in a comment; This is how I've seen Facebook's SDK work. If you build an app that uses the Facebook iOS SDK as the only login mechanism, then the way it works is like this:
In my app delegate's didFinishLaunchingWithOptions method I first check for an "already on file" access token in say, NSUserDefaults. If not found, I need to get one and so have my app delegate immediately launch a modal login flow that finishes with a valid access token that is then saved to NSUserDefaults for use on next app open.
If I do already have an access token on file in my didFinishLaunchingWithOptions, then I assume the happy path and open a "logged in user session" asynchronously using the access token I found on file at time of app open. If the access token I have on file to open the session with is legit, then no UX is displayed. If the access token I have on file is an illegitimate access token (server says it's too old, for example), then my open session method in my app delegate, upon finding this out, will display the proper modal login flow.
Since this openSession method executes asynchronously, you might be wondering how your root view controller, which needs a logged in user, is going to function in the meantime.
The answer is that it should be written as if it does have a logged in user. It should assume. If it ever runs code that can't run or finish executing successfully because it doesn't have a valid access token then that code should trigger the login UI if it's not already presented (i.e. the access token check on app open, by this time, has already presented the modal login UI to the user).
Lastly, this is a translated version of the Facebook SDK login flow. For example, if you use only their SDK you wouldn't ever be interfacing with NSUserDefaults like I suggest. I've translated their flow to a "custom implementation" of logging in to a remote API.
I am building an app, which uses facebook authorisation services. However, I am facing problems in two cases
The user is sent to the facebook app for giving permission. Instead, she presses the home button and again opens my app.
In this case, I need to do two things:
a. Re-show her the login page (and remove the animation from that page): For this I need to know that the user has come back to the app without logging into fb.
b. Cancel the last request sent to fb: If user tries to login again, my app sends two requests to the fb authorisation system, which leads to two popup windows in the fb app and also gives back multiple calls to my app.
The user presses the cancel button: In this case fb app is not re-directing to my app. I read that this was a bug and has been fixed; however, this still this does not work for me. Any suggestions?
I have tried to search for similar Q on the forum; however, have not been able to find exact answer. Please let me know if I missed looking at relevant question.
If you're using the Facebook SDK 3.1 for iOS, then
- (void)applicationDidBecomeActive:(UIApplication *)application {
[FBSession.activeSession handleDidBecomeActive];
}
Will cancel the auth request if the user happened to cancel the auth flow via doing something like hitting the Home button. You can then reset by showing your login view again.
The (2) problem should be fixed if you upgrade to the latest Facebook iOS app.
I'm currently developing my first native iPhone app (though I have many years of experience as a web developer). I'm having some difficulty understanding the best way to handle login and I'm looking for some advice on the best way to go about it. The more I think about all the things that can go wrong during login, the more my brain wants to jump out of my head. I'm getting really frustrated with this and could really use some advice from some more experienced iPhone developers. Thanks in advance for your help.
My goal is to support Facebook Connect in the first version of the app, and then to support other SSO services (Twitter, Google, etc.), as well as my own user account system in future versions. The current plan is to have a MySQL table on the server that looks something like this:
users (id, nickname, facebook_id, ...)
When a user logs into the app via Facebook for the first time, an entry will be created in this table for them. You may think this isn't necessary, but it will allow me to expand to other services later on. For example, I could do this:
users (id, nickname, facebook_id, twitter_id, google_id, username, ...)
This table would have nullable fields for facebook_id, twitter_id, google_id, and username. If the user logs in with facebook, they'll have a facebook_id. Twitter users will have a twitter_id, Google users a google_id, and my own users will have a username. They'll all be uniquely identified by my own id regardless of what login system they're using.
So I'm pretty comfortable with the back-end implementation of user accounts. I can setup a web service that the app can call to create/retrieve users, verify logins, etc. No problem.
The problem I'm having is implementing a proper login flow with the iPhone UI components. My particular app uses a UITabBarController that serves as the main navigation. One of the tabs is labeled "My Account" and contains information about the currently logged in user. If the user clicks on the "My Account" tab, they are presented with a table view that serves as a submenu. It has options such as "My Profile", "Settings", and some other things. If they click on any of these menu items and they aren't logged in, then I use the presentViewController function to pop up a login screen. They click "login with facebook" and go through the typical Facebook authorization process. When they've completed that process, I use dismissViewController to remove the login page and display the page they were trying to access. If they cancel the login or if the login fails, then I use popViewControllerAnimated on the UINavigationController to send them back up to the "My Account" submenu. For those of you who are having a difficult time envisioning this, check out the Amazon app. It is almost the exact same thing (just click the "More" tab when you're not logged in and try to click one of the menu items underneath it).
That all works pretty well and I'm happy with it. But here's where I get confused:
What the heck do I do if they're several levels deep into the UINavigationController within the "My Account" tab and their login session expires?
Let's take Facebook login for example. Facebook uses session tokens to keep users logged in. The tokens expire after a certain amount of time. Let's say the user navigated down into "My Account", then clicked "My Profile", and then clicked on "Edit" and are shown a screen where they can edit their profile information. So they obviously need to be authenticated in order to view this page. In fact, they're 2-3 levels deep into pages that they need to be authenticated to see. Now let's say they get interrupted by a phone call or something and forget all about what they were doing. The next time they access the app is a week later when their login session has expired. I can handle this in a few ways. None of them seem great to me.
Solution #1
The Facebook SDK will automatically call a method on the AppDelegate class that notifies me of the expired session. Since I am notified of the session expiration at the AppDelegate level, I have no idea what page the user is currently looking at and whether or not they need to be authenticated in order to use it. To get around this, I can have all ViewControllers that require login to extend a "ProtectedViewController" class or something that indicates the user should be logged in to see that page. Then when the AppDelegate is notified of the session expiration, it will try to figure out what the current ViewController is and check if it extends "ProtectedViewController". If it does, then present a login screen. If the user successfully logs in, then everything proceeds as normal. If not, then return the user to the first screen of the app where they have to start all over. This is bad because the user will lose anything they've typed in already, but I don't see any way to avoid it with this solution.
Solution #2
Ignore the session expiration event at the AppDelegate level and instead do this: before any action is taken that requires a user to be logged in (e.g. when the user clicks "Save" on their "Edit Profile" page), check if they are still logged in. If they aren't, then present a login screen. If the user fails to login, then send them back to the start screen. This solution is a pain in the ass to code because I have to perform a check on practically everything the user does within the protected area of the app -- when they view a page, when they click a button -- just about everything.
I would also prefer to avoid sending the user all the way back to the start screen of the app if they fail to re-authenticate. Instead, in this case, I'd prefer to send the user back up the UINavigationController to the "My Account" menu -- which is the closest page that doesn't require login. Sure, I could hardcode that, but I'm looking for a solution/pattern that works a little more naturally and that I can reuse in other apps.
I would really appreciate some guidance. Surely I'm not the first person in the world who has needed to solve this problem. Unfortunately, Google hasn't been much help.
Thanks.
EDIT: Another idea is to subclass UIViewController (e.g. "ProtectedViewController") and implement the "viewWillAppear" method. Inside this method, I can check if the user is logged in. If not, then I slide up a login page. I still don't know how to handle the case when they fail to login, though. This solution has a problem, though: if the user's session expires while they're using the app, then I won't re-authenticate them until the next time they click on a new view. If they're already looking at say an "edit" page and click the "save" button, then they won't be re-authenticated. But perhaps this is a step closer to the solution.
Don't forget that the app delegate is the one that adds the whole tab bar to the main UIWindow. On detection of credentials failing, you could simply remove the UITabBarController from the UIWindow, and replace it only with your own login view to re-authenticate. That eliminates any possibility they could interact with anything in the tab structure, but when restored means whatever position they are at within the tabs is preserved (since you would simply remove the tab bar controllers view but leave the controller intact).
Here how I managed it in a recent project using singletons.
Create a singleton class, say LoginManager that has a method called,
-(UserInfo*) getValidatedUser: (UIView*) senderView
Inside this method check to see if the token is still valid.
If it is not valid simply create a new view that forces the user to login using FB credentials and overlay it on top of the "senderView" so that the user is forced to login, like this:
[senderView addSubview:loginView];
Once the token is valid, you return back the user information.
With this basic logic in place you can now call this getValidatedUser method from your view controller classes whenever you need a valid credential to do something:
UserInfo* myUser = [loginManagerObj getValidatedUser:self.view]
The method internally decides if a login page should be shown or not.
Hope this helps.
I am designing an iOS application where a user is presented a "sign out" button as the client wants that to be there.
However I am having a tough time working through the logic.
Should I:
1). exit the application at that point since the entire app runs on the premise of authenticated web service calls. (if so how do I make my app exit? )
2). Take the user to the initial splash screen where he/she is given the choice of login/register. (if so how do I reset the app back to initial screen?)
I know what I am asking is confusing so I hope I am making sense.
Exiting from the app is not recommended. It would give the feeling of app crash to the user. You may use the second approach of sending the user back to the initial login screen after he sign outs. If you are using a navigation controller based approach you can try using popToRootViewController method of going back to the login screen(assuming login screen is your root).
Exiting the app is definitely not a good option. I would suggest you take the user back to the page where the user has the option to login or register. As an end user if he/she want to sign in with a different account if he/she can, it would certainly be the best option. No user would want to exit the app and launch it again to use them.
I've got it all working, I've even posted to fb already. I was using the xcode Simulator the first time and it asked for user authentication, i entered my user info, then it gave me a second fb dialog window saying it was authorized and had to press OKAY button. This takes me to my app.
What bugs me is that every time I run the app, it doesn't ask me for my credentials again, but it does pop-up a fb dialog window saying I've logged in fine, and i have to press the OKAY button in the bottom right.
Is there anyway to avoid this, cause still be a pain for my users every time.
u have been asking for permission for accessing the data everytime in facebook
to avoid this ask only one time for permission by setting the if loop with permission with bool ...
i think u understand