swiftuifacebook-sdk-4.0uiviewcontrollerrepresentablefbsdksharekit

SwiftUI How to share a URL to Facebook using FBSDKShareKit and ShareDialog?


I tried looking for a solution in posts such as this and this where people asked this very same question: How to share a url to Facebook using SwiftUI?

I even tried this post where somebody asked how to export a file using SwiftUI, but my problem is specifically with Facebook since I have no problem sharing urls to apps such as Whatsapp. However, I found no answers...

UIKit

By reading Facebook's Developer documentation, I found a way to share a post using UIKit.

I created a very simple sample project to make sure I understood the topic. Here is the sample project in UIKit:

import UIKit
import FBSDKShareKit

class ProfileViewController: UIViewController {
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }


    @IBAction func share(_ sender: UIButton) {
        shareLink(url: URL(string: "http://www.apple.com")!)
    }
    
    func shareLink(url: URL) {
        let content = ShareLinkContent()
        content.contentURL = url

        let dialog = ShareDialog(
            fromViewController: self,
            content: content,
            delegate: nil
        )
        dialog.show()
    }
}

Luckily, this worked right away. By making this project work, I confirmed that I wasn't forgetting to link my AppBundleID to Facebook, or forgetting to add my FacebookAppID or any other needed files inside my info.plist.

SwiftUI

I then tried to replicate the same project in SwiftUI to see if I could get it to work. I used ViewControllerRepresentable to be able to include UIActivityViewController into SwiftUI.

The reason for using UIActivityViewController is because I want the user to choose where they want to share the URL (Whatsapp, Twitter, Facebook, etc).

Here is the code:

ContentView

struct ContentView: View {
    @State var showSharingView = false
    var body: some View {
        Button("Share Link") {
            showSharingView.toggle()
        }
        
        .sheet(isPresented: $showSharingView) {
           ActivityViewController(activityItems: [URL(string: "https://www.apple.com/")!])
        }
    }
}

UIViewControllerRepresentable

struct ActivityViewController: UIViewControllerRepresentable {

    var activityItems: [URL]
    var applicationActivities: [UIActivity]? = nil
    
    func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
        
        let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
        
        controller.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
            
            if activityType == .postToFacebook {     
                shareLink(from: activityItems.first!)
            }
            
        }
        return controller
    }

    func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}

    func shareLink(from url: URL) {
        
        // controller was created so I would have a UIViewControllerType to put as a parameter for fromViewController in ShareDialog, even though I don't think it fits
        let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
        
        
        let content = ShareLinkContent()
        content.contentURL = url
        
        let dialog = ShareDialog(fromViewController: controller, content: content, delegate: nil)
        dialog.show()
    }
    
}

This code doesn't work because of what I assume is the controller variable used when initializing ShareDialog. (self doesn't work either because "XCode cannot convert value of type 'ActivityViewController' to expected argument type 'UIViewController?'")

Question

Facebook Developer's documentation tells me that I need to write the following code in order to share a link:

guard let url = URL(string: "https://developers.facebook.com") else {
    // handle and return
}

let content = ShareLinkContent()
content.contentURL = url

let dialog = ShareDialog(
    viewController: self, //<--this has been changed to 'fromViewController'
    content: content,
    delegate: self
)
dialog.show()

However, SwiftUI doesn't work with ViewControllers. How can I create a ViewController to use as a parameter in fromViewController in ShareDialog in order to successfully share my URL to Facebook?


Solution

  • Use like this,

    guard let url = URL(string: "https://developers.facebook.com") else {
        // handle and return
    }
    
    let content = ShareLinkContent()
    content.contentURL = url
    
    let dialog = ShareDialog(
        viewController: UIApplication.shared.windows.first!.rootViewController,
        content: content,
        delegate: UIApplication.shared.windows.first!.rootViewController
    )
    dialog.show()