實(shí)戰(zhàn):Countly SDK接入與事件設(shè)計(jì)避坑指南)
去年秋天接手了一個(gè)跑了快兩年的Unity游戲項(xiàng)目玩法迭代到3.2版本渠道方突然甩給我一個(gè)問(wèn)題次留是多少關(guān)卡3到關(guān)卡5之間的流失率又是多少我當(dāng)場(chǎng)有點(diǎn)發(fā)懵——后臺(tái)能看到的總下載量和啟動(dòng)次數(shù)都有但玩家到底在哪一步放棄了游戲、裝備系統(tǒng)上線后有沒(méi)有人真的在用、新手引導(dǎo)卡在了哪一屏這些全是黑的。這不是個(gè)例。項(xiàng)目做到中期幾乎每個(gè)Unity開發(fā)者都會(huì)撞上同樣的尷尬功能做了一堆卻沒(méi)有一套“行為數(shù)據(jù)”來(lái)告訴團(tuán)隊(duì)玩家到底買不買賬。當(dāng)時(shí)我花了兩三周專門調(diào)研埋點(diǎn)方案最后選了Countly在正式環(huán)境跑了大半年一直很穩(wěn)。這篇文章就是我整理的一份自用記錄核心是記錄Countly在Unity里的接入過(guò)程、事件設(shè)計(jì)思路和踩過(guò)的坑給同樣在Unity里糾結(jié)埋點(diǎn)選型的同行一個(gè)參考。全文基于我實(shí)際操作的版本記錄不同SDK版本API細(xì)節(jié)可能略有差異但整體思路是通用的。1. 為什么選了Countly需求倒推出來(lái)的方案選埋點(diǎn)方案這件事不能拍腦袋。我當(dāng)時(shí)的處境是游戲包體不想被第三方SDK拖重?cái)?shù)據(jù)不想放在別人手里被動(dòng)看報(bào)表但又不想從零手寫一套上報(bào)服務(wù)。所以篩選維度其實(shí)很明確。1.1 我當(dāng)時(shí)對(duì)比過(guò)的幾條路線市面上能給Unity用的埋點(diǎn)方案大致分四類通用統(tǒng)計(jì)分析平臺(tái)、海外大廠分析服務(wù)、游戲服務(wù)器自帶日志、開源部署方案。我簡(jiǎn)單拉了個(gè)對(duì)比表方案類型代表核心優(yōu)勢(shì)當(dāng)時(shí)勸退我的點(diǎn)國(guó)內(nèi)通用統(tǒng)計(jì)友盟、TalkingData接入快中文后臺(tái)自定義事件維度偏基礎(chǔ)數(shù)據(jù)出口不在自己手里海外平臺(tái)Firebase Analytics免費(fèi)額度大生態(tài)完善國(guó)內(nèi)訪問(wèn)不穩(wěn)定后臺(tái)習(xí)慣差異自建接口自己寫日志上報(bào)完全可控報(bào)表、漏斗、留存全部要自己弄工期爆炸開源部署Countly、Matomo等數(shù)據(jù)可控、可二次開發(fā)服務(wù)器要自己維護(hù)有運(yùn)維成本《自用記錄》到這兒其實(shí)已經(jīng)能看出傾向了我想要的是“自由度和完整度”的平衡。自建接口聽(tīng)起來(lái)最可控但一份能看的報(bào)表系統(tǒng)從數(shù)據(jù)存儲(chǔ)到查詢到前端展示工作量根本不是一個(gè)人一兩周能做完的。而直接用現(xiàn)成統(tǒng)計(jì)平臺(tái)又總覺(jué)得事件模型被鎖死。1.2 Countly讓我最終拍板的三個(gè)點(diǎn)第一開源社區(qū)版支持私有化部署。也就是說(shuō)我可以把它裝在自己的服務(wù)器上數(shù)據(jù)不出自己的機(jī)器。這一點(diǎn)對(duì)我這種對(duì)數(shù)據(jù)敏感的項(xiàng)目很重要不需要依賴第三方平臺(tái)的行為規(guī)范。第二Countly對(duì)Unity有官方SDK。GitHub上有countly-sdk-unity倉(cāng)庫(kù)一直有人維護(hù)不是那種社區(qū)愛(ài)好者順帶寫的半成品。SDK支持事件記錄、用戶屬性、崩潰日志、推送通知這些核心能力Unity里直接能調(diào)C#接口。第三學(xué)習(xí)成本可控。Countly的事件模型是典型的“Event Segmentation Count Sum”結(jié)構(gòu)和我之前的埋點(diǎn)經(jīng)驗(yàn)幾乎一樣不需要重新理解一套新概念。后臺(tái)報(bào)表也夠用實(shí)時(shí)數(shù)據(jù)、留存、漏斗、用戶畫像都有。提示如果你鐵了心不想維護(hù)任何服務(wù)器Countly也提供官方云服務(wù)可以直接注冊(cè)賬號(hào)使用。差別在于數(shù)據(jù)托管在對(duì)方環(huán)境但對(duì)小團(tuán)隊(duì)快速驗(yàn)證來(lái)說(shuō)完全夠用。2. 接入前必須確認(rèn)的兩件事服務(wù)端地址和應(yīng)用標(biāo)識(shí)Countly的接入流程第一步不是寫代碼而是先把服務(wù)端和應(yīng)用標(biāo)識(shí)準(zhǔn)備好。很多人在這一步栽跟頭是因?yàn)楦慊炝恕胺?wù)器地址”和“后臺(tái)地址”。2.1 自建服務(wù)器還是官方云我選的是自建。官方給了一套安裝腳本準(zhǔn)備一臺(tái)2核4G的Linux服務(wù)器裝好后通過(guò)IP或域名訪問(wèn)就是Countly后臺(tái)。整個(gè)過(guò)程大概十幾分鐘難點(diǎn)不在安裝而在服務(wù)器本身的網(wǎng)絡(luò)、域名、HTTPS證書這些常規(guī)配置。如果項(xiàng)目組本身有運(yùn)維資源這一步很省心。如果不方便自建直接去countly.com注冊(cè)一個(gè)云賬號(hào)創(chuàng)建應(yīng)用后同樣能拿到Server URL和App Key。我建議是正式項(xiàng)目無(wú)論如何都先確認(rèn)好服務(wù)端URL不要用默認(rèn)IP或者臨時(shí)域名去接SDK不然后面改一次URL歷史數(shù)據(jù)就要做遷移合并。2.2 在后臺(tái)創(chuàng)建應(yīng)用、拿App Key登錄Countly后臺(tái)后在Management里的Applications菜單下可以創(chuàng)建應(yīng)用。創(chuàng)建完會(huì)生成一個(gè)App Key這串字符是SDK和服務(wù)端通訊的憑證。同時(shí)要注意每個(gè)平臺(tái)Android、iOS、PC建議單獨(dú)創(chuàng)建應(yīng)用方便按平臺(tái)過(guò)濾數(shù)據(jù)。Server URL的寫法有個(gè)細(xì)節(jié)接口地址是HTTP根路徑通常填到不帶斜杠的域名或IP端口即可比如https://metrics.yourgame.com而不是https://metrics.yourgame.com/api。SDK會(huì)在內(nèi)部拼接請(qǐng)求路徑你多加了/api反而會(huì)導(dǎo)致404。2.3 SDK導(dǎo)入的兩種方式和版本坑Countly Unity SDK的導(dǎo)入方式有兩種通過(guò)Unity Package Manager用Git URL導(dǎo)入。在Package Manager窗口選擇“Add package from git URL”填入官方倉(cāng)庫(kù)地址比如https://github.com/Countly/countly-sdk-unity.git。這種方式后面要更新SDK版本時(shí)比較方便切換到對(duì)應(yīng)tag即可。下載官方發(fā)布頁(yè)里的unitypackage文件手動(dòng)導(dǎo)入。適合離線環(huán)境或者公司網(wǎng)絡(luò)訪問(wèn)不了GitHub的情況。我項(xiàng)目里用的是2020.3 LTS版本的UnitySDK版本在24.x左右C#語(yǔ)法兼容性沒(méi)問(wèn)題。但后來(lái)幫朋友看一個(gè)老項(xiàng)目時(shí)發(fā)現(xiàn)那個(gè)項(xiàng)目還停留在Unity 2019SDK拉最新版后會(huì)報(bào)編譯錯(cuò)誤因?yàn)樾耂DK用了比較新的C#語(yǔ)法特性。如果你也是老項(xiàng)目寧可找一個(gè)和Unity版本匹配的舊SDK tag也別直接拉最新。提示導(dǎo)入SDK后建議立刻在Unity里做一次全量編譯確認(rèn)沒(méi)有報(bào)錯(cuò)再往下走。Clue是SDK依賴的幾個(gè)DLL是否和項(xiàng)目里已有的插件沖突這一步越早發(fā)現(xiàn)越好。3. 初始化與第一次事件上報(bào)核心API的調(diào)用邏輯SDK導(dǎo)入成功后剩下就是代碼層面的活了。我的做法是把初始化放在一個(gè)專門的入口腳本里比如叫StartupManager確保在游戲場(chǎng)景的最開始執(zhí)行。3.1 初始化配置逐項(xiàng)拆解新版SDK的初始化方式是通過(guò)CountlyConfiguration配置對(duì)象using Countly; var config new CountlyConfiguration { ServerUrl https://metrics.yourgame.com, AppKey 你的AppKey, EnableDebug true, EnableConsoleLogging true, EnableManualSessionHandling false }; Countly.Init(config);這幾項(xiàng)配置的含義分別是ServerUrl服務(wù)端地址必須和后臺(tái)應(yīng)用所在服務(wù)器一致。AppKey創(chuàng)建應(yīng)用時(shí)生成的標(biāo)識(shí)復(fù)制時(shí)注意不要帶前后空格。EnableDebug是否開啟SDK內(nèi)部調(diào)試日志開發(fā)階段一定打開能看到請(qǐng)求URL和響應(yīng)狀態(tài)。EnableConsoleLogging是否把日志輸出到Unity Console配合上一條使用。EnableManualSessionHandling是否手動(dòng)控制會(huì)話。保持false時(shí)就由SDK根據(jù)應(yīng)用前后臺(tái)自動(dòng)開啟/結(jié)束會(huì)話這也是Countly默認(rèn)推薦的模式。如果是舊版本SDK可能會(huì)看到類似Countly.Init(https://..., appKey)這種極簡(jiǎn)寫法。功能上等價(jià)但我個(gè)人更喜歡新版配置類因?yàn)椴挥糜泤?shù)順序。3.2 會(huì)話管理在Unity生命周期里的落點(diǎn)Countly的“會(huì)話”概念對(duì)應(yīng)的是玩家使用App的一段連續(xù)時(shí)間。自動(dòng)模式下SDK會(huì)在應(yīng)用啟動(dòng)時(shí)自動(dòng)開啟會(huì)話應(yīng)用切后臺(tái)后暫停重新回前臺(tái)再恢復(fù)。這對(duì)大多數(shù)游戲項(xiàng)目都是合理的。如果你需要更精準(zhǔn)地定義“一局游戲”的開始和結(jié)束比如玩家從大廳進(jìn)入戰(zhàn)斗才算一個(gè)會(huì)話那就得開啟手動(dòng)會(huì)話管理Countly.SessionBegin(); // 游戲?qū)诌壿?.. Countly.SessionEnd();我早期接的時(shí)候其實(shí)踩過(guò)一個(gè)邏輯坑在場(chǎng)景加載時(shí)手動(dòng)調(diào)用SessionBegin但忘了在退出對(duì)局時(shí)調(diào)用SessionEnd結(jié)果后臺(tái)顯示會(huì)話時(shí)長(zhǎng)越累計(jì)越長(zhǎng)。如果以手動(dòng)模式管理會(huì)話一定要保證Begin和End成對(duì)出現(xiàn)最好的辦法是封裝成一個(gè)自定義Manager在進(jìn)入和退出場(chǎng)景的鉤子里統(tǒng)一調(diào)用。3.3 第一次驗(yàn)數(shù)據(jù)后臺(tái)看實(shí)時(shí)事件初始化一旦跑通先別著急鋪量埋點(diǎn)先發(fā)一個(gè)沒(méi)有參數(shù)的事件驗(yàn)證鏈路Countly.RecordEvent(app_started);運(yùn)行游戲后在Countly后臺(tái)左側(cè)菜單打開“實(shí)時(shí)數(shù)據(jù)”如果看到app_started事件開始跳動(dòng)就說(shuō)明SDK到服務(wù)端的鏈路是通的。這一步驗(yàn)證的意義非常大你會(huì)發(fā)現(xiàn)很多問(wèn)題在第一步就暴露了比如AppKey不對(duì)、服務(wù)器URL寫錯(cuò)、HTTPS證書不被信任等。鏈路通了后面所有埋點(diǎn)才有意義。4. 自定義事件的設(shè)計(jì)命名規(guī)范、參數(shù)維度和后續(xù)統(tǒng)計(jì)Countly事件模塊是整個(gè)埋點(diǎn)系統(tǒng)的核心也是我用得最多的功能。它的模型是一個(gè)事件由Key、Count、Sum和Segmentation組成。4.1 RecordEvent重載的幾種用法SDK提供了多個(gè)重載按常見(jiàn)需求排列// 最簡(jiǎn)單的只記錄事件發(fā)生了一次 Countly.RecordEvent(level_complete); // 帶維度參數(shù)比如記錄關(guān)卡完成時(shí)獲得了多少顆星 Countly.RecordEvent(level_complete, new Dictionarystring, object { { level, 3 }, { result, win }, { stars, 2 } }); // 帶計(jì)數(shù)和總和比如記錄一次內(nèi)購(gòu)金額可以累加 Countly.RecordEvent(iap_success, new Dictionarystring, object { { product_id, com.xxx.gem100 } }, 1, 6.0f);第三個(gè)參數(shù)count表示事件發(fā)生的次數(shù)權(quán)重第四個(gè)參數(shù)sum表示數(shù)值累加量。比如一次性購(gòu)買了6元的道具count1sum6后臺(tái)會(huì)根據(jù)sum自動(dòng)統(tǒng)計(jì)總收入。4.2 Segmentation參數(shù)的隱藏約束Segmentation是Countly里最靈活也最容易被濫用的地方。它本質(zhì)上是一個(gè)字符串到值的字典支持字符串、數(shù)字、布爾等類型。但要注意Segmentation里的值會(huì)在后臺(tái)以字符串形式存儲(chǔ)和展示。如果你希望對(duì)某個(gè)維度做數(shù)值區(qū)間排序或平均值計(jì)算建議在上報(bào)前自己先做一次預(yù)處理把區(qū)間歸好類再傳。我實(shí)際使用的規(guī)律是事件Key用下劃線連接全部小寫比如level_start、level_complete、item_equip、iap_success。Segmentation里的Key也是小寫下劃線而Value盡量保持同一種類型。同一事件里這次傳int下次傳string后臺(tái)的聚合報(bào)表會(huì)顯示得很亂。4.3 事件模型設(shè)計(jì)的經(jīng)驗(yàn)從統(tǒng)計(jì)需求反推埋點(diǎn)埋點(diǎn)不是把想得到的都記下來(lái)而是先想清楚“我要看什么報(bào)表”再?zèng)Q定埋什么事件。舉我們項(xiàng)目當(dāng)時(shí)的一個(gè)例子運(yùn)營(yíng)要評(píng)估裝備強(qiáng)化系統(tǒng)的健康度需要回答三個(gè)問(wèn)題有多少玩家進(jìn)入了強(qiáng)化頁(yè)面從強(qiáng)化頁(yè)到首次強(qiáng)化操作轉(zhuǎn)化率是多少每次強(qiáng)化操作消耗了多少金幣根據(jù)這三個(gè)問(wèn)題我們?cè)O(shè)計(jì)了三個(gè)事件equip_strengthen_view、equip_strengthen_click、equip_strengthen_cost。第一個(gè)看頁(yè)面曝光第二個(gè)看轉(zhuǎn)化第三個(gè)帶上gold_cost這個(gè)sum值算消耗總量。這就比單純的“strengthen”一個(gè)事件覆蓋所有情況清晰很多。4.4 長(zhǎng)駐事件和一次性事件的區(qū)分有些事件是高頻且短時(shí)的比如每次攻擊觸發(fā)一次有些是低頻但有數(shù)值意義的比如每日登錄。Countly官方建議控制事件上報(bào)頻率避免短時(shí)間產(chǎn)生海量事件把服務(wù)器寫入打滿。如果確實(shí)需要統(tǒng)計(jì)高頻行為我建議在客戶端先做聚合攢到一定閾值或者按時(shí)間批量上報(bào)一次而不是每個(gè)動(dòng)作都調(diào)用RecordEvent。我見(jiàn)過(guò)一個(gè)最典型的反面例子同事把子彈發(fā)射每個(gè)frame都記一次事件上線當(dāng)天服務(wù)器CPU就報(bào)警了。所以高頻行為一定要做節(jié)流、聚合或者抽樣。5. 用戶屬性與設(shè)備ID從匿名數(shù)據(jù)到可識(shí)別用戶只記錄事件看到的是一堆離散的行為點(diǎn)難以關(guān)聯(lián)到具體一個(gè)人。Countly提供用戶屬性模塊可以把某個(gè)玩家在不同時(shí)間、不同設(shè)備產(chǎn)生的行為串聯(lián)起來(lái)。5.1 默認(rèn)匿名標(biāo)識(shí)和登錄后切換Countly在玩家首次啟動(dòng)時(shí)會(huì)生成一個(gè)匿名的設(shè)備ID所有后續(xù)事件都掛在這個(gè)ID下面。這在用戶未登錄階段夠用了但游戲通常有賬號(hào)體系玩家換設(shè)備登錄后服務(wù)器就需要把前后兩段數(shù)據(jù)合并起來(lái)。SDK提供了兩個(gè)關(guān)鍵方法// 給用戶設(shè)置自定義ID不走合并邏輯謹(jǐn)慎使用 Countly.ChangeDeviceId(player_uid_12345); // 給用戶設(shè)置自定義ID同時(shí)把舊ID的數(shù)據(jù)合并到新ID下 Countly.ChangeDeviceIdWithMerge(player_uid_12345);我的建議是在登錄成功回調(diào)里調(diào)用ChangeDeviceIdWithMerge這樣玩家登錄前的匿名行為數(shù)據(jù)比如新手引導(dǎo)進(jìn)度、首啟時(shí)間就能完整掛到真實(shí)賬號(hào)下面。而如果明確知道這是一個(gè)全新的賬號(hào)不需要保留之前匿名數(shù)據(jù)那用ChangeDeviceId更干凈。5.2 用戶屬性的常用字段Countly用戶屬性包括內(nèi)置字段和自定義字段兩類。內(nèi)置字段有name、username、email、gender、birth year等直接調(diào)用對(duì)應(yīng)SetterCountly.UserData.SetProperty(name, 玩家昵稱); Countly.UserData.SetProperty(level, 12); Countly.UserData.SetProperty(vip_level, 3); Countly.UserData.SetProperty(guild_id, g12345); Countly.UserData.Save();這里有個(gè)小細(xì)節(jié)舊版SDK里UserData相關(guān)的API可能長(zhǎng)這樣新版我記得有些版本改成了通過(guò)配置器統(tǒng)一設(shè)置SDK文檔里有明確說(shuō)明。代碼里以當(dāng)前SDK版本為準(zhǔn)。但核心邏輯沒(méi)變先設(shè)置屬性再調(diào)用Save提交到服務(wù)端。如果不調(diào)用Save屬性不會(huì)真正上報(bào)。5.3 用戶屬性上報(bào)時(shí)機(jī)不要在每一幀都去Save用戶屬性服務(wù)端會(huì)有壓力。常規(guī)做法是關(guān)鍵節(jié)點(diǎn)才做一次整體上報(bào)比如登錄成功時(shí)、玩家等級(jí)變化時(shí)、重要信息修改時(shí)。我通常會(huì)把用戶屬性更新的邏輯收斂到一個(gè)方法里所有需要更新的地方調(diào)用同一個(gè)入口避免散落各處。注意用戶屬性可能涉及個(gè)人信息。如果游戲有隱私合規(guī)要求上報(bào)前想清楚哪些字段是非必要不可收集的能不上報(bào)就不上報(bào)能用匿名標(biāo)識(shí)的就別用真實(shí)手機(jī)號(hào)或社交賬號(hào)。6. 崩潰日志、后臺(tái)數(shù)據(jù)核對(duì)和調(diào)試經(jīng)驗(yàn)埋點(diǎn)工作做得再多如果線上崩潰情況一無(wú)所知產(chǎn)品迭代還是會(huì)心慌。Countly除了事件統(tǒng)計(jì)還內(nèi)置了崩潰日志采集能力這一點(diǎn)在Unity項(xiàng)目里尤其有用。6.1 崩潰采集的接入方式在初始化配置里開啟崩潰采集var config new CountlyConfiguration { ServerUrl https://metrics.yourgame.com, AppKey 你的AppKey, CrashReports true, EnableDebug false }; Countly.Init(config);SDK會(huì)監(jiān)聽(tīng)未捕獲的異常App下一次啟動(dòng)時(shí)上報(bào)崩潰堆棧。對(duì)Unity來(lái)說(shuō)C#層的異常能被捕獲到一些底層Native崩潰也能部分采集。崩潰信息在后臺(tái)Crash菜單下按分類展示能看到崩潰次數(shù)、影響的版本和堆棧信息。6.2 調(diào)試模式幫你核對(duì)數(shù)據(jù)鏈路開發(fā)階段把EnableDebug打開Unity Console里會(huì)看到類似這樣的日志Countly Request: POST https://metrics.yourgame.com/i Payload: {app_key:...,device_id:...,events:[...]}這段日志價(jià)值極高。我每次新增埋點(diǎn)時(shí)都會(huì)先看請(qǐng)求里是否真的帶上了對(duì)應(yīng)的事件名和參數(shù)。不要只上代碼不查包我曾經(jīng)遇到過(guò)編譯沒(méi)報(bào)錯(cuò)但事件名在另一處被覆蓋導(dǎo)致后臺(tái)一直收不到數(shù)據(jù)的情況。Console里的payload是最直接的證據(jù)鏈。6.3 排查后臺(tái)收不到數(shù)據(jù)的常見(jiàn)原因如果SDK日志顯示請(qǐng)求成功但后臺(tái)就是看不到數(shù)據(jù)按順序排查四件事AppKey是否正確復(fù)制完整有沒(méi)有混入空格或換行。ServerUrl是否以HTTP/HTTPS開頭且路徑?jīng)]有多余后綴。服務(wù)器是否開啟了“IP白名單校驗(yàn)”如果開啟了但SDK所在出口IP不在白名單里請(qǐng)求會(huì)被拒絕日志里會(huì)看到403。設(shè)備時(shí)間是否有問(wèn)題SDK上報(bào)時(shí)會(huì)附本地時(shí)間戳設(shè)備時(shí)間被玩家篡改到過(guò)去幾年上報(bào)的數(shù)據(jù)會(huì)落到奇怪的時(shí)間區(qū)間后臺(tái)默認(rèn)篩選看不到。其中IP白名單校驗(yàn)這個(gè)坑我最開始沒(méi)意識(shí)到查了整整一個(gè)下午后來(lái)去后臺(tái)安全設(shè)置里才發(fā)現(xiàn)默認(rèn)開啟了IP綁定。自建服務(wù)器時(shí)建議直接把IP綁定關(guān)掉或者把相關(guān)IP加進(jìn)去不然很容易在換網(wǎng)絡(luò)環(huán)境后突然收不到數(shù)據(jù)。7. 平臺(tái)差異和上線后要注意的坑Unity項(xiàng)目不只在編輯器里跑不同平臺(tái)的限制會(huì)讓同一套代碼的埋點(diǎn)表現(xiàn)完全不同。下面列的是我實(shí)際遇到過(guò)的平臺(tái)相關(guān)問(wèn)題也是我覺(jué)得每個(gè)接Countly的Unity項(xiàng)目都要提前看的注意事項(xiàng)。7.1 Android發(fā)布權(quán)限、混淆和Release驗(yàn)證Android工程需要確認(rèn)AndroidManifest里有網(wǎng)絡(luò)權(quán)限uses-permission android:nameandroid.permission.INTERNET /如果用了代碼混淆ProGuard/R8需要在混淆配置里保留Countly相關(guān)類-keep class ly.count.** { *; }這條我是在線上版本測(cè)試時(shí)發(fā)現(xiàn)的Release包打出來(lái)后其他功能都正常但埋點(diǎn)數(shù)據(jù)明顯偏少一開始還以為是SDK出問(wèn)題了后來(lái)發(fā)現(xiàn)是混淆把SDK內(nèi)部用于反射的類名改了。加了keep規(guī)則后數(shù)據(jù)立刻恢復(fù)正常。7.2 iOS平臺(tái)傳輸安全限制iOS默認(rèn)的App Transport Security要求請(qǐng)求必須走HTTPS如果你的Countly服務(wù)器只支持HTTP需要在Info.plist里做例外配置。但既然有選擇我更建議直接給服務(wù)器配好HTTPS證書一勞永逸不僅省了配置也避免被審核重點(diǎn)盯。7.3 WebGL、桌面和包體影響WebGL上跑Countly會(huì)遇到跨域問(wèn)題服務(wù)器需要配置CORS允許瀏覽器環(huán)境下發(fā)起請(qǐng)求。我自己的項(xiàng)目沒(méi)上WebGL這方面只是在社區(qū)看到不少人在問(wèn)可以先記住這個(gè)坑真要接的時(shí)候再針對(duì)性配置。桌面端Windows和macOS反而最簡(jiǎn)單基本引用SDK后就能直接跑。包體方面Countly Unity SDK本身只有幾百KB對(duì)包體影響很小我這邊的Android包加入SDK后體積增長(zhǎng)基本可以忽略。7.4 開發(fā)版和正式版一定要用不同AppKey我專門吃過(guò)一次虧開發(fā)階段和正式版用了同一套AppKey結(jié)果開發(fā)機(jī)的調(diào)試事件把正式用戶數(shù)據(jù)沖得很亂漏斗分析完全沒(méi)法看。后來(lái)在Countly后臺(tái)給開發(fā)環(huán)境單獨(dú)建了一個(gè)應(yīng)用用不同的AppKey開發(fā)數(shù)據(jù)和生產(chǎn)數(shù)據(jù)徹底隔離。建議所有從零接SDK的人都從第一天就這么干。這個(gè)改起來(lái)不復(fù)雜代碼里用一個(gè)宏區(qū)分編譯環(huán)境根據(jù)宏選擇不同配置即可#if DEVELOPMENT_BUILD private const string AppKey 開發(fā)環(huán)境AppKey; #else private const string AppKey 正式環(huán)境AppKey; #endif8. 集成后續(xù)的擴(kuò)展方向和我的體會(huì)Countly接入穩(wěn)定后我又陸續(xù)探索了幾個(gè)擴(kuò)展方向這里一并記錄下來(lái)當(dāng)作給未來(lái)的自己留個(gè)備忘。事件和用戶畫像只是Countly的基礎(chǔ)能力。它還有推送通知模塊Unity SDK支持本地通知和遠(yuǎn)程推送可以做到“給7日未登錄用戶發(fā)push”的運(yùn)營(yíng)玩法。雖然我的項(xiàng)目暫時(shí)沒(méi)接但了解到SDK里已經(jīng)有對(duì)應(yīng)模塊后面需求來(lái)了不用換方案。另一個(gè)方向是服務(wù)端查詢能力。Countly提供了REST API可以用來(lái)自動(dòng)導(dǎo)出報(bào)表接入團(tuán)隊(duì)自己的數(shù)據(jù)看板。如果哪天團(tuán)隊(duì)要從“全能型后臺(tái)”轉(zhuǎn)到“內(nèi)部數(shù)據(jù)平臺(tái)”這層擴(kuò)展通道是通的。最后說(shuō)幾句個(gè)人體會(huì)。埋點(diǎn)這件事初期投入兩三天就能看到效果但真正的價(jià)值在線上的長(zhǎng)期積累。最忌諱的是先鋪一百個(gè)事件再慢慢看而是應(yīng)該先埋幾個(gè)關(guān)鍵事件驗(yàn)證上報(bào)、存儲(chǔ)、展示再逐步擴(kuò)充。我自己的節(jié)奏是每次版本更新只加五到十個(gè)精確定義的事件數(shù)據(jù)質(zhì)量反而比一次性大量埋點(diǎn)高得多。再分享一個(gè)小技巧作為收尾把全部事件名集中放在一個(gè)靜態(tài)類里管理而不是散落在各業(yè)務(wù)腳本中。這樣做的好處是代碼里查事件名不容易拼錯(cuò)后臺(tái)報(bào)表里的命名風(fēng)格也統(tǒng)一。后期要下線某個(gè)事件時(shí)也能一眼看出哪些地方還在引用它。這個(gè)習(xí)慣堅(jiān)持了半年整個(gè)項(xiàng)目的事件體系始終清晰可控比任何花哨工具都管用。