From e269647d4192029d0536b8b472b8e68adbae9069 Mon Sep 17 00:00:00 2001 From: cheykrym Date: Wed, 3 Dec 2025 05:47:52 +0300 Subject: [PATCH] add push --- yobble.xcodeproj/project.pbxproj | 60 ++++++++ .../xcshareddata/swiftpm/Package.resolved | 128 +++++++++++++++++- yobble/AppDelegate.swift | 57 ++++++++ yobble/GoogleService-Info.plist | 30 ++++ yobble/Info.plist | 12 ++ yobble/Network/AuthService.swift | 2 +- yobble/PushAppDelegate.swift | 55 ++++++++ yobble/Services/SocketService.swift | 4 + yobble/Views/Tab/ContactsTab.swift | 2 +- yobble/config.swift | 2 +- yobble/yobble.entitlements | 12 +- yobble/yobbleApp.swift | 3 + 12 files changed, 359 insertions(+), 8 deletions(-) create mode 100644 yobble/AppDelegate.swift create mode 100644 yobble/GoogleService-Info.plist create mode 100644 yobble/Info.plist create mode 100644 yobble/PushAppDelegate.swift diff --git a/yobble.xcodeproj/project.pbxproj b/yobble.xcodeproj/project.pbxproj index a21b427..95a4d85 100644 --- a/yobble.xcodeproj/project.pbxproj +++ b/yobble.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 1A38EB882EDE871B00DD8FC4 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 1A38EB872EDE871B00DD8FC4 /* FirebaseMessaging */; }; + 1A38EB8C2EDE8CC700DD8FC4 /* FirebaseCore in Frameworks */ = {isa = PBXBuildFile; productRef = 1A38EB8B2EDE8CC700DD8FC4 /* FirebaseCore */; }; 1A85C6CC2EA6FD73009FA847 /* SocketIO in Frameworks */ = {isa = PBXBuildFile; productRef = 1A85C6CB2EA6FD73009FA847 /* SocketIO */; }; /* End PBXBuildFile section */ @@ -33,9 +35,22 @@ 1A6D61E42E7CD04100B9F736 /* yobbleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = yobbleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 1A38EB832EDE80E700DD8FC4 /* Exceptions for "yobble" folder in "yobble" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 1A6D61CB2E7CD03E00B9F736 /* yobble */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + /* Begin PBXFileSystemSynchronizedRootGroup section */ 1A6D61CE2E7CD03E00B9F736 /* yobble */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 1A38EB832EDE80E700DD8FC4 /* Exceptions for "yobble" folder in "yobble" target */, + ); path = yobble; sourceTree = ""; }; @@ -56,6 +71,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 1A38EB882EDE871B00DD8FC4 /* FirebaseMessaging in Frameworks */, + 1A38EB8C2EDE8CC700DD8FC4 /* FirebaseCore in Frameworks */, 1A85C6CC2EA6FD73009FA847 /* SocketIO in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -111,6 +128,8 @@ buildRules = ( ); dependencies = ( + 1A38EB922EDE8ED500DD8FC4 /* PBXTargetDependency */, + 1A38EB902EDE8ECA00DD8FC4 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( 1A6D61CE2E7CD03E00B9F736 /* yobble */, @@ -118,6 +137,8 @@ name = yobble; packageProductDependencies = ( 1A85C6CB2EA6FD73009FA847 /* SocketIO */, + 1A38EB872EDE871B00DD8FC4 /* FirebaseMessaging */, + 1A38EB8B2EDE8CC700DD8FC4 /* FirebaseCore */, ); productName = yobble; productReference = 1A6D61CC2E7CD03E00B9F736 /* yobble.app */; @@ -204,6 +225,7 @@ minimizedProjectReferenceProxies = 1; packageReferences = ( 1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */, + 1A38EB862EDE871B00DD8FC4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, ); preferredProjectObjectVersion = 77; productRefGroup = 1A6D61CD2E7CD03E00B9F736 /* Products */; @@ -266,6 +288,14 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 1A38EB902EDE8ECA00DD8FC4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 1A38EB8F2EDE8ECA00DD8FC4 /* FirebaseMessaging */; + }; + 1A38EB922EDE8ED500DD8FC4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + productRef = 1A38EB912EDE8ED500DD8FC4 /* FirebaseCore */; + }; 1A6D61DC2E7CD04000B9F736 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1A6D61CB2E7CD03E00B9F736 /* yobble */; @@ -409,6 +439,7 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = yobble/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; @@ -449,6 +480,7 @@ ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = yobble/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; @@ -609,6 +641,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 1A38EB862EDE871B00DD8FC4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMinorVersion; + minimumVersion = 12.6.0; + }; + }; 1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/socketio/socket.io-client-swift"; @@ -620,6 +660,26 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 1A38EB872EDE871B00DD8FC4 /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = 1A38EB862EDE871B00DD8FC4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; + 1A38EB8B2EDE8CC700DD8FC4 /* FirebaseCore */ = { + isa = XCSwiftPackageProductDependency; + package = 1A38EB862EDE871B00DD8FC4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseCore; + }; + 1A38EB8F2EDE8ECA00DD8FC4 /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = 1A38EB862EDE871B00DD8FC4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; + 1A38EB912EDE8ED500DD8FC4 /* FirebaseCore */ = { + isa = XCSwiftPackageProductDependency; + package = 1A38EB862EDE871B00DD8FC4 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseCore; + }; 1A85C6CB2EA6FD73009FA847 /* SocketIO */ = { isa = XCSwiftPackageProductDependency; package = 1A85C6CA2EA6FC08009FA847 /* XCRemoteSwiftPackageReference "socket" */; diff --git a/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c865547..3675701 100644 --- a/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/yobble.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,123 @@ { - "originHash" : "c9fb241c5f575df8f20b39649006995779013948e60c51c3f85b729f83b054e7", + "originHash" : "600d4311db652d123053aed731b25dc6c4fe63e106bb9043d105bb4fedf8b79b", "pins" : [ + { + "identity" : "abseil-cpp-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/abseil-cpp-binary.git", + "state" : { + "revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5", + "version" : "1.2024072200.0" + } + }, + { + "identity" : "app-check", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/app-check.git", + "state" : { + "revision" : "61b85103a1aeed8218f17c794687781505fbbef5", + "version" : "11.2.0" + } + }, + { + "identity" : "firebase-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/firebase-ios-sdk", + "state" : { + "revision" : "087bb95235f676c1a37e928769a5b6645dcbd325", + "version" : "12.6.0" + } + }, + { + "identity" : "google-ads-on-device-conversion-ios-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk", + "state" : { + "revision" : "35b601a60fbbea2de3ea461f604deaaa4d8bbd0c", + "version" : "3.2.0" + } + }, + { + "identity" : "googleappmeasurement", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleAppMeasurement.git", + "state" : { + "revision" : "c2d59acf17a8ba7ed80a763593c67c9c7c006ad1", + "version" : "12.5.0" + } + }, + { + "identity" : "googledatatransport", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleDataTransport.git", + "state" : { + "revision" : "617af071af9aa1d6a091d59a202910ac482128f9", + "version" : "10.1.0" + } + }, + { + "identity" : "googleutilities", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/GoogleUtilities.git", + "state" : { + "revision" : "60da361632d0de02786f709bdc0c4df340f7613e", + "version" : "8.1.0" + } + }, + { + "identity" : "grpc-binary", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/grpc-binary.git", + "state" : { + "revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6", + "version" : "1.69.1" + } + }, + { + "identity" : "gtm-session-fetcher", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/gtm-session-fetcher.git", + "state" : { + "revision" : "fb7f2740b1570d2f7599c6bb9531bf4fad6974b7", + "version" : "5.0.0" + } + }, + { + "identity" : "interop-ios-for-google-sdks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/interop-ios-for-google-sdks.git", + "state" : { + "revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe", + "version" : "101.0.0" + } + }, + { + "identity" : "leveldb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/leveldb.git", + "state" : { + "revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1", + "version" : "1.22.5" + } + }, + { + "identity" : "nanopb", + "kind" : "remoteSourceControl", + "location" : "https://github.com/firebase/nanopb.git", + "state" : { + "revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1", + "version" : "2.30910.0" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac", + "version" : "2.4.0" + } + }, { "identity" : "socket.io-client-swift", "kind" : "remoteSourceControl", @@ -18,6 +135,15 @@ "revision" : "c6bfd1af48efcc9a9ad203665db12375ba6b145a", "version" : "4.0.8" } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "c169a5744230951031770e27e475ff6eefe51f9d", + "version" : "1.33.3" + } } ], "version" : 3 diff --git a/yobble/AppDelegate.swift b/yobble/AppDelegate.swift new file mode 100644 index 0000000..7945c81 --- /dev/null +++ b/yobble/AppDelegate.swift @@ -0,0 +1,57 @@ +//e8DBOKOTPUGxtvK2mqZ-gy:APA91bGtJO3Jf8NxuvzSnfj4YyZllen29x1c_o3UtKHKTvnVcTz0TdHapCyjJH4ZsuiO9z2HhGW134165c-VXmrdKlYSBGz5-ZtU0lTWLe5LDLuZGDbqYdk + +import Firebase +import FirebaseMessaging +import UserNotifications +import UIKit + +class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate { + + func application(_ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + + print("hello") + FirebaseApp.configure() + + UNUserNotificationCenter.current().delegate = self + Messaging.messaging().delegate = self + + UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, _ in + if granted { + DispatchQueue.main.async { + UIApplication.shared.registerForRemoteNotifications() + } + } + } + + return true + } + + // Foreground notifications — вот это важное! + func userNotificationCenter( + _ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void + ) { + completionHandler([.banner, .sound, .badge]) // push +// completionHandler([]) // no push + } + + func application(_ application: UIApplication, + didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + + let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() + print("📨 APNs device token:", token) + + Messaging.messaging().apnsToken = deviceToken + } + + func application(_ application: UIApplication, + didFailToRegisterForRemoteNotificationsWithError error: Error) { + print("❌ APNs registration failed:", error) + } + + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + print("🔥 FCM token:", fcmToken ?? "NO TOKEN") + } +} diff --git a/yobble/GoogleService-Info.plist b/yobble/GoogleService-Info.plist new file mode 100644 index 0000000..0f79937 --- /dev/null +++ b/yobble/GoogleService-Info.plist @@ -0,0 +1,30 @@ + + + + + API_KEY + AIzaSyAdhhLghSRDeN9ivTG5jd9ZT6DNdQ8pBM4 + GCM_SENDER_ID + 1058456897662 + PLIST_VERSION + 1 + BUNDLE_ID + org.yobble.yobble + PROJECT_ID + yobble + STORAGE_BUCKET + yobble.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:1058456897662:ios:c2a898d6a6412b8709f02f + + \ No newline at end of file diff --git a/yobble/Info.plist b/yobble/Info.plist new file mode 100644 index 0000000..39d3a05 --- /dev/null +++ b/yobble/Info.plist @@ -0,0 +1,12 @@ + + + + + UIApplicationSupportsMultipleScenes + + UIBackgroundModes + + remote-notification + + + diff --git a/yobble/Network/AuthService.swift b/yobble/Network/AuthService.swift index 87eb2ff..3c38c95 100644 --- a/yobble/Network/AuthService.swift +++ b/yobble/Network/AuthService.swift @@ -44,7 +44,7 @@ final class AuthService { } NetworkClient.shared.request( - path: "/v1/auth/login", + path: "/v1/auth/login/password", method: .post, body: body, requiresAuth: false diff --git a/yobble/PushAppDelegate.swift b/yobble/PushAppDelegate.swift new file mode 100644 index 0000000..e7a84e3 --- /dev/null +++ b/yobble/PushAppDelegate.swift @@ -0,0 +1,55 @@ +//// +//// PushAppDelegate.swift +//// yobble +//// +//// Created by cheykrym on 02.12.2025. +//// 72acf38bfbf0e990f745a612527911f8df1d63d60de70d41391c54b52498f7ab +// +//import UIKit +//import UserNotifications +// +//class PushAppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { +// +// // Запрос разрешения на уведомления +// func application(_ application: UIApplication, +// didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { +// +// UNUserNotificationCenter.current().delegate = self +// +// UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in +// guard granted else { +// print("⛔️ User denied push notifications") +// return +// } +// +// DispatchQueue.main.async { +// UIApplication.shared.registerForRemoteNotifications() +// } +// } +// +// return true +// } +// +// // Получаем пуш-токен устройства +// func application(_ application: UIApplication, +// didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { +// +// let token = deviceToken.map { String(format: "%02x", $0) }.joined() +// print("📨 Device Token:", token) +// } +// +// // Ошибка регистрации +// func application(_ application: UIApplication, +// didFailToRegisterForRemoteNotificationsWithError error: Error) { +// print("❌ Failed to register for remote notifications:", error) +// } +// +// // Пуш пришёл в форграунде +// func userNotificationCenter(_ center: UNUserNotificationCenter, +// willPresent notification: UNNotification, +// withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { +// +// // показываем алерт даже если приложение открыто +// completionHandler([.banner, .sound, .badge]) +// } +//} diff --git a/yobble/Services/SocketService.swift b/yobble/Services/SocketService.swift index a66a68e..ff4b829 100644 --- a/yobble/Services/SocketService.swift +++ b/yobble/Services/SocketService.swift @@ -453,3 +453,7 @@ final class SocketService { extension Notification.Name { static let socketDidReceivePrivateMessage = Notification.Name("socketDidReceivePrivateMessage") } + + +//[SocketService] Failed to decode new message: typeMismatch(Swift.String, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "messageId", intValue: nil)], debugDescription: "Expected to decode String or number for key messageId", underlyingError: nil)) +//[SocketService] payload={"event":"chat_private:new_message","payload":{"is_viewed":false,"content":"Ttyijfff","message_id":241,"message_type":["text"],"chat_id":"838146ed-1251-42df-b529-da7870101fa3","media_link":null,"created_at":"2025-11-27T23:10:09.039724+00:00","updated_at":null,"sender_data":{"full_name":"Системный Админ 1","is_verified":true,"is_system":false,"rating":{"status":"fine","rating":5},"custom_name":null,"login":"admin","created_at":"2025-10-20T18:19:04.911483Z","stories":[],"user_id":"7a319996-8e6a-4cc4-a808-091eda7cea6f","permissions":{"you_can_call_permission":true,"you_can_public_invite_permission":true,"you_can_send_message":true,"you_can_group_invite_permission":true},"bio":null,"profile_permissions":{"allow_messages_from_non_contacts":true,"max_message_auto_delete_seconds":null,"force_auto_delete_messages_in_private":false,"is_searchable":true,"allow_message_forwarding":true,"allow_server_chats":true},"last_seen":3300664,"relationship":{"is_current_user_in_contacts_of_target":false,"is_current_user_in_blacklist_of_target":false,"is_target_user_blocked_by_current_user":false}},"forward_metadata":null,"sender_id":"7a319996-8e6a-4cc4-a808-091eda7cea6f"}} diff --git a/yobble/Views/Tab/ContactsTab.swift b/yobble/Views/Tab/ContactsTab.swift index 5aece24..41bc6e3 100644 --- a/yobble/Views/Tab/ContactsTab.swift +++ b/yobble/Views/Tab/ContactsTab.swift @@ -149,7 +149,7 @@ struct ContactsTab: View { contacts = payloads.map(Contact.init) } catch { loadError = error.localizedDescription - activeAlert = .error(message: error.localizedDescription) +// activeAlert = .error(message: error.localizedDescription) if AppConfig.DEBUG { print("[ContactsTab] load contacts failed: \(error)") } } diff --git a/yobble/config.swift b/yobble/config.swift index 07d12a1..5c6f7f0 100644 --- a/yobble/config.swift +++ b/yobble/config.swift @@ -1,7 +1,7 @@ import SwiftUI struct AppConfig { - static var DEBUG: Bool = true + static var DEBUG: Bool = false //static let SERVICE = Bundle.main.bundleIdentifier ?? "default.service" static let PROTOCOL = "https" static let API_SERVER = "\(PROTOCOL)://api.yobble.org" diff --git a/yobble/yobble.entitlements b/yobble/yobble.entitlements index f2ef3ae..6c23f6f 100644 --- a/yobble/yobble.entitlements +++ b/yobble/yobble.entitlements @@ -2,9 +2,13 @@ - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - + aps-environment + development + com.apple.developer.aps-environment + development + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + diff --git a/yobble/yobbleApp.swift b/yobble/yobbleApp.swift index f464a4b..8b413cd 100644 --- a/yobble/yobbleApp.swift +++ b/yobble/yobbleApp.swift @@ -10,6 +10,9 @@ import CoreData @main struct yobbleApp: App { +// @UIApplicationDelegateAdaptor(PushAppDelegate.self) var appDelegate + @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate + @StateObject private var themeManager = ThemeManager() @StateObject private var viewModel = LoginViewModel() @StateObject private var messageCenter = IncomingMessageCenter()