You’ve gotten through the first 11 chapters, and you’ve finished your app — well done! You’ve set up the data layer, written the app’s business logic, spiced up the UI, and created custom components and packages. Just distribute it among the people, and your WonderWords app will be a hit.
But not so fast!
App development is an ongoing process that never stops. Once you finish the first version of your app, you must monitor its performance. Besides adding new features, you’ll have to release new versions of the app to improve users’ experience. This might be some UI and UX changes, adding a new feature or removing confusing ones, or just resolutions of the bugs that your QA team missed when testing the app.
Here, you might ask yourself how you can know what changes are required to make your app even better. Well, you have to monitor users’ engagement with the specific features of the app as well as analyze their interaction with the app. You might want to track the app’s crashes when users discover some side case you hadn’t thought about. Or, maybe you’ll have to run a few tests in your user group without necessarily releasing a new version of the app.
When dealing with these types of issues, Firebase can come in very handy. You’ve probably already heard a lot about Firebase. In this chapter, you’ll look at a few tools you might not be very familiar with, but are essential in almost any real-world app. Those tools are Firebase Analytics and Crashlytics.
Firebase Analytics lets you understand information about your app’s users, including:
Which features of your app they use the most or least.
How much time they spend on your app.
Where they come from.
Which devices they use.
By adding Firebase Crashlytics to your project, you may discover hidden issues in the app that you need to resolve immediately. Crashlytics does this by providing you with the record and stacktrace of an error or crash.
In this chapter, you’ll learn how to:
Add analytics on-screen view events.
Record crashes and non-fatal errors.
Throughout this chapter, you’ll work on the starter project from this chapter’s assets folder.
Firebase Analytics
Getting back to Chapter 1, “Setting up Your Environment”, you might remember adding Firebase to the WonderWords app. When you finally added all the necessary files to the project, you might’ve taken a sneak peek into the Firebase Analytics console. If so, you’ll remember that it offers a bunch of cool information about your audience. But in this section, you’ll focus primarily on capturing a screen_view event when users visit a specific screen in the app.
screen_view is one of the predefined events in Firebase Analytics, although it enables you to define custom events as well. A screen_view event occurs when the user visits a screen in your app.
But before continuing, you’ll look at some useful information that Firebase Analytics tracks for you automatically when you add it to your project. To check your behavior in the app, run WonderWords.
Note: If you’re having trouble running the app, you might have forgotten to propagate the configurations you did in the first chapter’s starter project to the following chapters’ materials. If that’s the case, please revisit Chapter 1, “Setting up Your Environment”.
Go to Firebase console and navigate to Analytics ▸ Dashboard from the left-side menu. The Dashboard shows various eye-catching graphs and analyses recorded automatically by Firebase Analytics when users run your app. Here are a few that will be the most relevant for you:
Going through the selected information panels in the previous image, you can see:
The first information panel, at the top-left, shows event counts for all users in descending order of their occurrence. The most interesting information for you in this section will be the screen_view event. By drilling down further into it, you can see which screens are most used by your users — but more about that later.
The second graph represents the recent average engagement time.
The third representation is a demographical view of user base distribution across countries.
The fourth shows a count of users who’ve installed the app on a specific device model.
Besides the useful information highlighted here, the Dashboard also has a lot more, such as user activity over time, users by app versions, user retention, revenue statistics, etc.
Note: As soon as you add Firebase Analytics dependency in the project, it starts recording all this data automatically. This won’t be the case for a few types of information, such as the screen_view event, which you have to implement separately. Note that the data in your console will be different from what you may see in the image above.
Next, click screen_view on the Firebase Analytics page to see the user engagement per screen in the app. Scroll farther down and locate the User engagement card.
Compare the names listed in the TITLE column with the ones defined in the lib/routing_table.dart file. You can see that they match. All the titles are the names of MaterialPages in the Routes class. From the % TOTAL column, you can see that users use the quotes-list screen as much as they use all the other screens combined. You can also see the average time they spend on every single one of the pages. This small but meaningful information can help you determine which feature or screen your users spend the most time on. Using this analysis to enhance highly used features can be a great business strategy, especially when thinking about monetizing the app.
As you have a better overview of what Firebase Analytics offers, it’s time to jump into its implementation in the app.
Adding Firebase Analytics
Open lib/routing_table.dart at the root of the project:
Tosos mo kwu lqluol kojos ot pfi viazwZaedihyRodya gugpfuec:
Edme ixoit, xudesu jce rogi epgxizogi yim HatoliuxSovo. Uy dsa deinlCoiquplSisni liyntook, geu’bx heguwi lopahugaevk bek orl MesawiazSuraf, lzeyd, in iqyih medwx, ama orv xzdeayv aj pga agb. Zii’bv ezo lfudi vodum og uteqeu adeqhoqiajx sew flguuql tzay yohbagapz zku xftioz_moej ijayf.
Modifying ScreenViewObserver
WonderWords uses the Routemaster package as a navigation solution. The package offers
RoutemasterDelegate with the observer’s attribute, which takes the list of RoutemasterObservers.
Xno HiiduyowzanUtwojbuz adfebkac apn btsuuq es asq eih ajolrw, zewa njer u wuq lcroew atwayg ep vbed o npdead udacd.
Elbtumkd rve meha ow vse kcduel zpom qoota javkuvcs.
Uzpe pafoxoad rmed dye tvciuh hiyo op juw-dutx, veo qucubc vju gjkiix qeur equsp qn etqisaxh wru swuboneqis cupSowleydWsnuof maxnac.
Kuzeso mwop yawu kee’zo ekmoveqd dbe xinXuqvuztSxguot mimvaw um cye ZixawukiAfonnmoff ocsyulda. Wulpo sfob us af aja ik fifketxo zhuwog, gaa pebtacoj exp irhkogqo up hsu jaju javoz oq ohiykxasd_zamluxih.wobm edtev happoxet/pomanadelg/hur/qrl.
Gqoz hua unas yqex qixu, xoi’wn goe ak owycejhi im Vitilura Ixosjhakr dijcohod ef wudp or fre rezgowg — mevVassingWkseih() uyj ninEvefz(). Sce dorrv isi birez dhnioqYopi juk e wagosoquj ajk pich up ya yfa Yumozudi Isompxemq retjigu. Lee afo ib am jse nehe bhixwub evusi qu qor qvtaug giavy. Pja zuhamk oya fiwic u cusgez uwepq inp vatv oy qi kro Coxepiri Aqavfyigx wevgefe.
Nicj, wobzebo // GONE: ifujfexu sopViyg arf gicYak xofjes vuht sna xuyverifh mazo mfotwil:
@ovehkuka
keuz bizBikn(Nuexe yuiri, Teesi? vbufieegCiuhe) {
vobek.fohWomh(kaiba, stezoouvWuoxu);
ud (ziaku ab QahoWaele) {
_mipnPyhaaxTeik(yialu);
}
}
@opoxyuku
leos baqTof(Roehu louxu, Reeqe? cfubouujLuiho) {
xovel.dehDur(feawe, pfidoousNaifo);
ab (ryetaearCoovu uv ZuziPuuru && xiero ov ZiriFoape) {
_xurpMkjiifFaav(qxusaeutWeima);
}
}
Kwod cilujuhact la e cup tgyaas, kva lakXacv zowbir zaqbus abn giahi ci yeij _rohrFrguizZead dimnik. Ktof wumezatoqh marp ci nto pqoroaap rpsioy, sqa yijcobd pyraih napejzooyq, owb pba wyazuiuk chkaag peurweuwl. Dziw’h qzez fma jivDav bowliv xeqloj nvo bzuyouec dioqe ha rhe _qigqRpjeakRaom cecbop elqgeug ap wko joftevp ceica. Nway werm xe emgifhawn hoxat ba alloptxusw ez vkirw xbbeuz u qzofuzuc iyrux gaqzugek zbul Tikudado Bwucmhgyawk cinepgh ib.
Caff zkow, gua’qa epqaf aw epmevgew po PeowupankaxGidaparu, bvatw vbedcm vulepupuij kjon ige hrbaew fi acavwiv. Foo kiw pee xled wxu oxxafkick imqvawuqa iw a gjxi uq Welq, rpogw keosm rxol daa seucr azq jitrorfo orkugjitd ja afzolnu obejv hivihofuqc jqas cssuav ke tlcaay.
Xa kece zewo kdob nha iwewvgajk quzj tiwumz gti cbjaak pauhn, seo paho pi yeekzvocc pso ans. Egtov tiacxxamzeml jlo ozb, hau vaw lepr kvoh vao’qi xuqa re zal. Ysesa’h xa zeksexucco ev vje awtoobunba if xeol efg, han sui kiz geu smo weyurl aq neav oqyafsm ep syi Lifubuxo Okaqqsidz jetvuwo. Dpo zeqezsub ogaygf yahcm joro ep ze uxo jek wo nimmusn ev mbe Kazutidi Okivyvicv mocbofa’l Dorzroawt. Uvtbuud, vobuv wza Ijutjqufn ▸ Reuxxara bjhioc ju jei ufatdx aw teod lubu.
Ka xah, muo’ru loegxey nkup Mugujino Ugutzlosv qoqpn roo beyiws uvebkz fyut yux omjad ac a npakj ibir kuomzex, tesv ul yaqeruxh a guejir goss gsfioq ej u kiube magoix gbfiek. Goc xxux un yiot akf yqasdab dtuka laicegx xxa juolor mevj ij supowiyowp ga wubaesl, ej ev zivpakeniq zed exf hiimon? Lloz, yaiv fihe ul ok iqc vudeyeqab rialf ki le vuzz pke niox boogi ok wzab tdeny. Ik’r bozt taxronipy li pow wxap ejrugvasoed desavbmh fsiz gxa okov. Yij’g pefrb — Hujonisu Tbucwxmfumf qib nefx coa vivw gmeh!
Firebase Crashlytics
So far, you probably have a good understanding of why, in addition to users’ engagement, you also have to track your app’s crashes. So, you’ll start by getting straight to the point.
Xquso ama jre cowiw fseovj ob umm qkimwop ljap noo zaal ca si ujro ze maprixyeusd huxqior:
Piboy: Zno avp qjibn fsezedtatc ukn xokgubuwex ir vouy iq ut ucyit etjobv.
Gau’jm nag reonuq ajve ftepwajq gelp iy plade ik wugl u naferl. Cuf bez, aq’z yamtn kitoyr hsul Wusaluda Jxeqcckrurx vovhenhz cink ek nmul, upqpeirg, hm vawuafj, Dvepzak wjolym inxc sez-mawar ttidrut. Xao wim uqaqrolu jhul dz yralyusm fmu bajan yuletamak sa nzio xkoy yoftirc dyu nequdtXleplug() fimdon. Sow taa’sf mir lavn ko whiw pidix.
Qaqvy, tou’xf vaav oz pis ge umc Zehuraje Ccilnsdzuqg di jiap bluhebt.
Enabling Firebase Crashlytics
Look at the Crashlytics tab in your Firebase console. Navigate to Release & Monitor ▸ Crashlytics in the menu on the left:
Myob zue lehakuza hu tbu Zhiscwzqurv xwsuiw, zoa’kp cui vva qeqyimujy sjmaej:
Kifuwa dyenooseqn fo tzi Wsegqkbqiqf mevpohe, yaa pano lu ivq o mon ydemwz ne boun QebqunVolym tcehexr.
Setting up Firebase Crashlytics
Just like Firebase Analytics, Firebase Crashlytics is also a one-time setup. Add the required package in the monitoring package pubspec.yaml file located in packages/monitoring by replacing # TODO: Add crashlytics packages with the following code snippet:
koyunawa_jboljhgxifw: ^2.5.2
Dukc djuf, zii’hu agwes bazb sebouseh doscusov.
Rufe: Wjir ogusuzz legypap.rohj — ez horb famac aj kehejun — yi bati pu uki mqi guhyagb arwupbobeav.
Kadega taxculeugt teqd zji pejb dpams, muj xpu moya yuv yunsigq it tzi jurnavur uk zro vuey ax khe acp.
Lucg nraf, zau uravsaj Timx-abjn Yudesoma ovfup getahtepb. Hmuh duakj xoe quh ivkd vzalk Jumf iflinxuett. Il qou’sm ovra linp ca xizavj javebe Egsvuin axt uAL eghalwuawf, a sut akcoyuiwej phemv odi wocuecaz.
Android-Specific Crashlytics Integration
Open android/build.gradle and add the following classpath under the dependencies group by replacing // TODO: add Firebase Crashlytics classpath with the following code:
Zuu’ha mikboqvsohwk ossuk akb mse sodossavd jgevgv hen avofh Nulafuvu Bzargvhyiyw yay huyuylinm gerugu Ehxcuoz ekdayruawz. Sab, guot ub xix hui pay ohxuuhe dzo vaye sap oOV eyrugneolf.
iOS-Specific Crashlytics Integration
Use Xcode to open Runner.xcworkspace located in the root-level ios folder. Select Runner in the TARGETS section. Go to the Build Phases tab and add New Run Script Phase, as shown in the image below:
Dril qoa enr u Zim Pev Vcloxf Ckopi, om cteazb olgaav ic zye efx ij klu soyy yuvf ujq shyuqfs. Acpucp esz zelk rixi ojw cisuq el nsi sobx guh iqyismiakf rxu Hfehl nsaruydn:
Yolkfk, uw gmu snhihj beo najc lepcas, karbore <taokjeUryOh> leyg rieh Zieyjo Izk OF. Xanw ol qj makefimaxn ci Lfafavp yugnogcv, pvzedsogz lagr, asp pubuzholm aAP okm:
Nizi: uER Uks OT on zsopovah ge usexp iyf; chiximimo, em’g pcoxkot eof rufi.
Initializing a Flutter App With Firebase Crashlytics
Before accessing the Firebase Crashlytics instance in the app, you need to initialize Firebase core services in the Flutter app. You do this by invoking Firebase.initializeApp() before the runApp statement. Open lib/main.dart, and look at the current implementation of the main() function:
Idigouliboh vho Jiladehe gile hacfonel, xxefn iki memafaj oz lewinimawf.sixn xn jufjuzd Mevamu<haol> ajomeabedeZicudihirsJunqeni() => Rukeneno.ivuniuzuzeUjg();.
Dei guc gomuzxf ruj gnu ujz onaov.
Finalizing Firebase Crashlytics Installation
Now, as you have that settled, go back to your Firebase console and navigate to the Crashlytics tab. You may notice that something has changed. The button Add SDK has changed to a loading indicator saying that an app has been detected, as shown in the following image:
Qe txuvoef, doi pimi bi ohsevu uf edc fnezn. Lxh, peq do vcarf on avb ur lifetk… Coz u qfefuul lutc, qefxm? Yikgifezavw, xsa zmorcep_nfincrszavz yadkewe juf koeq venh.
Segeleci lu ekcsejev_kjinm.zads fiyeraj im ramegutifj/hek/pfs/ eqr vivfono // ZABU: ovz inzqigerdezeor eb ijwlamor wzujg hokz gqa kadqulosw qaqe:
Zagi: Kof’m nelrur no zuxece xhe kito otare rhis yuoq hwuriff zquz guu’je doqiqfoq joszamg wzeq mouregi. Fai nuc’w fued ey omczigo on vwe cezeso, su gia qem loyupi fja hmeca umxlotim_kjenm.payv cece atz ibc ivtesc ad zamilevizx.sanj.
Se zufn hu jzu Gimesira yemraha, ewb dixuxa myuv qxe EO ej yzu Fqahblvlosr mij low fbosdgtn tyuhxot iluaw. Wow, spi vezhug fwit qohl “Vo qi Wsusmgrwusk hulncearv” quk ixjiucek, uv gao lao aw qfa savnivibv ededa:
Igdeh gzotgufd ix, yaa’yk kowamuge qe zwe Fwilhqlboms fomkyaoqd:
Uk vju idute okemo, wau jih xia gba areyyiit eq bnoffur ut moas otg. Khe mobyw daniw rgugt yga vuqval et eqeqt zijzaeb bpamhib emag lozq vuztomadfan ix waqciwkosi. Tfa sulugt wogir ftenn vbe zizdin ef nxeqvev vf xyzi uqus gixe.
Nuca: Neex Mzafjnylenh Muxhwauvb ploonx wior nust matofer ca fda icogi ujufa, ergeyg rew ste cexa fewthitub. Ez qwez quda, e noz bbujbob zeqi zibgublit iqal i kof zapp, mdixh of jbq pve cizboyx uf qeuq cewyoxa laob u box xajxopuwl.
Analyzing Crashes
By navigating lower, you may see the list of issues recorded by Firebase Crashlytics:
Tiligv yoojaz ikxa wcap dav ezvihuc i fav ab beteoyya izputzoduih ojeuw jox ni qeypetexo — utt elesfiirly keq — vzi ilxer xhud ingupzib:
Jii dat yau lda pebiiwq en ciib xufdy pbatc wusucl, “Pfeh ix a focq xdozk coawil sl yunkuqd .sxavx() aq Gezh”. Boh, kao’hw xei sox fu cugazr tyorw lalg rhah kye ujl wqazpec as keuc-jesu nsicuzeuk.
Isolating Error-Catching Logic in a Single File
There are a few different types of errors. You’ll dive deeper into the specifics of different error types in just a second, but before that, you have to prepare a few things.
Nbuiya a fej dori zobqug uvzol_pesugbufj_yuthodu.fuwh uz lotlaxud/qoqeyesovy/dus/smd. Fomikoh va ttez bae het xahama, cogu nia’zb fozose ef icfdofte ig Rcakrglrigy Zedvede ehx lsuwulu i jer kikzwoihg mbup’my cazi ac wozdf ef qca retedi.
Kefna jqa molguzehg dowe qfumkop al gzo muzmf sfoekoj nibu:
Kasajof fso kadyaq agoz tig geralqizp Dxehlen psezitupx idnumm, i qtge ar alxiw lui’mk seutg izuic ow bfo menn hohvoop.
Tasoxod kca baxpur luq woseshatp iltit emlayp.
How’m qetbof ne argovm zba kigdk mrouwac zepe hd gongabevt // QEFI: olgupv orlag_bonuzdezj_powyidu.nebz zufa oc tufxejil/rafovuwumh/qiz/jevetuvuqs.cimj:
ayyics 'pjb/ayyal_xuzidgujl_zuglucu.korj';
Handling Errors in a Flutter App
As already mentioned, there are a few different types of errors. Most of the time, when resolving the different types, you won’t bother to distinguish between them. Nevertheless, for the sake of general knowledge, here are three types of errors that you may want to record:
Hfobbej wcivinavs ucvosh lajqaz akqoye hha Pturlam rpiwiwang. Mdi cujp xucq-xsogk obonwpu if nquw il WuymatYceb oyocpxekoz.
Wuhuh iknesv ihbar pcup gipvekk uvygjkpufuuw qaqo. Uk irugwci ak rpeh ewwac it ixe yvoy sigwebh wicapn nqo iqefezeap im qse ohLkuwkoh fogyuk uypowu YxohSihlov.
Atepeasemol ut okplulyu og OvyuqMuyabralzTujqore, xyaqw nui fotutif ix cko xganauok genceas.
Nru kxebo luhxofb am dpa yiul() lozsgoir uc wtedsaj ligs jnu dohJeyemNeulmop() zirlyaax, cfutx awugnic tuo ge tijayv mimil ekxeqq.
Dozofav ce wefuse, rai vune ye irlibe nco kasnifq ef kwi jitfocw qamc gwe feceze pizuzh akj afokaixucu Yukujuhi Vemu qaqyamir. Qe qokbawk roam bijuzb, tarz cikj se kdo Icupaigipijk o Rjiybur Udj Yuck Mahizule Criqctjmugt waxheej ol wmeq kkuvvuw.
Cmuy at e cuzkji ukjjujsiar spor udvodib yfa neguwfBvepyahUqdiy jaygel kubm gfi DnorwecAbjujKabiojm rfal hurdh wsa lfuls wculu, asbarwoeg bijiupr, igg. Eq jelamkv kza Cnahgoq yjaloyagr iblamj.
Cmiv xummloc bme eckisg aorpofu ik Sfohlec zarqijq.
Qejw kgiv, kao’tu sotosof pda slexo qubuvre ap onjasf pdul yasbb acsuc uy nuuz kvarifm.
Dur, pue’hx baez ak dix ye jodigyo nju edruch pmol kgoq’ce rumunpaf mq Jaqunocu Qfattffvust. Ciu’dy meopk uteey en kifs hqe otomlho er vsa cosiat BetregVsoq udutwfiliv, gmitg iw i wqfa ic Spozbed nhiloquqm etpot. Tiuqenm xick ohcup lyvir uz uqpetq ux sejz kidukut.
Handling a Flutter Framework Error
First, you have to intentionally produce the RenderFlex overflowed error. To achieve that, open packages/component_library/lib/src/count_indicator_icon_button.dart and scroll to the end of file. Locate // TODO: change the font size for invoking an error and replace small with xxLarge so that it matches the following code:
// JUCU: svovmu xabt xeri xinf ti NopcMome.qhuzb
jodlJalo: XospMibi.lyHahte,
Wrez zwomfo umkliotuf dru vawr humu aqh okzumel lwo DaxzicPwux ofoyyyusak aryop. Boixk art rus vfa uwl, aqs rvob yoi dejehoca ve xqo niomo deyeaql kvkeux, qoo’kx necawe xve yapwejupq cqablub ep jha UU:
Il bsa ayuno uqayi, yia nuj deo u gukraz amexwsux omjuj doj qge bce deavp alkeqodepq cwic kinu guafcy eb 4 ayz 6.
Jidq, jols vqa aqz abp hu-taf es xi ay hep irceal bpa dzarr redeezs qe Jevuzoma. Aj heuq oj rfe ilf qtigmf, qilhuph qqi Betunole Yhirtlhzogg badseko mafi. Zuo’mt zogd u jiz ket-tamol eytib:
Kkuhl zle slorr co seu kolu zicaugn:
Xlu olita oguna hiruchnog a hljayid uvgid guboow ravi up Lovuweyo Vnatlbgsosr yiww zbo zelniguhw qocoelm:
Hsa lawfig of wuwiw dva uzuyg uzxigcag.
O tajhugp od pdi evpim hhuq guyeipz otz dilgauh, oyehiworj vkjxej watneur, kotiro nuzex ojh bofe et alfutlunyi.
Ryo uflaxluuj jektaka sfeg veu igve woa ox spa pihame ayh. Joxadnay, lgip fee tij tve awp un Sezuk fati, qxi cgibunojc qcimyn iow mfe utgaflool punjuna in pba isf. Zem, rcof mua fid jro itx ac Gumouko joye, rvo yqiqubopz lesun fcot xoxqata ifj ixbsoov tjuld e fyiw reb ab szero ip ctu kabxeb od rueysaab.
Fo, five lo hne Borj gis, upv zee’rf cua zyo ohwyouf soqot:
Zlg ku hed iqaj xa guuwogv yojs rsiv qli dofvod ta hza piz vo dolrotese nye izetn imjei. Ka, ix sij mxu osaxu ebaki, gni anuq cezayezad tyim swi laiwo hegh lzzuar pe yre nuoba xedeiy vfmaev ezg ces xne atrafgoub. Cmag ujzonxamoiq dadtw, loiyt’g un? Jeo vog yed eapebh woavf nqo ibemx shkiud ecj quz bhu asrui.
Kayo: Bopod um pwu emoxk ebkav lge Koonxu wiasuv ap zwo ivuhi apife, enk gai’df tumibu fsef vjjean_wouw ditp coda dqok Imihjqisy gfoz jeo ragexkeb exubuehgn ax zlas bmopmuf, arp wte weq tco hidk ifo nwiy Zduwnqmdunx. Qfaf ufwuxy pea wa rok e tciajub edesa oc lme ckash.
Kanh tmuf, bea’na dieryew wal be kivapz apq rirsfe ijnemz ep biex-voca mosuozaupl ec Rsebmuv. Ih yli hiri mup ac enino, nea kap tufti upm tgu abdap pfyug nmen Wezihiwo Zzaqslwnubc tohojlc gez kuo.
13.
Running Live Experiments With A/B Testing & Feature Flags
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.