iOS8 Touch ID & Passcode - ios7

i using this code in iOS 8 for security and uses touch ID
- (IBAction)authenticateButtonTapped{
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Authenticate using your finger\r Scan Your Finger Now";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL succes, NSError *error) {
if (succes) {
[self showMessage:#"Authentication is successful" withTitle:#"Success"];
NSLog(#"User authenticated");
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
[self showMessage:#"Authentication is failed" withTitle:#"Error"];
NSLog(#"Authentication Failed");
break;
case LAErrorUserCancel:
[self showMessage:#"You clicked on Cancel" withTitle:#"Error"];
NSLog(#"User pressed Cancel button");
break;
case LAErrorUserFallback:
[self showMessage:#"You clicked on \"Enter Password\"" withTitle:#"Error"];
NSLog(#"User pressed \"Enter Password\"");
[self copyMatchingAsync];
break;
default:
[self showMessage:#"Touch ID is not configured" withTitle:#"Error"];
NSLog(#"Touch ID is not configured");
break;
}
NSLog(#"Authentication Fails");
}
}];
} else {
NSLog(#"Can not evaluate Touch ID");
[self showMessage:#"Can not evaluate TouchID" withTitle:#"Error"];
}
}
after for use the passcode system i copy this code from apple example
- (void)copyMatchingAsync
{
NSDictionary *query = #{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: #"SampleService",
(__bridge id)kSecReturnData: #YES,
(__bridge id)kSecUseOperationPrompt: NSLocalizedString(#"AUTHENTICATE_TO_ACCESS_SERVICE_PASSWORD", nil)
};
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CFTypeRef dataTypeRef = NULL;
NSString *msg;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(query), &dataTypeRef);
if (status == errSecSuccess)
{
NSData *resultData = ( __bridge_transfer NSData *)dataTypeRef;
NSString * result = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
msg = [NSString stringWithFormat:NSLocalizedString(#"RESULT", nil), result];
} else {
}
});
}
-(void) showMessage:(NSString*)message withTitle:(NSString *)title
{
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
its work great and rapid for fingerprint but the passcode system can't show and dosen't work. and i received "ERROR_ITEM_NOT_FOUND" = "error item not found";
this apple link https://developer.apple.com/library/ios/samplecode/KeychainTouchID/Introduction/Intro.html
but i can't good understand

Sorry to tell you but you can't do that.
You are mixing access control with keychain access, You don't have access to the user passcode.
using SecItemCopyMatching is possible if you added a resource with SecItemAdd using the same attributes (the contents of "query")

"ERROR_ITEM_NOT_FOUND" = "error item not found" show no item in keychain.
I also saw the Apple sample code "KeychainTouchID" as you said above.
iOS8's new feature make the developer can use the iPhone user's passcode & Touch ID for authentication.
You have to "Add Item" firstly, and then call "Query for Item".
If you want more convenient solution, maybe you can use SmileTouchID.
It is a library for integrate Touch ID & Passcode to iOS App conveniently that even support for iOS7 and the device that cannot support Touch ID.
You just need a few line of code and get what you want.
if ([SmileAuthenticator hasPassword]) {
[SmileAuthenticator sharedInstance].securityType = INPUT_TOUCHID;
[[SmileAuthenticator sharedInstance] presentAuthViewController];
}

Related

Objective C - Asking to save before you quit

I have an Objective-C/Cocoa text-editor I'm working on(It's a mac app, not iOS).
The current challenge I'm facing is having a dialog when someone try to quit without saving.
I already have a shared bool called issavedsomewhere to tell if the user has saved or not. I even have the textview data available as a shared variable, so I can access it from any class.
I'm thinking that I'd put the save dialog in the (void)applicationWillTerminate method.
My current saving code is simple:
NSSavePanel *panel = [NSSavePanel savePanel];
// NSInteger result;
[panel setAllowedFileTypes:#[#"txt"]];
[panel beginWithCompletionHandler:^(NSInteger result){
//OK button pushed
if (result == NSFileHandlingPanelOKButton) {
// Close panel before handling errors
[panel orderOut:self];
// Do what you need to do with the selected path
NSString *selpath = [[panel URL] path];
NSError *error;
BOOL didOK = [[theDATA.textvieww string]writeToFile:selpath atomically:NO encoding:NSUTF8StringEncoding error:&error];
if(!didOK){
//error while saving
NSLog(#"Couldn't Save!!! -> %#", [error localizedFailureReason]);
}else{
//success!
theDATA.issavedsomewhere=YES;
theDATA.filepath=selpath;
theDATA.filename=[[[panel URL] path] lastPathComponent];
}
}/*Button other than the OK button was pushed*/
else{
}
}];
All it is, is an NSSavePanel that pops up and asks where you want to save.
The problem is that when I add it to (void)applicationWillTerminate, it doesn't wait for the user to answer.
Your help and ideas are appreciated:)
There are better ways to do this within the Cocoa framework, such as by using NSDocument and its ilk. However, it is possible to do what you want to do.
You first want to return NSTerminateLater in applicationShouldTerminate::
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
if (theDATA.issavedsomewhere) {
return NSTerminateLater;
}
return NSTerminateNow;
}
Then, you handler should ultimately call [NSApp replyToApplicationShouldTerminate:YES] when it is done:
NSSavePanel *panel = [NSSavePanel savePanel];
// NSInteger result;
[panel setAllowedFileTypes:#[#"txt"]];
[panel beginWithCompletionHandler:^(NSInteger result){
//OK button pushed
if (result == NSFileHandlingPanelOKButton) {
// Close panel before handling errors
[panel orderOut:self];
// Do what you need to do with the selected path
NSString *selpath = [[panel URL] path];
NSError *error;
BOOL didOK = [[theDATA.textvieww string]writeToFile:selpath atomically:NO encoding:NSUTF8StringEncoding error:&error];
if(!didOK){
//error while saving
NSLog(#"Couldn't Save!!! -> %#", [error localizedFailureReason]);
}else{
//success!
theDATA.issavedsomewhere=YES;
theDATA.filepath=selpath;
theDATA.filename=[[[panel URL] path] lastPathComponent];
}
}/*Button other than the OK button was pushed*/
else{
}
[NSApp replyToApplicationShouldTerminate:YES];
}];
One possibility is to just save in a temp file and on launch check to see if the tempfile exists and perhaps ask the user if he want to use it or not.
Since changes to my data can happen in multiple places I simply post a "data modified" notification whenever this happens:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"DataModifiedNotification"
object:self];
My app delegate has a dataSaved property and adds itself as an observer of this notification and sets its value to NO whenever the data is mutated:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.dataSaved = YES; // set to NO when data mutated
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(receiveDataModifiedNotification:)
name:#"DataModifiedNotification"
object:nil];
}
-(void)receiveDataModifiedNotification:(NSNotification *) notification {
self.dataSaved = NO;
}
The the app delegate asks the user if they really want to quit to give
them the opportunity to save the data (done elsewhere):
-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
if (!self.dataSaved) {
NSAlert *alert = [[NSAlert alloc] init];
alert.alertStyle = NSAlertStyleWarning;
alert.messageText = #"Data unsaved!";
alert.informativeText = #"Do you really want to Quit the application?";
[alert addButtonWithTitle:#"Quit"];
[alert addButtonWithTitle:#"Cancel"];
[alert beginSheetModalForWindow:self.window
completionHandler:^(NSModalResponse returnCode) {
const BOOL shouldQuit = returnCode == NSAlertFirstButtonReturn;
[NSApp replyToApplicationShouldTerminate: shouldQuit];
}];
return NSTerminateLater;
}
return NSTerminateNow;
}
Note: Set app property NSSupportsSuddenTermination to NO
which is labeled "Application can be killed immediately when user is shutting down or logging out" in Info.plist.

TouchID forward to system passcode authentication

I want to use TouchID authenticate my own app.
1.I want user can click 'Enter passcode' to invoke system build-in passcode screen to authenticate,if success then enter my own app.
But I don't how know to make it forward to passcode authenticate view like the following screen in 'case LAErrorUserFallback'
Here is my code :
LAContext *context = [[LAContext alloc] init];
__block NSString *msg;
__block BOOL bAuth;
// show the authentication UI with our reason string
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(#"Unlock APP With FingerPrint", nil) reply:
^(BOOL success, NSError *authenticationError) {
if (success) {
bAuth = YES;
msg =[NSString stringWithFormat:NSLocalizedString(#"EVALUATE_POLICY_SUCCESS", nil)];
dispatch_async(dispatch_get_main_queue(), ^{
[[MYAppDelegate theDelegate] initializeAppAfterKeyVaultUnlocked];
});
NSLog(#"%#",msg);
} else {
bAuth = NO;
switch (authenticationError.code) {
case LAErrorAuthenticationFailed:
msg = [NSString stringWithFormat:NSLocalizedString(#"Authentication Failed", nil)];
// ...
break;
case LAErrorUserCancel:
msg = [NSString stringWithFormat:NSLocalizedString(#"User pressed Cancel button", nil)];
dispatch_async(dispatch_get_main_queue(), ^{
[[MYAppDelegate theDelegate] exitAndLock];
});
break;
case LAErrorUserFallback:
msg = [NSString stringWithFormat:NSLocalizedString(#"User pressed \"Enter Password\"", nil)];
//Here I want to fallback to iOS build-in passcode authenticate view, and get the auth result.
break;
default:
msg = [NSString stringWithFormat:NSLocalizedString(#"Touch ID is not configured", nil)];
// ...
break;
}
NSLog(#"%#",authenticationError.localizedDescription);
}
}];
Now in iOS 9 it is pretty simple actually - you just have to use LAPolicyDeviceOwnerAuthentication instead of LAPolicyDeviceOwnerAuthenticationWithBiometrics
So in your code you just replace this:
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:NSLocalizedString(#"Unlock APP With FingerPrint", nil) reply:
^(BOOL success, NSError *authenticationError) {
With this:
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:NSLocalizedString(#"Unlock APP With FingerPrint", nil) reply:
^(BOOL success, NSError *authenticationError) {
Thus, when user fails to authenticate with fingerprint, there'd be "enter passcode" option which would invoke system passcode input screen.
In my understanding, you will have to build the passcode screen yourself if you want to use evaluatePolicy.
If you use keychain, the SecItemCopyMatching function automatically falls back to passcode if fingering fails. Here's a reference on how to get it going (see section 3): https://www.secsign.com/fingerprint-validation-as-an-alternative-to-passcodes/
Didn't try that, but this post claim you can use the system as follow here (This works only with iOS 8 or later).
Or (which is what I did) you can build your passcode entry screen (to support older iOS versions), my controller have a passcode entry view, which will get exposed when the user select use passcode. At that point the call back from evaluatePolicy will return with LAErrorUserFallback, which can be the time to open your custom passcode screen.
something like that:
-(void)maybeShowTouchIDMessage {
if (![SettingsManager sharedManager].isUseTouchID || self.createPassCodeMode) {
self.shieldView.hidden = YES;
return;
}
self.shieldView.hidden = NO;
self.shieldView.alpha = 1.0;
LAContext *context = [[LAContext alloc] init];
NSError *evalError = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&evalError] ) {
__weak SecurityWindowViewController *weakSelf = self;
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:#"Use touch id \n or hit \"Cancel\" to enter passcode"
reply:^(BOOL success, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
SecurityWindowViewController *strongSelf = weakSelf;
if (success) {
[strongSelf hideWithSuccess:YES];
} else if (error){
NSString *errorMessage;
BOOL showError = NO;
switch (error.code) {
case LAErrorAuthenticationFailed:
errorMessage = #"Sorry couldn't autheticate";
showError = YES;
break;
case LAErrorPasscodeNotSet:
errorMessage = #"Sorry couldn't autheticate";
showError = YES;
break;
case LAErrorTouchIDNotEnrolled:
errorMessage = #"Touch ID has no enrolled fingers";
showError = YES;
break;
default:
showError = NO;
break;
}
[UIView animateWithDuration:0.5 animations:^{
strongSelf.shieldView.alpha = 0.0;
} completion:^(BOOL finished) {
strongSelf.shieldView.hidden = YES;
}];
if (showError) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:errorMessage
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
}
});
}];
}
For your case :
case LAErrorUserFallback:
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:NSLocalizedString(#"Unlock APP With PassCode", nil) reply: ^(BOOL success, NSError *authenticationError) {
if(success){
NSLog(#"PassCode Login successful");
}else{
NSLog(#"%#",authenticationError);
}
}
For device passcode verification you need to use LAPolicyDeviceOwnerAuthentication instead of LAPolicyDeviceOwnerAuthenticationWithBiometrics. Hope this helps !!
You can add another case and call your passcode screen from that.
Here is my code:
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = strMessage;
objFlockr.pVerificationBlock = objResponse;
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
if (!isShow) {
myContext.localizedFallbackTitle = #"";
}
else
{
myContext.localizedFallbackTitle = #"Set Up Passcode";
}
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL succes, NSError *error) {
if (!AppDel.firstAttampt && succes && !isShow)
{
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(1);
}
else if (succes) {
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(0);
NSLog(#"User authenticated");
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
NSLog(#"Authentication Failed");
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(1);
break;
case LAErrorUserCancel:
NSLog(#"User pressed Cancel button");
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(3);
break;
case LAErrorUserFallback:
NSLog(#"User pressed \"Enter Password\"");
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(4);
break;
default:
[self showMessage:#"Touch ID is not configured" withTitle:#"Error"];
if (objFlockr.pVerificationBlock)
objFlockr.pVerificationBlock(2);
NSLog(#"Touch ID is not configured");
break;
}
NSLog(#"Authentication Fails");
}
}];
} else {
NSLog(#"Can not evaluate Touch ID");
[self showMessage:#"Can not evaluate TouchID" withTitle:#"Error"];
}
Replace LAPolicy policy enum value deviceOwnerAuthenticationWithBiometrics with deviceOwnerAuthentication
Note: If user has enable biometric (face id or touch id) authentication, then device will ask first for biometric authentication and if user choose fall back authentication, then only deviceOwnerAuthentication will show passcode screen.
Try this and see (swift 4):
func touchIDAuthentication() {
let context = LAContext()
var error:NSError?
// edit line - deviceOwnerAuthentication
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
//showAlertViewIfNoBiometricSensorHasBeenDetected()
return
}
// edit line - deviceOwnerAuthentication
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &errorPointer) {
// edit line - deviceOwnerAuthentication
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason, reply: { (success, error) in
if success {
DispatchQueue.main.async {
print("Authentication was successful")
}
}else {
DispatchQueue.main.async {
//self.displayErrorMessage(error: error as! LAError )
print("Authentication was error")
}
}
})
}else {
// self.showAlertWith(title: "Error", message: (errorPointer?.localizedDescription)!)
}
}

Contact selector working in simulator but not on an actual iPhone

All my code works perfectly in the simulator. The contact picker is displayed and when a contact is pressed, it is dismissed having obtained the contact data. However, when I try this on my device, the picker is not dismissed and displays the details of the selected contact instead. From there you can press the individual properties such as numbers and addresses, but those just transfer you to the related app.
The button the user pressed to import a contact:
- (IBAction)AddContactPressed:(id)sender {
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
// First time access has been granted, add the contact
contactsAccessible = TRUE;
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
contactsAccessible = TRUE;
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
}
//Test if contacts have been enabled or not
if (contactsAccessible) {
//Display contact selection screen
addressBookController = [[ABPeoplePickerNavigationController alloc] init];
addressBookController.peoplePickerDelegate = self;
[self presentViewController:addressBookController animated:YES completion:nil];
}
else{
//Display text saying the contacts could not be accessed and provide a button to ask again
}
}
Here is all my code for the contact picker:
-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
//Creating dictionary to store contact info
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
initWithObjects:#[#"", #"", #"", #""]
forKeys:#[#"firstName", #"lastName", #"mobileNumber", #"homeNumber"]];
//First name
CFTypeRef generalCFObject;
generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge_transfer NSString *)generalCFObject forKey:#"firstName"];
CFRelease(generalCFObject);
}
//Last name
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge_transfer NSString *)generalCFObject forKey:#"lastName"];
CFRelease(generalCFObject);
}
//Phone numbers: (home and mobile)
ABMultiValueRef phonesRef = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (int i=0; i < ABMultiValueGetCount(phonesRef); i++) {
CFStringRef currentPhoneLabel = ABMultiValueCopyLabelAtIndex(phonesRef, i);
CFStringRef currentPhoneValue = ABMultiValueCopyValueAtIndex(phonesRef, i);
if (CFStringCompare(currentPhoneLabel, kABPersonPhoneMobileLabel, 0) == kCFCompareEqualTo) {
[contactInfoDict setObject:(__bridge_transfer NSString *)currentPhoneValue forKey:#"mobileNumber"];
}
if (CFStringCompare(currentPhoneLabel, kABHomeLabel, 0) == kCFCompareEqualTo) {
[contactInfoDict setObject:(__bridge_transfer NSString *)currentPhoneValue forKey:#"homeNumber"];
}
CFRelease(currentPhoneLabel);
CFRelease(currentPhoneValue);
}
CFRelease(phonesRef);
//Getting image if contact has image
if (ABPersonHasImageData(person)) {
NSData *contactImageData = (__bridge_transfer NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);
[contactInfoDict setObject:contactImageData forKey:#"image"];
}
//Add contact to array
if (contacts == nil) {
contacts = [[NSMutableArray alloc] init];
}
[contacts addObject:contactInfoDict];
//Save contact
[userDefaults setObject:contacts forKey:#"Contacts"];
[self dismissViewControllerAnimated:YES completion:nil];
return NO;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
return NO;
}
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
[self dismissViewControllerAnimated:YES completion:nil];
}
The reason could be that the delegate couldn't call the delegate method. This could cause that you use different iOS on simulator and on iPhone.
My best guess that you use iOS 8 on simulator and under iOS 8 there is a new delegate method for the picker
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person {
....// do whatever you need here
meantime the old one is what you are using.
From the documentation:
peoplePickerNavigationController:shouldContinueAfterSelectingPerson:property:identifier:
Return Value
YES to perform the action for the property selected and dismiss the picker.
NO to show the person in the picker.
So this is probably the issue. On simulator first method gets called while on the device the other. So you should handle picking in both methods and return YES from the one described above.

Objective C: Detect number of Facebook invites

I'm trying to detect how many invites the user has sent while logged into their Facebook account. For example, I'm giving the user an option to purchase an item by inviting 3 friends to use the iOS application. If they invite 3, they are rewarded with the item. I'm really stuck on this one. Any help would be great and much appreciated!
I actually found code snippet for this after much research. I can't remember if it was on here or not, but here it is.
- (IBAction)inviteFacebookFriendsButton:(id)sender
{
// FBSample logic
// if the session is open, then load the data for our view controller
if (!FBSession.activeSession.isOpen)
{
// if the session is closed, then we open it here, and establish a handler for state changes
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:NO
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if (session.isOpen) {
}
}];
}
MouseInTheHouseAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
if (appDelegate.session.isOpen)
{
NSMutableDictionary *postVariablesDictionary = [[NSMutableDictionary alloc] init];
[postVariablesDictionary setObject:#"Come play Mouse in the House with me!" forKey:#"message"];
[postVariablesDictionary setObject:#"Invite Friends" forKey:#"title"];
[FBWebDialogs presentDialogModallyWithSession:[FBSession activeSession] dialog:#"apprequests" parameters:postVariablesDictionary handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
// Case A: Error launching the dialog or sending request.
NSLog(#"Error sending request.");
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
// Case B: User clicked the "x" icon
NSLog(#"User canceled request.");
}
else
{
NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:#"to%5B\\d+%5D=(\\d+)"
options:NSRegularExpressionCaseInsensitive
error:NULL];
NSArray * matches = [regex matchesInString:resultURL.absoluteString
options:0
range:(NSRange){0, resultURL.absoluteString.length}];
NSMutableArray * ids = [NSMutableArray arrayWithCapacity:matches.count];
for (NSTextCheckingResult * match in matches)
{
[ids addObject:[resultURL.absoluteString substringWithRange:[match rangeAtIndex:1]]];
}
NSLog(#"Number of friends invited: %lu", (unsigned long)ids.count);
}
}
}];
}
}

Upload photo using new iOS Facebook SDK API (3.0)

How can I upload a photo to facebook from an iOS app using their new API/SDK? I've already tried and I'm not getting anywhere, just keep running in circles. Here is the code I currently have:
-(void)dataForFaceboo{
self.postParams =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
self.uploadPhoto.image, #"picture", nil];
}
-(void)uploadToFacebook{
[self dataForFacebook];
NSLog(#"Going to facebook: %#", self.postParams);
// Hide keyboard if showing when button clicked
if ([self.photoCaption isFirstResponder]) {
[self.photoCaption resignFirstResponder];
}
// Add user message parameter if user filled it in
if (![self.photoCaption.text
isEqualToString:kPlaceholderPostMessage] &&
![self.photoCaption.text isEqualToString:#""])
{
[self.postParams setObject:self.photoCaption.text forKey:#"message"];
}
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:self.postParams
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error)
{
NSString *alertText;
if (error) {
alertText = [NSString stringWithFormat:
#"error: domain = %#, code = %d",
error.domain, error.code];
} else {
alertText = [NSString stringWithFormat:
#"Posted action, id: %#",
[result objectForKey:#"id"]];
}
// Show the result in an alert
[[[UIAlertView alloc] initWithTitle:#"Result"
message:alertText
delegate:self
cancelButtonTitle:#"OK!"
otherButtonTitles:nil] show];
}];
}
Your code is fine, some slight changes to be done:
add the image to the dictionary in NSData format, like
[params setObject:UIImagePNGRepresentation(_image) forKey:#"picture"];
and change the graph path to "me/photos" instead of "me/feed"
Make these changes, it worked for me.
Remember you need to use "publish_actions" permissions.
"me/photos" is meant for the photo actually be in the "Photo's" list on your Facebook profile. "me/feed" is just a post on the timeline.