Swift 3 首次发送后无法使用 Firebase 数据库的照片共享扩展

Swift 3 Photo Share Extension with Firebase Database Not Working After First Send

我正在 Swift 3 中开发一个 iOS 照片共享扩展程序,它可以在 iOS 照片应用程序中捕获 user-selected 照片以及 user-entered caption 并将其存储在 Firebase 中。照片存储在 Firebase 存储中。 Firebase 存储中照片的标题和路径存储在 Firebase 实时数据库中。

我遇到的问题是共享扩展在第一次发送后停止工作。奇怪的是,如果我在 iOS 应用程序的常规视图控制器中执行类似的方法,代码就可以工作。我注意到共享扩展有两个问题:

问题 #1:共享扩展视图没有完全关闭。在正常情况下,视图会 return 到照片的 "gallery" 模式。但是,共享扩展视图将消失,但包含可用于共享的完整应用程序列表的共享菜单不会关闭。

Screenshot of what the Photos view looks like after the second send

问题 #2:数据没有被发送到 Firebase 存储或 Firebase 数据库。

下面请找到我的 ShareViewController 代码:

import UIKit
import Social
import Firebase
import MobileCoreServices

class ShareViewController: SLComposeServiceViewController {

    var ref: DatabaseReference!
    var storageRef: StorageReference!

    override func isContentValid() -> Bool {
        // Do validation of contentText and/or NSExtensionContext attachments here
        return true
    }

    override func didSelectPost() {
        // This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.

        FirebaseApp.configure()

        ref = Database.database().reference()
        storageRef = Storage.storage().reference()

        // Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.

        if let item = self.extensionContext?.inputItems[0] as? NSExtensionItem {
            for ele in item.attachments!{
                let itemProvider = ele as! NSItemProvider

                if itemProvider.hasItemConformingToTypeIdentifier("public.jpeg"){
                    itemProvider.loadItem(forTypeIdentifier: "public.jpeg", options: nil, completionHandler: { (item, error) in

                        do {
                            var imgData: Data!
                            if let url = item as? URL{
                                imgData = try Data(contentsOf: url)
                            }

                            if let img = item as? UIImage{
                                imgData = UIImagePNGRepresentation(img)
                            }

                            var updateRef = self.ref.child("demo_group").child("demo_patient").child("demo_updates").childByAutoId()
                            var updateStorageRef = self.storageRef.child("demo_photos" + "/\(Double(Date.timeIntervalSinceReferenceDate * 1000)).jpg")

                            updateRef.child("event_name").setValue(self.contentText)
                            updateRef.child("sender").setValue("demo_ff")

                            let metadata = StorageMetadata()
                            metadata.contentType = "image/jpeg"

                            updateStorageRef.putData(imgData, metadata: metadata) { (metadata, error) in
                                if let error = error {
                                    print("Error uploading: \(error)")
                                    return
                                }
                                // use sendMessage to add imageURL to database
                                updateRef.child("photos").childByAutoId().setValue(metadata?.path)
                            }

                        } catch let err{
                            print(err)
                        }
                    })
                }
            }
        }

        self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
    }

    override func configurationItems() -> [Any]! {
        // To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
        return []
    }

}

如果我能做些什么来解决这个问题,请告诉我!我将不胜感激。

FirebaseApp.configure() 如果连续调用多次,您的扩展程序将崩溃,因为系统没有完全释放为扩展程序创建的 firebase 应用程序实例。

我的解决方案是:

if let _ = FirebaseApp.app() {...} else {
     FirebaseApp.configure()
}

这应该可以解决您的问题。

编辑:另请注意,您应该在存储和数据库更新完成后调用 extensionContext.complete...而不是在

之前

因此,您将需要使用带有完成块的 setValue 方法。 1- 任务完成后上传到存储 2-更新数据库参考, 3-当调用完成块时...然后调用 extensionContext.completeWith() 或 .cancel()