iOS Facebook integration shows 'App Not Setup' error - objective-c

I am having Facebook login in my iOS App. After following all the steps from developer.facebook.com and successful integration I can see a button in my view on clicking that button it redirects to safari and asking for fb username and password but after logging in it shows 'App Not Setup' error. Here I have 3 questions
I want everything to load inside the app itself
I don't want the FB login button, I want to load the FB page on viewdidload/appear
Whats the reason for "App not Setup" error. I want to test with successful loginenter

There might be various reasons for "App not setup" like
Check your plist file where you are entering 'FacebookAppID' and URL string
a)check your facebook app id
b)check your URL String facebook app id has prefix 'fb'
c)Check your bundle id i.e com.yourapp.com is properly set on facebook app settings or not.
d) Check you have entered all correct information in app settings of your facebook app.

If you don't strictly need to use Facebook SDK you could use the Social.framework. That way you wouldn't have to worry about the bundle id or Facebook App ID.
Here's a sample code to show how it works:
SLComposeViewController *slComposeViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[slComposeViewController setInitialText:MyText];
[slComposeViewController setTitle:MyTitle];
if (![slComposeViewController addURL:url]) {
NSLog(#"Unable to add url");
}
[self presentViewController:slComposeViewController animated:YES completion:nil];
//Check the result
slComposeViewController.completionHandler = ^(SLComposeViewControllerResult result)
{
switch (result) {
case SLComposeViewControllerResultCancelled:
//Do something
break;
case SLComposeViewControllerResultDone:
//Do something
break;
}
};
//If iOS < 7.0 dismiss the viewcontroller
NSString *version = [[UIDevice currentDevice] systemVersion];
if ([version floatValue] < 7.0)
{
dispatch_async(dispatch_get_main_queue(), ^{
[slComposeViewController dismissViewControllerAnimated:NO completion:^{
// Do something
}];
});
}

Related

setInitialText not work with IOS 8.3 (facebook,social,SLComposeViewController)

The functionality of SLComposeViewController no longer works as expected with the newest Facebook iPhone app update as of April 24th. Any initial text specified is ignored, though the setInitialText method returns true as if it was successful. The dialog then always returns "Done" whether you hit "Done" or "Cancel". I realize this is an Apple call and I'm not even using the Facebook SDK, but I have verified that everything works perfectly with the previous version of the Facebook App installed but when you upgrade the Facebook app on your iPhone, this functionality no longer works as expected.
Note that the result of the completion handler now always returns "Done" - even when you hit "Cancel" and also, the setInitialText: does nothing now. Verified that the same code worked pre-the april 24th release.
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[controller setInitialText:#"hiiiiiii"];
[controller setCompletionHandler:^(SLComposeViewControllerResult result)
{
if (result == SLComposeViewControllerResultCancelled)
{
NSLog(#"The user cancelled.");
}
else if (result == SLComposeViewControllerResultDone)
{
NSLog(#"The user posted to Facebook");
}
}];
[self presentViewController:controller animated:YES completion:nil];
}
else
{
SCLAlertView *alert = [[SCLAlertView alloc] init];
[alert showWarning:self title:#"alert" subTitle:#"facebook not installed" closeButtonTitle:#"ok" duration:0.0f];
}
At the time of this post, FB's still not allowing to set initial text, even using FB SDK.
A way I implemented to bypass the issue is to copy the content to clipboard and show a dialog to notify users that they can paste the preset content.
setInitialText: is not working anymore because Facebook has recently changed its policy about prefilling, but addURL: is still working and may be useful.
SLComposeViewController *mySLComposerSheet = [[SLComposeViewController alloc] init];
mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
NSURL *url = [[NSURL alloc] initWithString:linkString];
[mySLComposerSheet addURL:url];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
[mySLComposerSheet setCompletionHandler:^(SLComposeViewControllerResult result) {
NSString *output;
switch (result) {
case SLComposeViewControllerResultCancelled:
NSLog(#"SLComposeViewControllerResultCancelled");
break;
case SLComposeViewControllerResultDone:
NSLog(#"SLComposeViewControllerResultDone");
break;
}
}];
This way I can prefill Facebook post composer with the URL to my App.
I hope it to be useful.

How do I post my own app with facebook

I have made an app and I want to create a UIButton that shares this app with facebook users.
I wrote the following code:
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[controller setInitialText:#"My App Name"];
[controller addURL:[NSURL URLWithString:#"https://itunes.apple.com/il/app/fruit-ninja-free/id403858572?mt=8/"]];
[self presentViewController:controller animated:YES completion:Nil];
}
else {
}
I've used an example URL of the famous fruit ninja cause my app is not yet on the app store and doesn't have it's own URL.
The issue:
If the app is not yet on iTunes, I don't have an iTunes URL to share yet... So how do I share my app?
Help is much appreciated...
You should create stub for your app at iTunes Connect. After that you'll be able to get link to your application even before submission.

iOS facebook SDK: Login already authenticated

I have had the Facebook iOS SDK running in an app I've been working on for a few months. At this point I am mostly using the SDK for SSO purposes.
Since I have started using iOS 6.0 I have been seeing an issue where the "Login to use your FB account with MY_APP" modal is blocking my current view.
The odd thing is that the user is already authenticated and apparently authorized to use my app. This is proven by the fact that I can get the user's email address and such.
It is also important to note that if I click the "X" it will close and everything is fine (user is authenticated/authorized). If I login as it tells me, it shows the "MY_APP is already authorized" modal which I cannot click the "Okay" button but I can click the "X" which again drops me back into my view with the user authenticated and authorized.
Here you can see the it:
To authenticate I am calling the following method in the appdelegate:
[appDelegate openSessionWithAllowLoginUI:YES];
The following are the relevant FB methods in my appdelegate:
// FACEBOOK STUFF
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [NSArray arrayWithObjects: #"email", nil];
return [FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
[self sessionStateChanged:session state:status error:error];
}];
}
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState)state
error:(NSError *)error {
// FBSample logic
// Any time the session is closed, we want to display the login controller (the user
// cannot use the application unless they are logged in to Facebook). When the session
// is opened successfully, hide the login controller and show the main UI.
switch (state) {
case FBSessionStateOpen: {
FBCacheDescriptor *cacheDescriptor = [FBFriendPickerViewController cacheDescriptor];
[cacheDescriptor prefetchAndCacheForSession:session];
[self sendAuthenticationStatusChangedNotification];
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
// FBSample logic
// Once the user has logged in, we want them to be looking at the root view.
[FBSession.activeSession closeAndClearTokenInformation];
//[self showLoginView];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// FBSample logic
// We need to handle URLs by passing them to FBSession in order for SSO authentication
// to work.
return [FBSession.activeSession handleOpenURL:url];
}
EDIT 1
I noticed that this is happing on one of my phones but not the other. The phone that wasn't working had an older version of the FB app installed. Updating the FB app stopped this issue from happening. I am still interested in a fix to avoid others from experiencing the same issue.
EDIT 2
The issue went away for a little but now is back even with the new facebook app installed. Please help!
The problem for me actually turned out to be a silly one. I was calling
[appDelegate openSessionWithAllowLoginUI:YES];
two times due to a button click event that was wired up twice. As soon as it was only being called once, the issue went away!

Ask permission to access Camera Roll

I have a settings view where the user can choose switch on or off the feature 'Export to Camera Roll'
When the user switches it on for the first time (and not when he takes the first picture), I would like the app to ask him the permission to access the camera roll.
I've seen behavior in many app but can't find the way to do it.
I'm not sure if there is some build in method for this, but an easy way would be to use ALAssetsLibrary to pull some meaningless bit of information from the photo library when you turn the feature on. Then you can simply nullify what ever info you pulled, and you will have prompted the user for access to their photos.
The following code for example does nothing more than get the number of photos in the camera roll, but will be enough to trigger the permission prompt.
#import <AssetsLibrary/AssetsLibrary.h>
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
[lib enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
NSLog(#"%zd", [group numberOfAssets]);
} failureBlock:^(NSError *error) {
if (error.code == ALAssetsLibraryAccessUserDeniedError) {
NSLog(#"user denied access, code: %zd", error.code);
} else {
NSLog(#"Other error code: %zd", error.code);
}
}];
EDIT: Just stumbled across this, below is how you can check the authorization status of your applications access to photo albums.
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
if (status != ALAuthorizationStatusAuthorized) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Attention" message:#"Please give this app permission to access your photo library in your settings app!" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil, nil];
[alert show];
}
Since iOS 8 with Photos framework use:
Swift 3.0:
PHPhotoLibrary.requestAuthorization { status in
switch status {
case .authorized:
<#your code#>
case .restricted:
<#your code#>
case .denied:
<#your code#>
default:
// place for .notDetermined - in this callback status is already determined so should never get here
break
}
}
Objective-C:
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusAuthorized:
<#your code#>
break;
case PHAuthorizationStatusRestricted:
<#your code#>
break;
case PHAuthorizationStatusDenied:
<#your code#>
break;
default:
break;
}
}];
Important note from documentation:
This method always returns immediately. If the user has previously granted or denied photo library access permission, it executes the handler block when called; otherwise, it displays an alert and executes the block only after the user has responded to the alert.
Since iOS 10, we also need to provide the photo library usage description in the info.plist file, which I described there. And then just use this code to make alert appear every time we need:
- (void)requestAuthorizationWithRedirectionToSettings {
dispatch_async(dispatch_get_main_queue(), ^{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
if (status == PHAuthorizationStatusAuthorized)
{
//We have permission. Do whatever is needed
}
else
{
//No permission. Trying to normally request it
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status != PHAuthorizationStatusAuthorized)
{
//User don't give us permission. Showing alert with redirection to settings
//Getting description string from info.plist file
NSString *accessDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:#"NSPhotoLibraryUsageDescription"];
UIAlertController * alertController = [UIAlertController alertControllerWithTitle:accessDescription message:#"To give permissions tap on 'Change Settings' button" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleCancel handler:nil];
[alertController addAction:cancelAction];
UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:#"Change Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}];
[alertController addAction:settingsAction];
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController animated:YES completion:nil];
}
}];
}
});
}
Also, there are some common cases when the alert doesn't appear. To avoid copying I would like you to take a look at this answer.
The first time the user tries to write to camera roll on ios 6 he/she is automatically asked for permission. You don't have to add extra code (before that the authorisationstatus is ALAuthorizationStatusNotDetermined ).
If the user denies the first time you cannot ask again (as far as I know). The user has to manually change that app specific setting in the settings->privacy-> photos section.
There is one other option and that is that it the user cannot give permission due other restrictions like parental control, in that case the status is ALAuthorizationStatusRestricted
Swift:
import AssetsLibrary
var status:ALAuthorizationStatus = ALAssetsLibrary.authorizationStatus()
if status != ALAuthorizationStatus.Authorized{
println("User has not given authorization for the camera roll")
}
#import <AssetsLibrary/AssetsLibrary.h>
//////
ALAuthorizationStatus status = [ALAssetsLibrary authorizationStatus];
switch (status) {
case ALAuthorizationStatusRestricted:
{
//Tell user access to the photos are restricted
}
break;
case ALAuthorizationStatusDenied:
{
// Tell user access has previously been denied
}
break;
case ALAuthorizationStatusNotDetermined:
case ALAuthorizationStatusAuthorized:
// Try to show image picker
myPicker = [[UIImagePickerController alloc] init];
myPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
myPicker.delegate = self;
[self presentViewController: myPicker animated:YES completion:NULL];
break;
default:
break;
}
iOS 9.2.1, Xcode 7.2.1, ARC enabled
'ALAuthorizationStatus' is deprecated: first deprecated in iOS 9.0 -
Use PHAuthorizationStatus in the Photos framework instead
Please see this post for an updated solution:
Determine if the access to photo library is set or not - PHPhotoLibrary (iOS 8)
Key notes:
Most likely you are designing for iOS7.0+ as of todays date, because of this fact you will need to handle both ALAuthorizationStatus and PHAuthorizationStatus.
The easiest is to do...
if ([PHPhotoLibrary class])
{
//Use the Photos framework
}
else
{
//Use the Asset Library framework
}
You will need to decide which media collection you want to use as your source, this is dictated by the device that your app. will run on and which version of OS it is using.
You might want to direct the user to settings if the authorization is denied by user.

Prompt login alert with Twitter framework in iOS5?

As you all may know, since iOS5 there is a native Twitter framework which make it easy to post tweets from your app.
Is there a way to prompt an alert that forwards the user to the settings app and ask for username and password?
I know that i could solve the problem with the following code:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"prefs:root=TWITTER"]];
But thats undocumented code..
Thanks in advance
Regards Billy
(My first post on SO)
In iOS5.1, we should use TWTweetComposeViewController to show the dialog since apple rejects apps using prefs:root=TWITTER.
But, I didn't like showing the tweet screen and keyboard
so I figured out the way to hide them, but show the pop up screen.
UPDATE:
Apple approved my app using this trick.
TWTweetComposeViewController *viewController = [[TWTweetComposeViewController alloc] init];
//hide the tweet screen
viewController.view.hidden = YES;
//fire tweetComposeView to show "No Twitter Accounts" alert view on iOS5.1
viewController.completionHandler = ^(TWTweetComposeViewControllerResult result) {
if (result == TWTweetComposeViewControllerResultCancelled) {
[self dismissModalViewControllerAnimated:NO];
}
};
[self presentModalViewController:viewController animated:NO];
//hide the keyboard
[viewController.view endEditing:YES];
//this approach doesn't work since you can't jump to settings
// [self dismissModalViewControllerAnimated:NO];
You don't need to implement this, if you set up your Twitter integration to make a post on Twitter and iOS detects that there is no Twitter account set up it will do this automatically for you!
This is a screenshot of one of my apps running on my iPhone 4S on iOS 5.1
The removal of Preferences links is in reference to custom actions by the developer, as in linking to your own preferences menu. This does not apply because not only is Twitter a built in function of iOS 5 but the UIAlertView that pops up to notify you isn't handled by the developer, it is an automatic function of iOS.
Here i found the way :
Display custom alert if no twitter account has been setup on your device settings:
if (![TWTweetComposeViewController canSendTweet]) {
UIAlertView *alertViewTwitter = [[[UIAlertView alloc]
initWithTitle:#"No Twitter Accounts"
message:#"There are no Twitter accounts configured. You can add or create a Twitter account in Settings."
delegate:self
cancelButtonTitle:#"Settings"
otherButtonTitles:#"Cancel",nil] autorelease];
[alertViewTwitter show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex==0) {
TWTweetComposeViewController *ctrl = [[TWTweetComposeViewController alloc] init];
if ([ctrl respondsToSelector:#selector(alertView:clickedButtonAtIndex:)]) {
[(id <UIAlertViewDelegate>)ctrl alertView:alertView
clickedButtonAtIndex:0];
}
[ctrl release];
}
}
Hope this will make sense :)
It's not possible, although it should automatically ask the user to login, if the user isn't logged in already.
As of iOS 5.1 that feature has been removed, as seen here