AppDelegate.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. //
  2. // AppDelegate.swift
  3. // Bark
  4. //
  5. // Created by huangfeng on 2018/3/7.
  6. // Copyright © 2018年 Fin. All rights reserved.
  7. //
  8. import CrashReporter
  9. import IQKeyboardManagerSwift
  10. import UIKit
  11. import UserNotifications
  12. @UIApplicationMain
  13. class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
  14. var window: UIWindow?
  15. // var syncEngine: SyncEngine?
  16. func setupRealm() {
  17. // Tell Realm to use this new configuration object for the default Realm
  18. Realm.Configuration.defaultConfiguration = kRealmDefaultConfiguration
  19. // // iCloud 同步
  20. // syncEngine = SyncEngine(objects: [
  21. // SyncObject(type: Message.self)
  22. // ], databaseScope: .private)
  23. #if DEBUG
  24. let realm = try? Realm()
  25. print("message count: \(realm?.objects(Message.self).count ?? 0)")
  26. #endif
  27. }
  28. func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  29. self.window = UIWindow(frame: UIScreen.main.bounds)
  30. self.window?.backgroundColor = UIColor.black
  31. #if !DEBUG
  32. let config = PLCrashReporterConfig(signalHandlerType: .mach, symbolicationStrategy: [])
  33. if let crashReporter = PLCrashReporter(configuration: config) {
  34. // Enable the Crash Reporter.
  35. do {
  36. try crashReporter.enableAndReturnError()
  37. } catch {
  38. print("Warning: Could not enable crash reporter: \(error)")
  39. }
  40. if crashReporter.hasPendingCrashReport() {
  41. let reportController = CrashReportViewController()
  42. do {
  43. let data = try crashReporter.loadPendingCrashReportDataAndReturnError()
  44. // Retrieving crash reporter data.
  45. let report = try PLCrashReport(data: data)
  46. if let text = PLCrashReportTextFormatter.stringValue(for: report, with: PLCrashReportTextFormatiOS) {
  47. reportController.crashLog = text
  48. } else {
  49. print("CrashReporter: can't convert report to text")
  50. }
  51. } catch {
  52. print("CrashReporter failed to load and parse with error: \(error)")
  53. }
  54. // Purge the report.
  55. crashReporter.purgePendingCrashReport()
  56. self.window?.rootViewController = reportController
  57. self.window?.makeKeyAndVisible()
  58. return true
  59. }
  60. } else {
  61. print("Could not create an instance of PLCrashReporter")
  62. }
  63. #endif
  64. // 必须在应用一开始就配置,否则应用可能提前在配置之前试用了 Realm() ,则会创建两个独立数据库。
  65. setupRealm()
  66. IQKeyboardManager.shared.enable = true
  67. if #available(iOS 14, *), UIDevice.current.userInterfaceIdiom == .pad {
  68. let splitViewController = BarkSplitViewController(style: .doubleColumn)
  69. self.window?.rootViewController = BarkSnackbarController(rootViewController: splitViewController)
  70. } else {
  71. let tabBarController = BarkTabBarController()
  72. self.window?.rootViewController = BarkSnackbarController(
  73. rootViewController: tabBarController
  74. )
  75. }
  76. // 需先配置好 tabBarController 的 viewControllers,显示时会默认显示上次打开的页面
  77. self.window?.makeKeyAndVisible()
  78. UNUserNotificationCenter.current().delegate = self
  79. UNUserNotificationCenter.current().setNotificationCategories([
  80. UNNotificationCategory(identifier: "myNotificationCategory", actions: [
  81. UNNotificationAction(identifier: "copy", title: NSLocalizedString("Copy2"), options: UNNotificationActionOptions.foreground)
  82. ], intentIdentifiers: [], options: .customDismissAction)
  83. ])
  84. UNUserNotificationCenter.current().getNotificationSettings { settings in
  85. dispatch_sync_safely_main_queue {
  86. if settings.authorizationStatus == .authorized {
  87. Client.shared.registerForRemoteNotifications()
  88. }
  89. }
  90. }
  91. // 调整返回按钮样式
  92. let bar = UINavigationBar.appearance(whenContainedInInstancesOf: [BarkNavigationController.self])
  93. bar.backIndicatorImage = UIImage(named: "back")
  94. bar.backIndicatorTransitionMaskImage = UIImage(named: "back")
  95. bar.tintColor = BKColor.grey.darken4
  96. return true
  97. }
  98. func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
  99. print(error)
  100. }
  101. func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  102. let deviceTokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
  103. Client.shared.deviceToken.accept(deviceTokenString)
  104. // 注册设备
  105. ServerManager.shared.syncAllServers()
  106. }
  107. func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
  108. notificatonHandler(userInfo: response.notification.request.content.userInfo)
  109. }
  110. func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
  111. if UIApplication.shared.applicationState == .active {
  112. stopCallNotificationProcessor()
  113. }
  114. return .alert
  115. }
  116. private func notificatonHandler(userInfo: [AnyHashable: Any]) {
  117. let viewController = Client.shared.currentSnackbarController
  118. func presentController() {
  119. let alert = (userInfo["aps"] as? [String: Any])?["alert"] as? [String: Any]
  120. let title = alert?["title"] as? String
  121. let body = alert?["body"] as? String
  122. let url: URL? = {
  123. if let url = userInfo["url"] as? String {
  124. return URL(string: url)
  125. }
  126. return nil
  127. }()
  128. // URL 直接打开
  129. if let url = url {
  130. Client.shared.openUrl(url: url)
  131. return
  132. }
  133. let alertController = UIAlertController(title: title, message: body, preferredStyle: .alert)
  134. alertController.addAction(UIAlertAction(title: NSLocalizedString("CopyContent"), style: .default, handler: { _ in
  135. if let copy = userInfo["copy"] as? String {
  136. UIPasteboard.general.string = copy
  137. } else {
  138. UIPasteboard.general.string = body
  139. }
  140. }))
  141. alertController.addAction(UIAlertAction(title: NSLocalizedString("MoreActions"), style: .default, handler: { _ in
  142. var shareContent = ""
  143. if let title = title {
  144. shareContent += "\(title)\n"
  145. }
  146. if let body = body {
  147. shareContent += "\(body)\n"
  148. }
  149. for (key, value) in userInfo {
  150. if ["aps", "title", "body", "url"].contains((key as? String) ?? "") {
  151. continue
  152. }
  153. shareContent += "\(key): \(value) \n"
  154. }
  155. var items: [Any] = []
  156. items.append(shareContent)
  157. if let url = url {
  158. items.append(url)
  159. }
  160. let controller = Client.shared.window?.rootViewController
  161. let activityController = UIActivityViewController(activityItems: items,
  162. applicationActivities: nil)
  163. controller?.present(activityController, animated: true, completion: nil)
  164. }))
  165. alertController.addAction(UIAlertAction(title: NSLocalizedString("Cancel"), style: .cancel, handler: nil))
  166. viewController?.present(alertController, animated: true, completion: nil)
  167. }
  168. if let presentedController = viewController?.presentedViewController {
  169. presentedController.dismiss(animated: false) {
  170. presentController()
  171. }
  172. } else {
  173. presentController()
  174. }
  175. }
  176. func applicationWillResignActive(_ application: UIApplication) {
  177. // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
  178. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
  179. }
  180. func applicationDidEnterBackground(_ application: UIApplication) {
  181. // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
  182. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
  183. }
  184. func applicationWillEnterForeground(_ application: UIApplication) {
  185. ServerManager.shared.syncAllServers()
  186. // 设置 -1 可以清除应用角标,但不清除通知中心的推送
  187. // 设置 0 会将通知中心的所有推送一起清空掉
  188. UIApplication.shared.applicationIconBadgeNumber = -1
  189. }
  190. func applicationDidBecomeActive(_ application: UIApplication) {
  191. // 如果有响铃通知,则关闭响铃
  192. stopCallNotificationProcessor()
  193. }
  194. func applicationWillTerminate(_ application: UIApplication) {
  195. // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
  196. }
  197. /// 停止响铃
  198. func stopCallNotificationProcessor() {
  199. CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFNotificationName(kStopCallProcessorKey as CFString), nil, nil, true)
  200. }
  201. }