0
votes

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()
1
Did you follow the steps here: 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
@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
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
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
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

1 Answers

3
votes

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)
  }
}