繁体   English   中英

重置推送通知/设备注册/实例 ID - 通过 TestFlight 或 App Store 进行应用更新 - Firebase Cloud Messaging iOS/React Native Firebase

[英]Reset Push Notifications/Device Registration/Instance Id - App Update via TestFlight or App Store - Firebase Cloud Messaging iOS/React Native Firebase

对这个问题做了很多研究,首先是我的设置:

尽管我似乎无法找到解决问题的明确方法,但我的问题非常简单明了。

我部署了我的应用程序的 4.2 版。 iOS 中的 Firebase 云消息传递 (FCM) 工作得很好。 然后我将 4.3 部署到 TestFlight 开始测试。 通过 TestFlight 安装 4.3 并且 FCM 停止工作,没有推送通知。 如果我删除应用程序并通过 TestFlight 推送通知再次安装 4.3,则设备已注册。

我也可以重现这个问题,从最新发布的 App Store 更新我的应用程序的安装版本,这并不奇怪。

我知道 InstanceId/device 令牌基于应用程序构建+设备,因此当应用程序更新时令牌更改是有道理的,但当我从 4.2 更新到 4.3 时,我的令牌是相同的:

const fcmToken = await firebase.messaging().getToken(); //same whether 4.2 or 4.3

是的 firebase.messaging().getToken() 在初始创建时缓存。

所以我连接到监听令牌更改事件:

firebase.messaging().onTokenRefresh(async () => {
  console.log('======onTokenRefresh=========');
  AsyncStorage.removeItem(FCM_TOKEN_KEY);
  await getToken();
});

那似乎永远不会着火。 我什至在我的应用程序中添加了一个按钮,以尝试强制使用新的 InstanceId 并在从 TestFlight 或 AppStore 更新版本后向 FCM 注册,这无济于事:

export async function forceRefresh() {
  console.log('================force a new registration!!!==========');
  AsyncStorage.removeItem(FCM_TOKEN_KEY);
  firebase.messaging().deleteToken();
  firebase.iid().deleteToken();
  registerForPushNotificationsAsync(true);
} 

不,不起作用。

所以这个故事的寓意是,当我更新我的应用程序版本时,我的客户,他们的推送通知正在工作,当他们将他们的应用程序更新到下一个版本时,他们将不再注册推送通知。

可能是我一直在研究的线索的参考文献:

有趣的应用程序更新开始,推送通知将停止工作,因为应用程序更新我看到两个不同的令牌,也许第一个是来自 AppleAPN 令牌

2020-01-17 18:48:09.371741-0800 native[4462:1287461] -[RNFirebaseMessaging messaging:didReceiveRegistrationToken:] [Line 86] Received new FCM token: eBBgznWj1FU:APA91bF8vTmpkwcojp4oDSKFzlPDp6ylEIe_WGNzu24SKHS6RR-3xPu2-cX-Qyc8rrMIQMvkCJftT9711ll1WdshBWS4iEpZ3XpiPeTynqM-nvDjpAUUUWJpfT5aeo6G_scDsN9iipwI
2020-01-17 18:48:09.378382-0800 native[4462:1287621] 6.15.0 - [Firebase/InstanceID][I-IID014012] Invalidating cached token for 255558254149 (*) due to token is no longer fresh.

然后稍后我从应用程序的先前版本加载推送通知工作的先前令牌我并在日志中看到工作“默认令牌”:

2020-01-17 18:48:09.987571-0800 native[4462:1287610] 6.15.0 - [Firebase/InstanceID][I-IID014001] Token fetch successful, token: dUY5psWDnkv2td1kB_t6Gs:APA91bEaREBt07CWiEyGvP4YAGjxmVQmF0IcXgef5XcvL5KWrHsqcxZZ8L9PqwGzKTPFGy6cdmuVXSvg6kDQjj-652jt5_jbbKMhUFTcam_-FeBp2vGZvBjaBd4aAOtQf1m48htQ8d6B, authorizedEntity: 255558254149, scope:*
2020-01-17 18:48:09.987764-0800 native[4462:1287461] -[RNFirebaseMessaging messaging:didReceiveRegistrationToken:] [Line 86] Received new FCM token: dUY5psWDnkv2td1kB_t6Gs:APA91bEaREBt07CWiEyGvP4YAGjxmVQmF0IcXgef5XcvL5KWrHsqcxZZ8L9PqwGzKTPFGy6cdmuVXSvg6kDQjj-652jt5_jbbKMhUFTcam_-FeBp2vGZvBjaBd4aAOtQf1m48htQ8d6B
2020-01-17 18:48:09.993088-0800 native[4462:1287610] 6.15.0 - [Firebase/InstanceID][I-IID003010] Successfully fetched default token.
2020-01-17 18:48:09.993755-0800 native[4462:1287610] 6.15.0 - [Firebase/InstanceID][I-IID003008] Got default token dUY5psWDnkv2td1kB_t6Gs:APA91bEaREBt07CWiEyGvP4YAGjxmVQmF0IcXgef5XcvL5KWrHsqcxZZ8L9PqwGzKTPFGy6cdmuVXSvg6kDQjj-652jt5_jbbKMhUFTcam_-FeBp2vGZvBjaBd4aAOtQf1m48htQ8d6B

有趣的是,在删除当前版本的应用程序并安装最新版本(在之前的日志中是更新版本)后,我们可以看到相反的过程,首先找到我当前的令牌并认为它不再新鲜:

messaging:didReceiveRegistrationToken:] [Line 86] Received new FCM token: dUY5psWDnkv2td1kB_t6Gs:APA91bEaREBt07CWiEyGvP4YAGjxmVQmF0IcXgef5XcvL5KWrHsqcxZZ8L9PqwGzKTPFGy6cdmuVXSvg6kDQjj-652jt5_jbbKMhUFTcam_-FeBp2vGZvBjaBd4aAOtQf1m48htQ8d6B
2020-01-17 19:03:06.651179-0800 native[4475:1291698] 6.15.0 - [Firebase/InstanceID][I-IID014012] Invalidating cached token for 255558254149 (*) due to token is no longer fresh.

随后,新令牌被加载并被视为默认令牌,我的新安装会立即收到 FCM 通知:

2020-01-17 19:03:07.997209-0800 native[4475:1291564] -[RNFirebaseMessaging messaging:didReceiveRegistrationToken:] [Line 86] Received new FCM token: ebz2ACPpBkg0kGsgs9yF7_:APA91bGErCaPMuLyRk-_BLZXUk8_U6FyxvKHbI0NPgddFWl_-nLZuCc6HbHg8kaLMDJiO7sHFS8THAuV132xgri8uQ9YV4g8zDXJySrKsSTNiDq9HcXpzUQXQlPy8bTaxZ3gyRxyCy3p
2020-01-17 19:03:08.018870-0800 native[4475:1291684] 6.15.0 - [Firebase/InstanceID][I-IID014001] Token fetch successful, token: ebz2ACPpBkg0kGsgs9yF7_:APA91bGErCaPMuLyRk-_BLZXUk8_U6FyxvKHbI0NPgddFWl_-nLZuCc6HbHg8kaLMDJiO7sHFS8THAuV132xgri8uQ9YV4g8zDXJySrKsSTNiDq9HcXpzUQXQlPy8bTaxZ3gyRxyCy3p, authorizedEntity: 255558254149, scope:*
2020-01-17 19:03:08.019018-0800 native[4475:1291684] 6.15.0 - [Firebase/InstanceID][I-IID003010] Successfully fetched default token.
2020-01-17 19:03:08.019065-0800 native[4475:1291684] 6.15.0 - [Firebase/InstanceID][I-IID003008] Got default token ebz2ACPpBkg0kGsgs9yF7_:APA91bGErCaPMuLyRk-_BLZXUk8_U6FyxvKHbI0NPgddFWl_-nLZuCc6HbHg8kaLMDJiO7sHFS8THAuV132xgri8uQ9YV4g8zDXJySrKsSTNiDq9HcXpzUQXQlPy8bTaxZ3gyRxyCy3p

刚刚在日志中发现了这个兴趣声明:

在检索发件人 ID '255558254149' 的 FCM 令牌之前未设置 APNS 设备令牌。 对此 FCM 令牌的通知将不会通过 APNS 传递。一旦设置了 APNS 设备令牌,请务必重新检索 FCM 令牌。

很难相信这种情况会如此持续地发生,但似乎确实如此,任何帮助将不胜感激。

好吧,它最终成为一个竞争条件,我在这里找到了一个很好的提示

似乎 react-native-firebase Firebase.messaging().getToken() 不会总是返回最新的令牌 - 使用 onTokenRefresh 代替。 我的应用程序正在保存和使用旧令牌,而不是更新新令牌 - 非常小的竞争条件。

只需使用 Firebase.messaging.onTokenRefresh() 作为事实来源,以避免迁移应用程序出现问题。 还要确保你得到一个有效的令牌。 您可能希望使用 v4 -> await Firebase.iid().deleteToken() 或 v5 (Firebase.messaging().deleteToken() 在诸如此类的迁移中删除您的令牌。然后依靠TokenRefresh 向您发送一个新令牌发送到您的服务器。

现在,当 TestFlight 或 Apple App Store 有应用更新时,上面引用中提到的firebase.messaging().deleteToken()还不足以导致令牌刷新。

我不得不调用异步(当涉及到这个问题时,一切都是异步的,这是经验法则):

firebase.iid().delete();

这个React Native Firebase api 方法删除了 InstanceId,它实际上是 Firebase Cloud Messaging (FCM) 用于令牌的。

这将触发 onTokenRefresh。 所以我所做的是检查应用程序的版本和内部版本号并将其存储在应用程序用户数据中(iOS 的 NSDefaults),我检查此版本和内部版本是否存在,如果不存在,则“刷新”设备令牌。 这样这只会发生一次。

我将添加我的代码,希望它可以帮助其他人解决这个问题,基本上,根据我的研究,使用 React Native Firebase 5.x,这是您在 iOS 应用程序中使用 Firebase Cloud Messaging 保持无缝推送通知注册所必须做的更新:

在您的 App.js 中添加以下内容:

   configureFirebaseCloudMessaging = async () => {
    //wire up Firebase Cloud Messaging onTokenRefresh listener

    this.fcmOnTokenRefreshUnsubscribe = await firebase.messaging().onTokenRefresh(async fcmToken => {
      console.log('*********************** onTokenRefresh *****************');
      //this is callBack called typically sometime in the future but can be call with app loaded but user not logged in
      //check for that case and exit if there is no accessToken to call APIs
      const accessToken = await AsyncStorage.getItem('access-token');
      if (!accessToken) {
        console.log('************** user is not logged in exit onTokenRefresh do not register device ************');
        return;
      }
      await this.registerDevice(fcmToken, BASE_URL);
      await AsyncStorage.setItem('fcmToken', fcmToken);
      firebase.crashlytics().log(`flushed new fcmToken: ${fcmToken}`);
      console.log('***************** success  account updated with latest token **************');
    });

    //Firebase Cloud Messaging time
    await this.requestPushPermission();
    await this.checkFlushv();
  }

  checkFlushv = async () => {
    let FLUSHV = `${DeviceInfo.getVersion()}-build-${DeviceInfo.getBuildNumber()}`;

    const flush = await AsyncStorage.getItem(FLUSHV);
    console.log('======= checking FLUSHV=========', flush);
    if (flush) {
      console.log('***** device token already been flushed ******');
      return;
    }

    const accessToken = await AsyncStorage.getItem('access-token');
    console.log('flushy access token:', accessToken);
    if (!accessToken) {
      console.log('******** user is not logged in do not flush ************');
      return;
    }

    //force push notifications, this will fire onTokenRefresh callback
    await firebase.iid().delete();

    //iterate all keys and remove other builds to keep tidy and TestFlighters possibly going up and back down build versions for testing
    const keys = await AsyncStorage.getAllKeys();
    const buildKeys = keys.filter(key => {
      return key.indexOf('build') !== -1;
    });
    await AsyncStorage.multiRemove(buildKeys);

    //add current build key so no more flushy
    await AsyncStorage.setItem(FLUSHV, FLUSHV);
    console.log(`=================FLUSHV clear: ${FLUSHV}===================`)
  }

  registerDevice = async (token, baseUrl) => {
    console.log(`******** registerDevice token: ${token}, baseUrl: ${baseUrl}`);
    let data = {
      device: 'firebase',
      token: token
    }

    //register token with  account
    axios.post(`${baseUrl}/myapi/register_device`, data)
      .then(response => {
        return {}
      })
      .catch(err => {
        console.log(err)
        return {}
      })
  }

然后在你的 App.js 中:

  async componentDidUpdate() {
    //a new version of the app could be loaded post/after App.componentDidMount
    await this.checkFlushv();
  }

  async componentWillUnmount() {
    console.log('app componentWillUnmount');
    this.fcmOnTokenRefreshUnsubscribe(); //not really sure unsubcribe is needed but keeping tidy
    this.fcmOnTokenRefreshUnsubscribe = null;
  }

  async componentDidMount() {
    await this.configureFirebaseCloudMessaging();
  }

我花了很多时间才找到解决方案。

所以,如果你在 iOS 中调用firebase.iid().delete()你需要在 APNs 中注册你的新令牌。 我在 react native firebase 文档中没有看到这个,只是在 lib 的类型中找到

await firebase.messaging().ios.registerForRemoteNotifications()

请在生成新令牌后调用此方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM