在Vue PWA中未触发页面可见性事件

时间:2020-01-02 16:54:41

标签: javascript vuejs2 firebase-authentication progressive-web-apps

我正在使用Firebase身份验证构建Vue PWA。该网络应用将在首次加载的App上监听Firebase的onAuthStateChanged事件,以通过调用Firebase的ID token自动登录用户并保存其getIdToken(/* forceRefresh */ true)的API请求。

除此之外,我还利用Page Visibility API在隐藏5分钟后重新加载了Web App(如果旧的Firebase ID token已过期,则重新获得该应用)。

在Android手机上,我在Chrome上访问我的Web应用程序URL,然后将图标添加到主屏幕,并通过该图标访问Web应用程序进行所有测试。

这是测试用例:登录并正常使用Web应用程序后,单击“主页”按钮隐藏该Web应用程序,然后约10分钟后,我从后台状态调用该应用程序,该Web应用程序已自动重新加载成功后,我可以继续正常使用它。问题是,如果我在很长一段时间(〜6小时)后从后台调用该应用程序,则该网络应用程序不会自动重新加载,因此我没有新的Firebase ID Token用户,因此我得到了提出API请求以获取用户个人资料时发生Token Expired错误...

我需要找到一种可靠的方式来触发autoLogin()功能,因此用户不需要每次使用WebApp回来时都重新登录。

以下是基本代码库:

main.js
const unsubscribe = fibAuth.onAuthStateChanged((user) => {
  new Vue({
    el: '#app',
    router,
    store,
    template: '<App/>',
    components: { App },
    created () {

      // Firebase auto login
      if (user) {
        store.dispatch('autoLogin', user)
      }

      // Reload after a duration
      document.addEventListener('visibilitychange', function () {
        store.dispatch('appVisibilityHandler', document.visibilityState)
      })

    } // end created()
  }) // end Vue()
  unsubscribe()
})
Vue商店-index.js
async autoLogin ({commit, state, dispatch}, userPayload) {
  commit('SET_APP_LOADING', true)
  try {
    let idToken = await userPayload.getIdToken(/* forceRefresh */ true)
    console.warn('store::autoLogin() - idToken:', idToken)

    let apiResponse = await UsersRepos.getMyProfile(idToken)
    // ... processing apiResponse ...
  } catch (error) {
    console.error('store::autoLogin() - error:', error)
  }
  commit('SET_APP_LOADING', false)
},

appVisibilityHandler (context, statePayload) {
  try {
    const APP_REFRESH_SECONDS_THRESHOLD = 300 // 5 minutes
    if (statePayload === 'hidden') {
      localStorage.setItem('app-hidden-ts', (new Date()).getTime())
    } else if (statePayload === 'visible') {
      let lastSec = parseInt(localStorage.getItem('app-hidden-ts') / 1000)
      let nowSec = parseInt((new Date()).getTime() / 1000)
      localStorage.setItem('app-hidden-ts', nowSec * 1000)

      console.warn('total hidden seconds:', (nowSec - lastSec))
      if (nowSec - lastSec > APP_REFRESH_SECONDS_THRESHOLD) {
        context.commit('SET_APP_LOADING', true)
        // refresh the whole web page
        router.go()
      }
    }
  } catch (error) {
    alert('appVisibilityHandler error:' + error.message)
  }
}

非常感谢您提供解决此问题的指南或线索。预先谢谢您!

1 个答案:

答案 0 :(得分:0)

Firebase身份验证使用有效期为一小时的ID令牌。调用getIdToken()会返回此令牌。 SDK会在后台自动刷新ID令牌,但由于身份验证状态未更改,因此当然无法调用autoLogin

您需要附加一个onIdTokenChanged handler来检测ID令牌何时已更改并提取。

firebase.auth().onIdTokenChanged(function(user) {
  if (user) {
    // User is signed in or token was refreshed.
    store.dispatch('autoLogin', user)
  }
});

实际上,此可能 替换您的onAuthStateChanged处理程序,因为这在用户登录时也会触发。