【问题标题】:Is there anyway to access the Firebase Topics a user is subscribed to?无论如何可以访问用户订阅的 Firebase 主题吗?
【发布时间】:2016-12-21 06:48:00
【问题描述】:

我目前正在尝试将我的应用迁移到 Firebase,并且我正在寻找与 Parse Installations and Channels 等效的 Firebase。

我发现我们应该使用主题,但是在我的应用中 “订阅”和“取消订阅”主题很常见,但没有办法(我发现)查看哪些主题用户订阅了。有什么想法吗?

我查看了 Firebase 文档,但我是 Firebase 的新手,所以也许有更多经验的人会知道:https://firebase.google.com/docs/cloud-messaging/android/topic-messaging#managing_topic_subscriptions_from_the_server

提前感谢您的帮助!

【问题讨论】:

  • 该代码是您尝试解决问题的方法吗?如果不是,则与手头的问题无关。
  • 不,这只是一个例子。我会删除它。

标签: swift firebase notifications firebase-cloud-messaging


【解决方案1】:

FCM 主题订阅基于应用程序的实例 ID,因此当您订阅或取消订阅某个主题或从某个主题取消订阅时,将使用 IID。

您可以使用 Instance ID API 获取有关特定 IID 的信息,此信息包括 IID 当前订阅的主题。见reference

【讨论】:

  • 因此,如果我希望本地记录用户订阅了哪些主题,我必须手动完成所有操作?
  • 是的,您必须自己在客户端维护这些记录。
  • 我明白了,这很不幸。无论如何,感谢您的帮助!我会把你标记为答案。
  • 我知道知道客户端在客户端订阅了哪些主题会很方便,但鉴于客户端可以在服务器端订阅或取消订阅,客户端可能并不总是知道关于客户订阅状态的真相。因此,根据客户对订阅的了解采取行动可能会导致意外行为。所以(目前)安全的事情是自己管理订阅状态。感谢您的反馈,我们将在以后的版本中记住它。
  • 考虑使用 Firebase 实时数据库作为客户端订阅保持客户端和服务器同步的一种方式。
【解决方案2】:

您必须向 Instance ID API 发出请求。我创建了一个扩展

https://gist.github.com/eduardo22i/0ee8960c36659b17fbc538964e929cac

扩展消息{

static private let accessToken = "" //Server Web Key

struct Topic : Decodable {
    var name : String?
    var addDate : String?
}

struct Rel : Decodable {
    var topics = [Topic]()

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let relContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .rel)
        let topicsContainer = try relContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .topics )

        for key in topicsContainer.allKeys {
            var topic = Topic()
            topic.name = key.stringValue

            let topicContainer = try? topicsContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: key)
            topic.addDate = try! topicContainer?.decode(String.self, forKey: .addDate)

            self.topics.append(topic)
        }
    }

    struct CodingKeys : CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int? { return nil }
        init?(intValue: Int) { return nil }

        static let rel = CodingKeys(stringValue: "rel")!
        static let topics = CodingKeys(stringValue: "topics")!
        static let addDate = CodingKeys(stringValue: "addDate")!
    }
}

func loadTopics(block : @escaping (_ topics: [Messaging.Topic]?, _ error: Error?) -> Void ) {
    if let token = InstanceID.instanceID().token() {
        let url = URL(string: "https://iid.googleapis.com/iid/info/\(token)?details=true")!
        var request = URLRequest(url: url)
        request.addValue("key=\(Messaging.accessToken)", forHTTPHeaderField: "Authorization")
        let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
        DataManager.shared.make(request: urlRequest, block: { (data, error) in
            if let data = data {
                let decoder = JSONDecoder()
                let rel = try? decoder.decode(Rel.self, from: data)
                block(rel?.topics, error)
            } else {
                block(nil, error)
            }
        }

        dataTask.resume()
    }
}
}

// Usage

Messaging.messaging().loadTopics { (topics, error) in
    topics?.forEach({ (topic) in
        print(topic.name)
    })
}

【讨论】:

  • 好人!我得到了它的工作,只有 2 个小注释:1)应该删除这一行:“DataManager.shared.make(request:urlRequest,block:{(data,error)in”2)对于使用代码的其他人,请确保在他的代码上填写“accesstoken”。这是您项目的 API 密钥,可在以下位置找到:(gear-next-to-project-name) > 项目设置 > 云消息传递 -> 服务器密钥是 API 密钥。
  • 不幸的是,代码不再工作了......有人可以分享更新吗? @瓦斯科
【解决方案3】:

这是来自@Eduardo's 的更新,由@Nico 请求

两件事:

  • 您需要导入 Firebase,因为您需要 InstanceID 和消息传递模块。
  • 确保填写 API 密钥 (accessToken),which can be found under: (gear-next-to-project-name) > Project Settings > Cloud Messaging -> Server Key 是 API 密钥。

这是更新后的代码:

import Firebase


// Grab susbcribed channels
// Source 1: https://stackoverflow.com/questions/38948720/is-there-anyway-to-access-the-firebase-topics-a-user-is-subscribed-to
// Source 2: https://developers.google.com/instance-id/reference/server#get_information_about_app_instances
extension Messaging {

// Needs to be grabbed from: https://stackoverflow.com/questions/37337512/where-can-i-find-the-api-key-for-firebase-cloud-messaging
static private let accessToken = ""

struct Topic : Decodable {
    var name : String?
    var addDate : String?
}

struct Rel : Decodable {
    var topics = [Topic]()

    init(from decoder: Decoder) throws {

        let container = try decoder.container(keyedBy: CodingKeys.self)
        let relContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .rel)
        let topicsContainer = try relContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .topics )

        for key in topicsContainer.allKeys {
            var topic = Topic()
            topic.name = key.stringValue

            let topicContainer = try? topicsContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: key)
            topic.addDate = try! topicContainer?.decode(String.self, forKey: .addDate)

            self.topics.append(topic)
        }
    }

    struct CodingKeys : CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int? { return nil }
        init?(intValue: Int) { return nil }

        static let rel = CodingKeys(stringValue: "rel")!
        static let topics = CodingKeys(stringValue: "topics")!
        static let addDate = CodingKeys(stringValue: "addDate")!
    }
}

func loadTopics(block : @escaping (_ topics: [Messaging.Topic]?, _ error: Error?) -> Void ) {
    InstanceID.instanceID().instanceID { (result, error) in
        if let err = error {
            block(nil, err)
        } else if let result = result {
            let url = URL(string: "https://iid.googleapis.com/iid/info/\(result.token)?details=true")!
            var request = URLRequest(url: url)
            request.addValue("key=\(Messaging.accessToken)", forHTTPHeaderField: "Authorization")
            let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
                if let data = data {
                    let decoder = JSONDecoder()
                    let rel = try? decoder.decode(Rel.self, from: data)
                    block(rel?.topics, error)
                } else {
                    block(nil, error)
                }
            }
            dataTask.resume()
        }
    }
}
}

用法是这样的:

Messaging.messaging().loadTopics { (topics, error) in
   topics?.forEach({ (topic) in
       print("Subscribed to topic: \(topic.name ?? "No name")")
   })
}

【讨论】:

  • 服务器密钥旨在供后端服务器使用,而不是存储在应用程序包中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多