How [FBDialogs canPresentShareDialogWithParams:nil] works? - facebook-ios-sdk

Does anyone make [FBDialogs canPresentShareDialogWithParams:nil] works properly ?
It's always returning me NO. What should I put in params ?
if ([FBDialogs canPresentShareDialogWithParams:nil]) {
NSURL* url = [NSURL URLWithString:#"http://www.google.fr"];
[FBDialogs presentShareDialogWithLink:url
handler:^(FBAppCall *call, NSDictionary *results, NSError *error) {
if(error) {
NSLog(#"Error: %#", error.description);
} else {
NSLog(#"Success!");
}
}];
} else {
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
SLComposeViewController *fbComposer = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[fbComposer setInitialText:#"Google rocks !"];
[self presentViewController:fbComposer animated:YES completion:nil];
} else {
[[[UIAlertView alloc] initWithTitle:#"Informations" message:#"You have to be registered into the settings of your phone in order to share" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles:nil] show];
}
}

According to the HelloFacebookSample from the SDK (and my own experience!):
FBShareDialogParams *p = [[FBShareDialogParams alloc] init];
p.link = [NSURL URLWithString:#"http://developers.facebook.com/ios"];
BOOL canShareFB = [FBDialogs canPresentShareDialogWithParams:p];
canShareFB will return YES if the Facebook app is installed in the system; returns NO if no Facebook app is found.

The fact is it always returns NO.
I think this the issue.

Make sure to pass a non-nil instance of FBShareDialogParams to the canPresentShareDialogWithParams method. The SDK expects to receive a valid instance of FBShareDialogParmas so the SDK can make sure that the version of the Facebook app on the device can actually open the content that's going to be shared.
For example, if FB adds support for sharing video via Share Dialog in a future version of the Facebook app on iOS, the canPresentShareDialogWithParams would return NO if an older version of the Facebook app is present on the device.
I can understand how the docs: https://developers.facebook.com/ios/share-dialog/ might be confusing here (apologies!). We'll update them to reflect this.
Thanks for the feedback; hope that helps!

Related

What Does The Random String In URI Of A PlayList In Spotify Stand For

I am currently integrating Spotify with our music player app. So I visited the official site of Spotify and studied its tutorial.
But when I came across code:
-(void)playUsingSession:(SPTSession *)session
{
// Create a new player if needed
if (self.player == nil)
{
self.player = [[SPTAudioStreamingController alloc] initWithClientId:[SPTAuth defaultInstance].clientID];
}
[self.player loginWithSession:session callback:^(NSError *error)
{
if (error != nil)
{
NSLog(#"*** Logging in got error: %#", error);
return;
}
NSURL *trackURI = [NSURL URLWithString:#"spotify:track:58s6EuEYJdlb0kO7awm3Vp"];
[self.player playURIs:#[ trackURI ] fromIndex:0 callback:^(NSError *error)
{
if (error != nil)
{
NSLog(#"*** Starting playback got error: %#", error);
return;
}
}];
}];
}
I don't know what "58s6EuEYJdlb0kO7awm3Vp" in this line means
NSURL *trackURI = [NSURL URLWithString:#"spotify:track:58s6EuEYJdlb0kO7awm3Vp"];
Is it the id of the track?
Because it is hardcoded, so I don't know how could I request it.
I read the documentation of the APIs especially on the part of SPTPlaylists. But I can't find any explanation of what this string stands for.
Please help me. Thanks in advance!
In the example, 58s6EuEYJdlb0kO7awm3Vp is the Spotify ID for the track, and spotify:track:58s6EuEYJdlb0kO7awm3Vp is its Spotify URI. There is some information in the Spotify Web API User Guide about how identifiers for the Spotify catalog work.
You can use the Spotify desktop client to find out the ID/URI of an album, artist, track or playlist by right-clicking on the header of the view that shows its contents, or you can use the Web API Search endpoint to find out these identifier.
We have just updated the iOS SDK Tutorial to explain better where this ID comes from.

Google UrlShortener "ipRefererBlocked"

I have a site hosted on Azure where the calls to the Google UrlShortner API are being blocked. I receive the error:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
The API works fine running locally and I have added the ip address to the API project credentials in the developer console. This appears to be an issue with Azure but I don't see where anyone has an answer.
Any suggestions would be great!
I was never able to get this resolved even using a static ip. Work around was tinyUrl. Their api worked flawlessly.
Yes use tiny URL, but not their API. I was never able to get their API to work.
+ (void) shortenLink:(NSString*) link andPerformBlock:(void (^)(NSString*, NSError*))block {
NSURLRequest* shortenedLinkRequest = [LinkShortener createTinyURLShortenerRequest:link];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:shortenedLinkRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSString*shortenedLink = #"";
UIAlertView* alert = nil;
if ([data length] > 0 && error == nil) {
NSString* shortenedLink = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
if (block) {
block(shortenedLink, error);
}
}
}
+ (NSURLRequest*) createTinyURLShortenerRequest:(NSString*) link {
NSString* escapedLink = [link stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];;
NSString* tinyURLShortenerURL = [NSString stringWithFormat:#"http://tinyurl.com/api-create.php?url=%#", escapedLink];
NSURL* tinyURLShortenerUrl = [NSURL URLWithString:tinyURLShortenerURL];
NSMutableURLRequest* shortenedLinkRequest = [NSMutableURLRequest requestWithURL:tinyURLShortenerUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:URL_SHORTENER_TIMEOUT];
[shortenedLinkRequest setHTTPMethod:#"GET"];
return shortenedLinkRequest;
}

Update Core Data store location to support App Groups

I have an app already in the App Store that uses core data to save data.
Now, when iOS 8 is about to come out I wanna add a widget to it, thus I must use App Groups to share data between the binaries.
One problem though - I need to change the store location to support App Groups to all the existing users.
I wrote the following code, trying to move the store to the new path:
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *oldStoreURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
oldStoreURL = [oldStoreURL URLByAppendingPathComponent:#"Schooler.sqlite"];
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.com.schooler.mycontainer"];
storeURL = [storeURL URLByAppendingPathComponent:#"Schooler.sqlite"];
if([[NSFileManager defaultManager] fileExistsAtPath:oldStoreURL.path] == YES && [[NSFileManager defaultManager] fileExistsAtPath:storeURL.path] == NO)
{
// Prior today extension - Need to move to new directory
NSError *error = nil;
if([[NSFileManager defaultManager] moveItemAtURL:oldStoreURL toURL:storeURL error:&error] == YES)
NSLog(#"Migrated successfully to new database location.");
else
NSLog(#"error: %#",error);
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
return _persistentStoreCoordinator;
}
The output is always "Migrated successfully to new database location.", although all the data that was saved on the app before has been deleted, As if it created a new database instead of just moving it.
What causes the problem? How should I fix it?
Thank you.
A Core Data NSSQLiteStoreType store created with the default options is actually several files, as described in Technical Q&A 1809: New default journaling mode for Core Data SQLite stores in iOS 7 and OS X Mavericks. This is important to remember when attempting to move a store outside of a migration process, and is the source of your issue - you are moving one file when you need to be moving all of them. Moving the files individually outside of Core Data and without the benefits of a file coordinator is not recommended, however. It's much better to use a migration instead.
A migration will take the data from the source store and migrate it to your new store location, essentially replicating the old data at the new location. The old data will still exist on the filesystem. In your application, you should perform the migration as you are now, but do not attempt to move the old data to the new location yourself - that is where things are going wrong.
Instead of moving files around yourself, you can rely on a migration to move the data for you. First, add a store to the persistent store coordinator with the URL of the source data. Then you will perform a migration to move that data to the new URL
NSPersistentStore *sourceStore = nil;
NSPersistentStore *destinationStore = nil;
NSDictionary *storeOptions = #{ NSSQLitePragmasOption : #{ #"journal_mode" :
#"WAL" } };
// Add the source store
if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:oldStoreURL options:storeOptions error:&error]){
// Handle the error
} else {
sourceStore = [coordinator persistentStoreForURL:oldStoreURL];
if (sourceStore != nil){
// Perform the migration
destinationStore = [coordinator migratePersistentStore:sourceStore toURL:storeURL options:storeOptions withType:NSSQLiteStoreType error:&error];
if (destinationStore == nil){
// Handle the migration error
} else {
// You can now remove the old data at oldStoreURL
// Note that you should do this using the NSFileCoordinator/NSFilePresenter APIs, and you should remove the other files
// described in QA1809 as well.
}
}
}
Once the migration has completed you can delete the old files. The example here explicitly specifies the SQLite journal options, this is to ensure that if the default options are changed in the future the code will still work. If you are using different options, you should use those instead.
In case having a version in Swift would be helpful:
let oldPersistentStoreURL: URL = ...
let sharedPersistentStoreURL: URL = ...
let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true] // + any database-specific options
if FileManager.default.fileExists(atPath: oldPersistentStoreURL.path) {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: oldPersistentStoreURL, options: options)
if let sourceStore = coordinator.persistentStore(for: oldPersistentStoreURL) {
let _ = try coordinator.migratePersistentStore(sourceStore, to: sharedPersistentStoreURL, options: options, withType: NSSQLiteStoreType)
// If migration was successful then delete the old files
}
} catch {
error.logErrors()
}
}

iOS 7 Core Data and iCloud sync

I am looking to integrate in my new app the option to sync core data in iCloud and so share the information on users devices. I looked around on the web but haven't found a good example or tutorial on how to do this with iOS7.
The last that I have done is to analyze the Apple receipt demo app and included in my app. It seams to work, at least at first view. Adding a record on one device and after a short while, the other device show the data - so far I was happy.
BUT, after restoring the app, the information was gone, on both devices. So i looked into the app (iExplorer) and have found the local Core Data and all my data is there. The next that I have observed is that the debugger shows this: (XXX) are of course not the real values :-)
2014-07-09 19:40:12.830 XXX[199:3507] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](771): CoreData: Ubiquity: mobile~XXXXX:XXX
Using local storage: 1
2014-07-09 19:40:12.837 XXX[199:60b] asynchronously added persistent store!
2014-07-09 19:40:13.478 XXX[199:1803] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](771): CoreData: Ubiquity: mobile~XXXXX:XXX
Using local storage: 0
What means first it seams like to use the local storage but than change to local storage 0.
this is the code used from Apple's demo app:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
// assign the PSC to our app delegate ivar before adding the persistent store in the background
// this leverages a behavior in Core Data where you can create NSManagedObjectContext and fetch requests
// even if the PSC has no stores. Fetch requests return empty arrays until the persistent store is added
// so it's possible to bring up the UI and then fill in the results later
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
// prep the store path and bundle stuff here since NSBundle isn't totally thread safe
NSPersistentStoreCoordinator* psc = persistentStoreCoordinator;
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:#"XXX.sqlite"];
// do this asynchronously since if this is the first time this particular device is syncing with preexisting
// iCloud content it may take a long long time to download
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
// this needs to match the entitlements and provisioning profile
NSURL *cloudURL = [fileManager URLForUbiquityContainerIdentifier:nil];
NSString* coreDataCloudContent = [[cloudURL path] stringByAppendingPathComponent:#"XXXXX"];
cloudURL = [NSURL fileURLWithPath:coreDataCloudContent];
// The API to turn on Core Data iCloud support here.
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:#"XXX", NSPersistentStoreUbiquitousContentNameKey, cloudURL, NSPersistentStoreUbiquitousContentURLKey, [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,nil];
NSError *error = nil;
[psc lock];
if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
Typical reasons for an error here include:
* The persistent store is not accessible
* The schema for the persistent store is incompatible with current managed object model
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[psc unlock];
// tell the UI on the main thread we finally added the store and then
// post a custom notification to make your views do whatever they need to such as tell their
// NSFetchedResultsController to -performFetch again now there is a real store
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"asynchronously added persistent store!");
[[NSNotificationCenter defaultCenter] postNotificationName:#"RefetchAllDatabaseData" object:self userInfo:nil];
});
});
return persistentStoreCoordinator;
}
Could anyone help with tutorial or solution?
Try these sample apps for iOS and OSX.
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/

Feed Dialog not working on iOS SDK 3.0 beta (API error code 110)

I am updating my app to use the new Facebook SDK for iOS (3.0). However, I have run across an issue trying to use the feed dialog. I followed the instructions on Facebook's developer website regarding how to use the feed dialog with the new SDK, but I am getting this error when I show the dialog:
API Error Code: 110
API Error Description: Invalid user id
Error Message: Missing user cookie (to validate session user)
Here is my code:
Facebook *facebook = [[Facebook alloc] initWithAppId:FBSession.activeSession.appID andDelegate:nil];
facebook.accessToken = FBSession.activeSession.accessToken;
facebook.expirationDate = FBSession.activeSession.expirationDate;
NSMutableDictionary *feedParams = [[NSMutableDictionary alloc] init];
[feedParams setObject:self.video.alternateLink.href
forKey:#"link"];
// link title = video title
[feedParams setObject:self.video.title.stringValue
forKey:#"name"];
// link picture = video thumbnail
[feedParams setObject:self.video.mediaGroup.highQualityThumbnail.URLString
forKey:#"picture"];
NSDictionary *privacyDict = [NSDictionary dictionaryWithObjectsAndKeys:#"CUSTOM", #"value", #"SELF", #"friends", nil];
SBJSON *jsonWriter = [[SBJSON alloc] init];
[feedParams setObject:[jsonWriter stringWithObject:privacyDict error:NULL]
forKey:#"privacy"];
[jsonWriter release];
[facebook dialog:#"feed"
andParams:feedParams
andDelegate:self];
[feedParams release];
self.facebook = facebook;
[facebook release];
It seems like an authentication problem, but I am passing a valid access token to the Facebook object, so I'm not sure what the problem is. If anybody could help me, that would be great. Thanks.
You may use FBSession.activeSession when integrating with the legacy Facebook class, as you have shown. One possible gotcha when you use activeSession, rather than directly instantiating a session object, is that it may not be open. Here is a simple sample that shows the form for integrating the Facebook class with active session:
if (FBSession.activeSession.isOpen) {
// Create a Facebook instance
Facebook *facebook = [[Facebook alloc] initWithAppId:FBSession.activeSession.appID
andDelegate:nil]; // commonly self
// Set the session information for the Facebook instance
facebook.accessToken = FBSession.activeSession.accessToken;
facebook.expirationDate = FBSession.activeSession.expirationDate;
// Put together the dialog parameters
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
#"I'm using the the Facebook SDK for iOS", #"name",
#"Facebook for iOS", #"caption",
#"Check out the Facebook SDK for iOS!", #"description",
#"https://developers.facebook.com/ios", #"link",
#"http://www.facebookmobileweb.com/hackbook/img/facebook_icon_large.png", #"picture",
nil];
// Invoke the dialog
[facebook dialog:#"feed" andParams:params andDelegate:nil];
[facebook release];
}
If the active session is not open, then you would get a failure along the lines of what you are seeing. A call along the lines of the following, somewhere earlier in your logic remedy this:
[FBSession openActiveSessionWithAllowLoginUI:YES];
Hope this helps!

Resources