无论如何都可以访问用户订阅的 Firebase 主题吗?

Is there anyway to access the Firebase Topics a user is subscribed to?

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

我发现我们应该使用主题但是在我的应用程序中 "subscribing" 和 "unsubscribing" 主题很常见但是没有办法(我已找到)以查看用户订阅了哪些主题。有什么想法吗?

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

在此先感谢您的帮助!

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

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

您必须向实例 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)
    })
}

这是来自, requested by @Nico

的更新

2 件事:

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

这是更新后的代码:

import Firebase


// Grab susbcribed channels
// Source 1: 
// Source 2: https://developers.google.com/instance-id/reference/server#get_information_about_app_instances
extension Messaging {

// Needs to be grabbed from: 
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")")
   })
}