Why FBSDK Share Dialog does not work with image attachment? - ios

I want to share image on Facebook, for this I do:
let photo: FBSDKSharePhoto = FBSDKSharePhoto()
photo.image = croppedImage
photo.userGenerated = true
photo.caption = "Add Your caption"
let content: FBSDKSharePhotoContent = FBSDKSharePhotoContent()
content.photos = [photo]
FBSDKShareDialog.showFromViewController(self, withContent: content, delegate: nil)
but it does not show me ShareViewController. But when I'm trying this code:
let content: FBSDKShareLinkContent = FBSDKShareLinkContent()
content.contentURL = NSURL(string: "http://")
content.contentTitle = "App Testing"
content.contentDescription = "I'm working over the app!"
How can I fix the first snippet?

I know this is an old question but just in case anyone faces the same issue:
According to the documentation, You need the native Facebook app to be installed in order to use FBSDKSharePhotoContent and you cannot use FBSDKShareDialog in that case.
A close workaround to achieve almost the same result is using FBSDKShareDialog (which only supports FBSDKShareLinkContent) as follows:
let content: FBSDKShareLinkContent = FBSDKShareLinkContent()
content.imageURL = URL(string: "www.example.com/my_image.jpg")
content.contentURL = URL(string: "www.example.com/target_url")
content.contentTitle = "My Title"
content.contentDescription = "My Description"
let dialog: FBSDKShareDialog = FBSDKShareDialog()
dialog.fromViewController = self
dialog.delegate = self // make sure to conform to FBSDKSharingDelegate protocol
dialog.shareContent = content
if !dialog.canShow() {
// fallback to non-native mode
dialog.mode = .feedBrowser
}
dialog.show()
You can find the protocol's methods here.

It only works when Facebook app is installed. Also, specify mode = .native explicitly.
let content = FBSDKSharePhotoContent()
let photo = FBSDKSharePhoto(image: image, userGenerated: true)
content.photos = [photo].flatMap({ $0 })
let dialog = FBSDKShareDialog()
dialog.fromViewController = viewController
dialog.shareContent = content
dialog.delegate = self
dialog.mode = .native
dialog.show()
If not, it will use SLComposeViewController, and you will get error
SLComposeViewController isAvailableForServiceType got serviceType com.apple.social.facebook isAvailable 0
Good practice is to debug on FBSDKShareDialog.m to see if things don't work for you
- (BOOL)show
{
BOOL didShow = NO;
NSError *error = nil;
if ([self _validateWithError:&error]) {
switch (self.mode) {
case FBSDKShareDialogModeAutomatic:{
didShow = [self _showAutomatic:&error];
break;
}
case FBSDKShareDialogModeBrowser:{
didShow = [self _showBrowser:&error];
break;
}
case FBSDKShareDialogModeFeedBrowser:{
didShow = [self _showFeedBrowser:&error];
break;
}
case FBSDKShareDialogModeFeedWeb:{
didShow = [self _showFeedWeb:&error];
break;
}
case FBSDKShareDialogModeNative:{
didShow = [self _showNativeWithCanShowError:&error validationError:&error];
break;
}
case FBSDKShareDialogModeShareSheet:{
didShow = [self _showShareSheetWithCanShowError:&error validationError:&error];
break;
}
case FBSDKShareDialogModeWeb:{
didShow = [self _showWeb:&error];
break;
}
}
}
if (!didShow) {
[self _invokeDelegateDidFailWithError:error];
} else {
[self _logDialogShow];
[FBSDKInternalUtility registerTransientObject:self];
}
return didShow;
}
Lesson learned:
Be aware of FB changes.
Check for change log every morning
Things that work today may not work tomorrow

Related

Deep linking for Facebook shareLinkContent

I'm working with deep link in iOS. I am going to share a link in Facebook using `FBSDKShareLinkContent. I have created deep linking URL in Facebook like https://fb.me/****************.
I have already done AppInviteContent and it works good like this:
let content : FBSDKAppInviteContent = FBSDKAppInviteContent()
content.appLinkURL = NSURL(string: "https://fb.me/****************")!
content.appInvitePreviewImageURL = NSURL(string: "http://***.***.***.***/shareImage.png" as String)!
FBSDKAppInviteDialog.showWithContent(content, delegate: self)
Now, I am sharing link in Facebook like this:
let shareLinkContent : FBSDKShareLinkContent = FBSDKShareLinkContent()
shareLinkContent.contentURL = NSURL(string: "https://example.com/a2d69835ae")!
shareLinkContent.contentTitle = "App_Name"
shareLinkContent.contentDescription = "Description"
let dialog : FBSDKShareDialog = FBSDKShareDialog()
dialog.fromViewController = self
dialog.delegate = self
dialog.shareContent = shareLinkContent
dialog.mode = FBSDKShareDialogMode.Web
dialog.show()
How to set deep link URL (e.g. https://fb.me/****************) in this shareLinkContent.
A very apt idea is to use Branch framework for the deep linking feature. You can get to know how to use this framework from here https://branch.io/
It can be used to share your app contents to any of the social networking sites. it has the feature on universal linking and deep linking.
Remove this below code, this have been modified in latest pod version.
let dialog : FBSDKShareDialog = FBSDKShareDialog()
dialog.fromViewController = self
dialog.delegate = self
dialog.shareContent = shareLinkContent
dialog.mode = FBSDKShareDialogMode.Web
dialog.show()
Add this code will show Facebook Share dialog:
FBSDKShareDialog.show(from: self, with: shareLinkContent, delegate: self)
This will fix your FBSDK share issue.
For APP invite try some thing like this:
{
let content : FBSDKAppInviteContent = FBSDKAppInviteContent()
content.appLinkURL = NSURL(string: "https://fb.me/****************")!
content.appInvitePreviewImageURL = NSURL(string: "http://***.***.***.***/shareImage.png" as String)!
FBSDKAppInviteDialog.show(from: self, with: content, delegate: self)
}

Automatically select Instagram in UIDocumentInteractionController or UIActivityViewController

UIDocumentInteractionController and UIActivityViewController both present menus for sharing images out to other networks. After hitting Instagram, you are presented with a nice modal that allows you to post to Instgram without leaving the app. My question is, how do I automatically show that modal without showing the menu?
This app called Sounds does it so I know it's possible, but I can't find any documentation online about how it's done. Here is the current code I have which shows the menu:
NSString *documentDirectory=[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *saveImagePath=[documentDirectory stringByAppendingPathComponent:#"Image.ig"];
NSData *imageData=UIImagePNGRepresentation(cardImage);
[imageData writeToFile:saveImagePath atomically:YES];
NSURL *imageURL=[NSURL fileURLWithPath:saveImagePath];
UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:imageURL];
docController.UTI = #"com.instagram.exclusivegram";
docController = [self setupControllerWithURL:imageURL usingDelegate:self];
[docController presentOpenInMenuFromRect:CGRectMake(1, 1, 1, 1) inView:self.view animated:YES];
Here's the menu:
Here's what I want to automatically show:
You're able to use UIActivityViewController to show up Instagram as long there is just an UIImage inside the activity items.
It won't show up if you add more items like text, url etc.
This is a bad limitation made by Instagram.
Like so:
NSMutableArray *items = [NSMutableArray array];
[items addObject:[UIImage ...]];
// show view
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:items
applicationActivities:nil];
[vc presentViewController:activityVC animated:YES completion:nil];
The code I used to share image on instagram
import UIKit
import Photos
class SocialShare: NSObject {
static let shared = SocialShare()
func postImageToInstagram(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(SocialShare.image(_:didFinishSavingWithError:contextInfo:)), nil)
}
func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo:UnsafePointer<Void>) {
if error != nil {
print(error)
}
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssetsWithMediaType(.Image, options: fetchOptions)
if let lastAsset = fetchResult.firstObject as? PHAsset {
let localIdentifier = lastAsset.localIdentifier
let u = "instagram://library?LocalIdentifier=" + localIdentifier
UIApplication.sharedApplication().openURL(NSURL(string: u)!)
}
}
}
No anywhere you want to use just call
SocialShare.shared.postImageToInstagram(UIImage(named: "1"))
Here's a Swift 4 class that implements Zuhair's answer.
import Foundation
import Photos
class InstagramSharer: NSObject {
static let shared = InstagramSharer()
func post(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(image:didFinishSavingWithError:contextInfo:)), nil)
}
#objc
private func image(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
guard error == nil else {
return
}
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions)
if let lastAsset = fetchResult.firstObject {
let localIdentifier = lastAsset.localIdentifier
let url = "instagram://library?LocalIdentifier=" + localIdentifier
UIApplication.shared.openURL(URL(string: url)!)
}
}
}
Usage
InstagramSharer.shared.post(image: #YOUR_IMAGE#)
To remove the other applications from being displayed change following lines of code (Just flip them):
docController.UTI = #"com.instagram.exclusivegram";
docController = [self setupControllerWithURL:imageURL usingDelegate:self];
So that the .UTI variable is set after overriding the docController object.
EDIT: If you are attempting to directly open the Instagram application with the information filled out and ready to share check out the iPhone hooks here.

Why is my share dialog empty? Facebook SDK

I'm trying to post to facebook, which works fine but none of my strings from my content variables are being added to the share dialog.
let content : FBSDKShareLinkContent = FBSDKShareLinkContent()
content.contentURL = NSURL(string: "<INSERT STRING HERE>")
content.contentTitle = "My Title Here"
content.contentDescription = "My description here!"
content.imageURL = NSURL(string: "<INSERT STRING HERE>")
let shareDialog = FBSDKShareDialog()
shareDialog.fromViewController = self
shareDialog.shareContent = content
shareDialog.delegate = self
if !shareDialog.canShow() {
print("cannot show native share dialog")
}
shareDialog.show()
Facebook's policies don't allow you to pre-populate status messages and require all content to be user generated. Here is what I have done and I managed to get the URL in the Facebook popup:
let activityItems = ["My app text", "", "http://google.com"]
let vc = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
self.presentViewController(vc, animated: true, completion: nil)
If I open Twitter for example I get "My app text" and the URL, for Facebook I only get the URL.

Is there a way to attach a status to FBSDKShareContent

I need to attach a description or status when users share photos videos to apps this is the code I have right now:
for video:
let fbVideo: FBSDKShareVideo = FBSDKShareVideo()
fbVideo.videoURL = self.videoUrl!
var content: FBSDKShareVideoContent = FBSDKShareVideoContent()
content.video = fbVideo
FBSDKShareAPI.shareWithContent(content, delegate: nil)
and for images:
let photo : FBSDKSharePhoto = FBSDKSharePhoto()
photo.image = self.image
photo.userGenerated = true
var content: FBSDKSharePhotoContent = FBSDKSharePhotoContent()
content.photos = [photo]
FBSDKShareAPI.shareWithContent(content, delegate: nil)
can't seem a way to attach the text status to the FBSDKShareContent

Post image on Instagram using Swift (need to translate code)

I found this code in another user question, but its objective-c and i need it in Swift. I tried to translate it, but when the apple share dialog appears and i touch Instagram, the application crashes.
The code is this one: from How to share an image on Instagram in iOS?
UIImage *screenShot = finalImage;
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.igo"];
[UIImagePNGRepresentation(screenShot) writeToFile:savePath atomically:YES];
CGRect rect = CGRectMake(0 ,0 , 0, 0);
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.igo"];
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", jpgPath]];
self.dic = [UIDocumentInteractionController interactionControllerWithURL:igImageHookFile];
self.dic.UTI = #"com.instagram.photo";
self.dic.annotation = [NSDictionary dictionaryWithObject:#"Enter your caption here" forKey:#"InstagramCaption"];
[self.dic presentOpenInMenuFromRect:rect inView:self.view animated:YES];
NSURL *instagramURL = [NSURL URLWithString:#"instagram://media?id=MEDIA_ID"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[self.dic presentOpenInMenuFromRect: rect inView: self.view animated: YES ];
} else {
NSLog(#"No Instagram Found");
}
Of course, in the example the user uses finalImage to declare the screenShot UIImage, so i simply did this to try: (i have an asset called posteo-01 in the project)
func postImage() {
var imagePost = UIImage(named: "posteo-01")
var savePath = documentsDirectory().stringByAppendingPathComponent("Test.igo")
UIImageJPEGRepresentation(imagePost, 100).writeToFile(savePath, atomically: true)
var rect = CGRectMake(0, 0, 0, 0)
var igImageHookFile = NSURL(string: "file://\(savePath)")
var dic = UIDocumentInteractionController(URL: igImageHookFile!)
dic.UTI = "com.instagram.photo"
dic.annotation = ["InstagramCaption": "hola"]
dic.presentOpenInMenuFromRect(rect, inView: self.view, animated: true)
var instagramURL = NSURL(string: "instagram://media?id=MEDIA_ID")
if(UIApplication.sharedApplication().canOpenURL(instagramURL!)) {
dic.presentOpenInMenuFromRect(rect, inView: self.view, animated: true)
} else {
println("no instagram found")
}
}
func documentsDirectory() -> String {
let documentsFolderPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
return documentsFolderPath
}
Thanks!
Already solve it:
var docController = UIDocumentInteractionController()
func postImage2() {
var instagramURL = NSURL(string: "instagram://app")
if(UIApplication.sharedApplication().canOpenURL(instagramURL!)) {
var imagePost = UIImage(named: "posteo-01")
var fullPath = documentsDirectory().stringByAppendingPathComponent("insta.igo")
var imageData = UIImagePNGRepresentation(imagePost).writeToFile(fullPath, atomically: true)
var rect = CGRectMake(0, 0, 0, 0)
self.docController.UTI = "com.instagram.exclusivegram"
var igImageHookFile = NSURL(string: "file://\(fullPath)")
self.docController = UIDocumentInteractionController(URL: igImageHookFile!)
self.docController.annotation = ["InstagramCaption":"Text"]
self.docController.presentOpenInMenuFromRect(rect, inView: self.view, animated: true)
} else {
println("no instagram found")
}
}
func documentsDirectory() -> String {
let documentsFolderPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
return documentsFolderPath
}

Resources