🔗

[iOS]Firebase Dynamic Linksを使ってシェア機能を実装する

2021/11/24に公開

弊アプリPostLikeでシェア機能を実装したので、その時得た知見を簡単なアプリを通して紹介したいと思います。
アプリの全体像はこちら↓

全体のソースコードをgithubに載せました↓
https://github.com/taichi830/Share_App

事前準備

Dynamic Linksを受信するには以下の準備が必要です。

1.Provisioning Profileの作成

2.Firebaseの設定
プロジェクトの設定からAppStoreIDとチーム IDを入力してください。


3.Firebase Dynamic Linksでカスタムドメインを作成

4.Xcodeの設定
TARGETSのSigning&Capabilitiesで作成したProvisioning Profileをimportしてください。

+CapabilityからAssociated Domainsを追加して作成したカスタムドメインを入力してください。

以上で準備が完了しました。

シェア機能を実装する

コードは以下の通りです。カスタムURLを作成して、共有したい情報をURLに保存して最後にUIActivityViewControllerに渡してあげます。

ViewController.swift
import UIKit
import Firebase

class ViewController: UIViewController {

    
    @IBOutlet weak var logoImageView: UIImageView!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    
    
    @IBAction func share(_ sender: Any) {
        var components = URLComponents()
        components.scheme = "https"
        //作成したドメイン
        components.host = "shareApp123.page.link"
        //任意のパス
        components.path = "/share"
        
        //アプリに戻ってきた時に受け取る値を保存
        let queryItem = URLQueryItem(name: "share", value: "Hello")
        components.queryItems = [queryItem]
        
        //リンクの作成
        guard let link = components.url else {return}
        let dynamicLinksDomainURIPrefix = "https://shareApp123.page.link"
        guard let shareLink = DynamicLinkComponents(link: link, domainURIPrefix: dynamicLinksDomainURIPrefix) else {return}
        
        if let bundleID = Bundle.main.bundleIdentifier {
            shareLink.iOSParameters = DynamicLinkIOSParameters(bundleID: bundleID)
        }
        shareLink.iOSParameters?.appStoreID = "Your AppStoreID"
        shareLink.socialMetaTagParameters = DynamicLinkSocialMetaTagParameters()
        
        shareLink.socialMetaTagParameters?.title = "Hello World"
        shareLink.socialMetaTagParameters?.descriptionText = "テストです"
        shareLink.socialMetaTagParameters?.imageURL = URL(string: "https://storage.googleapis.com/zenn-user-upload/topics/0b0064a451.jpeg")
        
        
        //ショートリンクの作成
        shareLink.shorten { url, warnings, err in
            if err != nil {
                return
            }else{
                if let warnings = warnings {
                    for warning in warnings {
                        print("\(warning)")
                    }
                }
                guard let url = url else {return}
                let activityItems: [Any] = [url,ShareActivitySource(url: url, title: "Hello World", image: self.logoImageView.image!)]
                let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: .none)
                self.present(activityViewController, animated: true, completion: nil)
            }
        }
    }
    
    
    
}

これで共有できるのですが、下の写真のようにプレビューが反映されるのが遅かったり、画像がFireStorageにある場合プレビューに反映されなかったりと問題があるので、これを解消するために以下のコードを追加します。

ViewController.swift
import LinkPresentation

class ShareActivitySource:NSObject, UIActivityItemSource{

    private let linkMetadata:LPLinkMetadata

    init(url: URL,title:String,image:UIImage) {
        linkMetadata = LPLinkMetadata()
        super.init()

        // 完全な情報が取得できるまでプレビューに表示しておく仮の情報を入れておく
        linkMetadata.title = title
        linkMetadata.url = url
        linkMetadata.iconProvider = NSItemProvider(object: image)
    }


    func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
        return ""
    }

    func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
        return nil
    }


    func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? {
        return linkMetadata
    }



}

activityItemsにShareActivitySourceを追加

ViewController.swift
let activityItems: [Any] = [url,ShareActivitySource(url: url, title: "Hello World", image: self.logoImageView.image!)]

これで問題が解消しました!

リンクタップ後の処理

シェアしたリンクをタップすると、アプリがインストールされていない場合は先ほど設定したAppStoreに、インストールされている場合はアプリが起動してSceneDelegateのfunc scene(_ scene: UIScene, continue userActivity: NSUserActivity){}が呼ばれます。

handleIncomingDynamiclink関数では、URLのパスが"share"だったら、そのURLに保存した値

ViewController.swift
//アプリに戻ってきた時に受け取る値を保存
let queryItem = URLQueryItem(name: "share", value: "Hello")

をSecondViewControllerに渡して遷移する、という処理を書いています。

SceneDelegate.swift
func handleIncomingDynamiclink(_ dynamiclink: DynamicLink,window: UIWindow){
        guard let url = dynamiclink.url else {
            return
        }
        guard (dynamiclink.matchType == .unique || dynamiclink.matchType == .default) else {
            return
        }
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),let queryItems = components.queryItems else {
            return
        }
        if components.path == "/share" {
            if let queryItem = queryItems.first(where: { $0.name == "share" }){
                guard let text = queryItem.value else { return }
                let storyboard = UIStoryboard(name: "Main", bundle: nil)
                guard let secondVC = storyboard.instantiateViewController(withIdentifier: "second") as? SecondViewController else {return}
                secondVC.passedText = text
                (self.window?.rootViewController as? UINavigationController)?.pushViewController(secondVC, animated: true)
            }
        }
    }

↑の関数をscene(_ scene: UIScene, continue userActivity: NSUserActivity)に呼び出す。

SceneDelegate.swift
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        
        guard let url = userActivity.webpageURL else { return }
        DynamicLinks.dynamicLinks().handleUniversalLink(url) { dynamicLink, err in
            if err != nil {
                return
            }else{
                guard let scene = (scene as? UIWindowScene) else { return }
                let window = UIWindow(windowScene: scene)
                self.handleIncomingDynamiclink(dynamicLink!, window: window)
            }
        }
        
    }

渡ってきた値をlabelに表示

SecondViewController.swift
import UIKit

class SecondViewController: UIViewController {
    
    @IBOutlet weak var label: UILabel!
    
    var passedText = String()

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = passedText
    }
    

}

これでリンクをタップしたらSecondViewControllerに遷移して"Hello"が表示されるようになりました!

参考

Discussion