【问题标题】:Unsubscribe from all topics at once from Firebase Messaging一次从 Firebase 消息中取消订阅所有主题
【发布时间】:2016-11-07 19:17:15
【问题描述】:

有什么方法可以一次性取消订阅所有主题?

我正在使用 Firebase Messaging 接收来自某些已订阅主题的推送通知,并且不知何故我需要取消订阅所有主题而无需一一取消订阅。这可能吗?

【问题讨论】:

  • AFAIK 没有“全部删除”的 API 调用
  • 目前无法实现。
  • 如果您检索所有主题的列表并循环遍历它,您会认为它是“一个接一个”吗?
  • 取消订阅 FirebaseMessaging.unsubscribeFromTopic("new_updates"); 后我仍然收到通知但它不起作用,仍然收到通知。取消订阅单个用户的任何其他方式。我做错了什么?
  • @MehulGajjar 你检查你的代码,如果它没有在另一个时刻订阅?如果不是,你可以试试FirebaseInstanceId.getInstance().deleteInstanceId()

标签: android firebase firebase-cloud-messaging


【解决方案1】:

您可以使用Instance API 查询订阅给定令牌的所有可用主题,然后调用多个请求以取消订阅所有主题。

但是,如果您想停止从所有主题接收,然后令牌根本没有用,您可以调用 FirebaseInstanceId.getInstance().deleteInstanceId()(参考:deleteInstanceId() 并用 try/catch 包围潜在的 IOException)将重置实例 ID,然后您可以再次从新实例 ID 和令牌订阅新主题。

希望这对某人有所帮助。

【讨论】:

  • 在我的情况下它不起作用,因为我没有存储任何instance。用户只能从订阅的主题中获取信息
  • @Lennon 重置实例 ID 将删除所有订阅状态。并给你一个空的新实例
  • 你怎么知道删除实例所有订阅的主题都会被撤销?
  • 检查我答案中的链接。 deleteInstanceId() 调用重置实例 ID 并撤销所有令牌。在此调用之后,您可以使用对https://iid.googleapis.com/iid/info/IID_TOKEN 的获取请求查询您以前的令牌,如此处所述:developers.google.com/instance-id/reference/… 您将看到您的令牌不再存在。因此它将无法接收任何事件消息。
  • 我看到了,它确实说所有令牌都被撤销了,但是我怎么知道如果我撤销了令牌,所有主题都将不再被订阅?
【解决方案2】:

对于 Java 用户:

如果您想按主题进行操作,请参考其他答案,如果您想停止接收 FCM 推送通知,请执行以下操作:

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            FirebaseInstanceId.getInstance().deleteInstanceId();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

我已将 deleteInstanceId() 放在单独的线程中以停止 java.io.IOException: MAIN_THREAD W/System.err 并用 try / catch 包裹以处理 IOException

【讨论】:

    【解决方案3】:

    在首选项中保留订阅主题的私人列表。

    这并不难。这是我的工作:

    public class PushMessagingSubscription {
    
      private static SharedPreferences topics;
    
      public static void init(ApplicationSingleton applicationSingleton) {
        topics = applicationSingleton.getSharedPreferences("pushMessagingSubscription", 0);
      }
    
      public static void subscribeTopic(String topic) {
        if (topics.contains(topic)) return; // Don't re-subscribe
        topics.edit().putBoolean(topic, true).apply();
    
        // Go on and subscribe ...
      }
    
    
      public static void unsubscribeAllTopics() {
        for (String topic : topics.getAll().keySet()) {
          FirebaseMessaging.getInstance().unsubscribeFromTopic(topic);
        }
        topics.edit().clear().apply();
        // FirebaseInstanceId.getInstance().deleteInstanceId();
      }
    }
    

    【讨论】:

      【解决方案4】:

      如果您想避免删除 InstanceId 以及避免在保存在本地数据库或远程数据库时由于极有可能的错误实现而丢失某些订阅的主题。

      首先获取所有订阅的主题:

          var options = BaseOptions(headers: {'Authorization':'key = YOUR_KEY'});
          var dio = Dio(options);
          var response = await dio.get('https://iid.googleapis.com/iid/info/' + token,
                                   queryParameters: {'details': true});
          Map<String, dynamic> subscribedTopics = response.data['rel']['topics'];
      

      在此处获取您的密钥: Firebase 控制台 -> 您的项目 -> 项目设置 -> 云消息传递 -> 服务器密钥

      获取您的令牌:

      var firebaseMessaging = FirebaseMessaging();
      String token;
      firebaseMessaging.getToken().then((value) {
        token = value;
      });
      

      现在退订所有主题:

        Future<void> unsubscribeFromAllTopics() async {
          for (var entry in subscribedTopics.entries) {
            await Future.delayed(Duration(milliseconds: 100)); // throttle due to 3000 QPS limit
            unawaited(firebaseMessaging.unsubscribeFromTopic(entry.key)); // import pedantic for unawaited
            debugPrint('Unsubscribed from: ' + entry.key);
          }
        }
      

      所有代码都在 Dart 中。

      有关实例 ID 的更多信息: https://developers.google.com/instance-id/reference/server

      【讨论】:

        【解决方案5】:

        我知道这不是最好的方法,但它有效! 您可以将所有主题的列表存储在数据库中,然后在用户退出时取消订阅所有主题

        final FirebaseMessaging messaging= FirebaseMessaging.getInstance();
              FirebaseDatabase.getInstance().getReference().child("topics").addChildEventListener(new ChildEventListener() {
                  @Override
                  public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                      String topic  = dataSnapshot.getValue(String.class);
                      messaging.unsubscribeFromTopic(topic);
        }...//rest code
        

        【讨论】:

          【解决方案6】:

          我们可以在服务器端使用unsubcribeAllTopics,如下所示。

          例子,

          interface GetTopics {
            rel: {topics: {[key: string]: any}}
          }
          
          /**
           * Unsubcribe all topics except one topic
           * 
           * Example response of `https://iid.googleapis.com/iid/info/${fcmToken}?details=true`
           * {
              "applicationVersion": "...",
              "application": "...",
              "scope": "*",
              "authorizedEntity": "...",
              "rel": {
                  "topics": {
                      "TOPIC_KEY_STRING": { // topic key
                          "addDate": "2020-12-23"
                      }
                  }
              },
              "appSigner": "...",
              "platform": "ANDROID"
          }
           */
          export const unsubcribeAllTopics = async (
            fcmTokens: string | string[],
            exceptTopic?: string,
          ) => {
            const headers = {
              'Content-Type': 'application/json',
              Authorization: `key=${process.env.FCM_SERVER_KEY}`,
            }
          
            const url = `https://iid.googleapis.com/iid/info/${fcmTokens}?details=true`
          
            try {
              const response = await fetch(url, {method: 'GET', headers: headers})
              const result: GetTopics = await response.json()
              const keys = Object.keys(result.rel.topics)
          
              keys.forEach(key => {
                key !== exceptTopic &&
                  messaging()
                    .unsubscribeFromTopic(fcmTokens, key)
                    .catch(error => {
                      console.error('error', {data: error})
                    })
              })
            } catch (error) {
              console.error('error', {data: error})
            }
          }
          

          https://gist.github.com/JeffGuKang/62c280356b5632ccbb6cf146e2bc4b9d

          【讨论】:

            【解决方案7】:

            如果你正在使用flutter,如果你想退订所有主题,请使用-

              final FirebaseMessaging _fcm = FirebaseMessaging();
              _fcm.deleteInstanceID().then((value){
                            print('deleted all'+value.toString());
                          });
            

            【讨论】:

              【解决方案8】:
              Firebase.messaging.deleteToken()
              

              是 2021 年的实际答案。

              【讨论】:

              • 需要POST。我认为 GET 行不通
              【解决方案9】:
              try {
                  FirebaseInstallations.getInstance().delete()
              } catch (e: IOException) {
              
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2019-06-02
                • 1970-01-01
                • 2017-04-14
                • 1970-01-01
                相关资源
                最近更新 更多