Skip to content

Commit

Permalink
๐Ÿ”— :: (#142) FCM
Browse files Browse the repository at this point in the history
  • Loading branch information
HongSJae committed Mar 11, 2024
2 parents 8795ec5 + 34466fa commit ea5af89
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 30 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,5 @@ Derived/
Tuist/Dependencies

XCConfig/

Projects/App/Resources/GoogleService-Info.plist
113 changes: 113 additions & 0 deletions .package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"pins" : [
{
"identity" : "abseil-cpp-swiftpm",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git",
"state" : {
"revision" : "583de9bd60f66b40e78d08599cc92036c2e7e4e1",
"version" : "0.20220203.2"
}
},
{
"identity" : "boringssl-swiftpm",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/boringssl-SwiftPM.git",
"state" : {
"revision" : "dd3eda2b05a3f459fc3073695ad1b28659066eab",
"version" : "0.9.1"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "7e80c25b51c2ffa238879b07fbfc5baa54bb3050",
"version" : "9.6.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "c1cfde8067668027b23a42c29d11c246152fe046",
"version" : "9.6.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
"version" : "9.4.0"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "26c898aed8bed13b8a63057ee26500abbbcb8d55",
"version" : "7.13.1"
}
},
{
"identity" : "grpc-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/grpc/grpc-ios.git",
"state" : {
"revision" : "8440b914756e0d26d4f4d054a1c1581daedfc5b6",
"version" : "1.44.3-grpc"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "5ccda3981422a84186387dbb763ba739178b529c",
"version" : "2.3.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "43aaef65e0c665daadf848761d560e446d350d3d",
"version" : "1.22.4"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692",
"version" : "2.30909.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
"version" : "2.4.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8",
"version" : "1.25.2"
}
}
],
"version" : 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ public extension TargetDependency.SPM {
static let KeychainSwift = TargetDependency.external(name: "KeychainSwift")
static let ReactorKit = TargetDependency.external(name: "ReactorKit")
static let RxGesture = TargetDependency.external(name: "RxGesture")
static let FCM = TargetDependency.package(product: "FirebaseMessaging")
}

public extension Package {
static let FCM = Package.remote(url: "https://github.com/firebase/firebase-ios-sdk", requirement: .upToNextMajor(from: "9.5.0"))
}
1 change: 1 addition & 0 deletions Projects/App/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ let schemes: [Scheme] = [
let project = Project(
name: env.targetName,
organizationName: env.organizationName,
packages: [.FCM],
settings: settings,
targets: targets,
schemes: schemes
Expand Down
54 changes: 53 additions & 1 deletion Projects/App/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import Presentation
import Domain
import Core
import DesignSystem
import UserNotifications
import Firebase

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {

static var container = Container()
var assembler: Assembler!

Expand All @@ -26,6 +27,25 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
UseCaseAssembly(),
PresentationAssembly()
], container: AppDelegate.container)

// ํŒŒ์ด์–ด๋ฒ ์ด์Šค ์„ค์ •
FirebaseApp.configure()

// ์•ฑ ์‹คํ–‰ ์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ ํ—ˆ์šฉ ๊ถŒํ•œ์„ ๋ฐ›์Œ
UNUserNotificationCenter.current().delegate = self

let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] // ํ•„์š”ํ•œ ์•Œ๋ฆผ ๊ถŒํ•œ์„ ์„ค์ •
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: { _, _ in }
)

// UNUserNotificationCenterDelegate๋ฅผ ๊ตฌํ˜„ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ด
application.registerForRemoteNotifications()

// ํŒŒ์ด์–ด๋ฒ ์ด์Šค Meesaging ์„ค์ •
Messaging.messaging().delegate = self

return true
}

Expand All @@ -43,3 +63,35 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
didDiscardSceneSessions sceneSessions: Set<UISceneSession>
) {}
}

extension AppDelegate: UNUserNotificationCenterDelegate {
// ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ํƒญํ–ˆ์„ ๋•Œ ์‹คํ–‰
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("APNS token: \(deviceToken)")
Messaging.messaging().apnsToken = deviceToken
}

// Foreground(์•ฑ ์ผœ์ง„ ์ƒํƒœ)์—์„œ๋„ ์•Œ๋ฆผ ์˜ค๋Š” ์„ค์ •
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.list, .banner])
}
}

extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
let token = String(describing: fcmToken)
print("Firebase registration token: \(token)")

let dataDict: [String: String] = ["token": fcmToken ?? ""]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: dataDict
)
}
}
14 changes: 10 additions & 4 deletions Projects/App/Support/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>API_BASE_URL</key>
<string>$(API_BASE_URL)</string>
<key>AppIdentifierPrefix</key>
<string>$(AppIdentifierPrefix)</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>API_BASE_URL</key>
<string>$(API_BASE_URL)</string>
<key>S3_BASE_URL</key>
<string>$(S3_BASE_URL)</string>
<key>CFBundleDisplayName</key>
<string>$(BUNDLE_DISPLAY_NAME)</string>
<key>CFBundleExecutable</key>
Expand All @@ -28,6 +28,8 @@
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>S3_BASE_URL</key>
<string>$(S3_BASE_URL)</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
Expand All @@ -47,6 +49,10 @@
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
Expand Down
2 changes: 2 additions & 0 deletions Projects/App/Support/JOBIS-DSM-iOS-v2.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.team.jobis.JOBIS-DSM-iOS-v2.keychainGroup</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@ public struct SigninRequestQuery: Encodable {
public let accountID: String
public let password: String
public let platformType: String
public let deviceToken: String?

public init(accountID: String, password: String) {
public init(
accountID: String,
password: String,
deviceToken: String?
) {
self.accountID = accountID
self.password = password
self.platformType = "IOS"
self.deviceToken = deviceToken
}

enum CodingKeys: String, CodingKey {
case accountID = "account_id"
case password
case platformType = "platform_type"
case deviceToken = "device_token"
}
}
4 changes: 3 additions & 1 deletion Projects/Flow/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ let project = Project.makeModule(
name: "Flow",
product: .staticLibrary,
targets: [.unitTest],
packages: [.FCM],
dependencies: [
.Projects.data,
.Projects.presentation
.Projects.presentation,
.SPM.FCM
]
)
4 changes: 2 additions & 2 deletions Projects/Modules/DesignSystem/Sources/Image/JobisIcon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public enum JobisIcon {
case arrowUp
case arrowDown

// swiftlint: disable cyclomatic_complexity
// swiftlint: disable cyclomatic_complexity function_body_length
func uiImage() -> UIImage {
let dsIcons = DesignSystemAsset.Icons.self

Expand Down Expand Up @@ -119,5 +119,5 @@ public enum JobisIcon {
return dsIcons.arrowDown.image
}
}
// swiftlint: enable cyclomatic_complexity
// swiftlint: enable cyclomatic_complexity function_body_length
}
4 changes: 3 additions & 1 deletion Projects/Presentation/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ let project = Project.makeModule(
name: "Presentation",
product: .staticLibrary,
targets: [.unitTest],
packages: [.FCM],
dependencies: [
.Projects.domain,
.Modules.designSystem
.Modules.designSystem,
.SPM.FCM
]
)
41 changes: 23 additions & 18 deletions Projects/Presentation/Sources/Signin/SigninReactor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import RxCocoa
import Domain
import RxFlow
import Core
import FirebaseMessaging

public final class SigninReactor: BaseReactor, Stepper {
public let steps = PublishRelay<Step>()
Expand Down Expand Up @@ -91,25 +92,29 @@ extension SigninReactor {
} else if password.isEmpty {
return .just(.passwordError("๋นˆ์นธ์„ ์ฑ„์›Œ์ฃผ์„ธ์š”"))
} else {
return self.signinUseCase.execute(req: .init(accountID: "\(email)@dsm.hs.kr", password: password))
.asObservable()
.map { _ in Mutation.signinSuccess }
.catch { error in
guard let error = error as? UsersError,
let description = error.errorDescription
else { return .never() }

switch error {
case .notFoundPassword, .badRequest:
return .just(.passwordError(description))

case .notFoundEmail:
return .just(.emailError(description))

case .internalServerError:
return .just(.emailError(error.localizedDescription))
}
return self.signinUseCase.execute(req: .init(
accountID: "\(email)@dsm.hs.kr",
password: password,
deviceToken: Messaging.messaging().fcmToken ?? "mac"
))
.asObservable()
.map { _ in Mutation.signinSuccess }
.catch { error in
guard let error = error as? UsersError,
let description = error.errorDescription
else { return .never() }

switch error {
case .notFoundPassword, .badRequest:
return .just(.passwordError(description))

case .notFoundEmail:
return .just(.emailError(description))

case .internalServerError:
return .just(.emailError(error.localizedDescription))
}
}
}
}

Expand Down
Loading

0 comments on commit ea5af89

Please sign in to comment.