Skip to content

Commit 98f15c2

Browse files
authored
[Horizon] Crashlytics integration (#3303)
1 parent 2e5924c commit 98f15c2

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

Core/Core/Features/Login/LoginFindSchoolViewController.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,10 @@ class LoginFindSchoolViewController: UIViewController {
144144
host = host.lowercased()
145145

146146
// For manual oauth logins we trust the developer and don't modify the host.
147-
if method != .manualOAuthLogin, !host.contains(".") {
147+
if method != .manualOAuthLogin, !host.contains("."), env.app != .horizon {
148148
host = "\(host).instructure.com"
149+
} else if env.app == .horizon {
150+
host = replaceRootDomain(urlString: host, newRootDomain: "instructure.com") ?? ""
149151
}
150152

151153
searchField.resignFirstResponder()
@@ -157,6 +159,32 @@ class LoginFindSchoolViewController: UIViewController {
157159
showLoginForHost(host)
158160
}
159161

162+
func replaceRootDomain(urlString: String, newRootDomain: String) -> String? {
163+
let urlWithScheme = "https://\(urlString)"
164+
165+
guard let url = URL(string: urlWithScheme) else {
166+
return nil
167+
}
168+
169+
// Try to extract host, fallback to raw string if needed
170+
let host = url.host ?? urlString
171+
let parts = host.components(separatedBy: ".")
172+
173+
let subdomain: String
174+
if parts.count >= 3 {
175+
// Full domain with subdomain (subdomain.domain.com
176+
subdomain = parts.dropLast(2).joined(separator: ".")
177+
} else if parts.count == 1 {
178+
// Only a subdomain was typed (subdomain)
179+
subdomain = parts[0]
180+
} else {
181+
subdomain = parts.dropLast().joined(separator: ".")
182+
}
183+
184+
let newHost = "\(subdomain).\(newRootDomain)"
185+
return newHost
186+
}
187+
160188
private func toggleNextButtonVisibility() {
161189
if let host = searchField.text?.trimmingCharacters(in: .whitespacesAndNewlines), !host.isEmpty {
162190
nextButton.accessibilityIdentifier = "nextButton"

Horizon/Horizon/Sources/AppDelegate.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import Combine
2020
import Core
21+
import Firebase
2122
import HorizonUI
2223
import UIKit
2324

@@ -44,6 +45,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, AppEnvironmentDelegate {
4445
_: UIApplication,
4546
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?
4647
) -> Bool {
48+
// MARK: - Firebase
49+
50+
setupFirebase()
51+
4752
// MARK: Root view
4853

4954
window = UIWindow()
@@ -122,3 +127,57 @@ extension AppDelegate: Core.AnalyticsHandler {
122127
analyticsTracker.endSession()
123128
}
124129
}
130+
131+
// MARK: - Crashlytics
132+
133+
extension AppDelegate {
134+
@objc func setupFirebase() {
135+
guard !testing else {
136+
setupDebugCrashLogging()
137+
return
138+
}
139+
140+
if FirebaseOptions.defaultOptions()?.apiKey != nil {
141+
FirebaseApp.configure()
142+
configureRemoteConfig()
143+
Core.Analytics.shared.handler = self
144+
RemoteLogger.shared.handler = self
145+
}
146+
}
147+
148+
func setupDebugCrashLogging() {
149+
NSSetUncaughtExceptionHandler { exception in
150+
print("CRASH: \(exception)")
151+
print("Stack Trace:")
152+
for symbol in exception.callStackSymbols {
153+
print(" \(symbol)")
154+
}
155+
}
156+
}
157+
158+
func configureRemoteConfig() {
159+
let remoteConfig = RemoteConfig.remoteConfig()
160+
remoteConfig.fetch(withExpirationDuration: 0) { _, _ in
161+
remoteConfig.activate { _, _ in
162+
let keys = remoteConfig.allKeys(from: .remote)
163+
for key in keys {
164+
guard let feature = ExperimentalFeature(rawValue: key) else { continue }
165+
let value = remoteConfig.configValue(forKey: key).boolValue
166+
feature.isEnabled = value
167+
Firebase.Crashlytics.crashlytics().setCustomValue(value, forKey: feature.userDefaultsKey)
168+
}
169+
}
170+
}
171+
}
172+
}
173+
174+
extension AppDelegate: RemoteLogHandler {
175+
func handleBreadcrumb(_ name: String) {
176+
Firebase.Crashlytics.crashlytics().log(name)
177+
}
178+
179+
func handleError(_ name: String, reason: String) {
180+
let model = ExceptionModel(name: name, reason: reason)
181+
Firebase.Crashlytics.crashlytics().record(exceptionModel: model)
182+
}
183+
}

0 commit comments

Comments
 (0)