Google Analytics 적용하기
GA를 적용하고 테스트해 보았다.
data를 기반으로 UX를 설계하고, 사용자들이 많이 사용하는 기능에 대해서 알 필요가 있을려면 데이타를 수집할 수 있어야 한다.
계산기 앱을 만들었는데 거기에 GA를 적용해 보았다.
build.gradle
compile "com.google.android.gms:play-services-analytics:7.0.0"
proguard-rules.pro
-dontwarn com.google.android.gms.common.GooglePlayServicesUtil
-keep class com.google.android.gms.**
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
....
<application
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
GAConst.java
// 구글에서 Analytics 계정을 하나 생성하고, tracking ID를 발급받는다. public class GAConst {
public static final String trackingId = "UA-XXXXXX";
public static final double sampleRate = 100d; // 0.01 ~ 100
}
GAHelper.java
package com.mdiwebma.calculator.ga;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.SparseArray;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.mdiwebma.base.ApplicationKeeper;
import com.mdiwebma.base.BuildConfig;
import com.mdiwebma.base.debug.TraceUtils;
import com.mdiwebma.base.utils.VersionUtils;
/**
* @author djkim
*/
public class GAHelper {
private final boolean enabled;
private Tracker tracker;
private boolean isNewSession = true;
private String lastScreenName;
private static class LazyHolder {
private static final GAHelper INSTANCE = new GAHelper();
}
public static GAHelper getInstance() {
return LazyHolder.INSTANCE;
}
private GAHelper() {
enabled = init();
}
private boolean init() {
try {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(ApplicationKeeper.get());
return resultCode == ConnectionResult.SUCCESS;
} catch (Exception ignored) {
return false;
}
}
public void sendEvent(String category, String action) {
if (enabled) {
sendEvent(category, action, null);
}
}
public void sendEvent(String category, String action, String label) {
if (enabled) {
sendEvent(category, action, label, null, null);
}
}
public void sendEvent(String category, String action, @Nullable String label, @Nullable Long value, @Nullable SparseArray<String> customDimensions) {
if (enabled) {
HitBuilders.EventBuilder eventBuilder = new HitBuilders.EventBuilder(category, action);
if (isNewSession) {
isNewSession = false;
eventBuilder.setNewSession();
}
if (!TextUtils.isEmpty(label)) {
eventBuilder.setLabel(label);
}
if (value != null) {
eventBuilder.setValue(value);
}
if (customDimensions != null) {
for (int i = 0; i < customDimensions.size(); i++) {
int index = customDimensions.keyAt(i);
String dimension = customDimensions.get(index);
eventBuilder.setCustomDimension(index, dimension);
}
}
getTracker().send(eventBuilder.build());
if (BuildConfig.DEBUG) {
dispatchLocalHit();
TraceUtils.v("sendEvent=%s > %s %s %s", category, action, label != null ? label : "", value != null ? String.format("value=%d", value) : "");
}
}
}
public void sendEvent(GAEvent event) {
if (enabled) {
sendEvent(event.category, event.action, event.label, null, null);
}
}
public void sendMenuWhich(GAEvent event, long which) {
if (enabled) {
sendSetting(event, String.valueOf(which));
}
}
public void sendSetting(GAEvent event, long value) {
if (enabled) {
sendSetting(event, String.valueOf(value));
}
}
public void sendSetting(GAEvent event, boolean value) {
if (enabled) {
sendSetting(event, String.valueOf(value));
}
}
public void sendSetting(GAEvent event, String value) {
if (enabled) {
String label;
if (!TextUtils.isEmpty(event.label)) {
label = event.label + "_" + value;
} else {
label = event.action + "_" + value;
}
sendEvent(event.category, event.action, label, null, null);
}
}
public void sendScreen(@NonNull String screenName) {
if (enabled) {
HitBuilders.AppViewBuilder appViewBuilder = new HitBuilders.AppViewBuilder();
if (isNewSession) {
isNewSession = false;
appViewBuilder.setNewSession();
}
if (lastScreenName != null) {
appViewBuilder.setCustomDimension(1, lastScreenName);
}
Tracker tracker = getTracker();
tracker.setScreenName(screenName);
tracker.send(appViewBuilder.build());
lastScreenName = screenName;
if (BuildConfig.DEBUG) {
dispatchLocalHit();
TraceUtils.v("sendScreen=%s", screenName);
}
}
}
@NonNull
private Tracker getTracker() {
if (tracker == null) {
synchronized (this) {
if (tracker == null) {
GoogleAnalytics analytics = GoogleAnalytics.getInstance(ApplicationKeeper.get());
tracker = analytics.newTracker(GAConst.trackingId);
tracker.setAppId(ApplicationKeeper.get().getPackageName());
tracker.setAppName(VersionUtils.getSimpleAppId());
tracker.setAppVersion(VersionUtils.getVersionName());
//tracker.setSampleRate(GAConst.sampleRate);
tracker.enableExceptionReporting(true);
}
}
}
return tracker;
}
public void dispatchLocalHit() {
GoogleAnalytics.getInstance(ApplicationKeeper.get()).dispatchLocalHits();
}
}
GAEvent.jva 이벤트 정의
public enum GAEvent {
KEYPAD_CLEAR("keypad", "clear", null),
KEYPAD_ALL_CLEAR("keypad", "all_clear", null),
KEYPAD_PERCENT("keypad", "percent", null),
KEYPAD_ROUND_OPEN("keypad", "round_open", null),
KEYPAD_ROUND_CLOSE("keypad", "round_close", null),
KEYPAD_ROUND_OPENCLOSE("keypad", "round_openclose", null),
KEYPAD_ROUND_OPEN_OR_CLOSE("keypad", "round_open_or_close", null),
KEYPAD_ROUND_DIVIDE("keypad", "round_divide", null),
KEYPAD_ROUND_MULTIPLY("keypad", "round_multiply", null),
KEYPAD_MEMORY_RETURN("keypad", "memory_return", null),
KEYPAD_MEMORY_CLEAR("keypad", "memory_clear", null),
KEYPAD_MEMORY_PLUS("keypad", "memory_plus", null),
KEYPAD_MEMORY_MINUS("keypad", "memory_minus", null),
KEYPAD_MEMORY_SET("keypad", "memory_set", null),
KEYPAD_PLUS_MINUS("keypad", "plus_minus", null),
KEYPAD_EQUAL("keypad", "equal", null),
KEYPAD_UNDO("keypad", "undo", null),
KEYPAD_CLEAR_UNDO("keypad", "clear_undo", null),
KEYPAD_PLUS("keypad", "plus", null),
KEYPAD_MINUS("keypad", "minus", null),
KEYPAD_MULTIPLY("keypad", "multiply", null),
KEYPAD_DIVIDE("keypad", "divide", null),
KEYPAD_POW("keypad", "pow", null),
KEYPAD_E("keypad", "e", null),
KEYPAD_PI("keypad", "pi", null),
KEYPAD_00("keypad", "00", null),
KEYPAD_000("keypad", "000", null),
KEYPAD_0000("keypad", "0000", null),
KEYPAD_N000("keypad", "n000", null),
MAIN_COPY_EXPR("main", "copy_expr", null),
MAIN_COPY_RESULT("main", "copy_result", null),
MAIN_HISTORY_MENU("main", "history_menu", null),
MAIN_MEMORY_MENU("main", "memory_menu", null),
MAIN_SHARE_THIS_APP("main", "share_this_app", null),
HISTORY_OPEN_LAYER("history", "open_layer", null),
HISTORY_ITEM_SELECTED("history", "item_selected", null),
HISTORY_ITEM_MENU("history", "item_menu", null),
HISTORY_FAVORITE("history", "favorite", null),
HISTORY_COPY_EXPR("history", "copy_expr", null),
HISTORY_REMOVE_ALL("history", "remove_all", null),
SETTINGS_DIVIDE_SYMBOL("settings", "divide_symbol", null),
SETTINGS_SHOW_MEMORY_BUTTON("settings", "show_memory_button", null),
SETTINGS_SHOW_LONG_CLICK_DESC("settings", "show_long_click_desc", null),
SETTINGS_VIBRATE_ON_TOUCH("settings", "vibrate_on_touch", null),
SETTINGS_KEEP_SCREEN_ON("settings", "keep_screen_on", null),
SETTINGS_GROUPING_SEPARATOR("settings", "grouping_separator", null),
SETTINGS_GROUPING_METHOD("settings", "grouping_method", null),
SETTINGS_NUMBERS_SIZE("settings", "numbers_size", null),;
public final String category;
public final String action;
public final String label;
GAEvent(String category, String action, String label) {
this.category = category;
this.action = action;
this.label = label;
}
}
Activity 생성, 버튼 클릭시, 메뉴 선택시 GAEvent로 보내기
// Activity 생성시 onCreate(..) {
GAHelper.getInstance().sendScreen("SettingsActivity");// 버튼 클릭시 @LongClick(R.id.num0)
public void onLongClickNum0(View v) {
appendNumberExpr("000");
calc();
GAHelper.getInstance().sendEvent(GAEvent.KEYPAD_000);
} // 메뉴 선택시 DialogHelper.showItems(context, items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { GAHelper.getInstance().sendMenuWhich(GAEvent.MAIN_MEMORY_MENU, which); switch (which) {
24시간 마다 세팅값 GAEvent로 보내기
public static void maybeSendSettingsToGA() {
if (System.currentTimeMillis() - Settings.lastSendSettingsTime.getValue() > DateUtils.DAY_IN_MILLIS) {
Settings.lastSendSettingsTime.setValue(System.currentTimeMillis());
// send settings
CommonExecutors.execute(new Runnable() {
@Override
public void run() {
if (BuildConfig.DEBUG) {
TraceUtils.v("maybeSendSettingsToGA");
}
GAHelper helper = GAHelper.getInstance();
helper.sendSetting(GAEvent.SETTINGS_DIVIDE_SYMBOL, Settings.multiplyDivideSymbolComStyle.getValue());
helper.sendSetting(GAEvent.SETTINGS_SHOW_MEMORY_BUTTON, Settings.showMemoryButton.getValue());
helper.sendSetting(GAEvent.SETTINGS_SHOW_LONG_CLICK_DESC, Settings.showLongClickDescription.getValue());
helper.sendSetting(GAEvent.SETTINGS_VIBRATE_ON_TOUCH, Settings.vibrateClickButton.getValue());
helper.sendSetting(GAEvent.SETTINGS_KEEP_SCREEN_ON, Settings.keepScreenOn.getValue());
helper.sendSetting(GAEvent.SETTINGS_GROUPING_SEPARATOR, Settings.digitGroupingSeparator.getValue());
helper.sendSetting(GAEvent.SETTINGS_GROUPING_METHOD, Settings.digitGroupingMethod.getValue());
helper.sendSetting(GAEvent.SETTINGS_NUMBERS_SIZE, Settings.numbersSize.getValue());
}
});
}
}
GA사이트에서 확인하기
- 행동 흐름 Activity 플로우
- Event 수 (버튼 클릭 수, 세팅 설정 비율)