この記事は Wanoグループ Advent Calendar 2017の11日目の記事になります。
社内共有ツールの方で随時書いてたら肝心のこっちに書くネタがない...
GoogleAnalytics と FirebaseAnalytics両方に送りたい
ネイティブアプリのログはFirebaseの方にどんどん寄せていこう、というGoogle先生の強い意思を感じる今日この頃です。
しかしいかんせんGUIがわかりづらい。
特に画面間のユーザー移動を出そうとしただけでも、Firebaseの裏側で蓄積されているBigQueryのデータを直接いじらなければならなくなったりします。
一方、GoogleAnalyticsは歴史の蓄積があり、エンジニア以外の人員もある程度見方がわかっていることも多いかと思います。
今回はFireBaseだけでなく、GoogleAnalyticsの画面でも実験的に画面遷移イベントやアクションイベントを送ってみます。
なお、FirebaseからGoogleAnalyticsへの同期機能もあるのですが、こいつもまた取り回しが悪いです。
ここでは自分たちでハンドリングしたいため、手動で両送信します。
object Logger {
fun sendScreenName(activity : Activity, screenName : String){
val app = MainApplication.getApplication()
val tracker = app.defaultTracker
try {
//Google Analytics
tracker.setScreenName(screenName)
tracker.send(HitBuilders.ScreenViewBuilder().build())
//Firebase Analytics
var mHandler = Handler(Looper.getMainLooper())
mHandler.post(Runnable {
var fAnalytics = app.firebaseAnalytics;
fAnalytics.setCurrentScreen(activity , screenName , null)
// ここに処理
})
} catch (error : Exception) {
Log.e(TAG , error.toString())
}
}
fun sendEvent(category : String , action : String , labelKey : String , labelValue :String , numValue : Long){
val app = MainApplication.getApplication()
val firebaseAnalytics = app.firebaseAnalytics
val tracker = app.defaultTracker
try {
// GA
tracker.send(HitBuilders.EventBuilder()
.setCategory(category)
.setAction(action)
.setLabel(labelKey + ":" + labelValue)
.setValue(numValue)
.build()
)
// FA
val bundle = Bundle()
bundle.putString(labelKey , labelValue)
bundle.putLong("value" , numValue)
firebaseAnalytics.logEvent(category + "_" + action , bundle)
} catch (error : Exception) {
Log.e("¥TAG , error.toString())
}
}
}
マッピング
例えば、GoogleAnalyticsの方には生えているCategoryという概念はFirebaseの方にはなく、BundleをKVS的に扱って自在に値を格納できるだけです。
なので一旦独自のマッピングルールを設けて送信することにしています。
Firebaseの方の
firebaseAnalytics.logEvent(category + "_" + action , bundle)
という部分ですね。
また、Google Analyticsの方には連続した数値を専門に扱う .setValue(数値)
が生えているのですが、これもFirebase上はbundleの前に等価なため、苦肉の策でvalueというkeyを追加しています。valueとはって話ですね。
その他
また、これを搭載したアプリでは、実際のイベント送信のトリガーはReactNativeから送っているので一応ついでに載せておきます。
受信側
@ReactMethod
fun setScreenName(screenName : String){
var activity = getCurrentActivity();
if (activity != null){
Logger.sendScreenName(activity , screenName)
}
}
@ReactMethod
fun sendEvent(category : String , action : String , labelKey : String , labelValue :String, numValue : Int){
Logger.sendEvent(category , action , labelKey , labelValue , numValue.toLong())
}
@ReactMethod
fun setUserID(userID :String){
MainApplication.getApplication().setUserID(userID)
}
送信側
import { NativeModules } from 'react-native';
const bridgeModuleNative : any = NativeModules["BridgeModule"];
export default class BridgeModule {
....
public static setScreenName(name : string){
bridgeModuleNative.setScreenName(name);
}
public static sendEvent(category : string , action : string , labelKey : string , labelValue :string , numValue : number = 1){
const sendNum = numValue ? numValue : 1;
bridgeModuleNative.sendEvent(category , action , labelKey , labelValue , sendNum);
}
public static setUserID(userID :string){
bridgeModuleNative.setUserID(userID);
}
}