うるおいらんど

【iOS】ShareExtension で Firestore が使えなくてハマりまくって解決した話

ShareExtensionSwift

どうも。Reoです。ShareExtension で FireStore が使えなくて、かれこれ6時間くらい溶かしました。

ようやく解決しましたので、ちょっとメモがてら書いていきます。

まずは、いつもありがとう Stack Overflow。

firebase - Can FirebaseFirestore be used in an iOS app extension? - Stack Overflow

こちらの質問の方は自己解決してるんですが、ありがとう回答残してくれて...助かりました。

 

環境

  • Xcode 11.3
  • Swift 5.1.3
  • iOS 13.3

ShareExtension は、前回書いた記事「【iOS】ShareExtension を導入してみたよ」で導入した状態です。

 

問題

ShareExtension で Firestore が使えない。

具体的には、setData の completion が呼ばれてくれないのです。


Firestore.firestore().collection("data").document(uid).setData(docData) { error in
    // ここが実行されない...
}

特にエラーになるとかではなく、実行がされません。

簡易的に、print(Firestore.firestore())をすると落ちます。BAD_ACCESS になります。


let data = try! Firestore.Encoder().encode(data)

これはちゃんとエンコードできるんですよね。なので、Firestore.firestore() がいない。

 

解決法

さて。色々試しました。本当に色々試しました。

firebase - Can FirebaseFirestore be used in an iOS app extension? - Stack Overflowがドンピシャでした。これを一番最初に見つけられてたらハマらなかったので検索下手か...。

 

まず、 Podfile の書き方が悪かったです。

# うまくいかない
target 'MainXXXXXX' do
  use_frameworks!
  pod 'R.swift'
  pod 'SwiftLint'
  pod 'Firebase/Analytics'
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'
  pod 'FirebaseFirestoreSwift', '~> 0.2'

  target 'ShareExtension' do
    inherit! :search_paths
      pod 'Firebase/Analytics'
      pod 'Firebase/Core'
      pod 'Firebase/Firestore'
      pod 'FirebaseFirestoreSwift', '~> 0.2'
  end
end

こうしていました。これを以下のように修正します。

# 修正後
target 'MainXXXXXX' do
  use_frameworks!
  pod 'R.swift'
  pod 'SwiftLint'
  pod 'Firebase/Analytics'
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'
  pod 'FirebaseFirestoreSwift', '~> 0.2'

end

target 'ShareExtension' do
  use_frameworks!
  pod 'Firebase/Analytics'
  pod 'Firebase/Core'
  pod 'Firebase/Firestore'
  pod 'FirebaseFirestoreSwift', '~> 0.2'
end

はい。これで pod install しておいて。

ここまでは自分で気づいたんですよね。今朝起きてコーヒーを淹れながら頭で考えていて、今日一番に試したんですが、これだけじゃ上手くいかず。

はい????上手くいくやん???

あっれーーーーーーーーーーーーーー

Git で戻って試してみてるんですけども、これだけで上手くいくじゃないか...

 

できました。はい。

ShareExtension の Other Linker Flags を "$(inherited)" に設定したからだと思ってましたが、違いました。Podfile の書き方問題でした。はい。

これだったら今日の朝一の時点で自己解決してたじゃんかああああ(´;ω;) なんでえええ(´;ω;)

 

大体のコード

こんな感じ。

import UIKit
import Firebase
import FirebaseFirestoreSwift
import Social

class ShareViewController: SLComposeServiceViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        FirebaseApp.configure()
    }

    override func didSelectPost() {
        getURL { url in
            let uid = UUID().uuidString
            // Data は Codable に準拠したもの
            let data: Data = Data(uid: uid, title: contentText, url: url, createDate: Date())
            let docData = try! Firestore.Encoder().encode(data)
            let collection = Firestore.firestore().collection("data")
            collection.document(uid).setData(docData) { error in
                self?.extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
            }
        }
    }

    private func getURL(completion: @escaping (URL) -> Void) {
        guard let extensionItem: NSExtensionItem = extensionContext?.inputItems.first as? NSExtensionItem, let itemProviders = extensionItem.attachments else { return }
        // URL を取得する
        let identifier = "public.url"
        let urlProvider = itemProviders.first(where: { $0.hasItemConformingToTypeIdentifier(identifier)})
        urlProvider?.loadItem(forTypeIdentifier: identifier, options: nil) { (item, error) in
            guard let url = item as? URL else { return }
            completion(url)
        }
    }
}

作ってるやつでは一応 RxSwift を使ったり、ViewModel をアプリ側の投稿画面のを流用したりしています。

 

解決しなかった方法

解決しなかった方法です。

  • GoogleServiece-Info.plist を ShareExtension の BunldeID で取得して配置する

色々試したけれど、主となってなのはこの方法でした。

ShareExtension とメインアプリでは BundleID が違います。

なので、Firebase 側で新規アプリを作成して、ShareExtension の BundleID を使ったものを作成して配置してみました。

すると以下のような Warning がログに出力されました。

[Firebase/Core][I-COR000008] The project's Bundle ID is inconsistent with either the Bundle ID in 'GoogleService-Info.plist', or the Bundle ID in the options if you are using a customized options. To ensure that everything can be configured correctly, you may need to make the Bundle IDs consistent. To continue with this plist file, you may change your app's bundle identifier to 'xxx.xxx.xxx.ShareExtension'. Or you can download a new configuration file that matches your bundle identifier from https://console.firebase.google.com/ and replace the current one.

GoogleService-Info.plist の BundleID と ShareExtension の BundleID を揃えたので、正しいことをしたつもりでしたが、揃えろって言われちゃってます。

この辺で、もしかして読み込みがおかしい?とか思っちゃって迷走しました。

 

ShareExtension を使う場合にも GoogleService-Info.plistは1つだけで良い!のです。追加で Firebase 側でアプリを作る必要はないです。

ターゲットにチェックを入れてあげるだけで良いです。

 

おわりに

今回は Podfile の書き方でコケていただけの話でした。

同じことでハマっている人がいて本当によかった。一度試していてダメだったので(なんでだろうね)、見つけられてなかったら再度この方法を試すことはなかったと思うので...

 

そして自分の頭の中で思いついた解決方法が合っていたことに驚きましたね。ハマっている時は、一度離れて寝て起きたらわかるっていうのを実証してしまった。大抵のことは一度寝れば解決するんや...

久々にもう無理なんじゃないかと思ったけれど、解決して本当に良かったです。

 

やる気があればもうすこしちゃんとした手順を書こうと思います。やる気があれば。

ではでは。

 

参考リンク

Comments

コメントはありません。

現在コメントフォームは工事中です。