From 87b0383d8a62893fb93e3d5d273f6f185c3becde Mon Sep 17 00:00:00 2001 From: Anton Poltoratskyi Date: Thu, 20 Sep 2018 18:18:41 +0300 Subject: [PATCH 1/5] [NY-3564] Don't disconnect before share extension presentation. --- Nynja/Library/UI/AlertManager.swift | 8 +++----- Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift | 1 - Nynja/Modules/Message/View/MessageVC.swift | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Nynja/Library/UI/AlertManager.swift b/Nynja/Library/UI/AlertManager.swift index cbea0456e..521f6d729 100644 --- a/Nynja/Library/UI/AlertManager.swift +++ b/Nynja/Library/UI/AlertManager.swift @@ -11,7 +11,7 @@ import UIKit class AlertManager { - static let sharedInstance : AlertManager = { + static let sharedInstance: AlertManager = { let instance = AlertManager() return instance }() @@ -188,11 +188,9 @@ class AlertManager { }, cancel: cancel) } - func showNativeShare(with activityItems: [Any]) { + func showNativeShare(with activityItems: [Any], completion: UIActivityViewControllerCompletionWithItemsHandler? = nil) { let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - activityViewController.completionWithItemsHandler = { (type, flag, objects, error) in - MQTTService.sharedInstance.reconnect() - } + activityViewController.completionWithItemsHandler = completion presentingController?.present(activityViewController, animated: true, completion: nil) } diff --git a/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift b/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift index afbdace84..78d8c5776 100644 --- a/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift +++ b/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift @@ -213,7 +213,6 @@ class GroupStorageListVC : UIViewController, GroupStorageCellDelegate, ContextMe delegate?.pathForUrl(url, completion: { (path) in if path != nil { - MQTTService.sharedInstance.disconnect() let localUrl = URL(fileURLWithPath: path!) AlertManager.sharedInstance.showNativeShare(with: [localUrl]) } diff --git a/Nynja/Modules/Message/View/MessageVC.swift b/Nynja/Modules/Message/View/MessageVC.swift index c8cc69c0b..c93c62e82 100644 --- a/Nynja/Modules/Message/View/MessageVC.swift +++ b/Nynja/Modules/Message/View/MessageVC.swift @@ -908,7 +908,6 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw } func showNativeShare(for fileUrl: URL) { - MQTTService.sharedInstance.disconnect() AlertManager.sharedInstance.showNativeShare(with: [fileUrl]) } -- GitLab From 0361cd1d3794dd1c03cced3415a819208b4e2587 Mon Sep 17 00:00:00 2001 From: Anton Poltoratskyi Date: Fri, 21 Sep 2018 17:28:24 +0300 Subject: [PATCH 2/5] [NY-3564] Implemented post notification from share extension to host Nynja application. --- .../UI/ForwardSelectorViewController.swift | 1 + Nynja.xcodeproj/project.pbxproj | 20 +++ Nynja/Library/UI/AlertManager.swift | 19 ++- .../DarwinNotificationManager+Share.swift | 28 ++++ .../DarwinNotificationManager.swift | 142 ++++++++++++++++++ 5 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 Nynja/Notifications/DarwinNotificationManager+Share.swift create mode 100644 Nynja/Notifications/DarwinNotificationManager.swift diff --git a/Nynja-Share/UI/ForwardSelectorViewController.swift b/Nynja-Share/UI/ForwardSelectorViewController.swift index 5a85c781d..e13d8707a 100644 --- a/Nynja-Share/UI/ForwardSelectorViewController.swift +++ b/Nynja-Share/UI/ForwardSelectorViewController.swift @@ -290,6 +290,7 @@ final class ForwardSelectorViewController: UIViewController, ForwardSelectorView override func viewDidLoad() { super.viewDidLoad() + DarwinNotificationManager.shared.postShareDidOpen() getAttachmentContent() presenter.view = self presenter.interactor.handlerServerSignals = { [weak self] signal in diff --git a/Nynja.xcodeproj/project.pbxproj b/Nynja.xcodeproj/project.pbxproj index 179cef84f..73e6956f8 100644 --- a/Nynja.xcodeproj/project.pbxproj +++ b/Nynja.xcodeproj/project.pbxproj @@ -944,6 +944,10 @@ 8580BAF420BD9B8000239D9D /* Range+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8580BAF220BD9B7F00239D9D /* Range+Extension.swift */; }; 8584C90E20920F3C001A0BBB /* StickerGridCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8584C90C20920F3C001A0BBB /* StickerGridCollectionViewCell.swift */; }; 8584C90F20920F3C001A0BBB /* StickerGridCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8584C90D20920F3C001A0BBB /* StickerGridCellModel.swift */; }; + 85855BC82154FD5B00D1580E /* DarwinNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */; }; + 85855BCA2155180400D1580E /* DarwinNotificationManager+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */; }; + 85855BCB215531A100D1580E /* DarwinNotificationManager+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */; }; + 85855BCC215531A600D1580E /* DarwinNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */; }; 8586CAC5203335C7009F2A75 /* ForwardAvatarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8586CAC4203335C7009F2A75 /* ForwardAvatarViewModel.swift */; }; 8586CACB203338F6009F2A75 /* ForwardTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8586CACA203338F6009F2A75 /* ForwardTarget.swift */; }; 858A72E5A4AE48CE24AFF649 /* MainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CEB31C47B0FEB0040FD0DA /* MainInteractor.swift */; }; @@ -3006,6 +3010,8 @@ 8580BAF220BD9B7F00239D9D /* Range+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Range+Extension.swift"; sourceTree = ""; }; 8584C90C20920F3C001A0BBB /* StickerGridCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerGridCollectionViewCell.swift; sourceTree = ""; }; 8584C90D20920F3C001A0BBB /* StickerGridCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerGridCellModel.swift; sourceTree = ""; }; + 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarwinNotificationManager.swift; sourceTree = ""; }; + 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DarwinNotificationManager+Share.swift"; sourceTree = ""; }; 8586CAC4203335C7009F2A75 /* ForwardAvatarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardAvatarViewModel.swift; sourceTree = ""; }; 8586CACA203338F6009F2A75 /* ForwardTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardTarget.swift; sourceTree = ""; }; 858BC122203320BB0022EB25 /* ForwardSelectorDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardSelectorDataSource.swift; sourceTree = ""; }; @@ -5635,6 +5641,7 @@ 3A768E1C1ECD152300108F7C /* Services */ = { isa = PBXGroup; children = ( + 85855BC62154FD3400D1580E /* Notifications */, 4BE2C5E42142EB5A00A73DD9 /* NynjaCalls */, 4BE2C5CE2142EAC500A73DD9 /* Audio */, 4B0DBA892137F6F800D79163 /* ChatService */, @@ -8068,6 +8075,15 @@ path = StickerPack; sourceTree = ""; }; + 85855BC62154FD3400D1580E /* Notifications */ = { + isa = PBXGroup; + children = ( + 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */, + 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */, + ); + path = Notifications; + sourceTree = ""; + }; 8595E0DA204863CF00178171 /* CollectionView */ = { isa = PBXGroup; children = ( @@ -13312,6 +13328,7 @@ 2610D4642076516900E6E2B2 /* Array+Feature.swift in Sources */, 262D4389203352D4002F1E45 /* FriendExtansion+BERT.swift in Sources */, A42CE5A220692EDB000889CC /* operation.swift in Sources */, + 85855BCC215531A600D1580E /* DarwinNotificationManager.swift in Sources */, A42D519B206A34E200EEB952 /* IoHandler.swift in Sources */, 26352917207572DC00DC6FBD /* JobExtension+BERT.swift in Sources */, 26C0C1CB2073C93800C530DA /* ForwardTarget.swift in Sources */, @@ -13364,6 +13381,7 @@ 266AE8C42034971A0096A12C /* AsyncOperation.swift in Sources */, 00E9825F205FE86E008BF03D /* AuthHandler.swift in Sources */, 359EB27C1F9A2C8C00147437 /* MQTTServiceHelper.swift in Sources */, + 85855BCB215531A100D1580E /* DarwinNotificationManager+Share.swift in Sources */, A4B544F020EFB4EC00EB7B0F /* BertTupleExtension.swift in Sources */, 2604C0962069163C0051E4FB /* HandlerServiceProtocol.swift in Sources */, 26B5F7431FB0FF7B00CEC6AE /* FileManager.swift in Sources */, @@ -14192,6 +14210,7 @@ 2648C4192069B52100863614 /* ChangeNumberStep2ViewController.swift in Sources */, 85788C4E20443DD2003600C9 /* BuildNumberItemsFactory.swift in Sources */, A42D52CB206A53AB00EEB952 /* CDR_Spec.swift in Sources */, + 85855BCA2155180400D1580E /* DarwinNotificationManager+Share.swift in Sources */, 2603139220A0A4B9009AC66D /* LanguageSettingProtocol.swift in Sources */, F105C6BD20A1347E0091786A /* PhotoPreviewViewController.swift in Sources */, B79FA03921091ED000F286BF /* InterpretationInteractor.swift in Sources */, @@ -14574,6 +14593,7 @@ 5C468A609C445962C0D19DD3 /* HistoryViewController.swift in Sources */, 854A4B2D2080D68200759152 /* CellWithArrowCellModel.swift in Sources */, C9405149204C7FAF00D72B04 /* DataAndStoragePresenter.swift in Sources */, + 85855BC82154FD5B00D1580E /* DarwinNotificationManager.swift in Sources */, 3819EAEB412EBA913146F443 /* HistoryPresenter.swift in Sources */, E7718BF51FB5D6080070B402 /* UIView+Debug.swift in Sources */, 26245F44204EF67C00C8D3DD /* PresenterApearingProtocol.swift in Sources */, diff --git a/Nynja/Library/UI/AlertManager.swift b/Nynja/Library/UI/AlertManager.swift index 521f6d729..ea2740f8a 100644 --- a/Nynja/Library/UI/AlertManager.swift +++ b/Nynja/Library/UI/AlertManager.swift @@ -188,9 +188,24 @@ class AlertManager { }, cancel: cancel) } - func showNativeShare(with activityItems: [Any], completion: UIActivityViewControllerCompletionWithItemsHandler? = nil) { + func showNativeShare(with activityItems: [Any]) { + var shareExtensionWasOpen = false + + let notificationManager = DarwinNotificationManager.shared + + notificationManager.observeShareDidOpen(self) { _ in + shareExtensionWasOpen = true + MQTTService.sharedInstance.disconnect() + } + let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - activityViewController.completionWithItemsHandler = completion + activityViewController.completionWithItemsHandler = { _, _, _, _ in + + notificationManager.stopObservingShareExtension(self) + if shareExtensionWasOpen { + MQTTService.sharedInstance.reconnect() + } + } presentingController?.present(activityViewController, animated: true, completion: nil) } diff --git a/Nynja/Notifications/DarwinNotificationManager+Share.swift b/Nynja/Notifications/DarwinNotificationManager+Share.swift new file mode 100644 index 000000000..28eb04895 --- /dev/null +++ b/Nynja/Notifications/DarwinNotificationManager+Share.swift @@ -0,0 +1,28 @@ +// +// DarwinNotificationManager+Share.swift +// Nynja +// +// Created by Anton Poltoratskyi on 21.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +extension DarwinNotificationManager { + + private var notificationName: String { + return "com.nynja.dev.mobile.communicator.NynjaShare-did-open" + } + + func postShareDidOpen() { + postNotification(name: notificationName) + } + + func observeShareDidOpen(_ observer: AnyObject, handler: @escaping (Notification) -> Void) { + addObserver(observer, forName: notificationName, handler: handler) + } + + func stopObservingShareExtension(_ observer: AnyObject) { + removeObserver(observer, forName: notificationName) + } +} diff --git a/Nynja/Notifications/DarwinNotificationManager.swift b/Nynja/Notifications/DarwinNotificationManager.swift new file mode 100644 index 000000000..31fd983a8 --- /dev/null +++ b/Nynja/Notifications/DarwinNotificationManager.swift @@ -0,0 +1,142 @@ +// +// DarwinNotificationManager.swift +// Nynja +// +// Created by Anton Poltoratskyi on 21.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +final class DarwinNotificationManager { + + // MARK: - Handlers + + private final class Subscriber: WeakRef { + var handler: (Notification) -> Void + + init(value: AnyObject?, handler: @escaping (Notification) -> Void) { + self.handler = handler + super.init(value: value) + } + } + + private var handlers: [String: [Subscriber]] = [:] + + private let notificationCenter = NotificationCenter.default + + private var darwinNotificationCenter: CFNotificationCenter { + return CFNotificationCenterGetDarwinNotifyCenter() + } + + + // MARK: - Init + + static let shared = DarwinNotificationManager() + + private init() {} + + + // MARK: - Actions + + func postNotification(name: String) { + let name = CFNotificationName(name as CFString) + CFNotificationCenterPostNotification(darwinNotificationCenter, name, nil, nil, true) + } + + func addObserver(_ object: AnyObject, forName name: String, handler: @escaping (Notification) -> Void) { + let subscriber = Subscriber(value: object, handler: handler) + + guard handlers[name] == nil || handlers[name]!.isEmpty else { + handlers[name]?.append(subscriber) + return + } + handlers[name] = [subscriber] + + // Global Observer + + var selfObserver = self + let observer = UnsafeRawPointer(withUnsafePointer(to: &selfObserver, { $0 })) + + CFNotificationCenterAddObserver(darwinNotificationCenter, observer, notificationCallback, name as CFString, nil, .deliverImmediately) + + // Local Observer + + let name = Notification.Name(name) + notificationCenter.addObserver(self, selector: #selector(handleNotification), name: name, object: nil) + } + + func removeObserver(_ object: AnyObject, forName name: String){ + guard let subscribers = handlers[name], !subscribers.isEmpty else { + return + } + let newSubscribers = subscribers.filter { $0.value !== object && $0.value != nil } + handlers[name] = newSubscribers + + guard newSubscribers.isEmpty else { + return + } + removeInnerObservers(self, forName: name) + } + + func removeObserver(_ object: AnyObject) { + guard case let subscribers = handlers.values, !subscribers.isEmpty else { + return + } + for (name, subscribers) in handlers { + handlers[name] = subscribers.filter { $0.value !== object && $0.value != nil } + } + guard handlers.isEmpty else { + return + } + removeInnerObservers(self) + } + + private func removeInnerObservers(_ object: AnyObject, forName name: String) { + var object = object + let name = CFNotificationName(name as CFString) + let observer = UnsafeRawPointer(withUnsafePointer(to: &object, { $0 })) + + CFNotificationCenterRemoveObserver(darwinNotificationCenter, observer, name, nil) + notificationCenter.removeObserver(object, name: name.nsNotificationName, object: nil) + } + + private func removeInnerObservers(_ object: AnyObject) { + var object = object + let observer = UnsafeRawPointer(withUnsafePointer(to: &object, { $0 })) + + CFNotificationCenterRemoveEveryObserver(darwinNotificationCenter, observer) + notificationCenter.removeObserver(object) + } + + + // MARK: - Notifications + + @objc private func handleNotification(_ notification: Notification) { + let name = notification.name.rawValue + handlers[name]?.forEach { $0.handler(notification) } + } +} + +extension CFNotificationName { + + var nsNotificationName: Notification.Name { + return Notification.Name(rawValue: rawValue as String) + } +} + +// MARK: - Callback + +private func notificationCallback(_ center: CFNotificationCenter?, + _ observer: UnsafeMutableRawPointer?, + _ name: CFNotificationName?, + _ object: UnsafeRawPointer?, + _ userInfo: CFDictionary?) { + + guard let name = name?.nsNotificationName else { + return + } + print("SHARE NOTIFICATION: \(name)") + let notification = Notification(name: name) + NotificationCenter.default.post(notification) +} -- GitLab From b6bfbfaff4ad041d4d3dc9eb1be3e9a7e6b4f3da Mon Sep 17 00:00:00 2001 From: Anton Poltoratskyi Date: Fri, 21 Sep 2018 17:36:20 +0300 Subject: [PATCH 3/5] [NY-3564] Fixed activity view controller on InviteFriendsWireframe. --- .../InviteFriends/WireFrame/InviteFriendsWireframe.swift | 3 +-- Nynja/Notifications/DarwinNotificationManager.swift | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift b/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift index 9c05f4b5a..0908aad2c 100644 --- a/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift +++ b/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift @@ -58,8 +58,7 @@ class InviteFriendsWireFrame: InviteFriendsWireFrameProtocol { } func shareNynja() { - let activityVC = UIActivityViewController(activityItems: ["nynja_share_string".localized], applicationActivities: nil) - viewController?.present(activityVC, animated: true, completion: nil) + AlertManager.sharedInstance.showNativeShare(with: ["nynja_share_string".localized]) } func closeSMSscreen(smsScreen: MFMessageComposeViewController) { diff --git a/Nynja/Notifications/DarwinNotificationManager.swift b/Nynja/Notifications/DarwinNotificationManager.swift index 31fd983a8..73f19fe0f 100644 --- a/Nynja/Notifications/DarwinNotificationManager.swift +++ b/Nynja/Notifications/DarwinNotificationManager.swift @@ -125,6 +125,7 @@ extension CFNotificationName { } } + // MARK: - Callback private func notificationCallback(_ center: CFNotificationCenter?, @@ -136,7 +137,6 @@ private func notificationCallback(_ center: CFNotificationCenter?, guard let name = name?.nsNotificationName else { return } - print("SHARE NOTIFICATION: \(name)") let notification = Notification(name: name) NotificationCenter.default.post(notification) } -- GitLab From 5776f8b1f2c24ae72c838ffd8780ba71e40410f8 Mon Sep 17 00:00:00 2001 From: Anton Poltoratskyi Date: Mon, 24 Sep 2018 15:40:03 +0300 Subject: [PATCH 4/5] [NY-3564] Implemented watching app group file container in order to check if share extension is opened. --- .../UI/ForwardSelectorInteractor.swift | 16 +++- .../UI/ForwardSelectorViewController.swift | 2 +- Nynja.xcodeproj/project.pbxproj | 22 +++++ Nynja/Files/AppGroupFlagContainer.swift | 66 +++++++++++++ Nynja/Files/AppGroupFlagObserver.swift | 40 ++++++++ Nynja/Files/DirectoryWatcher.swift | 96 +++++++++++++++++++ Nynja/Library/UI/AlertManager.swift | 26 +++-- 7 files changed, 258 insertions(+), 10 deletions(-) create mode 100644 Nynja/Files/AppGroupFlagContainer.swift create mode 100644 Nynja/Files/AppGroupFlagObserver.swift create mode 100644 Nynja/Files/DirectoryWatcher.swift diff --git a/Nynja-Share/UI/ForwardSelectorInteractor.swift b/Nynja-Share/UI/ForwardSelectorInteractor.swift index 0e9293cf6..ad930c42f 100644 --- a/Nynja-Share/UI/ForwardSelectorInteractor.swift +++ b/Nynja-Share/UI/ForwardSelectorInteractor.swift @@ -73,14 +73,26 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P private var contacts: [ForwardTarget]? private var groups: [ForwardTarget]? - required init(mode: ForwardSelectorMode) { self.mode = mode ProfileHandler.delegate = self MessageHandler.delegate = self ContactHandler.delegate = self IoHandler.delegate = self - setupAmazon() + setupAmazon() + notifyHostApplication() + } + + func notifyHostApplication() { + guard let container = AppGroupFlagContainer(fileManager: .default, appGroup: Bundle.main.appGroupName) else { + return + } + do { + try container.prepare() + try container.setFlag(.shareExtension) + } catch { + LogService.log(topic: .fileSystem) { error.localizedDescription } + } } func connectToServer() { diff --git a/Nynja-Share/UI/ForwardSelectorViewController.swift b/Nynja-Share/UI/ForwardSelectorViewController.swift index e13d8707a..e23b724bd 100644 --- a/Nynja-Share/UI/ForwardSelectorViewController.swift +++ b/Nynja-Share/UI/ForwardSelectorViewController.swift @@ -290,7 +290,7 @@ final class ForwardSelectorViewController: UIViewController, ForwardSelectorView override func viewDidLoad() { super.viewDidLoad() - DarwinNotificationManager.shared.postShareDidOpen() + getAttachmentContent() presenter.view = self presenter.interactor.handlerServerSignals = { [weak self] signal in diff --git a/Nynja.xcodeproj/project.pbxproj b/Nynja.xcodeproj/project.pbxproj index 73e6956f8..2e2e9c220 100644 --- a/Nynja.xcodeproj/project.pbxproj +++ b/Nynja.xcodeproj/project.pbxproj @@ -723,6 +723,10 @@ 850833DB2037171600587EEF /* FileExtensionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850833DA2037171600587EEF /* FileExtensionView.swift */; }; 8509452B206E684300B43C1C /* AddParticipantsContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509452A206E684300B43C1C /* AddParticipantsContactCell.swift */; }; 8509AC62206A54420089089B /* ResponseResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509AC61206A54420089089B /* ResponseResult.swift */; }; + 8509FC852158F7D100734D93 /* AppGroupFlagContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */; }; + 8509FC872158F7FC00734D93 /* DirectoryWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC862158F7FC00734D93 /* DirectoryWatcher.swift */; }; + 8509FC89215908B300734D93 /* AppGroupFlagObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC88215908B300734D93 /* AppGroupFlagObserver.swift */; }; + 8509FC8A2159095900734D93 /* AppGroupFlagContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */; }; 850A0C6520469AED004F79AD /* UserSettingsRespondable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850A0C6420469AED004F79AD /* UserSettingsRespondable.swift */; }; 850A0C672046B65D004F79AD /* WCItemsFactoryDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850A0C662046B65D004F79AD /* WCItemsFactoryDecorator.swift */; }; 850A2BB0203584B000D68FDF /* SearchActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850A2BAF203584B000D68FDF /* SearchActionsView.swift */; }; @@ -2820,6 +2824,9 @@ 850833DA2037171600587EEF /* FileExtensionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileExtensionView.swift; sourceTree = ""; }; 8509452A206E684300B43C1C /* AddParticipantsContactCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsContactCell.swift; sourceTree = ""; }; 8509AC61206A54420089089B /* ResponseResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseResult.swift; sourceTree = ""; }; + 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupFlagContainer.swift; sourceTree = ""; }; + 8509FC862158F7FC00734D93 /* DirectoryWatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryWatcher.swift; sourceTree = ""; }; + 8509FC88215908B300734D93 /* AppGroupFlagObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupFlagObserver.swift; sourceTree = ""; }; 850A0C6420469AED004F79AD /* UserSettingsRespondable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsRespondable.swift; sourceTree = ""; }; 850A0C662046B65D004F79AD /* WCItemsFactoryDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WCItemsFactoryDecorator.swift; sourceTree = ""; }; 850A2BAF203584B000D68FDF /* SearchActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchActionsView.swift; sourceTree = ""; }; @@ -5641,6 +5648,7 @@ 3A768E1C1ECD152300108F7C /* Services */ = { isa = PBXGroup; children = ( + 8509FC832158F7B400734D93 /* Files */, 85855BC62154FD3400D1580E /* Notifications */, 4BE2C5E42142EB5A00A73DD9 /* NynjaCalls */, 4BE2C5CE2142EAC500A73DD9 /* Audio */, @@ -7178,6 +7186,16 @@ path = ThemePicker; sourceTree = ""; }; + 8509FC832158F7B400734D93 /* Files */ = { + isa = PBXGroup; + children = ( + 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */, + 8509FC88215908B300734D93 /* AppGroupFlagObserver.swift */, + 8509FC862158F7FC00734D93 /* DirectoryWatcher.swift */, + ); + path = Files; + sourceTree = ""; + }; 850C3015204DA84400DB26C2 /* Privacy */ = { isa = PBXGroup; children = ( @@ -13390,6 +13408,7 @@ 85E3AB3D21218A57005FC49A /* SeparatorView.swift in Sources */, A47785A220D18D4A0053E0D2 /* BaseView.swift in Sources */, A42CE58020692EDB000889CC /* error2.swift in Sources */, + 8509FC8A2159095900734D93 /* AppGroupFlagContainer.swift in Sources */, A42CE58820692EDB000889CC /* Cursor.swift in Sources */, A49E1BD320A9AA0E0074DFD3 /* BaseChatModel.swift in Sources */, A42CE5C820692EDB000889CC /* act_Spec.swift in Sources */, @@ -13697,6 +13716,7 @@ A42CE5AF20692EDB000889CC /* TypeSpec.swift in Sources */, FB0B721320907DB5003B9757 /* MessageEditService.swift in Sources */, 859B862C204820DC003272B2 /* ThemePickerPresenter.swift in Sources */, + 8509FC872158F7FC00734D93 /* DirectoryWatcher.swift in Sources */, 2603139B20A0A4BA009AC66D /* LanguageSelectorViewController.swift in Sources */, 2686D3201FC3E39C0079CB75 /* ContentNavigationVC.swift in Sources */, B7EF8EDB210C759400E0E981 /* InterpretationTypeCellModel.swift in Sources */, @@ -14798,6 +14818,7 @@ 26B32B961FE20BAB00888A0A /* DescExtension+BERT.swift in Sources */, 4B1D7E0B2029D8CD00703228 /* GroupOptionsItemsFactory.swift in Sources */, CCF8AA193F15D4191EC99051 /* SplashProtocols.swift in Sources */, + 8509FC852158F7D100734D93 /* AppGroupFlagContainer.swift in Sources */, 26342CAF20ECD16A00D2196B /* TranscribeShortResponseData.swift in Sources */, E743B5881FB08F0F00F72F92 /* ParticipantsAvatarCell.swift in Sources */, D883A2CBD629A340B27997EF /* SplashViewController.swift in Sources */, @@ -15150,6 +15171,7 @@ A432CF1F20B44C0000993AFB /* MaterialTextContainer.swift in Sources */, 5AD8110B5B87B1AB9F1C5B52 /* CreateGroupPresenter.swift in Sources */, A43B259520AB1DFA00FF8107 /* InputContentProtocol.swift in Sources */, + 8509FC89215908B300734D93 /* AppGroupFlagObserver.swift in Sources */, 2625DBF620EFC52E00E01C05 /* AudioFileConvertOperation.swift in Sources */, 0062D9482062EC4100B915AC /* InviteFriendsInteractor.swift in Sources */, 8562853220D140FC000C9739 /* InputBar+ButtonType.swift in Sources */, diff --git a/Nynja/Files/AppGroupFlagContainer.swift b/Nynja/Files/AppGroupFlagContainer.swift new file mode 100644 index 000000000..f7341dca5 --- /dev/null +++ b/Nynja/Files/AppGroupFlagContainer.swift @@ -0,0 +1,66 @@ +// +// AppGroupFlagContainer.swift +// Nynja +// +// Created by Anton Poltoratskyi on 24.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +class AppGroupFlagContainer { + + enum Flag: String { + case shareExtension = "share-extension.lock" + + var fileName: String { + return rawValue + } + } + + let fileManager: FileManager + + let containerURL: URL + + var flagsDirectoryURL: URL { + return containerURL.appendingPathComponent("flags") + } + + + // MARK: - Init + + init?(fileManager: FileManager, appGroup: String) { + self.fileManager = fileManager + + guard let containerURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { + return nil + } + self.containerURL = containerURL + } + + func prepare() throws { + if !fileManager.fileExists(atPath: flagsDirectoryURL.path) { + try fileManager.createDirectory(at: flagsDirectoryURL, withIntermediateDirectories: true, attributes: nil) + } + } + + + // MARK: - Flags + + func setFlag(_ flag: Flag) throws { + let flagURL = flagsDirectoryURL.appendingPathComponent(flag.fileName) + + // From Apple docs: + // If a file already exists at path, this method overwrites the contents of that file + // if the current process has the appropriate privileges to do so. + fileManager.createFile(atPath: flagURL.path, contents: nil, attributes: nil) + } + + func removeFlagIfExists(_ flag: Flag) throws { + let flagURL = flagsDirectoryURL.appendingPathComponent(flag.fileName) + guard fileManager.fileExists(atPath: flagURL.path) else { + return + } + try fileManager.removeItem(atPath: flagURL.path) + } +} diff --git a/Nynja/Files/AppGroupFlagObserver.swift b/Nynja/Files/AppGroupFlagObserver.swift new file mode 100644 index 000000000..d934c1f35 --- /dev/null +++ b/Nynja/Files/AppGroupFlagObserver.swift @@ -0,0 +1,40 @@ +// +// AppGroupFlagObserver.swift +// Nynja +// +// Created by Anton Poltoratskyi on 24.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +final class AppGroupFlagObserver: AppGroupFlagContainer { + + private var directoryWatcher: DirectoryWatcher? + + + // MARK: - Init + + deinit { + stopObserving() + } + + func observe(callback: @escaping ([Flag]) -> Void) throws { + try prepare() + + directoryWatcher = DirectoryWatcher.makeDirectoryWatcher(withPath: flagsDirectoryURL.path) { [weak self] watcher in + guard let `self` = self else { + return + } + do { + let content = try self.fileManager.contentsOfDirectory(atPath: self.flagsDirectoryURL.path) + let flags = content.compactMap { Flag(rawValue: $0) } + callback(flags) + } catch { } + } + } + + func stopObserving() { + directoryWatcher?.stop() + } +} diff --git a/Nynja/Files/DirectoryWatcher.swift b/Nynja/Files/DirectoryWatcher.swift new file mode 100644 index 000000000..f6950e471 --- /dev/null +++ b/Nynja/Files/DirectoryWatcher.swift @@ -0,0 +1,96 @@ +// +// DirectoryWatcher.swift +// Nynja +// +// Created by Anton Poltoratskyi on 24.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +public class DirectoryWatcher { + + public typealias Callback = (DirectoryWatcher) -> Void + + private var directoryFileDescriptor: Int32 = -1 { + didSet { + if oldValue != -1 { + close(oldValue) + } + } + } + + private var dispatchSource: DispatchSourceFileSystemObject? + + private let queue: DispatchQueue + + + // MARK: - Init + + private init(queue: DispatchQueue) { + self.queue = queue + } + + deinit { + stop() + } + + public static func makeDirectoryWatcher(withPath path: String, + onQueue queue: DispatchQueue = .main, + callback: @escaping Callback) -> DirectoryWatcher? { + let directoryWatcher = DirectoryWatcher(queue: queue) + + if !directoryWatcher.watch(path: path, callback: callback) { + assertionFailure() + return nil + } + + return directoryWatcher + } + + + // MARK: - Watch + + private func watch(path: String, callback: @escaping Callback) -> Bool { + // Open the directory + directoryFileDescriptor = open(path, O_EVTONLY) + if directoryFileDescriptor < 0 { + return false + } + + // Create and configure a DispatchSource to monitor it + let dispatchSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: directoryFileDescriptor, + eventMask: .write, + queue: queue) + dispatchSource.setEventHandler { [unowned self] in + callback(self) + } + dispatchSource.setCancelHandler { [unowned self] in + self.directoryFileDescriptor = -1 + } + self.dispatchSource = dispatchSource + + // Start monitoring + dispatchSource.resume() + + // Success + return true + } + + public func stop() { + // Leave if not monitoring + guard let dispatchSource = dispatchSource else { + return + } + + // Don't listen to more events + dispatchSource.setEventHandler(handler: nil) + + // Cancel the source (this will also close the directory) + dispatchSource.cancel() + + dispatchSource.setCancelHandler(handler: nil) + + self.dispatchSource = nil + } +} diff --git a/Nynja/Library/UI/AlertManager.swift b/Nynja/Library/UI/AlertManager.swift index ea2740f8a..19e17b0c1 100644 --- a/Nynja/Library/UI/AlertManager.swift +++ b/Nynja/Library/UI/AlertManager.swift @@ -20,6 +20,9 @@ class AlertManager { return UIApplication.shared.keyWindow?.presentedViewController } + // FIXME: need to be removed from here when share extension won't require new mqtt connection. + private var appGroupObserver: AppGroupFlagObserver? + func showAlertOk(title: String, message: String, completion:(()->Void)? = nil) { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) let defaultAction = UIAlertAction(title: "ok".localized, style: .default) { (action) in @@ -191,17 +194,26 @@ class AlertManager { func showNativeShare(with activityItems: [Any]) { var shareExtensionWasOpen = false - let notificationManager = DarwinNotificationManager.shared - - notificationManager.observeShareDidOpen(self) { _ in - shareExtensionWasOpen = true - MQTTService.sharedInstance.disconnect() + self.appGroupObserver = AppGroupFlagObserver(fileManager: .default, appGroup: Bundle.main.appGroupName) + do { + try appGroupObserver?.prepare() + try appGroupObserver?.removeFlagIfExists(.shareExtension) + try appGroupObserver?.observe { flags in + if !shareExtensionWasOpen, flags.contains(.shareExtension) { + shareExtensionWasOpen = true + MQTTService.sharedInstance.disconnect() + } + } + } catch { + LogService.log(topic: .fileSystem) { error.localizedDescription } } let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - activityViewController.completionWithItemsHandler = { _, _, _, _ in + activityViewController.completionWithItemsHandler = { [weak self] _, _, _, _ in + + self?.appGroupObserver?.stopObserving() + self?.appGroupObserver = nil - notificationManager.stopObservingShareExtension(self) if shareExtensionWasOpen { MQTTService.sharedInstance.reconnect() } -- GitLab From 7a8840a5a618150cf04a89e1e6dbb3e030864db7 Mon Sep 17 00:00:00 2001 From: Anton Poltoratskyi Date: Mon, 24 Sep 2018 15:46:31 +0300 Subject: [PATCH 5/5] [NY-3564] Remove DarwinNotificationCenter. --- Nynja.xcodeproj/project.pbxproj | 20 --- .../DarwinNotificationManager+Share.swift | 28 ---- .../DarwinNotificationManager.swift | 142 ------------------ 3 files changed, 190 deletions(-) delete mode 100644 Nynja/Notifications/DarwinNotificationManager+Share.swift delete mode 100644 Nynja/Notifications/DarwinNotificationManager.swift diff --git a/Nynja.xcodeproj/project.pbxproj b/Nynja.xcodeproj/project.pbxproj index 2e2e9c220..dc4105519 100644 --- a/Nynja.xcodeproj/project.pbxproj +++ b/Nynja.xcodeproj/project.pbxproj @@ -948,10 +948,6 @@ 8580BAF420BD9B8000239D9D /* Range+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8580BAF220BD9B7F00239D9D /* Range+Extension.swift */; }; 8584C90E20920F3C001A0BBB /* StickerGridCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8584C90C20920F3C001A0BBB /* StickerGridCollectionViewCell.swift */; }; 8584C90F20920F3C001A0BBB /* StickerGridCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8584C90D20920F3C001A0BBB /* StickerGridCellModel.swift */; }; - 85855BC82154FD5B00D1580E /* DarwinNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */; }; - 85855BCA2155180400D1580E /* DarwinNotificationManager+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */; }; - 85855BCB215531A100D1580E /* DarwinNotificationManager+Share.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */; }; - 85855BCC215531A600D1580E /* DarwinNotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */; }; 8586CAC5203335C7009F2A75 /* ForwardAvatarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8586CAC4203335C7009F2A75 /* ForwardAvatarViewModel.swift */; }; 8586CACB203338F6009F2A75 /* ForwardTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8586CACA203338F6009F2A75 /* ForwardTarget.swift */; }; 858A72E5A4AE48CE24AFF649 /* MainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CEB31C47B0FEB0040FD0DA /* MainInteractor.swift */; }; @@ -3017,8 +3013,6 @@ 8580BAF220BD9B7F00239D9D /* Range+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Range+Extension.swift"; sourceTree = ""; }; 8584C90C20920F3C001A0BBB /* StickerGridCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerGridCollectionViewCell.swift; sourceTree = ""; }; 8584C90D20920F3C001A0BBB /* StickerGridCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickerGridCellModel.swift; sourceTree = ""; }; - 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarwinNotificationManager.swift; sourceTree = ""; }; - 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DarwinNotificationManager+Share.swift"; sourceTree = ""; }; 8586CAC4203335C7009F2A75 /* ForwardAvatarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardAvatarViewModel.swift; sourceTree = ""; }; 8586CACA203338F6009F2A75 /* ForwardTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardTarget.swift; sourceTree = ""; }; 858BC122203320BB0022EB25 /* ForwardSelectorDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardSelectorDataSource.swift; sourceTree = ""; }; @@ -5649,7 +5643,6 @@ isa = PBXGroup; children = ( 8509FC832158F7B400734D93 /* Files */, - 85855BC62154FD3400D1580E /* Notifications */, 4BE2C5E42142EB5A00A73DD9 /* NynjaCalls */, 4BE2C5CE2142EAC500A73DD9 /* Audio */, 4B0DBA892137F6F800D79163 /* ChatService */, @@ -8093,15 +8086,6 @@ path = StickerPack; sourceTree = ""; }; - 85855BC62154FD3400D1580E /* Notifications */ = { - isa = PBXGroup; - children = ( - 85855BC72154FD5B00D1580E /* DarwinNotificationManager.swift */, - 85855BC92155180400D1580E /* DarwinNotificationManager+Share.swift */, - ); - path = Notifications; - sourceTree = ""; - }; 8595E0DA204863CF00178171 /* CollectionView */ = { isa = PBXGroup; children = ( @@ -13346,7 +13330,6 @@ 2610D4642076516900E6E2B2 /* Array+Feature.swift in Sources */, 262D4389203352D4002F1E45 /* FriendExtansion+BERT.swift in Sources */, A42CE5A220692EDB000889CC /* operation.swift in Sources */, - 85855BCC215531A600D1580E /* DarwinNotificationManager.swift in Sources */, A42D519B206A34E200EEB952 /* IoHandler.swift in Sources */, 26352917207572DC00DC6FBD /* JobExtension+BERT.swift in Sources */, 26C0C1CB2073C93800C530DA /* ForwardTarget.swift in Sources */, @@ -13399,7 +13382,6 @@ 266AE8C42034971A0096A12C /* AsyncOperation.swift in Sources */, 00E9825F205FE86E008BF03D /* AuthHandler.swift in Sources */, 359EB27C1F9A2C8C00147437 /* MQTTServiceHelper.swift in Sources */, - 85855BCB215531A100D1580E /* DarwinNotificationManager+Share.swift in Sources */, A4B544F020EFB4EC00EB7B0F /* BertTupleExtension.swift in Sources */, 2604C0962069163C0051E4FB /* HandlerServiceProtocol.swift in Sources */, 26B5F7431FB0FF7B00CEC6AE /* FileManager.swift in Sources */, @@ -14230,7 +14212,6 @@ 2648C4192069B52100863614 /* ChangeNumberStep2ViewController.swift in Sources */, 85788C4E20443DD2003600C9 /* BuildNumberItemsFactory.swift in Sources */, A42D52CB206A53AB00EEB952 /* CDR_Spec.swift in Sources */, - 85855BCA2155180400D1580E /* DarwinNotificationManager+Share.swift in Sources */, 2603139220A0A4B9009AC66D /* LanguageSettingProtocol.swift in Sources */, F105C6BD20A1347E0091786A /* PhotoPreviewViewController.swift in Sources */, B79FA03921091ED000F286BF /* InterpretationInteractor.swift in Sources */, @@ -14613,7 +14594,6 @@ 5C468A609C445962C0D19DD3 /* HistoryViewController.swift in Sources */, 854A4B2D2080D68200759152 /* CellWithArrowCellModel.swift in Sources */, C9405149204C7FAF00D72B04 /* DataAndStoragePresenter.swift in Sources */, - 85855BC82154FD5B00D1580E /* DarwinNotificationManager.swift in Sources */, 3819EAEB412EBA913146F443 /* HistoryPresenter.swift in Sources */, E7718BF51FB5D6080070B402 /* UIView+Debug.swift in Sources */, 26245F44204EF67C00C8D3DD /* PresenterApearingProtocol.swift in Sources */, diff --git a/Nynja/Notifications/DarwinNotificationManager+Share.swift b/Nynja/Notifications/DarwinNotificationManager+Share.swift deleted file mode 100644 index 28eb04895..000000000 --- a/Nynja/Notifications/DarwinNotificationManager+Share.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// DarwinNotificationManager+Share.swift -// Nynja -// -// Created by Anton Poltoratskyi on 21.09.2018. -// Copyright © 2018 TecSynt Solutions. All rights reserved. -// - -import Foundation - -extension DarwinNotificationManager { - - private var notificationName: String { - return "com.nynja.dev.mobile.communicator.NynjaShare-did-open" - } - - func postShareDidOpen() { - postNotification(name: notificationName) - } - - func observeShareDidOpen(_ observer: AnyObject, handler: @escaping (Notification) -> Void) { - addObserver(observer, forName: notificationName, handler: handler) - } - - func stopObservingShareExtension(_ observer: AnyObject) { - removeObserver(observer, forName: notificationName) - } -} diff --git a/Nynja/Notifications/DarwinNotificationManager.swift b/Nynja/Notifications/DarwinNotificationManager.swift deleted file mode 100644 index 73f19fe0f..000000000 --- a/Nynja/Notifications/DarwinNotificationManager.swift +++ /dev/null @@ -1,142 +0,0 @@ -// -// DarwinNotificationManager.swift -// Nynja -// -// Created by Anton Poltoratskyi on 21.09.2018. -// Copyright © 2018 TecSynt Solutions. All rights reserved. -// - -import Foundation - -final class DarwinNotificationManager { - - // MARK: - Handlers - - private final class Subscriber: WeakRef { - var handler: (Notification) -> Void - - init(value: AnyObject?, handler: @escaping (Notification) -> Void) { - self.handler = handler - super.init(value: value) - } - } - - private var handlers: [String: [Subscriber]] = [:] - - private let notificationCenter = NotificationCenter.default - - private var darwinNotificationCenter: CFNotificationCenter { - return CFNotificationCenterGetDarwinNotifyCenter() - } - - - // MARK: - Init - - static let shared = DarwinNotificationManager() - - private init() {} - - - // MARK: - Actions - - func postNotification(name: String) { - let name = CFNotificationName(name as CFString) - CFNotificationCenterPostNotification(darwinNotificationCenter, name, nil, nil, true) - } - - func addObserver(_ object: AnyObject, forName name: String, handler: @escaping (Notification) -> Void) { - let subscriber = Subscriber(value: object, handler: handler) - - guard handlers[name] == nil || handlers[name]!.isEmpty else { - handlers[name]?.append(subscriber) - return - } - handlers[name] = [subscriber] - - // Global Observer - - var selfObserver = self - let observer = UnsafeRawPointer(withUnsafePointer(to: &selfObserver, { $0 })) - - CFNotificationCenterAddObserver(darwinNotificationCenter, observer, notificationCallback, name as CFString, nil, .deliverImmediately) - - // Local Observer - - let name = Notification.Name(name) - notificationCenter.addObserver(self, selector: #selector(handleNotification), name: name, object: nil) - } - - func removeObserver(_ object: AnyObject, forName name: String){ - guard let subscribers = handlers[name], !subscribers.isEmpty else { - return - } - let newSubscribers = subscribers.filter { $0.value !== object && $0.value != nil } - handlers[name] = newSubscribers - - guard newSubscribers.isEmpty else { - return - } - removeInnerObservers(self, forName: name) - } - - func removeObserver(_ object: AnyObject) { - guard case let subscribers = handlers.values, !subscribers.isEmpty else { - return - } - for (name, subscribers) in handlers { - handlers[name] = subscribers.filter { $0.value !== object && $0.value != nil } - } - guard handlers.isEmpty else { - return - } - removeInnerObservers(self) - } - - private func removeInnerObservers(_ object: AnyObject, forName name: String) { - var object = object - let name = CFNotificationName(name as CFString) - let observer = UnsafeRawPointer(withUnsafePointer(to: &object, { $0 })) - - CFNotificationCenterRemoveObserver(darwinNotificationCenter, observer, name, nil) - notificationCenter.removeObserver(object, name: name.nsNotificationName, object: nil) - } - - private func removeInnerObservers(_ object: AnyObject) { - var object = object - let observer = UnsafeRawPointer(withUnsafePointer(to: &object, { $0 })) - - CFNotificationCenterRemoveEveryObserver(darwinNotificationCenter, observer) - notificationCenter.removeObserver(object) - } - - - // MARK: - Notifications - - @objc private func handleNotification(_ notification: Notification) { - let name = notification.name.rawValue - handlers[name]?.forEach { $0.handler(notification) } - } -} - -extension CFNotificationName { - - var nsNotificationName: Notification.Name { - return Notification.Name(rawValue: rawValue as String) - } -} - - -// MARK: - Callback - -private func notificationCallback(_ center: CFNotificationCenter?, - _ observer: UnsafeMutableRawPointer?, - _ name: CFNotificationName?, - _ object: UnsafeRawPointer?, - _ userInfo: CFDictionary?) { - - guard let name = name?.nsNotificationName else { - return - } - let notification = Notification(name: name) - NotificationCenter.default.post(notification) -} -- GitLab