How to add "Touch Id" with "In app Purchase" in Objective c? - ios

I have successfully implemented "In App Purchase" in my project and now i am trying to implement a "Touch Id" to buy a product except asking a "Sign in to iTunes" popup. Here in my code it asks "touch id" and "Sign in to iTunes" popup both one after another, why this one wired both things i want only "touch id" to buy product. I have gone for IAP How do you add an in-app purchase to an iOS application? and for Touch ID How do i integrate Touch ID for my IAP? but not getting proper way to implement a touch id for IAP.Here is the code i have added,
Is this possible through code or it shows apple at the time of buying a product from app store.
Check above snapshot,
#import <LocalAuthentication/LocalAuthentication.h>
-(void) localAunthentication
{
//LocalAuthentication
LAContext *authContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *authLocalizedReasonString = #"Please aunthenticate to proceed";
if ([authContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError])
{
[authContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:authLocalizedReasonString
reply:^(BOOL success, NSError *error)
{
if (success)
{
// Allocated here for succinctness.
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperationWithBlock: ^
{
}];
}
else
{
switch (error.code)
{
case LAErrorAuthenticationFailed:
//Authentication Failed
break;
case LAErrorUserCancel:
break;
case LAErrorUserFallback:
break;
default:
//Touch ID is not configured
break;
}
NSLog(#"%#",error.localizedDescription);
}
}];
}
else
{
}
}
What should i do to asks only "Touch Id" instead of "Sign in To iTunes" popup.

The iTunes Store controls what kind of authentication it presents, not your app. If necessary, an alert will be presented, otherwise the TouchID/FaceID overlay.
The reason you're never seeing the TouchID/FaceID overlay is that during development, your app is not using the real iTunes Store but a sandbox. The sandbox environment, AFAIK, always presents an alert.

Related

LAContext evaluatePolicy:localizedReason:reply: errors with LAErrorUserCancel when user doesn't cancel

I am trying to implement Touch ID on my app:
LAContext *ctx = [[LAContext alloc] init];
[ctx evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:#"Authenticate to access." reply:^(BOOL success, NSError *error) {
if(success){
...
}else{
dispatch_async(dispatch_get_main_queue(), ^{
switch (error.code) {
case LAErrorTouchIDNotAvailable:
case LAErrorUserFallback:
self.passwordPanel.hidden = NO;
break;
default:
//we hit here with error code -2
}
});
}
}];
This is an in-house app that is currently used by 5 users. Four people including me (with a mix of iPhone 6 and iPhone 5s devices), have no problems. The last user (also having an iPhone 6) constantly hits the default case and their error code is -2, which is set to LAErrorUserCancel. The problem is that, they are hitting it instantly when evaluatePolicy is called, without even being able to scan their finger or tap cancel.
Why would this happen?

FBDialogs canPresentMessageDialogWithParams returns false

I'm currently trying to add Facebook SDK to the iOS version of my app. The login, logout, share, and request features are all currently working, but I'm having difficulty getting the MessageDialog feature to work. The Facebook app and the Facebook Messenger app are currently installed on my devices. However, every time I call 'FBDialog canPresentMessageDialogWithParams:params' it returns false.
My guess is that this feature doesn't work while the app is still in development mode, but that is just a guess. Does anyone know if Message Dialog works with apps that are under development? Or do you have any ideas as to what I am doing wrong?
I've also included my code in case I've made any bone-headed mistakes. Any help is greatly appreciated!
// Check if the Facebook app is installed and we can present the share dialog
FBLinkShareParams *params = [[FBLinkShareParams alloc] init];
params.link = [NSURL URLWithString:#"https://www.facebook.com/"];
params.name = #"Flash Bear";
params.caption = nil;
params.picture = nil;
params.linkDescription = #"I'm playing Flash Bear. Why don't you come join me?";
// If the Facebook Messenger app is installed and we can present the share dialog
if ([FBDialogs canPresentMessageDialogWithParams:params]) {
// Present message dialog
[FBDialogs presentMessageDialogWithParams:params
clientState:nil
handler: ^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
NSLog(#"Error messaging link: %#", error.description);
} else {
// Success
NSLog(#"result %#", results);
}
}];
} else {
// Present the feed dialog
// Put together the dialog parameters
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Sorry!"
message:#"There was an error connecting to FB Messenger. Please make sure that it is installed."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
}
I also had same problem with my application.
I resolved it by checking active session state. If state for active session is other than open then we need to open session again.
For doing the same use following code.
if([FBSession activeSession].state != FBSessionStateOpen){
BOOL result = [FBSession openActiveSessionWithAllowLoginUI:NO];
if(result)
{
//Do your stuff here
}
}
Best luck.

iOS Handle IAP download fail on SKDownloadStateFailed state

Our app provides in app purchases to apple hosted extra content which the user downloads, but some users are reporting problems with the download.
It seems to fail halfway through, alert the user and resets all buttons etc to allow the user to buy again (for free as they have already purchased). If the user then tries to re buy or restore purchases in the app it still fails. The following code is what handles a failed state.
-(void) paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads{
for (SKDownload *download in downloads){
switch (download.downloadState){
case SKDownloadStateActive:{
//code removed for post
break;
}
case SKDownloadStateCancelled:{ break; }
case SKDownloadStateFailed:
{
//log the error
NSLog(#"Transaction error: %#", download.transaction.error.localizedDescription);
//let the user know
[[[UIAlertView alloc] initWithTitle:#"Error!" message:[NSString stringWithFormat:#"%# download failed, please try again later", download.contentIdentifier] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
//post notification - caught in view controller for updating buy buttons etc
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperDownloadFailedNotification object:download userInfo:nil];
// This should delete the download assets from the Cache folder.
NSError* error = nil;
[[NSFileManager defaultManager] removeItemAtURL:download.contentURL error:&error];
if(error){
//
}
//finish the transaction
[[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
break;
}
case SKDownloadStateFinished:{
//code removed for post
break;
}
case SKDownloadStatePaused:{
break;
}
case SKDownloadStateWaiting:{
break;
}
}
}
I've looked around stack overflow and elsewhere and what little examples I can find on in app purchases all do the same as above. Any help or info would be great.
I got similar problem and just found a possible resolution in Apple's FAQ on IAP:
Q: How do I resolve the "You've already purchased this In-App Purchase but it hasn't been downloaded." error message?
A: You are getting the "You've already purchased this In-App Purchase but it hasn't been downloaded." error message because you did not call SKPaymentQueue 's finishTransaction:method in your application. Calling finishTransaction: allows you to remove a transaction from the payment queue.
I think I will ask my IAP engine to check whether there is any IAP is being processed when app exits(my problem occurs when user stopped the app while downloading), if yes, calls finishTransaction:.
Hope it helps.

nil resultURL after successfully posting with FBWebDialogs (Facebook SDK 3.5)

I'm integrating Facebook on my application to share links of websites. I'm using the Feed Dialog to accomplish this and I'm following this tutorial:
https://developers.facebook.com/docs/howtos/feed-dialog-using-ios-sdk/.
I've managed to login and post to Facebook but I wanted to add a message when the post was successful. The tutorial has this built in, but every time I post, I see "User canceled story publishing." in the Log which is the message that is displayed when the user clicks on cancel. Besides I've confirmed with the debugger that the param resultURL received by the handler is always nil even on successful posts.
At first I though it was a configuration issue in my Facebook App, but I decided to make a test. I opened the RPSSample that comes with the framework, added a completion handler to the presentRequestsDialogModallyWithSession call in the clickInviteFriends method in the RPSFriendsViewController.m view controller and I was getting a nil resultURL on successful posts there too.
I'm I missing something?
I know the 3.5 SDK version is very new, but according to the documentation I should be getting a valid resultURL param after posting through a Facebook Web Dialog so I'm not sure if it's a bug or if I'm missing some callback or handler somewhere.
Just in case, this is my call to the Feed Web Dialog. It has minor changes compared to the one that comes in the tutorial (it's actually simpler)
- (void)publish: (EntityToShare *)entityToShare {
NSMutableDictionary *params =
[NSMutableDictionary dictionaryWithObjectsAndKeys:
entityToShare.link, #"link",
nil];
// Invoke the dialog
[FBWebDialogs presentFeedDialogModallyWithSession:nil
parameters:params
handler:
^(FBWebDialogResult result, NSURL *resultURL, NSError *error) {
if (error) {
// Error launching the dialog or publishing a story.
NSLog(#"Error publishing story.");
} else {
if (result == FBWebDialogResultDialogNotCompleted) {
// User clicked the "x" icon
NSLog(#"User canceled story publishing.");
} else {
// Handle the publish feed callback
NSDictionary *urlParams = [self parseURLParams:[resultURL query]];
if (![urlParams valueForKey:#"post_id"]) {
// User clicked the Cancel button
NSLog(#"User canceled story publishing.");
} else {
// User clicked the Share button
NSString *msg = [NSString stringWithFormat:
#"Posted story, id: %#",
[urlParams valueForKey:#"post_id"]];
NSLog(#"%#", msg);
// Show the result in an alert
[[[UIAlertView alloc] initWithTitle:#"Result"
message:msg
delegate:nil
cancelButtonTitle:#"OK!"
otherButtonTitles:nil]
show];
}
}
}
}];
}
We have a fix for this in place and will be pushed out soon.
Edited:
This has now been fixed in the SDK release 3.5.1
Check it out here: https://developers.facebook.com/ios/

How to resolve "com.facebook.sdk error 2" under the condition that "allow these apps to use your account" is off for my app

I am working on an iOS app using the latest FB SDK for native log in. When I switch my app off in "allow these apps to use your account" in the settings, an error "com.facebook.sdk error 2" is expected to come.
I am wondering is there any elegant way to solve this error even if "allow these apps to use your account" is off for my app? I have searched for the solution but all the answers are saying that You need to switch that option on. But I think the better way is that if user switches that option off, we can still let him log in, falling back to the fast-app-switch way seamlessly, just like he doesn't log into Facebook on his device at all. How can I do this in the newest FB SDK? Thanks!
====================================Update=========================================
I solve it using a deprecated function openActiveSessionWithPermissions:allowLoginUI:completionHandler
first we need to check whether user switch this option off:
self.useAccountAllowed = true;
ACAccountStore *accountStore;
ACAccountType *accountTypeFB;
if ((accountStore = [[ACAccountStore alloc] init]) &&
(accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (!fbAccounts)
{
//do not log into FB on the device
}
else if ([fbAccounts count] == 0) {
[FBSession.activeSession closeAndClearTokenInformation];
self.useAccountAllowed = false; //user switch this option off
}
then in openSession function, using that deprecated function if self.useAccountAllowed is false:
if (self.useAccountAllowed) {
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
}
else {
NSArray* lPermission = FBSession.activeSession.permissions;
[FBSession openActiveSessionWithPermissions:lPermission allowLoginUI:YES completionHandler:^(FBSession* session, FBSessionState status, NSError* error){
[self sessionStateChanged:session state:status error:error];}];
not sure whether it is a correct way.
This is how I solved it. On the AppDelegate implementation file, in the applicationDidBecomeActive method, use the regular [FBSession.activeSession handleDidBecomeActive] method, as recommended by the FB SDK documentation. Plus, add a new method that checks the user permissions in Settings (that I called checkPermissionSettings in the example below):
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSLog(#"applicationDidBecomeActive: in NHOCAppDelegate");
//
// The flow back to your app may be interrupted (for ex: if the user clicks the Home button
// while if authenticating via the Facebook for iOS app).
// If this happens, the Facebook SDK can take care of any cleanup that may include starting a fresh session.
//
[FBSession.activeSession handleDidBecomeActive];
[self checkPermissionSettings];
}
//
// Verify if the user pressed the Home Button, went to Settings and deauthorized the app via "Allow These Apps to Use Your Account..."
// If so, redirect him to the login screen (this happens automagically, see below).
//
- (void)checkPermissionSettings
{
NSLog(#"checkPermissionSettings: in NHOCAppDelegate");
//
// Now 'startForMeWithCompletionHandler' may return 'FBSessionStateClosed' (meaning that the user probably unauthorized the app in Settings).
//
// If that is the case:
//
// - Hide the 'logged' View Controller
// - Remove it (NHOCLoggedVC) from the Notification Center
// - Show the 'login' View Controller
// - And finally add it (NHOCLoginVC) to the Notification Center, closing the loop
//
// Check the console for further info.
//
[FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id<FBGraphUser> user, NSError *error) {
if (!error) {
//
// Everything went fine... The app is in good shape.
// Notice that 'user.location' requires user_location permission
//
NSLog(#"user.location: %#: ", [user.location objectForKey:#"name"]);
}
}];
}
To make it work as designed, I also use Notification Center. You can check the entire example here:
FB SDK + Storyboards with Publish to Feed
I hope it helps.

Resources