From 5bb348efd703419c7dfc8e510a67f044a37fb0b5 Mon Sep 17 00:00:00 2001 From: jihee-daily Date: Sat, 25 May 2024 01:33:30 +0900 Subject: [PATCH 1/3] [Feat/#71] add setting for noti, and home view's title --- DDooing/DDooing.xcodeproj/project.pbxproj | 62 ++++++++++++------- DDooing/DDooing/DDooing.entitlements | 2 +- DDooing/DDooing/DDooingRelease.entitlements | 16 +++++ DDooing/DDooing/Info.plist | 19 ++++++ .../Models/NotificationDataModel.swift | 22 +++++++ DDooing/DDooing/Views/Home/HomeView.swift | 14 ++++- DDooing/DDooingWidgetExtension.entitlements | 2 +- DDooing/GoogleService-Info.plist | 36 +++++++++++ 8 files changed, 147 insertions(+), 26 deletions(-) create mode 100644 DDooing/DDooing/DDooingRelease.entitlements create mode 100644 DDooing/DDooing/Models/NotificationDataModel.swift create mode 100644 DDooing/GoogleService-Info.plist diff --git a/DDooing/DDooing.xcodeproj/project.pbxproj b/DDooing/DDooing.xcodeproj/project.pbxproj index b13e2a7..39f3bbb 100644 --- a/DDooing/DDooing.xcodeproj/project.pbxproj +++ b/DDooing/DDooing.xcodeproj/project.pbxproj @@ -7,6 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 10DDE2562C00F07C0084E1BF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 10DDE2552C00F07C0084E1BF /* GoogleService-Info.plist */; }; + 10DDE2572C00F07C0084E1BF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 10DDE2552C00F07C0084E1BF /* GoogleService-Info.plist */; }; + 10DDE2582C00F07C0084E1BF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 10DDE2552C00F07C0084E1BF /* GoogleService-Info.plist */; }; + 10DDE2592C00F07C0084E1BF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 10DDE2552C00F07C0084E1BF /* GoogleService-Info.plist */; }; + 10DDE25B2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; + 10DDE25C2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; + 10DDE25D2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; + 10DDE25E2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; 4F1A593D2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */; }; 4F1A593E2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */; }; 4F1A593F2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */; }; @@ -45,8 +53,6 @@ 4F3F81422BFE10AE008C920C /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FF515932BF33F810056531C /* HomeView.swift */; }; 4F3F81542BFE63CA008C920C /* AppModelContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F3F81532BFE63CA008C920C /* AppModelContainer.swift */; }; 4F3F81552BFE63CA008C920C /* AppModelContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F3F81532BFE63CA008C920C /* AppModelContainer.swift */; }; - 4F8D878D2BFF864F006BEF4A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4F8D878C2BFF84DF006BEF4A /* GoogleService-Info.plist */; }; - 4F8D878E2BFF8650006BEF4A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4F8D878C2BFF84DF006BEF4A /* GoogleService-Info.plist */; }; 4FAD25B02BF3339A00EBD37A /* DDooingApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FAD25AF2BF3339A00EBD37A /* DDooingApp.swift */; }; 4FAD25B22BF3339A00EBD37A /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FAD25B12BF3339A00EBD37A /* MainView.swift */; }; 4FAD25B42BF3339B00EBD37A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4FAD25B32BF3339B00EBD37A /* Assets.xcassets */; }; @@ -126,6 +132,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 10DDE24D2C00EF2D0084E1BF /* DDooingRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DDooingRelease.entitlements; sourceTree = ""; }; + 10DDE2552C00F07C0084E1BF /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationDataModel.swift; sourceTree = ""; }; 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-ExtraBold.otf"; sourceTree = ""; }; 4F1A59352BF8892000C3EF2C /* Pretendard-ExtraLight.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-ExtraLight.otf"; sourceTree = ""; }; 4F1A59362BF8892000C3EF2C /* Pretendard-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Regular.otf"; sourceTree = ""; }; @@ -140,7 +149,6 @@ 4F3F813B2BFDDCEC008C920C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4F3F813D2BFDDDE2008C920C /* WidgetColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetColor.swift; sourceTree = ""; }; 4F3F81532BFE63CA008C920C /* AppModelContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModelContainer.swift; sourceTree = ""; }; - 4F8D878C2BFF84DF006BEF4A /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 4FAD25AC2BF3339A00EBD37A /* DDooing.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DDooing.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4FAD25AF2BF3339A00EBD37A /* DDooingApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DDooingApp.swift; sourceTree = ""; }; 4FAD25B12BF3339A00EBD37A /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; @@ -261,6 +269,7 @@ children = ( 9D79E9362BF5FAD700A05D95 /* MessageModel.swift */, 4F3F81532BFE63CA008C920C /* AppModelContainer.swift */, + 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */, ); path = Models; sourceTree = ""; @@ -324,7 +333,7 @@ 4FAD25A32BF3339A00EBD37A = { isa = PBXGroup; children = ( - 4F8D878C2BFF84DF006BEF4A /* GoogleService-Info.plist */, + 10DDE2552C00F07C0084E1BF /* GoogleService-Info.plist */, 4FBE64CB2BFDCB80008363A0 /* DDooingWidgetExtension.entitlements */, 4FAD25AE2BF3339A00EBD37A /* DDooing */, 4FAD25BF2BF3339B00EBD37A /* DDooingTests */, @@ -350,6 +359,7 @@ 4FAD25AE2BF3339A00EBD37A /* DDooing */ = { isa = PBXGroup; children = ( + 10DDE24D2C00EF2D0084E1BF /* DDooingRelease.entitlements */, 4F1A595C2BF8896A00C3EF2C /* Info.plist */, 4FAD25B52BF3339B00EBD37A /* Preview Content */, 4F3E652B2BFB14CE00996806 /* Views */, @@ -564,11 +574,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4F8D878D2BFF864F006BEF4A /* GoogleService-Info.plist in Resources */, 4FAD25B72BF3339B00EBD37A /* Preview Assets.xcassets in Resources */, 4F1A59492BF8892000C3EF2C /* Pretendard-Bold.otf in Resources */, 4F3F813C2BFDDCEC008C920C /* Assets.xcassets in Resources */, 4F1A59432BF8892000C3EF2C /* Pretendard-Regular.otf in Resources */, + 10DDE2562C00F07C0084E1BF /* GoogleService-Info.plist in Resources */, 4F1A59552BF8892000C3EF2C /* Pretendard-SemiBold.otf in Resources */, 4F1A594C2BF8892000C3EF2C /* Pretendard-Thin.otf in Resources */, 4F1A594F2BF8892000C3EF2C /* Pretendard-Black.otf in Resources */, @@ -592,6 +602,7 @@ 4F1A59442BF8892000C3EF2C /* Pretendard-Regular.otf in Resources */, 4F1A59562BF8892000C3EF2C /* Pretendard-SemiBold.otf in Resources */, 4F1A59502BF8892000C3EF2C /* Pretendard-Black.otf in Resources */, + 10DDE2572C00F07C0084E1BF /* GoogleService-Info.plist in Resources */, 4F1A593E2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -608,6 +619,7 @@ 4F1A59452BF8892000C3EF2C /* Pretendard-Regular.otf in Resources */, 4F1A59572BF8892000C3EF2C /* Pretendard-SemiBold.otf in Resources */, 4F1A59512BF8892000C3EF2C /* Pretendard-Black.otf in Resources */, + 10DDE2582C00F07C0084E1BF /* GoogleService-Info.plist in Resources */, 4F1A593F2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -616,8 +628,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 10DDE2592C00F07C0084E1BF /* GoogleService-Info.plist in Resources */, 4F3F813F2BFDDEDC008C920C /* Assets.xcassets in Resources */, - 4F8D878E2BFF8650006BEF4A /* GoogleService-Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -644,6 +656,7 @@ 4FAD25B02BF3339A00EBD37A /* DDooingApp.swift in Sources */, 4F3F81542BFE63CA008C920C /* AppModelContainer.swift in Sources */, 4F1A59592BF8894600C3EF2C /* FontManager.swift in Sources */, + 10DDE25B2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */, 4FF515982BF33FD70056531C /* ShowMessageView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -653,6 +666,7 @@ buildActionMask = 2147483647; files = ( 4F1A595A2BF8894600C3EF2C /* FontManager.swift in Sources */, + 10DDE25C2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */, 4FAD25C12BF3339B00EBD37A /* DDooingTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -663,6 +677,7 @@ files = ( 4FAD25CB2BF3339B00EBD37A /* DDooingUITests.swift in Sources */, 4F1A595B2BF8894600C3EF2C /* FontManager.swift in Sources */, + 10DDE25D2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */, 4FAD25CD2BF3339B00EBD37A /* DDooingUITestsLaunchTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -678,6 +693,7 @@ 4F3F81422BFE10AE008C920C /* HomeView.swift in Sources */, 4FBE64BC2BFDC940008363A0 /* DDooingWidgetLiveActivity.swift in Sources */, 4F3F81402BFDE116008C920C /* WidgetColor.swift in Sources */, + 10DDE25E2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */, 4F3F81552BFE63CA008C920C /* AppModelContainer.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -833,7 +849,7 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"DDooing/Preview Content\""; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = DDooing/Info.plist; @@ -847,7 +863,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooing; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_EMIT_LOC_STRINGS = YES; @@ -862,12 +878,12 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = DDooing/DDooing.entitlements; + CODE_SIGN_ENTITLEMENTS = DDooing/DDooingRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"DDooing/Preview Content\""; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = DDooing/Info.plist; @@ -881,7 +897,7 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooing; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_EMIT_LOC_STRINGS = YES; @@ -897,11 +913,11 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.4; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooingTests; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooingTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -917,11 +933,11 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.4; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooingTests; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooingTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -936,10 +952,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooingUITests; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooingUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -954,10 +970,10 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooingUITests; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooingUITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; @@ -975,7 +991,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = DDooingWidget/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = DDooingWidget; @@ -986,7 +1002,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooing.DDooingWidget; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooing.DDooingWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; @@ -1004,7 +1020,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = U6CCD5BT22; + DEVELOPMENT_TEAM = 3GB5WJ43G4; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = DDooingWidget/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = DDooingWidget; @@ -1015,7 +1031,7 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.Seodongwon.DDooing.DDooingWidget; + PRODUCT_BUNDLE_IDENTIFIER = com.iOSDevJoy.DDooing.DDooingWidget; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/DDooing/DDooing/DDooing.entitlements b/DDooing/DDooing/DDooing.entitlements index cd16938..0a83c30 100644 --- a/DDooing/DDooing/DDooing.entitlements +++ b/DDooing/DDooing/DDooing.entitlements @@ -8,7 +8,7 @@ com.apple.security.application-groups - group.com.Seodongwon.DDooing + group.com.iOSDevJoy.DDooing diff --git a/DDooing/DDooing/DDooingRelease.entitlements b/DDooing/DDooing/DDooingRelease.entitlements new file mode 100644 index 0000000..544e831 --- /dev/null +++ b/DDooing/DDooing/DDooingRelease.entitlements @@ -0,0 +1,16 @@ + + + + + aps-environment + development + com.apple.developer.applesignin + + Default + + com.apple.security.application-groups + + group.com.iOSDevJoy.DDooing + + + diff --git a/DDooing/DDooing/Info.plist b/DDooing/DDooing/Info.plist index cf8c929..9bdac0a 100644 --- a/DDooing/DDooing/Info.plist +++ b/DDooing/DDooing/Info.plist @@ -2,6 +2,19 @@ + NSAppTransportSecurity + + NSExceptionDomains + + 114.70.193.152 + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + + UIAppFonts Pretendard-Black.otf @@ -14,5 +27,11 @@ Pretendard-SemiBold.otf Pretendard-Thin.otf + UIBackgroundModes + + fetch + processing + remote-notification + diff --git a/DDooing/DDooing/Models/NotificationDataModel.swift b/DDooing/DDooing/Models/NotificationDataModel.swift new file mode 100644 index 0000000..b8f6f9e --- /dev/null +++ b/DDooing/DDooing/Models/NotificationDataModel.swift @@ -0,0 +1,22 @@ +// +// NotificationData.swift +// DDooing +// +// Created by kimjihee on 5/25/24. +// + +import SwiftData +import SwiftUI + +@Model +final class NotificationDataModel { + @Attribute(.unique) var id: UUID + var body: String + var title: String + + init(body: String, title: String) { + self.id = UUID() + self.body = body + self.title = title + } +} diff --git a/DDooing/DDooing/Views/Home/HomeView.swift b/DDooing/DDooing/Views/Home/HomeView.swift index 665f752..91d3ab7 100644 --- a/DDooing/DDooing/Views/Home/HomeView.swift +++ b/DDooing/DDooing/Views/Home/HomeView.swift @@ -12,6 +12,7 @@ import SwiftData struct HomeView: View { @State var name: String = "" + @State var partnerName: String = "" @Environment(\.modelContext) private var modelContext @Query private var messages: [MessageModel] @State private var randomMessages : String = "" @@ -19,6 +20,9 @@ struct HomeView: View { let partnerUID: String! @GestureState private var isPressed = false @State private var isLongPressed = false + @Query private var notificationDataList: [NotificationDataModel] + @State var pushMessage = "" + @State var deviceToken = "" init(partnerUID: String?) { self.partnerUID = partnerUID @@ -32,6 +36,15 @@ struct HomeView: View { var body: some View { NavigationStack{ VStack { + HStack { + Text("DDooing") + .font(.largeTitle.bold()) + Spacer() + } + .padding(.vertical) + + Spacer() + Image("Heart button") .resizable() .aspectRatio(contentMode: .fit) @@ -86,7 +99,6 @@ struct HomeView: View { } .padding() - .navigationTitle("DDooing") .onAppear { fetchMyConnectedNickname { fetchedName in name = fetchedName diff --git a/DDooing/DDooingWidgetExtension.entitlements b/DDooing/DDooingWidgetExtension.entitlements index 849f0cc..1dfcb4c 100644 --- a/DDooing/DDooingWidgetExtension.entitlements +++ b/DDooing/DDooingWidgetExtension.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.Seodongwon.DDooing + group.com.iOSDevJoy.DDooing diff --git a/DDooing/GoogleService-Info.plist b/DDooing/GoogleService-Info.plist new file mode 100644 index 0000000..47231dc --- /dev/null +++ b/DDooing/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 752780593979-1avvvfte69oookeoh9lqjk6o2mmtu7b3.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.752780593979-1avvvfte69oookeoh9lqjk6o2mmtu7b3 + API_KEY + AIzaSyAwf1U7zVB9zrctnZmQtRqbAaE7BdMYA7k + GCM_SENDER_ID + 752780593979 + PLIST_VERSION + 1 + BUNDLE_ID + com.iOSDevJoy.DDooing + PROJECT_ID + ddooing-8881b + STORAGE_BUCKET + ddooing-8881b.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:752780593979:ios:10788a37714cbc50dac51e + DATABASE_URL + https://ddooing-8881b-default-rtdb.firebaseio.com + + \ No newline at end of file From 7d50f368fccda50ff0e18701646749570be333ef Mon Sep 17 00:00:00 2001 From: jihee-daily Date: Sat, 25 May 2024 01:52:05 +0900 Subject: [PATCH 2/3] [Feat/#71] add delegate setting for noti in DDooingApp file --- DDooing/DDooing.xcodeproj/project.pbxproj | 8 ++ DDooing/DDooing/Views/DDooingApp.swift | 128 ++++++++++++++++++++++ DDooing/DDooing/Views/Home/HomeView.swift | 9 +- 3 files changed, 137 insertions(+), 8 deletions(-) diff --git a/DDooing/DDooing.xcodeproj/project.pbxproj b/DDooing/DDooing.xcodeproj/project.pbxproj index 39f3bbb..202b3b3 100644 --- a/DDooing/DDooing.xcodeproj/project.pbxproj +++ b/DDooing/DDooing.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 10DDE25C2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; 10DDE25D2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; 10DDE25E2C00F7F40084E1BF /* NotificationDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10DDE25A2C00F7F40084E1BF /* NotificationDataModel.swift */; }; + 10DDE2602C00F9AA0084E1BF /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 10DDE25F2C00F9AA0084E1BF /* FirebaseMessaging */; }; 4F1A593D2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */; }; 4F1A593E2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */; }; 4F1A593F2BF8892000C3EF2C /* Pretendard-ExtraBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 4F1A59342BF8892000C3EF2C /* Pretendard-ExtraBold.otf */; }; @@ -189,6 +190,7 @@ files = ( 4FD812D32BF87AB900F16ED0 /* FirebaseDatabaseSwift in Frameworks */, 4FD812D12BF87AB900F16ED0 /* FirebaseDatabase in Frameworks */, + 10DDE2602C00F9AA0084E1BF /* FirebaseMessaging in Frameworks */, 4FD812CD2BF87AB900F16ED0 /* FirebaseAnalytics in Frameworks */, 4FD812D52BF87AB900F16ED0 /* FirebaseFirestore in Frameworks */, 4FD812CF2BF87AB900F16ED0 /* FirebaseAuth in Frameworks */, @@ -451,6 +453,7 @@ 4FD812D22BF87AB900F16ED0 /* FirebaseDatabaseSwift */, 4FD812D42BF87AB900F16ED0 /* FirebaseFirestore */, 4FD812D62BF87AB900F16ED0 /* FirebaseFirestoreSwift */, + 10DDE25F2C00F9AA0084E1BF /* FirebaseMessaging */, ); productName = DDooing; productReference = 4FAD25AC2BF3339A00EBD37A /* DDooing.app */; @@ -1102,6 +1105,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 10DDE25F2C00F9AA0084E1BF /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = 4FD812C72BF8798A00F16ED0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; 4FBE64D12BFDD572008363A0 /* FirebaseAnalytics */ = { isa = XCSwiftPackageProductDependency; package = 4FD812C72BF8798A00F16ED0 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; diff --git a/DDooing/DDooing/Views/DDooingApp.swift b/DDooing/DDooing/Views/DDooingApp.swift index 72787db..2ded5b6 100644 --- a/DDooing/DDooing/Views/DDooingApp.swift +++ b/DDooing/DDooing/Views/DDooingApp.swift @@ -22,9 +22,137 @@ struct DDooingApp: App { } } +// Initializing firebase and cloud messaging class AppDelegate: NSObject, UIApplicationDelegate { + let gcmMessageIDKey = "gcm.message_id" + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + FirebaseApp.configure() + + // Setting cloud messaging + Messaging.messaging().delegate = self + + // Setting notifications + UNUserNotificationCenter.current().delegate = self + + let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] + UNUserNotificationCenter.current().requestAuthorization( + options: authOptions, + completionHandler: { _, _ in } + ) + + application.registerForRemoteNotifications() + return true } + + func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], + fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { + + // Do something with message data here. + + UIImpactFeedbackGenerator(style: .medium).impactOccurred() + + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: \(messageID)") + } + + // Print full message. + print(userInfo) + + completionHandler(UIBackgroundFetchResult.newData) + } + + // In order to receive notifications you need implement these methods. + func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: any Error) { + + } + + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { +// Messaging.messaging().token { token, error in +// if let error = error { +// print("Error fetching FCM registration token: \(error)") +// } else if let token = token { +// print("FCM registration token: \(token)") +//// self.fcmRegTokenMessage.text = "Remote FCM registration token: \(token)" +// } +// } + } + + +} + +// Cloud messaging +extension AppDelegate: MessagingDelegate { + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + print("Firebase register action token:") + + // Store this token to firebase and retrieve when to send message to someone. + let dataDict: [String: String] = ["token": fcmToken ?? ""] + + if let user = Auth.auth().currentUser { + setUsersFCMToken(token: fcmToken!, userAUID: user.uid) + } + + // Store token in firestore for sending notifications from server in future + print(dataDict) + } + + private func setUsersFCMToken(token : String, userAUID: String) { + let db = Firestore.firestore() + + db.collection("Users").document(userAUID).updateData([ + "deviceToken": token + ]) { err in + if let err = err { + print("Error updating document: \(err)") + } else { + print("토큰 저장 성공 : \(token)") + } + } + } +} + +// User notifications (InApp Notifications) +extension AppDelegate: UNUserNotificationCenterDelegate { + func userNotificationCenter(_ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + let userInfo = notification.request.content.userInfo + + // Haptics + // UIImpactFeedbackGenerator(style: .medium).impactOccurred() + + // Do something with message data. + print("User Info: \(userInfo)") + if let aps = userInfo["aps"] as? [String: Any], + let alert = aps["alert"] as? [String: String], + let body = alert["body"], + let title = alert["title"] { + // body와 title 값을 추출했습니다. + // 여기서 SwiftData를 사용하여 값을 저장합니다. +// saveNotificationData(body: body, title: title) + print("User alert: \(alert)") + print("User body: \(body)") + print("User title: \(title)") + } + + completionHandler([[.banner, .badge, .sound]]) + } + + + func userNotificationCenter(_ center: UNUserNotificationCenter, + didReceive response: UNNotificationResponse, + withCompletionHandler completionHandler: @escaping () -> Void) { + let userInfo = response.notification.request.content.userInfo + + if let messageID = userInfo[gcmMessageIDKey] { + print("Message ID: \(messageID)") + } + + print("User Info: \(userInfo)") + + completionHandler() + } } diff --git a/DDooing/DDooing/Views/Home/HomeView.swift b/DDooing/DDooing/Views/Home/HomeView.swift index 91d3ab7..a322bfa 100644 --- a/DDooing/DDooing/Views/Home/HomeView.swift +++ b/DDooing/DDooing/Views/Home/HomeView.swift @@ -89,14 +89,7 @@ struct HomeView: View { Text("\(postPositionText(name)) 생각하며 눌러보세요.") .font(.headline) .padding(.bottom,60) - - - - - - - - + Spacer() } .padding() .onAppear { From 37f2eac7f7971d3b53c273c1daf05b8802e48c95 Mon Sep 17 00:00:00 2001 From: jihee-daily Date: Sun, 26 May 2024 16:39:22 +0900 Subject: [PATCH 3/3] [Feat/#71] add sending push notification --- DDooing/DDooing/DDooing.entitlements | 2 + DDooing/DDooing/Info.plist | 2 + .../DDooing/Views/Auth/RandomCodeView.swift | 34 ++-- DDooing/DDooing/Views/DDooingApp.swift | 14 +- DDooing/DDooing/Views/Home/HomeView.swift | 179 ++++++++++++++---- 5 files changed, 170 insertions(+), 61 deletions(-) diff --git a/DDooing/DDooing/DDooing.entitlements b/DDooing/DDooing/DDooing.entitlements index 0a83c30..544e831 100644 --- a/DDooing/DDooing/DDooing.entitlements +++ b/DDooing/DDooing/DDooing.entitlements @@ -2,6 +2,8 @@ + aps-environment + development com.apple.developer.applesignin Default diff --git a/DDooing/DDooing/Info.plist b/DDooing/DDooing/Info.plist index 9bdac0a..3655ad9 100644 --- a/DDooing/DDooing/Info.plist +++ b/DDooing/DDooing/Info.plist @@ -2,6 +2,8 @@ + FirebaseAppDelegateProxyEnabled + NSAppTransportSecurity NSExceptionDomains diff --git a/DDooing/DDooing/Views/Auth/RandomCodeView.swift b/DDooing/DDooing/Views/Auth/RandomCodeView.swift index 683abdd..7a96b88 100644 --- a/DDooing/DDooing/Views/Auth/RandomCodeView.swift +++ b/DDooing/DDooing/Views/Auth/RandomCodeView.swift @@ -13,6 +13,8 @@ struct RandomCodeView: View { @State private var isConnectionMode = true @State private var code = "" @State private var randomCode = "" + @AppStorage("userDeviceToken") private var userDeviceToken: String = "" + var body: some View { NavigationStack{ @@ -88,6 +90,7 @@ struct RandomCodeView: View { sendRandomCodeToFirebase(for: user, with: randomCode) viewModel.observeUserConnectionStatus(userId: user.uid) } + print("Device Token in HomeView: \(userDeviceToken)") } .navigationBarBackButtonHidden(true) } @@ -95,25 +98,26 @@ struct RandomCodeView: View { let lettersAndDigits = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" return String((0.. private var notificationDataList: [NotificationDataModel] - @State var pushMessage = "" - @State var deviceToken = "" + @State var partnerDeviceToken = "" init(partnerUID: String?) { self.partnerUID = partnerUID if messages.randomElement() != nil { - _randomMessages = State(initialValue: randomMessages) + _pushMessage = State(initialValue: pushMessage) } else { - _randomMessages = State(initialValue: "") + _pushMessage = State(initialValue: "") } } @@ -66,7 +65,9 @@ struct HomeView: View { ForEach(messages) { mess in if mess.isStarred { Button (action: { - sendMessage(messageText: mess.message, isStarred: true) + pushMessage = mess.message + sendMessage(messageText: pushMessage, isStarred: true) + fetchAccessTokenAndSendPushNotification() }, label: { Text(mess.message) }) @@ -78,10 +79,11 @@ struct HomeView: View { if !isLongPressed { print("짧게누름") if let randomMessage = messages.randomElement() { - randomMessages = randomMessage.message + pushMessage = randomMessage.message } - saveRandomMessage() print("메시지 입력") + sendMessage(messageText: pushMessage, isStarred: false) + fetchAccessTokenAndSendPushNotification() } isLongPressed = false } @@ -97,13 +99,48 @@ struct HomeView: View { name = fetchedName } + + } + } + } + func fetchPartnerDeviceToken(completion: @escaping (String) -> Void) { + let db = Firestore.firestore() + db.collection("Users").document(partnerUID).getDocument { document, error in + if let document = document, document.exists { + partnerDeviceToken = document.data()?["deviceToken"] as? String ?? "Unknown" + completion(partnerDeviceToken) + } else { + completion("Unknown") } } } - func saveRandomMessage() { - guard let partnerUID = partnerUID else { return } - sendMessage(messageText: randomMessages, isStarred: false) + func fetchPartnerConnectedNickname(completion: @escaping (String) -> Void) { + let db = Firestore.firestore() + db.collection("Users").document(partnerUID).getDocument { document, error in + if let document = document, document.exists { + partnerName = document.data()?["ConnectedNickname"] as? String ?? "Unknown" + completion(partnerName) + } else { + completion("Unknown") + } + } + } + private func fetchMyConnectedNickname(completion: @escaping (String) -> Void) { + let db = Firestore.firestore() + guard let currentUid = Auth.auth().currentUser?.uid else { + completion("Unknown") + return + } + + db.collection("Users").document(currentUid).getDocument { document, error in + if let document = document, document.exists { + name = document.data()?["ConnectedNickname"] as? String ?? "Unknown" + completion(name) + } else { + completion("Unknown") + } + } } func sendMessage(messageText: String, isStarred: Bool) { @@ -111,52 +148,120 @@ struct HomeView: View { guard let currentUid = Auth.auth().currentUser?.uid else { return } - let currenrUserRef = db.collection("Received-Messages") - .document(currentUid).collection(partnerUID).document() - - let PartnerRef = db.collection("Received-Messages") - .document(partnerUID).collection(currentUid) + let currentUserRef = db.collection("Received-Messages") + .document(partnerUID).collection(currentUid).document() // let recentCurrentUserRef = db.collection("Received-Messages") -// .document(currentUid).collection("recent-messages") -// .document(partnerUID) +// .document(partnerUID).collection("recent-messages") +// .document(currentUid) - let recentPartnerRef = db.collection("Received-Messages") - .document(partnerUID).collection("recent-messages") - .document(currentUid) - - let messageId = currenrUserRef.documentID + let messageId = currentUserRef.documentID let messageData: [String: Any] = [ - "fromId": currentUid, - "toId": partnerUID!, + "fromId": partnerUID!, + "toId": currentUid, "messageText": messageText, "timeStamp": Timestamp(date: Date()), "isStarred": isStarred, "messageId": messageId ] -// currenrUserRef.setData(messageData) - PartnerRef.document(messageId).setData(messageData) + currentUserRef.setData(messageData) // recentCurrentUserRef.setData(messageData) - recentPartnerRef.setData(messageData) } - private func fetchMyConnectedNickname(completion: @escaping (String) -> Void) { - let db = Firestore.firestore() - guard let currentUid = Auth.auth().currentUser?.uid else { - completion("Unknown") + func fetchAccessTokenAndSendPushNotification() { + fetchPartnerDeviceToken { fetchedtoken in + partnerDeviceToken = fetchedtoken + } + fetchPartnerConnectedNickname { fetchedName in + partnerName = fetchedName + } + + // 서버로부터 OAuth 2.0 액세스 토큰 가져오기 + guard let url = URL(string: "") else { + print("Invalid URL for token") return } + + var request = URLRequest(url: url) + request.httpMethod = "GET" - db.collection("Users").document(currentUid).getDocument { document, error in - if let document = document, document.exists { - name = document.data()?["ConnectedNickname"] as? String ?? "Unknown" - completion(name) + let session = URLSession(configuration: .default) + session.dataTask(with: request) { data, response, err in + if let err = err { + print(err.localizedDescription) + return + } + guard let data = data else { + print("No data received") + return + } + + // 서버로부터 받은 응답을 문자열로 변환하여 출력 + if let accessToken = String(data: data, encoding: .utf8) { + print("Access Token String: \(accessToken)") + sendPushNotification(with: accessToken) } else { - completion("Unknown") + print("Invalid token response") } + }.resume() + } + + func sendPushNotification(with accessToken: String) { + guard !accessToken.isEmpty else { + print("Access token is empty") + return + } + + // HTTP v1 API의 엔드포인트 URL + guard let url = URL(string: "https://fcm.googleapis.com/v1/projects/ddooing-8881b/messages:send") else { + print("Invalid URL for FCM") + return } + print("partnerdevicetoken >>> \(partnerDeviceToken)") + print("pushMessage >>> \(pushMessage)") + print("parname >>> \(partnerName)") + let json: [String: Any] = [ + "message": [ + "token": partnerDeviceToken, + "notification": [ + "body": pushMessage, + "title": partnerName + ] + ] + ] + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: [.prettyPrinted]) + request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + let session = URLSession(configuration: .default) + session.dataTask(with: request) { data, response, err in + if let err = err { + print("Error sending push notification: \(err.localizedDescription)") + return + } + + guard let httpResponse = response as? HTTPURLResponse else { + print("Invalid response") + return + } + + print("Push notification response status code: \(httpResponse.statusCode)") + + if let data = data, let responseBody = String(data: data, encoding: .utf8) { + print("Response Body: \(responseBody)") + } + + if httpResponse.statusCode == 200 { + print("Push notification sent successfully") + } else { + print("Failed to send push notification") + } + }.resume() } }