Skip to content

Commit 6c4b282

Browse files
authored
feat: Firebase Crashlytics 모듈 추가 및 내부 이벤트 반영 코드 추가 (#727)
* feat: Core모듈 내부 BBAnalyticsLogParametable, BBAnalyticsLogType, BBEventAnalyticsLog, BBLogManager 추가 - Tuist TuistScript+Templates dsym Upload를 하기 위한 Script 파일 추가 - 각 ViewController에 Analytics Event log 메서드 추가 - Crashlytics Log Method 추가 * feat: github Action PRD Lane dsym Upload Method 추가 * fix: ViewController Analytics LogEvent Method Reactor로 코드 이전
1 parent 00c1345 commit 6c4b282

31 files changed

+370
-12
lines changed

14th-team5-iOS/App/Sources/Application/AppDelegate.swift

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import UIKit
1313
import AuthenticationServices
1414
import Firebase
1515
import FirebaseCore
16-
import FirebaseAnalytics
1716
import FirebaseMessaging
1817
import KakaoSDKAuth
1918
import RxKakaoSDKAuth

14th-team5-iOS/App/Sources/Presentation/Account/AccountSignUp/ViewControllers/AccountProfileViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ final class AccountProfileViewController: BaseViewController<AccountSignUpReacto
6060
profileButton.rx.tap
6161
.throttle(RxConst.milliseconds300Interval, scheduler: MainScheduler.instance)
6262
.withUnretained(self)
63+
.do { _ in BBLogManager.analytics(logType: BBEventAnalyticsLog.clickAccountButton(entry: .profileNickNameEdit))}
6364
.bind(onNext: { $0.0.createAlertController(owner: $0.0) })
6465
.disposed(by: disposeBag)
6566

14th-team5-iOS/App/Sources/Presentation/Calendar/ViewController/MonthlyCalendarViewController.swift

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ public final class MonthlyCalendarViewController: BBNavigationViewController<Mon
5757
.disposed(by: disposeBag)
5858
}
5959

60+
public override func viewDidLoad() {
61+
super.viewDidLoad()
62+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .calendar))
63+
}
64+
6065
public override func setupUI() {
6166
super.setupUI()
6267
view.addSubviews(collectionView)
@@ -90,6 +95,7 @@ public final class MonthlyCalendarViewController: BBNavigationViewController<Mon
9095

9196
collectionView.layoutIfNeeded()
9297
collectionView.scroll(to: IndexPath(item: reactor!.currentState.pageDatasource.first!.items.count - 1, section: 0)) // 다시 리팩토링하기
98+
BBLogManager.sendError(message: "Monthly CalendarView Index out of bounds")
9399
}
94100
}
95101

14th-team5-iOS/App/Sources/Presentation/Camera/CameraDisplayViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public final class CameraDisplayViewController: BaseViewController<CameraDisplay
4848

4949
public override func viewDidLoad() {
5050
super.viewDidLoad()
51+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .cameraDetail))
5152
}
5253

5354
//MARK: Configure

14th-team5-iOS/App/Sources/Presentation/Camera/CameraViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public final class CameraViewController: BaseViewController<CameraViewReactor> {
6060

6161
public override func viewDidLoad() {
6262
super.viewDidLoad()
63+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .camera))
6364
setupCameraPermission()
6465
}
6566

14th-team5-iOS/App/Sources/Presentation/FamilyEntrance/ViewController/JoinFamilyViewController.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,17 @@ final class JoinFamilyViewController: BaseViewController<JoinFamilyReactor> {
7777

7878
private func bindInput(reactor: JoinFamilyReactor) {
7979
makeFamilyButton.rx.tap
80-
.do(onNext: { MPEvent.Account.creatGroup.track(with: nil) })
80+
.do(onNext: {
81+
MPEvent.Account.creatGroup.track(with: nil)
82+
BBLogManager.analytics(logType: BBEventAnalyticsLog.clickFamilyButton(entry: .createFamilyGroup))
83+
})
8184
.throttle(RxConst.milliseconds300Interval, scheduler: MainScheduler.instance)
8285
.withUnretained(self)
8386
.bind(onNext: { $0.0.newGroupAlertController()})
8487
.disposed(by: disposeBag)
8588

8689
joinFamilyButton.rx.tap
90+
.do { _ in BBLogManager.analytics(logType: BBEventAnalyticsLog.clickFamilyButton(entry: .inviteFamily)) }
8791
.map { Reactor.Action.joinFamily }
8892
.bind(to: reactor.action)
8993
.disposed(by: disposeBag)

14th-team5-iOS/App/Sources/Presentation/Home/ViewControllers/MainViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ final class MainViewController: BBNavigationViewController<MainViewReactor>, UIC
3030

3131
override func viewDidLoad() {
3232
super.viewDidLoad()
33+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .main))
3334
}
3435

3536
override func bind(reactor: MainViewReactor) {

14th-team5-iOS/App/Sources/Presentation/Management/Reactor/FamilyNameSettingViewReactor.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public final class FamilyNameSettingViewReactor: Reactor {
100100
case let .didTapUpdateFamilyGroupNickname(type):
101101
let familyName = type == .initial ? nil : currentState.familyGroupNickName
102102
let updateFamilyBody = UpdateFamilyNameRequest(familyName: familyName)
103-
103+
BBLogManager.analytics(logType: BBEventAnalyticsLog.clickFamilyButton(entry: .familyNameSetting))
104104
return updateFamilyNameUseCase.execute(body: updateFamilyBody)
105105
.asObservable()
106106
.compactMap { $0 }

14th-team5-iOS/App/Sources/Presentation/Management/ViewController/FamilyNameSettingViewController.swift

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ final class FamilyNameSettingViewController: BBNavigationViewController<FamilyNa
2424
private let groupEditerView: JoinFamilyGroupEdtiorView = JoinFamilyGroupEdtiorView()
2525

2626

27+
override func viewDidLoad() {
28+
super.viewDidLoad()
29+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .familyGroupNameSetting))
30+
}
31+
2732
//MARK: Configures
2833
override func setupUI() {
2934
super.setupUI()

14th-team5-iOS/App/Sources/Presentation/Management/ViewController/ManagementViewController.swift

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ public final class ManagementViewController: BBNavigationViewController<Manageme
3939
prepareDatasource()
4040
}()
4141

42+
public override func viewDidLoad() {
43+
super.viewDidLoad()
44+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .familyManagement))
45+
}
46+
47+
4248
// MARK: - Helpers
4349

4450
public override func bind(reactor: ManagementReactor) {

14th-team5-iOS/App/Sources/Presentation/PostDetail/ViewControllers/PostViewController.swift

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ final class PostViewController: BaseViewController<PostReactor> {
2929

3030
override func viewDidLoad() {
3131
super.viewDidLoad()
32+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .postDetail))
3233
self.navigationController?.navigationBar.isHidden = true
3334
}
3435

14th-team5-iOS/App/Sources/Presentation/Privacy/PrivacyViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ extension PrivacyViewController {
222222

223223
let confirmAction = UIAlertAction(title: "확인", style: .default) { [weak self]_ in
224224
guard let self else { return }
225+
BBLogManager.analytics(logType: BBEventAnalyticsLog.clickAccountButton(entry: .logout))
225226
self.reactor?.action.onNext(.didTapLogoutButton)
226227
}
227228

@@ -242,6 +243,7 @@ extension PrivacyViewController {
242243
let confirmAction = UIAlertAction(title: "확인", style: .default) { [weak self ]_ in
243244
guard let self else { return }
244245
self.reactor?.action.onNext(.didTapFamilyUserResign)
246+
BBLogManager.analytics(logType: BBEventAnalyticsLog.clickAccountButton(entry: .familyResign))
245247
}
246248

247249
[cancelAction, confirmAction].forEach(resignAlertController.addAction(_:))

14th-team5-iOS/App/Sources/Presentation/Privacy/Reactor/PrivacyViewReactor.swift

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public final class PrivacyViewReactor: Reactor {
6464
public func mutate(action: Action) -> Observable<Mutation> {
6565
switch action {
6666
case .viewDidLoad:
67+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .setting))
6768
return .concat(
6869
.just(.setLoading(true)),
6970
.merge(

14th-team5-iOS/App/Sources/Presentation/Profile/ProfileFeedPageViewController.swift

+12-3
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,19 @@ extension ProfileFeedPageViewController: ReactorKit.View {
8484
extension ProfileFeedPageViewController: UIPageViewControllerDelegate, UIPageViewControllerDataSource {
8585
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
8686
guard let index = feedViewControllers.firstIndex(of: viewController),
87-
index - 1 >= 0 else { return nil }
87+
index - 1 >= 0 else {
88+
BBLogManager.sendError(error: BBCrashError.indexOutBounds)
89+
return nil
90+
}
8891
return feedViewControllers[index - 1]
8992
}
9093

9194
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
9295
guard let index = feedViewControllers.firstIndex(of: viewController),
93-
index + 1 != feedViewControllers.count else { return nil }
96+
index + 1 != feedViewControllers.count else {
97+
BBLogManager.sendError(error: BBCrashError.indexOutBounds)
98+
return nil
99+
}
94100

95101
return feedViewControllers[index + 1]
96102
}
@@ -99,7 +105,10 @@ extension ProfileFeedPageViewController: UIPageViewControllerDelegate, UIPageVie
99105
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
100106

101107
guard let currentViewController = pageViewController.viewControllers?.first,
102-
let currentIndex = feedViewControllers.firstIndex(of: currentViewController) else { return }
108+
let currentIndex = feedViewControllers.firstIndex(of: currentViewController) else {
109+
BBLogManager.sendError(error: BBCrashError.indexOutBounds)
110+
return
111+
}
103112
reactor?.action.onNext(.updatePageViewController(currentIndex))
104113
}
105114

14th-team5-iOS/App/Sources/Presentation/Profile/ProfileViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public final class ProfileViewController: BaseViewController<ProfileViewReactor>
5050

5151
public override func viewDidLoad() {
5252
super.viewDidLoad()
53+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .profile))
5354
}
5455

5556
public override func setupUI() {
@@ -131,6 +132,7 @@ public final class ProfileViewController: BaseViewController<ProfileViewReactor>
131132

132133
profileView.circleButton
133134
.rx.tap
135+
.do { _ in BBLogManager.analytics(logType: BBEventAnalyticsLog.clickAccountButton(entry: .profileImageEdit))}
134136
.throttle(.milliseconds(300), scheduler: MainScheduler.instance)
135137
.withUnretained(self)
136138
.bind(onNext: {$0.0.createAlertController()})

14th-team5-iOS/App/Sources/Presentation/Profile/Reactor/ProfileViewReactor.swift

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ public final class ProfileViewReactor: Reactor {
151151
profileNavigator.toPrivacy(memberId)
152152
return .empty()
153153
case let .didTappedProfileEditButton(memberId):
154+
BBLogManager.analytics(logType: BBEventAnalyticsLog.clickAccountButton(entry: .profileNickNameEdit))
154155
profileNavigator.toAccountNickname(memberId)
155156
return .empty()
156157
case let .didTappedAlertButton(memberId):

14th-team5-iOS/App/Sources/Presentation/Resign/AccountResignViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ final class AccountResignViewController: BaseViewController<AccountResignViewRea
2626

2727
override func viewDidLoad() {
2828
super.viewDidLoad()
29+
BBLogManager.analytics(logType: BBEventAnalyticsLog.viewPage(pageName: .resign))
2930
}
3031

3132
override func setupUI() {
@@ -175,6 +176,7 @@ extension AccountResignViewController {
175176

176177
let confirmAction = UIAlertAction(title: "확인", style: .default) { [weak self] _ in
177178
guard let self else { return }
179+
BBLogManager.analytics(logType: BBEventAnalyticsLog.clickAccountButton(entry: .resign))
178180
self.reactor?.action.onNext(.didTapResignButton)
179181
}
180182

14th-team5-iOS/Core/Sources/Bibbi/BBNetwork/Network/BBNetworkError.swift

+25
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,28 @@ extension BBUploadError: LocalizedError {
140140
}
141141
}
142142
}
143+
144+
145+
/// Firebase Crashlytics에 사용하는 Error Type입니다.
146+
public enum BBCrashError: Error {
147+
/// 범위에 벗어나는 모든 경우에 발생하는 에러를 의미합니다.
148+
case indexOutBounds
149+
/// 강제 언래핑 실패할 경우에 발생하는 에러를 의미합니다.
150+
case forceUnwrapFailed
151+
/// 알 수 없는 에러일 경우 해당 에러를 사용합니다.
152+
case unknown
153+
}
154+
155+
156+
extension BBCrashError: LocalizedError {
157+
public var errorDescription: String? {
158+
switch self {
159+
case .indexOutBounds:
160+
return "Index Out of Bounds Error"
161+
case .forceUnwrapFailed:
162+
return "Unexpectedly found nil while unwrapping an Optional value"
163+
case .unknown:
164+
return "Unknown Error"
165+
}
166+
}
167+
}

14th-team5-iOS/Core/Sources/Extensions/String+Ext.swift

+36
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,42 @@ extension String {
2222
}
2323

2424
extension String {
25+
public func toSnakeCase() -> String {
26+
var result = ""
27+
var previousStringWasCapitalized = false
28+
var previousStringWasNumber = false
29+
30+
for (index, string) in self.enumerated() {
31+
var mutableString = String(string)
32+
33+
if !mutableString.isAlphabet {
34+
if index != 0,
35+
!previousStringWasNumber {
36+
mutableString = "_" + mutableString
37+
}
38+
previousStringWasNumber = true
39+
} else if mutableString == mutableString.uppercased() {
40+
mutableString = mutableString.lowercased()
41+
42+
if index != 0,
43+
!previousStringWasCapitalized {
44+
mutableString = "_" + mutableString
45+
}
46+
previousStringWasCapitalized = true
47+
} else {
48+
previousStringWasCapitalized = false
49+
previousStringWasNumber = false
50+
}
51+
result += mutableString
52+
}
53+
return result
54+
}
55+
56+
public var isAlphabet: Bool {
57+
let alphabetSet = CharacterSet.uppercaseLetters.union(.lowercaseLetters).union(.whitespacesAndNewlines)
58+
return self.rangeOfCharacter(from: alphabetSet.inverted) == nil
59+
}
60+
2561
public func toDate(with format: String = "yyyy-MM-dd") -> Date {
2662
let dateFormatter = DateFormatter.withFormat(format)
2763
guard let date = dateFormatter.date(from: self) else { return .now }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// BBAnalyticsLogParametable.swift
3+
// Core
4+
//
5+
// Created by 김도현 on 12/19/24.
6+
//
7+
8+
import Foundation
9+
10+
public protocol BBAnalyticsLogParametable: RawRepresentable, CustomStringConvertible where RawValue == String { }
11+
12+
public extension BBAnalyticsLogParametable {
13+
var description: String {
14+
self.rawValue
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// BBAnalyticsLogType.swift
3+
// Core
4+
//
5+
// Created by 김도현 on 12/19/24.
6+
//
7+
8+
import Foundation
9+
10+
public protocol BBAnalyticsLogType {
11+
var name: String { get }
12+
var params: [String: Any] { get }
13+
}
14+
15+
public extension BBAnalyticsLogType {
16+
var name: String {
17+
Mirror(reflecting: self)
18+
.children
19+
.first?
20+
.label?
21+
.toSnakeCase() ?? String(describing: self).toSnakeCase()
22+
}
23+
24+
var params: [String: Any] {
25+
var dict: [String: Any] = [:]
26+
27+
let enumMirror = Mirror(reflecting: self)
28+
29+
guard let associated = enumMirror.children.first else { return dict }
30+
31+
for enumParams in Mirror(reflecting: associated.value).children {
32+
guard let label = enumParams.label?.toSnakeCase() else { continue }
33+
dict[label] = enumParams.value
34+
}
35+
36+
return dict
37+
}
38+
}

0 commit comments

Comments
 (0)