0

When sharing still photos, I can make my app switch to Facebook to share that image. It doesn't seem to work the same with video.

This shares a photo just fine. It moves to the Facebook application to confirm the post:

let sharePhoto = FBSDKSharePhoto()
sharePhoto.image = photo

let content = FBSDKSharePhotoContent()
content.photos = [sharePhoto]

let shareDialog: FBSDKShareDialog = FBSDKShareDialog()
shareDialog.shareContent = content
shareDialog.mode = .native
shareDialog.show()

Similarly, I cannot do this when sharing video! No dialog, does not switch to the Facebook application, and does not post the video:

let shareVdo: FBSDKShareVideo = FBSDKShareVideo()
shareVdo.videoURL = self.fileURL
let vdoContent = FBSDKShareVideoContent()
vdoContent.video = shareVdo

let shareDialog: FBSDKShareDialog = FBSDKShareDialog()
shareDialog.shareContent = vdoContent
shareDialog.mode = .native
shareDialog.show()

This will share my video, but immediately with no dialog, or moving to the Facebook app first!

let shareVdo: FBSDKShareVideo = FBSDKShareVideo()
shareVdo.videoURL = self.fileURL
let vdoContent = FBSDKShareVideoContent()
vdoContent.video = shareVdo
FBSDKShareAPI.share(with: vdoContent, delegate:self)

According to the documentation, I may have needed to convert my fileURL to an asset URL. I'm unclear if I should use the FBSDKShareAPI or not:

let shareVdo: FBSDKShareVideo = FBSDKShareVideo()
let asset = AVAsset(url: self.fileURL)
let assetURL = self.getAssetUrl(asset:asset)
shareVdo.videoURL = assetURL
let vdoContent = FBSDKShareVideoContent()
vdoContent.video = shareVdo
//FBSDKShareAPI.share(with: vdoContent, delegate:self)

let shareDialog: FBSDKShareDialog = FBSDKShareDialog()
shareDialog.shareContent = vdoContent
shareDialog.mode = .native
shareDialog.show()

If I uncomment the FBSDKShareAPI.share function call, I see "TIC Read Status" printed in my console, and it eventually posts to Facebook, but does this without showing a native share dialog. (Basically it invisibly shares to Facebook without any visual feedback to the user). I want it to move to the Facebook app with the content to be confirmed by the user, just like how sharing a photo works in my app.

Yet another attempt was to use FBSDKShareVideo with initializer arguments "videoURL" and "previewPhoto". I made sure the video is under 12 megabytes (in my case it was 4.4 MB), sharePhoto and that fileURL were both valid. The share dialog does not work, meaning it doesn't shift into the native Facebook app. The Facebook developers guide shows it using an imagePickerController, which might mean that the SDK requires the video coming from your camera roll.

let photo = self.uiImages[0]

let sharePhoto = FBSDKSharePhoto()
sharePhoto.image = photo

let filePath = self.fileURL

// get size of video in bytes
do {
    var fileSize : UInt64
    let attr = try FileManager.default.attributesOfItem(atPath: (filePath?.path)!)
    fileSize = attr[FileAttributeKey.size] as! UInt64

    print(fileSize)

} catch {
    print("Error: \(error)")
}

let shareVideo = FBSDKShareVideo(videoURL: self.fileURL, previewPhoto: sharePhoto)

let content = FBSDKShareVideoContent()
content.video = shareVideo

let shareDialog: FBSDKShareDialog = FBSDKShareDialog()

shareDialog.shareContent = content

shareDialog.mode = .native
shareDialog.show()
Chewie The Chorkie
  • 4,896
  • 9
  • 46
  • 90
  • Did you follow the steps here: https://developers.facebook.com/docs/sharing/ios#videos? The video URL videoURL must be an asset URL. You can get a video asset URL e.g. from UIImagePickerController. – Pranav Kasetti May 11 '18 at 21:44
  • @PranavKasetti I have the asset URL, and I've also tried the original URL. I have two sharer methods, and they aren't showing any errors or results. I'll update my answer to show what else I've tried. That is in objective-c, and it's not necessary to use to get an asset URL. I'm unclear if I should use the FBSDKShareAPI or not, or just use the shareDialog. – Chewie The Chorkie May 14 '18 at 17:10
  • Another thing I should note here, is that I'm not using any sort of imagepicker. I have my app create a video from a source image or from recording a video. It goes straight to another view with the video previewing, which would allow the user to post it to their Facebook. All examples I've seen so far use an imagepicker controller. – Chewie The Chorkie May 14 '18 at 17:32
  • Do any errors get printed on the console? If not it may be worth conforming to `FBSDKSharingDelegate`. That way you can check what error is the problem under the hood. – Pranav Kasetti May 15 '18 at 15:00
  • Thanks Pranav. I've conformed to the FBSDKSharingDelegate with the sharing functions, and errors do not appear. – Chewie The Chorkie May 15 '18 at 15:46
  • Ok. Hmm. In that case I have checked docs (https://developers.facebook.com/docs/reference/ios/current/class/FBSDKShareVideo/) and you can try one of their factory convenience initialiser methods like `video(with: videourl, previewPhoto: image)`. I haven't tried it, but I think there may be an issue with not setting all the stored properties in the initialiser before sharing (previewPhoto namely). In general, in Swift all stored properties must be set in the initialiser. – Pranav Kasetti May 15 '18 at 15:57
  • I updated the post. I tried that convenience initializer, but did not post that until now. I have the feeling that videos may only be shared from imagePickerController if you want to display the native view, or more precisely, ones that are already saved to the camera roll. However, I have successfully shared videos without displaying a dialog, but that is against Facebook's guidelines. – Chewie The Chorkie May 15 '18 at 16:14
  • 1
    Ok. Yes it looks like the video has to be saved to the device's camera roll first. Facebook need to improve their docs! ;) – Pranav Kasetti May 15 '18 at 16:21

1 Answers1

3

Here's how I got it to work. There's a particular URL format that FB requires.

if let lastAsset = fetchResult.firstObject {
  let localID = lastAsset.localIdentifier
  let assetID = localID.replacingOccurrences(of: "/.*", with: "", options: NSString.CompareOptions.regularExpression, range: nil)
  let ext = "mp4"
  let assetURLStr = "assets-library://asset/asset.\(ext)?id=\(assetID)&ext=\(ext)"
  let video = FBSDKShareVideo(videoURL: URL(string: assetURLStr))
  let content = FBSDKShareVideoContent()
  content.video = video                    
  let dialog = FBSDKShareDialog()
  dialog.delegate = self
  dialog.shareContent = content
  dialog.shouldFailOnDataError = true
  dialog.mode = .automatic                    
  dialog.fromViewController = self

  dialog.show()
}

This uses the other approach with ShareDialog() instead of FBSDKShareDialog()

let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
let fetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions)
if let lastAsset = fetchResult.firstObject {
  let localID = lastAsset.localIdentifier
  let assetID = localID.replacingOccurrences(of: "/.*", with: "", options: NSString.CompareOptions.regularExpression, range: nil)
  let ext = "mp4"
  let assetURLStr = "assets-library://asset/asset.\(ext)?id=\(assetID)&ext=\(ext)"
  let video = Video(url: URL(string: assetURLStr)!)
  let content = VideoShareContent(video: video)
  let dialog = ShareDialog(content: content)
  dialog.failsOnInvalidData = true
  dialog.mode = .automatic
  dialog.presentingViewController = self
  do {
    try dialog.show()
  } catch {
    print(error)
  }
}
Bill
  • 56
  • 5