[iOS]Firebase Dynamic Linksを使ってシェア機能を実装する
弊アプリPostLikeでシェア機能を実装したので、その時得た知見を簡単なアプリを通して紹介したいと思います。
アプリの全体像はこちら↓
全体のソースコードをgithubに載せました↓
事前準備
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に渡してあげます。
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にある場合プレビューに反映されなかったりと問題があるので、これを解消するために以下のコードを追加します。
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を追加
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に保存した値
//アプリに戻ってきた時に受け取る値を保存
let queryItem = URLQueryItem(name: "share", value: "Hello")
をSecondViewControllerに渡して遷移する、という処理を書いています。
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)に呼び出す。
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に表示
import UIKit
class SecondViewController: UIViewController {
@IBOutlet weak var label: UILabel!
var passedText = String()
override func viewDidLoad() {
super.viewDidLoad()
label.text = passedText
}
}
これでリンクをタップしたらSecondViewControllerに遷移して"Hello"が表示されるようになりました!
参考
- Firebase公式ドキュメント https://firebase.google.cn/docs/dynamic-links/ios/create?hl=ja
- Getting Started with Dynamic Links on iOS - Pt.1 https://youtu.be/KLBjAg6HvG0
- Getting Started with Dynamic Links on iOS - Pt.2 https://youtu.be/iSC5ed6OowA
- Getting Started with Dynamic Links on iOS - Pt.3 https://youtu.be/LqCi-TaUfJs
- [iOS] シェアシート上のプレビューをあるべき姿に https://qiita.com/ezura/items/6036c6e100599b601482
Discussion