Problem with custom UIImagePickerController with SDK 4.0 - iphone

I'm trying to create own UIImagePickerController using Assets Library Framework from the latest SDK 4.0. Here's the code:
-(void)viewDidLoad{
[super viewDidLoad];
groups = [[NSMutableArray alloc] init];
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
NSUInteger groupTypes = ALAssetsGroupAlbum;
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOL *stop) {
if (group)
[groups addObject:group];
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {
NSString *errorTitle = [error localizedDescription];
NSString *errorMessage = [error localizedRecoverySuggestion];
NSString *errorFailureDesc = [error localizedFailureReason];
NSLog(#"Error: %#, Suggestion: %#, Failure desc: %#", errorTitle, errorMessage, errorFailureDesc);
};
[assetsLibrary enumerateGroupsWithTypes:groupTypes usingBlock:listGroupBlock failureBlock:failureBlock];
}
The problem here is that I receive an error and the failure block is called from the gorups enumerator. Here's the log:
Error: Global denied access
Suggestion: This setting can be
changed in Preferences.
Failure desc: The user has denied all
applications access to their media.
As shown in the SDK 4.0 demonstrations there should be displayed a message that the application wants access to the photo albums and the user should grand access. I see no message at all and receive the error described above. Is there someone who can tell me what should be changed in the Preferences to solve the problem?
Thanks,
Viktor.

In order to access this information Location Serivices should be tunred ON!!! There is no need to reset all the settings. In this case the allow access dialog will appear.

Related

iOS Facebook native login (without Facebook SDK)

I am trying to use native (iOS 6-7x) libraries to authorize a user with Facebook from my app. I would like to pass the auth token to my server when login is successful.
The code below works fine except when the user has not set up their Facebook account in the OS. I get the following error in this case:
Error Domain=com.apple.accounts Code=6 "The operation couldn’t be completed. (com.apple.accounts error 6.)
-(void) initFacebookLogin
{
LRAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
if (appDelegate.accountStore == nil)
appDelegate.accountStore = [[ACAccountStore alloc] init];
__block ACAccount *facebookAccount = nil;
ACAccountType *facebookAccountType = [appDelegate.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSArray * permissions = #[#"publish_stream", #"publish_actions", #"email"];
NSMutableDictionary *options = [[NSMutableDictionary alloc] initWithObjectsAndKeys:FACEBOOK_APP_ID, ACFacebookAppIdKey, permissions, ACFacebookPermissionsKey, ACFacebookAudienceOnlyMe, ACFacebookAudienceKey, nil];
[appDelegate.accountStore requestAccessToAccountsWithType:facebookAccountType
options: options
completion: ^(BOOL granted, NSError *error) {
if ( granted )
{
NSArray *accounts = [appDelegate.accountStore accountsWithAccountType:facebookAccountType];
facebookAccount = [accounts lastObject];
ACAccountCredential* accountCredential = [facebookAccount credential];
NSString* token = [accountCredential oauthToken];
NSLog( #"token=%#", token );
}
else {
// WHAT DO I DO HERE???
// Error Domain=com.apple.accounts Code=6 "The operation couldn’t be completed. (com.apple.accounts error 6.)"
NSLog(#"%#", [error description]);
}
}];
}
Do I still need to use the Facebook SDK to ask the user to log in? Is there another iOS native library I could use to prompt the user to set up Facebook access in iOS?
OR, is there a better way to do streamlined Facebook auth (not asking the user to log in if they have already done so in the OS)?
You should take a look at Facebook docs here (there's a simple login example):
https://developers.facebook.com/docs/ios/ios-sdk-tutorial/authenticate/
In my opinion, I would use the Facebook SDK to perform the login, you can do something like this:
/* Constants */
#define K_FACEBOOK_REQUEST_CREDENTIALSURL #"me/?fields=id,location,name,username,bio,picture,gender,website,birthday,email"
#define K_FACEBOOK_PERMISSIONS #[#"user_about_me",#"user_birthday",#"email"]
/* Facebook Keys */
#define K_FACEBOOK_REQUEST_ID #"id"
#define K_FACEBOOK_REQUEST_USERNAME #"username"
#define K_FACEBOOK_REQUEST_LOCATION #"location"
#define K_FACEBOOK_REQUEST_FULLNAME #"name"
#define K_FACEBOOK_REQUEST_BIO #"bio"
#define K_FACEBOOK_REQUEST_WEBSITE #"website"
#define K_FACEBOOK_REQUEST_EMAIL #"email"
#define K_FACEBOOK_REQUEST_BIRTHDAY #"birthday"
#define K_FACEBOOK_REQUEST_GENDER #"gender"
- (void)initWithLoginFacebook
{
[PFFacebookUtils logInWithPermissions:K_FACEBOOK_PERMISSIONS block:^(PFUser *user, NSError *error) {
if (!user) {
if (!error)
NSLog("ERROR_CAUSE_AUTH_USERCANCELLED");
else
NSLog("ERROR_CAUSE_AUTH_FAILEDLOGIN");
} else if (user.isNew) {
FBRequest *request = [FBRequest requestForMe];
[request startWithCompletionHandler:^(FBRequestConnection *connection,id result,NSError *error) {
if (error)
NSLog("ERROR_CAUSE_AUTH_FAILEDLOGIN");
else
[self requestLoginFacebook:result];
}];
} else
NSLog("User logged and not new!");
}];
}
- (void)requestLoginFacebook:(id)result
{
NSDictionary *userData = (NSDictionary *)result;
// Do something with the data... For example
NSString *facebookId = userData[K_FACEBOOK_REQUEST_ID];
NSString *name = userData[K_FACEBOOK_REQUEST_FULLNAME];
NSString *username = [userData[K_FACEBOOK_REQUEST_USERNAME] lowercaseString];
NSString *bio = userData[K_FACEBOOK_REQUEST_BIO];
NSString *website = userData[K_FACEBOOK_REQUEST_WEBSITE];
NSString *location = userData[K_FACEBOOK_REQUEST_LOCATION][#"name"];
NSString *gender = userData[K_FACEBOOK_REQUEST_GENDER];
NSString *birthday = userData[K_FACEBOOK_REQUEST_BIRTHDAY];
NSString *email = userData[K_FACEBOOK_REQUEST_EMAIL];
NSString *profileImage = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?width=180&height=180",userData[#"id"]];
}
You have to configure the Facebook SDK in the appDelegate and in the .plist file.
Your code only will work fine if the user has a Facebook account set in the device Settings.
I.

iOS: Facebook error "missing message or attachment"

Upgrading my app. Target is iOS5.1. Xcode 4.5.2 and am using FacebookSDK 3.0 along with Twitter Frameworks.
App is logging into Facebook without issue. When I attempt to publish a post, I get this returned in the log:
2012-12-18 10:39:31.934 MyApp[31754:1d603] Error Domain=com.facebook.sdk Code=5
"The operation couldn’t be completed. (com.facebook.sdk error 5.)"
UserInfo=0xab74630 {com.facebook.sdk:ParsedJSONResponseKey={
body = {
error = {
code = 100;
message = "(#100) Missing message or attachment";
type = OAuthException;
};
};
code = 400;
}, com.facebook.sdk:HTTPStatusCode=400}
2012-12-18 10:39:31.935 MyApp[31754:1d603] (null)
This last line is the result of a log expression to list the "postParams" in the "publishStory" method listed below. Note that it is (null).
The error result in simulator is "error: domain = com.facebook.sdk, code = 5"
I used the Facebook tutorial to build the FB interface. I've got the params listed in initWithNibName, just as the tutorial indicates.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// this stuff will change... just get it working
self.postParams = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
#"Share...", #"message",
#"http://MyApp.com", #"link",
#"icon.png", #"picture",
#"MyApp", #"name",
#"A wonderful way to record your life events.", "caption",
#"Easy to use.", #"description",
nil];
}
return self;
}
Then, the "publish" is in a separate method, which is where it stops and I get the above error.
- (void)publishStory
{
[FBRequestConnection
startWithGraphPath:#"me/feed"
parameters:_postParams
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
NSString *alertText;
if (error) {
NSLog(#"%#",error);
NSLog(#"%#", _postParams);
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];
}];
}
I think, that the actual params are not being uploaded. I've been searching for several days trying to find a solution.
Anyone have an idea of how to fix this and get the post to complete? Any help would be greatly appreciated!
I Had a similar problem, but my problem was that the postParams weren't retained because I didn't use a property and I was creating the postParams in the same publish method. The parameters need to me retained somewhere in the class.
Assure that your property is using retain, also make sure that the init method is being called.

Iphone: unable to show photos using AlAssetsLibrary

I currently sending ipa to friends for testing. Funny thing is, one of my tester able view her photos stored on her phone which was running IOS 5 using iPhone 4.
Another 2 testers: one has iPhone 4 (IOS 4.3.3) , and iPhone 3GS (IOS 5.0.1) both of them can't see photos stored on their phone.
These are the code I have used:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
//NSLog(#"See Asset: %#", #"ggg");
[assets addObject:result];
}
};
NSLog(#"location = %i length = %i ", range->location, range->length );
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
NSRange *datarange = malloc(sizeof(NSRange));
range->total = [group numberOfAssets];
datarange->location = [group numberOfAssets] - range->location - range->length;
datarange->length = range->length;
NSLog(#" total = %i", range->total);
int location = [group numberOfAssets] - range->location - range->length;
if (location < 0)
{
datarange->location = 0;
datarange->length = [group numberOfAssets] - range->location;
}
NSIndexSet *indexset = [ [NSIndexSet alloc] initWithIndexesInRange:*datarange];
[group enumerateAssetsAtIndexes:indexset options:NULL
usingBlock:assetEnumerator];
[indexset release];
free(datarange);
[self loadAssetToScrollView:assets];
}
};
[assets release];
assets = [[NSMutableArray alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock: ^(NSError *error) {
NSLog(#"Failure");
}];
[library release];
I saw somebody say about asynchronous thing in some other threads but don't know is it the case. He say put dispatch_async in the enumerate group block.
Does anyone know what is wrong.
Additionally, one of tester with iOS 4.3.3 can show his photos after enabling location services under General->Setting. Why we have to enable it? Can we enabled it on code since it will be quite disturbing to the user who using our application.
Also on iOS 5.x you must retain your ALAssetsLibrary instance so long as you need to work with the collected assets. When you release your ALAssetsLibrary instance like in your code just after calling [library enumerateGroupsWithTypes:…] all the collected assets will be invalid.
See also the ALAssetsLibrary doc - overview:
"… The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance. …"
Yes, it is incredibly frustrating, but that is how it is, and you cannot enable location services in code (that is a good thing though).
I would move the first block ^assetGroupEnumerator to the heap by [[<#block#> copy] autorelease]. Why? Because this block would be autoreleased by the runloop, if there are many assets need to be enumerated through.
One more thing: don't use [self loadAssetToScrollView:assets]; inside the block but get the weak reference of self before the block like this:
__block YourExampleClassInstance *weakSelf = self;
and further use this weakSelf instance inside the block:
[weakSelf loadAssetToScrollView:assets];
void (^assetGroupEnumerator)… = ^(ALAssetsGroup *group, BOOL *stop) {
…
};
Why? To avoid retain cycles.

is there any way to get all photos from gallery prophetically using objective-c code?

i have to fetch all photos from the iphone gallery without open the imagepickercontroller. if any have any idea or reference then post here and help me to complete my task.
Thanks in advance
Ravi
You can use ALAssetsLibrary for that. Keep in mind that users have to grant your application access to the location services to be able to "read" the items in your library. Try this piece of code and let me know if it works:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryGroupsEnumerationResultsBlock successBlock = ^(ALAssetsGroup *group, BOOL *stop) {
if (group != nil) {
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result != nil) {
// do something with your asset
}
}];
}
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) {
NSLog(#"Could not enumarate assets. Reason: %#", error);
};
[library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:successBlock failureBlock:failureBlock];
[library release];
You can also read this for more details. Also, don't forget to add #import <AssetsLibrary/AssetsLibrary.h> in your .h file and link the AssetsLibrary.framework to your project before.
Let me know if that helps!

ELCImagePickerController without allowing access to user location

I used ELCImagePickerController in my app.
but when we start our application first time and on Image gallery it will ask for accessing user location , if we don't allow to access user location to it then it will give error in UIAlertView and it wont show image gallery.
But after that if we go to setting app -> location services -> [turn on switch for access location for our app] then start app -> go to gallery page -> we can show image gallery in our app.
So my question is how can we show image gallery with ELCImagePickerController with location services turn off for our app or user don't allow to access location to our app.
ELCImagePickerController can be downloadable at this LINK
Then find ELCAlbumPickerController.m file then go to View Did Load then this causes error alert when user location access turned off,
dispatch_async(dispatch_get_main_queue(), ^
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Group enumerator Block
void (^assetGroupEnumerator)(struct ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop)
{
if (group == nil)
{
return;
}
[self.assetGroups addObject:group];
// Keep this line! w/o it the asset count is broken for some reason. Makes no sense
NSLog(#"count: %d", [group numberOfAssets]);
// Reload albums
[self performSelectorOnMainThread:#selector(reloadTableView) withObject:nil waitUntilDone:YES];
};
// Group Enumerator Failure Block
void (^assetGroupEnumberatorFailure)(NSError *) = ^(NSError *error) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat:#"Album Error: %#", [error description]] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
NSLog(#"A problem occured %#", [error description]);
};
// Enumerate Albums
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:assetGroupEnumerator
failureBlock:assetGroupEnumberatorFailure];
[library release];
[pool release];
});
The answer is that you can't show the image gallery with ELCImagePickerController with location services turned off.
ELCImagePickerController uses the Assets Library Framework to access the device's photo album. Because this framework also gives access to the metadata of the photos - including location data - the user needs to grant permission for the app to use Location Services.
There's no way around this, except if you use the standard UIImagePickerController (but I assume that won't cover the requirements for your app)