当未加载/被广告拦截器阻止时,firebase_analytics 使 Flutter Web 应用程序崩溃

Posted

技术标签:

【中文标题】当未加载/被广告拦截器阻止时,firebase_analytics 使 Flutter Web 应用程序崩溃【英文标题】:firebase_analytics crashes Flutter Web app when not loaded / blocked by ad blocker 【发布时间】:2021-06-09 21:07:06 【问题描述】:

当用户启用了阻止 firebase-analytics.js 的广告拦截器时,我的 Flutter Web 应用程序崩溃。我只剩下一个空白页。

这是我收到的错误:

top_level.dart.lib.js:110 Uncaught (in promise) TypeError: dart.global.firebase.analytics is not a function
    at Object.analytics$ [as analytics] (top_level.dart.lib.js:110)
    at new firebase_analytics_web.FirebaseAnalyticsWeb.new (:7357/packages/firebase_analytics_web/firebase_analytics_web.dart.lib.js:56)
    at Function.registerWith (:7357/packages/firebase_analytics_web/firebase_analytics_web.dart.lib.js:19)
    at Object.registerPlugins (:7357/packages/triage/generated_plugin_registrant.dart.lib.js:13)
    at main (:7357/web_entrypoint.dart.lib.js:29)

我正在使用以下版本的firebase_analytics plugin:

firebase_analytics: ^7.1.1

【问题讨论】:

【参考方案1】:

问题

这是因为firebase package(由firebase_analytics_web 使用)依赖于现有的firebase.analytics() 函数在JS中。见the related piece of code。 因此,当广告拦截器阻止 firebase-analytics.js 的加载时,这段代码会抛出,进而导致整个 Flutter Web 初始化崩溃。

解决方案

我们可以创建一个firebase.analytics()mock 来解决这个问题。注意在firebase_analytics_web,the firebase.analytics() function is only called once 然后存储在一个实例中。这就是为什么我们的 mock 必须确保以某种方式再次在 JS 中调用 firebase.analytics(),如果我们希望能够在稍后的时间点加载到 firebase-analytics.js 库中。

这是一个脚本,您可以在至少加载 firebase-app.js 后将其插入到您的 <body> 中。例如,如果您遵守 GDPR 并异步加载 Firebase 分析(例如在用户通过 Google 跟踪代码管理器同意之后),这将非常有用。无论如何,这是一个完全解决问题的模拟并且允许稍后加载 Firebase Analytics:

<!--
  We need to create a mock for Firebase Analytics that ensures that it *does not matter **when***
  the JS library is loaded. This is because Google Tag Manager will load firebase-analytics.js
  and this 1. happens asynchronously and 2. only after the user consented.
  The firebase.dart Dart library will crash if the firebase.analytics object does not exist,
  which is why this is absolutely crucial for starting the app.
  https://***.com/a/66589887/6509751
-->
<script>
  // This mock ensures that if the firebase_analytics Flutter plugin uses this mock as its
  // instance (which does not change over time), the plugin will *still* be able to reach out
  // to the actual firebase.analytics() instance because the object will be overridden once the
  // firebase-analytics.js library is loaded in.
  firebase.analytics = function () 
    return 
      mock: true,
      app: function () 
        var instance = firebase.analytics()
        // Prevent infinite recursion if the real instance has not yet been loaded.
        if (instance.mock === true) return
        return instance.app
      ,
      logEvent: function () 
        var instance = firebase.analytics()
        if (instance.mock === true) return
        return instance.logEvent(...arguments)
      ,
      setAnalyticsCollectionEnabled: function () 
        var instance = firebase.analytics()
        if (instance.mock === true) return
        return instance.setAnalyticsCollectionEnabled(...arguments)
      ,
      setCurrentScreen: function () 
        var instance = firebase.analytics()
        if (instance.mock === true) return
        return instance.setCurrentScreen(...arguments)
      ,
      setUserId: function () 
        var instance = firebase.analytics()
        if (instance.mock === true) return
        return instance.setUserId(...arguments)
      ,
      setUserProperties: function () 
        var instance = firebase.analytics()
        if (instance.mock === true) return
        return instance.setUserProperties(...arguments)
      ,
    
  
</script>

【讨论】:

以上是关于当未加载/被广告拦截器阻止时,firebase_analytics 使 Flutter Web 应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

苹果手机怎么阻止弹出网页?

怎样在谷歌浏览器上安装拦截广告的插件呢?

广告拦截:AdGuard Premium v7.11 .3正式破解版(Windows/Android/Mac)

如何在浏览器中阻止 webview 中的任何广告,例如 adblock 或 adblock plus?

window.open打开网址被拦截

如何去掉浏览器的广告?