开篇闲聊
又是很久没有写博客的一段时间,主要原因是腾出了一些时间复习iOS原生开发的知识 ???? ,巩固自己的技术栈,以及开发基础。同样是年底,也做了一些个人总结和以后的发展规划花费了一些时间。今天终于写了 2021 年的第一篇博客。
前言
在对Flutter的报错统计或者线上用户的行为统计上,大家一定会有自己的选择 ???? 。也会根据自己业务、核心功能、实用情况进行选择。譬如常用的Bugly、友盟或者自己公司内部的报错监控系统 ???? 等等。其实这方面的工具类个人认为没有优劣或者排名顺序,但是一个好的、适合自己的工具可以让你在排查线上问题或者做性能调优时更轻车熟路。写这篇文章的目的也是为了在这方面给各位多一个选择 ???? 。
写这篇文章的目的是个人在接入多个Firebase功能的时候可能遇到国内相关资料少,细节问题相关处理方案少等接入问题,希望写一篇通俗易懂的实用工具类文章,能给有相关需求的人提供一些帮助。各位后续有接入计划 ???? 也可以先点赞收藏,阿里嘎多 ????。
什么是 Firebase
其实可能还会有一些同学对Firebase这个平台了解比较少,也趁这个机会做一个简单的介绍 ???? 。
Firebase是一家实时后端数据库创业公司,它能帮助开发者很快的写出Web端和移动端的应用。自 2014 年 10 月Google收购Firebase以来,用户可以在更方便地使用Firebase的同时,结合 Google 的云服务。Firebase 提供了各种工具,帮助您开发优质应用并扩大用户群,赚取更多收益。我们包揽了基础性工作,让您可以专心通过业务获利,并将关注点放在用户身上。
Why Firbase?
为什么这篇文章介绍的是Firebase呢?其实之前我用的线上报错监控一直用的是Bugly,其实Bugly本身的实用性还是比较强的,对于线上的报错统计分析也是比较到位的 ???? 。那我将项目中的报错及相关统计迁移到Firebase的原因主要有以下几点(这里先说大方向,细节部分可阅读后文):
- 和Flutter同属Google靠山强大???? 。
- 有非常成熟的插件库和集成方案。
- 非常清晰的控制台信息 ➕ 良好的交互体验。
- 用户信息更全面、报错更详细 ???? 。
- 功能更加丰富和多元。
其实还有一个比较私人的原因就是前一阵子公司和网易的伙伴做技术交流会的时候听网易的小伙伴反馈用Firebase很久了而且感受非常好 ???? 。
食用正餐 ????
Firebase官网提供的配套功能非常多,可以说是应有尽有,这里我们仅选择在Flutter中最实用的几个做介绍。(弱弱吐槽,真不是舔,国内啥时候能有如此平台,简直泪 ???? )
创建项目、应用
这里我默认各位已经注册好了Firebase的账号并且进入到控制台(有手 ???? 就行)。创建完毕账号后在你的控制台是一无所有的,我们可以选择添加项目一步一步慢慢来 ???? 。
创建项目的过程中,Firebase会提示你开启相关监测功能,直接按照推荐的做法,不用进行相关选择 ???? 。
创建项目完成后可以直接进入项目对应的控制台。可以看到控制台首页最核心的中间部分有四个按钮 ???? ,分别对应:iOS、Android、Web、Unity(游戏引擎)。我们点击对应的按钮即可进入相关的集成页面 ???? 。
iOS ????
step 1 注册应用
注册应用需要填写几个信息,这里的软件包 ID,其实就是我们常说的Bundle ID在你的Xcode中的Targets -> General选项下可以找到,应用的别名和App Store ID建议如实填写,可以避免不必要的麻烦 ???? 。
step 2 下载配置文件
根据你上一步所填写的信息,Firebase会生成一份配置文件(.plist),下载这个插件,并且我们打开我们Flutter项目的 iOS 工程 ????????♂️ 。
将配置文件拖到指定的位置(对应到Flutter中通常为 Runner - Runer, 和 AppDelegate为同一层级),并且在弹框中,选择如下 ???? :
step 3 初步结束
之后的两步,添加Firebase SDK和添加初始化代码,我们直接跳过即可,因为我们将在Flutter层完成相关的操作 ???? 。
Android ????️
完成iOS端相关工作后,可以继续回到控制台,选择创建新的应用 ???? ,并且选择Android。
step 1 注册应用
和 iOS 类似,Android 端也需要你输入一些基础信息 ???? ,用于生成配置文件。主要信息是软件的包名。(对应AndroidManifest.xml文件中的package)
step 2 下载配置文件
同样,我们下载配置文件,添加到指定位置 ???? (app目录下,与build.gradle同级)。
需要注意的是这一步,可以直接在Flutter工程下操作,也可以通过Flutter工程对应的Android工程操作。推荐后一种不容易拖错位置 ⏳ 。
step 3 初步结束
可以注意到,在Android集成的过程中相对于iOS少了一步 —— 添加初始化代码, 甚至不需要添加任何运行时代码 ???? 。
Flutter ????
以上针对iOS和Android端的集成算是我们完成了第一大步 ???? 。接下来我们还要在我们的Flutter App中接入Firebase,这里就要请出我们的主角 —— FlutterFire 系列全家桶。全系标配iOS Support以及Android Support部分插件甚至已经有Web和MacOS支持,并且全系都出自Google,原汤化原食 ???? ,彻底告别插件不兼容。
firebase_core
这是我们第一个要接入的插件,这个插件的作用是什么呢 ???? ?来看官方注解
A Flutter plugin to use the Firebase Core API, which enables connecting to multiple Firebase apps.
一个 Flutter 插件用来使用 Firebase Core API,从而可以连接到多个 Firebase 应用。
首先这个插件是用于初始化我们Firebase的一个插件,而且由于某些App体量较大,可能开发者希望通过分模块的方式对应用内部进行用户分析或报错统计相关,所以这个插件也提供了这个功能 ⚙️ 。毫无疑问,我们如果想要接入Firebase,这个插件必不可少。因此我们直接在.yaml文件中导入。
dependencies: firebase_core: ^0.7.0 复制代码复制代码
在这个插件的Example中的接入代码其实有一大串。但如果你不在你的应用内进行分块处理 ???? ,你所需要的代码就只有 1 句
await Firebase.initializeApp(); 复制代码复制代码
firebase_analytics
这是一个用于收集你的应用用户信息、记录用户行为的插件库,也是很多开发者的必选项,通过监测线上用户量以及用户分布和使用习惯,可以让我们更了解客户更贴近客户???? ,由此有针对性的提高我们的应用受欢迎程度,甚至是用户量 ???? 。 一般使用:
FirebaseAnalytics analytics = FirebaseAnalytics(); /// 一般在你的main.dart中可以找到 MaterialApp( home: MyAppHome(), navigatorObservers: [ FirebaseAnalyticsObserver(analytics: analytics), ], ); 复制代码复制代码
记录用户行为 (有非常多的用户行为和模版,可以在firebase_analytics的example中自行选择,这里仅仅介绍 3 种),以下几种方法,可以在你的某按钮点击或者页面路由等等所有地方调用 ???? 。根据你的需求在合适的时候调用,就可以获取到你想要的用户信息 ???? 。
/// 可以自定义事件类型甚至传递某些有意义的参数 Future<void> _sendAnalyticsEvent() async { await analytics.logEvent( name: 'test_event', parameters: <String, dynamic>{ 'string': 'string', 'int': 42, 'long': 12345678910, 'double': 42.0, 'bool': true, }, ); setMessage('logEvent succeeded'); } /// 获取对应用户ID Future<void> _testSetUserId() async { await analytics.setUserId('some-user'); setMessage('setUserId succeeded'); } /// 可以获取当前视图 并发送 Future<void> _testSetCurrentScreen() async { await analytics.setCurrentScreen( screenName: 'Analytics Demo', screenClassOverride: 'AnalyticsDemo', ); setMessage('setCurrentScreen succeeded'); } 复制代码复制代码
firebase_crashlytics
这是我们的报错统计插件,非常实用的一个插件,可以监测到你在线上的崩溃和错误 ❌ 问题,类似于Bugly功能。具体使用:
- 首先在main函数中指定我们的错误上报工具 ???? 为FirebaseCrashlytics
main() { WidgetsFlutterBinding.ensureInitialized(); runZonedGuarded(() { runApp(MyApp()); }, (error, stackTrace) { print('runZonedGuarded: Caught error in my root zone.'); FirebaseCrashlytics.instance.recordError(error, stackTrace); }); } 复制代码复制代码
- 之后在runApp对应的页面中进行相应的配置 (这部分代码实在有点多 ???? ,建议查看example代码)
- firebase_crashlytics example
Future<void> _testAsyncErrorOnInit() async { Future<void>.delayed(const Duration(seconds: 2), () { final List<int> list = <int>[]; print(list[100]); }); } // Define an async function to initialize FlutterFire Future<void> _initializeFlutterFire() async { // Wait for Firebase to initialize await Firebase.initializeApp(); if (_kTestingCrashlytics) { // Force enable crashlytics collection enabled if we're testing it. await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true); } else { // Else only enable it in non-debug builds. // You could additionally extend this to allow users to opt-in. await FirebaseCrashlytics.instance .setCrashlyticsCollectionEnabled(!kDebugMode); } // Pass all uncaught errors to Crashlytics. Function originalOnError = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails errorDetails) async { await FirebaseCrashlytics.instance.recordFlutterError(errorDetails); // Forward to original handler. originalOnError(errorDetails); }; if (_kShouldTestAsyncErrorOnInit) { await _testAsyncErrorOnInit(); } } 复制代码复制代码
firebase_performance
firebase_performance是针对你的应用进行性能监控的插件,这里的性能包括但不仅限于页面启动性能以及网络性能 ???? 。但是有关firebase_performance的相关功能仅建议存在海外 ???? 用户或需要进行详细页面性能分析的应用接入。因为网络相关的性能只能监测到国外用户的请求,国内用户的请求无法收集,显得有些鸡肋 ???? 。具体使用: 首先声明一个FirebasePerformance实例
FirebasePerformance _performance = FirebasePerformance.instance; 复制代码复制代码
在合适的地方(一般在首页或之前的动画页)建立和FirebasePerformance的连接。
await _performance .setPerformanceCollectionEnabled(!_isPerformanceCollectionEnabled); final bool isEnabled = await _performance.isPerformanceCollectionEnabled(); setState(() { _isPerformanceCollectionEnabled = isEnabled; _performanceCollectionMessage = _isPerformanceCollectionEnabled ? 'Performance collection is enabled.' : 'Performance collection is disabled.'; }); debugPrint(_performanceCollectionMessage); 复制代码复制代码
更多细节
firebase 版本
你可能会接入多个Firebase的功能但注意插件的版本号,必须是对应的 ???? ,这里主要指的是firebase_core,保险起见,所有插件均采用最新版本即可,截止我发文时,我的应用内均采用最新版本的插件。以下可供参考 ???? :
# Google 性能监控 Firebase firebase_core: ^0.7.0 firebase_analytics: ^7.0.1 firebase_crashlytics: ^0.4.0+1 firebase_performance: ^0.5.0+1 复制代码复制代码
意外发现,如果某个插件版本不对应 ???? ,会在导入插件时报错,报错信息友好(这就是亲儿子插件的魅力吗 ???? ):
iOS 符号表配置(dSYM)
为了更好的分析iOS端的报错,也就是让最终上传到Firebase控制台的报错堆栈信息更友好 ???? ,我们一般需要上传iOS的符号表至平台。如果你不知道自己是否上传了符号表 ???? ,可以在Firebase控制台的crashlytics功能模块中找到。如果显示缺失dSYM可以根据在终端运行脚本手动上传 ⚙️ 。
也可以在 iOS 工程中配置运行脚本在运行时自动上传 ???? (这部分仅推荐使用过 iOS 原生开发的同学使用),在Xcdoe 的 Build Phases中添加以下脚本
"${PODS_ROOT}/FirebaseCrashlytics/run" "${PODS_ROOT}/FirebaseCrashlytics/upload-symbols" -gsp "${PROJECT_DIR}/GoogleService-Info.plist" -p ios "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}" 复制代码复制代码
注意???? :这里的脚本并不是固定的,和你自己的工程目录有关,例如下图红框中GoogleService-Info.plist文件的位置
运行时问题
- 完整接入Firebase相关功能后应用启动时,可能会出现一段黑屏。不用担心 ???? ,这是debug模式下启用部分功能,以及我们采用FutureBuilder组件的原因,在release情况下一切正常 ???? 。
- 接入Firebase之后由于我们会在运行打包时上传部分日志以及符号表,所以务必确保全程你的网络环境是科学上网的,否则会可能会导致运行失败 ???? 。
- 就算你完整且成功的接入了Firebase,你的所有数据第一次生成也是有延迟的,会在12h左右不等,所以你在控制台可能不会立即看到你接入数据的看板 ⏳ 。
大功告成、体验功能
一个完整的、可自由排版的主控制台,几乎可以看到所有你需要的核心数据,非常 ???? 。
用户分析
点击用户分析模块,你可以得到非常非常多的你所集成的数据 ???? ,例如你集成的页面统计、热门用户事件等等,当然还包括一些用户数据。实际这个界面的信息量有多大,各位可以自己体验一下。数了一下有十几个用户相关的表格,包括折线图、曲线图、饼图等等 ???? ???? ,各类数据比较私密,这里就不给各位一一展示了,只能展示两个不太相关的表格。看到各类图表的那一刻,会非常有成就感 ???? :
报错排查
点击Crashlytics模块,每一个报错和崩溃现在你都可以捕获到 ???? ,你可以用获取到相关的用户信息,并根据下方的报错日志进行排查,甚至可以自己自定义报错的等级,和将相应的报错设置为待办以卡片形式一个一个处理 ???? ,就感觉你在审批 ???? 文件,有条不紊。
性能监测
点击Performance模块,里面有你的应用的详细性能信息。
甚至还有 ???? 网络相关的性能分析。针对网络请求的成功率,时长,可以进行网络测试。后台返回速度慢,成功率低可以直接和后台人员沟通处理对应接口(再也不用为网络卡顿背锅,有理有据的甩 ???? )