Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 97 additions & 3 deletions Runnect-iOS/Runnect-iOS/Global/Analytics/GAEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,81 @@
import Foundation

struct GAEvent {

struct Param {
static let source = "source"
static let courseId = "course_id"
static let distanceM = "distance_m"
static let pointCount = "point_count"
static let drawingTimeSec = "drawing_time_sec"
static let departureName = "departure_name"
static let elapsedSec = "elapsed_sec"
static let totalTimeSec = "total_time_sec"
static let totalDistanceM = "total_distance_m"
static let avgPaceSecPerKm = "avg_pace_sec_per_km"
static let pauseCount = "pause_count"
static let totalPauseSec = "total_pause_sec"
static let pauseDurationSec = "pause_duration_sec"
static let completionRate = "completion_rate"
static let abandonReason = "abandon_reason"
static let targetDistanceM = "target_distance_m"
static let countdownSecRemaining = "countdown_sec_remaining"
static let method = "method"
static let isNewUser = "is_new_user"
static let errorCode = "error_code"
static let nicknameLength = "nickname_length"
static let shareTarget = "share_target"
static let keyword = "keyword"
static let resultCount = "result_count"
static let storageType = "storage_type"
static let daysSinceCreated = "days_since_created"
static let courseCount = "course_count"
static let recordId = "record_id"
static let launchType = "launch_type"
static let referrer = "referrer"
static let deeplinkUrl = "deeplink_url"
static let targetScreen = "target_screen"
static let screenName = "screen_name"
static let withdrawReason = "withdraw_reason"
static let daysSinceSignup = "days_since_signup"
static let totalRuns = "total_runs"
static let totalCourses = "total_courses"
static let changedFields = "changed_fields"
}

struct View {

// 진입 화면
static let viewHome = "view_home" // 앱 실행
static let viewSocialLogin = "view_social_login"

// 코스발견
static let viewCourseSearch = "view_course_search"
static let viewCourseDetail = "view_course_detail"
static let viewUserProfile = "view_user_profile"
static let viewCourseUpload = "view_course_upload"

// 마이페이지
static let viewSuccessLogout = "view_success_logout"
static let viewSuccessWithdraw = "view_success_withdraw"

// 코스 그리기 / 러닝
static let viewGiveNickname = "view_give_nickname"
static let viewCourseDrawing = "view_course_drawing"
static let viewCourseCompleteResult = "view_course_complete_result"
static let viewCountdown = "view_countdown"
static let viewEndRun = "view_end_run"

// 코스 발견 / 보관함
static let viewDiscoverPick = "view_discover_pick"
static let viewStorageMyDraw = "view_storage_my_draw"
static let viewStorageScrap = "view_storage_scrap"
static let viewMyDrawDetail = "view_my_draw_detail"
static let viewMyHistoryDetail = "view_my_history_detail"

// 마이페이지 추가
static let viewMyReward = "view_my_reward"
static let viewEditProfile = "view_edit_profile"
}

struct Button {
Expand Down Expand Up @@ -80,9 +140,43 @@ struct GAEvent {
static let clickJoinInCourseDiscovery = "click_join_in_course_discovery"
static let clickJoinInStorage = "click_join_in_storage"
static let clickJoinInMyPage = "click_join_in_my_page"

// 신규 클릭 이벤트
static let clickCancelCountdown = "click_cancel_countdown"
static let clickRunFromDetail = "click_run_from_detail"
static let clickRunFromStorage = "click_run_from_storage"
static let clickUnscrap = "click_unscrap"
static let clickSaveRunRecord = "click_save_run_record"
static let clickShareRunRecord = "click_share_run_record"
static let clickRunAgain = "click_run_again"
static let clickMyDrawCourse = "click_my_draw_course"
static let clickNicknameSkip = "click_nickname_skip"
static let clickShareAfterCourseComplete = "click_share_after_course_complete"
static let clickRunAgainFromHistory = "click_run_again_from_history"
}

struct Share {
static let openShareLink = "open_share_link"
}

struct Action {
static let loginSuccess = "action_login_success"
static let loginFail = "action_login_fail"
static let nicknameComplete = "action_nickname_complete"
static let courseDrawingStart = "action_course_drawing_start"
static let courseDrawingComplete = "action_course_drawing_complete"
static let runStart = "action_run_start"
static let runPause = "action_run_pause"
static let runResume = "action_run_resume"
static let runComplete = "action_run_complete"
static let runAbandon = "action_run_abandon"
static let courseSearchExecute = "action_course_search_execute"
static let courseUploadComplete = "action_course_upload_complete"
static let editProfileComplete = "action_edit_profile_complete"
}

struct System {
static let appOpen = "sys_app_open"
static let deeplinkOpen = "sys_deeplink_open"
}
}
5 changes: 5 additions & 0 deletions Runnect-iOS/Runnect-iOS/Global/Analytics/GAManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final class GAManager {
case screen(screenName: String)
case button(buttonName: String)
case share(eventName: String, courseType: String, courseId: Int)
case custom(eventName: String, parameters: [String: Any]?)

var eventName: String {
switch self {
Expand All @@ -27,6 +28,8 @@ final class GAManager {
return "button"
case .share(let eventName, _, _):
return eventName
case .custom(let eventName, _):
return eventName
}
}

Expand All @@ -38,6 +41,8 @@ final class GAManager {
return ["button": buttonName]
case .share(_, let courseType, let courseId):
return ["course_type": courseType, "course_id": courseId]
case .custom(_, let parameters):
return parameters
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
courseId: courseId
))

let targetScreen = courseType == .publicCourse ? "CourseDetailVC" : "RunningWaitingVC"
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.System.deeplinkOpen,
parameters: [
GAEvent.Param.deeplinkUrl: incomingURL.absoluteString,
GAEvent.Param.targetScreen: targetScreen
]
))

guard let windowScene = scene as? UIWindowScene else { return }
let window = UIWindow(windowScene: windowScene)
let navigationController = UINavigationController()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,17 @@ extension CourseDetailVC {
showToastOnWindow(text: "러넥트에 가입하면 코스를 스크랩할 수 있어요")
return
}

guard let publicCourseId = publicCourseId else { return }


// 스크랩 취소 이벤트
if sender.isSelected, let courseId = self.courseId {
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.Button.clickUnscrap,
parameters: [GAEvent.Param.courseId: courseId]
))
}

scrapCourse(scrapTF: !sender.isSelected)
delegate?.didUpdateScrapState(publicCourseId: publicCourseId, isScrapped: !sender.isSelected) /// 코스 발견 UI Update 부분
marathonDelegate?.didUpdateMarathonScrapState(publicCourseId: publicCourseId, isScrapped: !sender.isSelected) // 마라톤 코스 UI
Expand Down Expand Up @@ -199,7 +207,7 @@ extension CourseDetailVC {
return
}

analyze(screenName: GAEvent.Button.clickUserProfile)
analyze(buttonName: GAEvent.Button.clickUserProfile)

guard let userId = self.userId else {return}
let userProfile = UserProfileVC()
Expand All @@ -210,6 +218,10 @@ extension CourseDetailVC {
@objc private func startButtonDidTap() {
guard handleVisitor() else { return }
guard let courseId = self.courseId else { return }
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.Button.clickRunFromDetail,
parameters: [GAEvent.Param.courseId: courseId]
))
getCourseDetailWithPath(courseId: courseId)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ class CourseEditVC: UIViewController {
setTapGesture()
addKeyboardObserver()
textViewDidChange(self.activityTextView)

if let publicCourseId = publicCourseId {
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.View.viewMyDrawDetail,
parameters: [GAEvent.Param.courseId: publicCourseId]
))
}
}

override func viewWillDisappear(_ animated: Bool) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,13 @@ extension CourseSearchVC {
let responseDto = try result.map(BaseResponse<PickedMapListResponseDto>.self)
guard let data = responseDto.data else { return }
self.analyze(buttonName: GAEvent.Button.clickTrySearchCourse)
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.Action.courseSearchExecute,
parameters: [
GAEvent.Param.keyword: keyword,
GAEvent.Param.resultCount: data.publicCourses.count
]
))
self.setData(data: data.publicCourses)
} catch {
self.setData(data: [])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ extension CourseUploadVC {
case .success(let result):
let status = result.statusCode
if 200..<300 ~= status {
if let courseId = self.courseModel?.id {
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.Action.courseUploadComplete,
parameters: [GAEvent.Param.courseId: courseId]
))
}
delegate?.didUploadCourse()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.navigationController?.popToRootViewController(animated: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ final class CourseDrawingVC: UIViewController {
self.setAddTarget()
self.bindMapView()
self.setNavigationGesture(false)
analyze(screenName: GAEvent.View.viewCourseDrawing)
}

override func viewWillDisappear(_ animated: Bool) {
Expand Down Expand Up @@ -214,6 +215,13 @@ extension CourseDrawingVC {
}

private func presentAlertVC(courseId: Int) {
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.Action.courseDrawingComplete,
// distance는 km 단위이므로 *1000하여 m으로 변환 (Android 동일)
parameters: [GAEvent.Param.courseId: courseId, GAEvent.Param.distanceM: Int(self.distance * 1000)]
))
analyze(screenName: GAEvent.View.viewCourseCompleteResult)

let alertVC = CustomAlertVC()
alertVC.modalPresentationStyle = .overFullScreen

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ extension CourseStorageVC {
viewPager.$selectedTabIndex.sink { [weak self] selectedTabIndex in
guard let self = self else { return }
self.deleteCourseButton.isHidden = (selectedTabIndex != 0)
if selectedTabIndex == 0 {
self.analyze(screenName: GAEvent.View.viewStorageMyDraw)
} else {
self.analyze(screenName: GAEvent.View.viewStorageScrap)
}
}.store(in: cancelBag)

privateCourseListView.courseDrawButtonTapped.sink { [weak self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ final class ActivityRecordDetailVC: UIViewController {
self.view = view
self.setKeyboardNotification()
self.setTapGesture()
analyze(screenName: GAEvent.View.viewMyHistoryDetail)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ final class GoalRewardInfoVC: UIViewController {
setDelegate()
register()
getGoalRewardInfo()
analyze(screenName: GAEvent.View.viewMyReward)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ final class NicknameEditorVC: UIViewController {
setLayout()
showKeyboard()
setAddTarget()
analyze(screenName: GAEvent.View.viewEditProfile)
}
}

Expand Down Expand Up @@ -195,6 +196,10 @@ extension NicknameEditorVC {
case .success(let result):
let status = result.statusCode
if 200..<300 ~= status {
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.Action.editProfileComplete,
parameters: [GAEvent.Param.changedFields: "nickname"]
))
self.delegate?.nicknameEditDidSuccess()
self.navigationController?.popViewController(animated: false)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ final class CountDownVC: UIViewController {
setLayout()
WatchSessionService.shared.sendCountdownStarted()
animateTimeLabel()

if let courseId = runningModel?.courseId {
GAManager.shared.logEvent(eventType: .custom(
eventName: GAEvent.View.viewCountdown,
parameters: [GAEvent.Param.courseId: courseId]
))
}
}
}

Expand Down
Loading