├── .gitignore ├── AppExtensionCommunicator.xcodeproj └── project.pbxproj ├── AppExtensionCommunicator ├── AppExtensionCommunicator.h ├── AppExtensionCommunicator.swift ├── AppExtensionCommunicatorHelper │ ├── DarwinNotifyCenterCallback.h │ ├── DarwinNotifyCenterCallback.m │ └── module.modulemap └── Info.plist ├── Example ├── Example.xcodeproj │ └── project.pbxproj ├── Example │ ├── AppDelegate.swift │ ├── AppExtensionCommunicator Example.entitlements │ ├── Base.lproj │ │ └── LaunchScreen.xib │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ └── ViewController.swift └── TodayWidget │ ├── Info.plist │ ├── TodayViewController.swift │ └── TodayWidget.entitlements ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Screenshots 2 | privacy 3 | xcuserdata 4 | xcshareddata 5 | .DS_Store 6 | *.xcworkspace 7 | -------------------------------------------------------------------------------- /AppExtensionCommunicator.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E01BB39E1A890AA300F33C39 /* AppExtensionCommunicator.h in Headers */ = {isa = PBXBuildFile; fileRef = E01BB39D1A890AA300F33C39 /* AppExtensionCommunicator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | E01BB3B51A890AC000F33C39 /* AppExtensionCommunicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E01BB3B41A890AC000F33C39 /* AppExtensionCommunicator.swift */; }; 12 | E01BB3B91A890BBE00F33C39 /* DarwinNotifyCenterCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = E01BB3B71A890BBE00F33C39 /* DarwinNotifyCenterCallback.h */; }; 13 | E01BB3BA1A890BBE00F33C39 /* DarwinNotifyCenterCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = E01BB3B81A890BBE00F33C39 /* DarwinNotifyCenterCallback.m */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXFileReference section */ 17 | E01BB3981A890AA300F33C39 /* AppExtensionCommunicator.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AppExtensionCommunicator.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 18 | E01BB39C1A890AA300F33C39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 19 | E01BB39D1A890AA300F33C39 /* AppExtensionCommunicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppExtensionCommunicator.h; sourceTree = ""; }; 20 | E01BB3B41A890AC000F33C39 /* AppExtensionCommunicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppExtensionCommunicator.swift; sourceTree = ""; }; 21 | E01BB3B71A890BBE00F33C39 /* DarwinNotifyCenterCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DarwinNotifyCenterCallback.h; path = AppExtensionCommunicatorHelper/DarwinNotifyCenterCallback.h; sourceTree = ""; }; 22 | E01BB3B81A890BBE00F33C39 /* DarwinNotifyCenterCallback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DarwinNotifyCenterCallback.m; path = AppExtensionCommunicatorHelper/DarwinNotifyCenterCallback.m; sourceTree = ""; }; 23 | /* End PBXFileReference section */ 24 | 25 | /* Begin PBXFrameworksBuildPhase section */ 26 | E01BB3941A890AA300F33C39 /* Frameworks */ = { 27 | isa = PBXFrameworksBuildPhase; 28 | buildActionMask = 2147483647; 29 | files = ( 30 | ); 31 | runOnlyForDeploymentPostprocessing = 0; 32 | }; 33 | /* End PBXFrameworksBuildPhase section */ 34 | 35 | /* Begin PBXGroup section */ 36 | E01BB38E1A890AA300F33C39 = { 37 | isa = PBXGroup; 38 | children = ( 39 | E01BB39A1A890AA300F33C39 /* AppExtensionCommunicator */, 40 | E01BB3991A890AA300F33C39 /* Products */, 41 | ); 42 | sourceTree = ""; 43 | }; 44 | E01BB3991A890AA300F33C39 /* Products */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | E01BB3981A890AA300F33C39 /* AppExtensionCommunicator.framework */, 48 | ); 49 | name = Products; 50 | sourceTree = ""; 51 | }; 52 | E01BB39A1A890AA300F33C39 /* AppExtensionCommunicator */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | E01BB39B1A890AA300F33C39 /* Supporting Files */, 56 | E01BB39D1A890AA300F33C39 /* AppExtensionCommunicator.h */, 57 | E01BB3B41A890AC000F33C39 /* AppExtensionCommunicator.swift */, 58 | ); 59 | path = AppExtensionCommunicator; 60 | sourceTree = ""; 61 | }; 62 | E01BB39B1A890AA300F33C39 /* Supporting Files */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | E01BB39C1A890AA300F33C39 /* Info.plist */, 66 | E01BB3B61A890ACC00F33C39 /* Private Helpers */, 67 | ); 68 | name = "Supporting Files"; 69 | sourceTree = ""; 70 | }; 71 | E01BB3B61A890ACC00F33C39 /* Private Helpers */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | E01BB3B71A890BBE00F33C39 /* DarwinNotifyCenterCallback.h */, 75 | E01BB3B81A890BBE00F33C39 /* DarwinNotifyCenterCallback.m */, 76 | ); 77 | name = "Private Helpers"; 78 | sourceTree = ""; 79 | }; 80 | /* End PBXGroup section */ 81 | 82 | /* Begin PBXHeadersBuildPhase section */ 83 | E01BB3951A890AA300F33C39 /* Headers */ = { 84 | isa = PBXHeadersBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | E01BB3B91A890BBE00F33C39 /* DarwinNotifyCenterCallback.h in Headers */, 88 | E01BB39E1A890AA300F33C39 /* AppExtensionCommunicator.h in Headers */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | /* End PBXHeadersBuildPhase section */ 93 | 94 | /* Begin PBXNativeTarget section */ 95 | E01BB3971A890AA300F33C39 /* AppExtensionCommunicator */ = { 96 | isa = PBXNativeTarget; 97 | buildConfigurationList = E01BB3AE1A890AA300F33C39 /* Build configuration list for PBXNativeTarget "AppExtensionCommunicator" */; 98 | buildPhases = ( 99 | E01BB3931A890AA300F33C39 /* Sources */, 100 | E01BB3941A890AA300F33C39 /* Frameworks */, 101 | E01BB3951A890AA300F33C39 /* Headers */, 102 | E01BB3961A890AA300F33C39 /* Resources */, 103 | ); 104 | buildRules = ( 105 | ); 106 | dependencies = ( 107 | ); 108 | name = AppExtensionCommunicator; 109 | productName = AppExtensionCommunicator; 110 | productReference = E01BB3981A890AA300F33C39 /* AppExtensionCommunicator.framework */; 111 | productType = "com.apple.product-type.framework"; 112 | }; 113 | /* End PBXNativeTarget section */ 114 | 115 | /* Begin PBXProject section */ 116 | E01BB38F1A890AA300F33C39 /* Project object */ = { 117 | isa = PBXProject; 118 | attributes = { 119 | LastSwiftUpdateCheck = 0710; 120 | LastUpgradeCheck = 1420; 121 | ORGANIZATIONNAME = "CHEN Xian’an"; 122 | TargetAttributes = { 123 | E01BB3971A890AA300F33C39 = { 124 | CreatedOnToolsVersion = 6.2; 125 | DevelopmentTeam = YUAX44CNP6; 126 | }; 127 | }; 128 | }; 129 | buildConfigurationList = E01BB3921A890AA300F33C39 /* Build configuration list for PBXProject "AppExtensionCommunicator" */; 130 | compatibilityVersion = "Xcode 3.2"; 131 | developmentRegion = en; 132 | hasScannedForEncodings = 0; 133 | knownRegions = ( 134 | en, 135 | Base, 136 | ); 137 | mainGroup = E01BB38E1A890AA300F33C39; 138 | productRefGroup = E01BB3991A890AA300F33C39 /* Products */; 139 | projectDirPath = ""; 140 | projectRoot = ""; 141 | targets = ( 142 | E01BB3971A890AA300F33C39 /* AppExtensionCommunicator */, 143 | ); 144 | }; 145 | /* End PBXProject section */ 146 | 147 | /* Begin PBXResourcesBuildPhase section */ 148 | E01BB3961A890AA300F33C39 /* Resources */ = { 149 | isa = PBXResourcesBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXResourcesBuildPhase section */ 156 | 157 | /* Begin PBXSourcesBuildPhase section */ 158 | E01BB3931A890AA300F33C39 /* Sources */ = { 159 | isa = PBXSourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | E01BB3B51A890AC000F33C39 /* AppExtensionCommunicator.swift in Sources */, 163 | E01BB3BA1A890BBE00F33C39 /* DarwinNotifyCenterCallback.m in Sources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXSourcesBuildPhase section */ 168 | 169 | /* Begin XCBuildConfiguration section */ 170 | E01BB3AC1A890AA300F33C39 /* Debug */ = { 171 | isa = XCBuildConfiguration; 172 | buildSettings = { 173 | ALWAYS_SEARCH_USER_PATHS = NO; 174 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 176 | CLANG_CXX_LIBRARY = "libc++"; 177 | CLANG_ENABLE_MODULES = YES; 178 | CLANG_ENABLE_OBJC_ARC = YES; 179 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 180 | CLANG_WARN_BOOL_CONVERSION = YES; 181 | CLANG_WARN_COMMA = YES; 182 | CLANG_WARN_CONSTANT_CONVERSION = YES; 183 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 184 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 185 | CLANG_WARN_EMPTY_BODY = YES; 186 | CLANG_WARN_ENUM_CONVERSION = YES; 187 | CLANG_WARN_INFINITE_RECURSION = YES; 188 | CLANG_WARN_INT_CONVERSION = YES; 189 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 190 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 191 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 192 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 193 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 194 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 195 | CLANG_WARN_STRICT_PROTOTYPES = YES; 196 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 197 | CLANG_WARN_UNREACHABLE_CODE = YES; 198 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 199 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 200 | COPY_PHASE_STRIP = NO; 201 | CURRENT_PROJECT_VERSION = 1; 202 | ENABLE_STRICT_OBJC_MSGSEND = YES; 203 | ENABLE_TESTABILITY = YES; 204 | GCC_C_LANGUAGE_STANDARD = gnu99; 205 | GCC_DYNAMIC_NO_PIC = NO; 206 | GCC_NO_COMMON_BLOCKS = YES; 207 | GCC_OPTIMIZATION_LEVEL = 0; 208 | GCC_PREPROCESSOR_DEFINITIONS = ( 209 | "DEBUG=1", 210 | "$(inherited)", 211 | ); 212 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 213 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 214 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 215 | GCC_WARN_UNDECLARED_SELECTOR = YES; 216 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 217 | GCC_WARN_UNUSED_FUNCTION = YES; 218 | GCC_WARN_UNUSED_VARIABLE = YES; 219 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 220 | MTL_ENABLE_DEBUG_INFO = YES; 221 | ONLY_ACTIVE_ARCH = YES; 222 | SDKROOT = iphoneos; 223 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 224 | TARGETED_DEVICE_FAMILY = "1,2"; 225 | VERSIONING_SYSTEM = "apple-generic"; 226 | VERSION_INFO_PREFIX = ""; 227 | }; 228 | name = Debug; 229 | }; 230 | E01BB3AD1A890AA300F33C39 /* Release */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | ALWAYS_SEARCH_USER_PATHS = NO; 234 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 235 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 236 | CLANG_CXX_LIBRARY = "libc++"; 237 | CLANG_ENABLE_MODULES = YES; 238 | CLANG_ENABLE_OBJC_ARC = YES; 239 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 240 | CLANG_WARN_BOOL_CONVERSION = YES; 241 | CLANG_WARN_COMMA = YES; 242 | CLANG_WARN_CONSTANT_CONVERSION = YES; 243 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 244 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 245 | CLANG_WARN_EMPTY_BODY = YES; 246 | CLANG_WARN_ENUM_CONVERSION = YES; 247 | CLANG_WARN_INFINITE_RECURSION = YES; 248 | CLANG_WARN_INT_CONVERSION = YES; 249 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 250 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 251 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 252 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 253 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 254 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 255 | CLANG_WARN_STRICT_PROTOTYPES = YES; 256 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 257 | CLANG_WARN_UNREACHABLE_CODE = YES; 258 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 259 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 260 | COPY_PHASE_STRIP = NO; 261 | CURRENT_PROJECT_VERSION = 1; 262 | ENABLE_NS_ASSERTIONS = NO; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | GCC_C_LANGUAGE_STANDARD = gnu99; 265 | GCC_NO_COMMON_BLOCKS = YES; 266 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 267 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 268 | GCC_WARN_UNDECLARED_SELECTOR = YES; 269 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 270 | GCC_WARN_UNUSED_FUNCTION = YES; 271 | GCC_WARN_UNUSED_VARIABLE = YES; 272 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 273 | MTL_ENABLE_DEBUG_INFO = NO; 274 | SDKROOT = iphoneos; 275 | SWIFT_COMPILATION_MODE = wholemodule; 276 | TARGETED_DEVICE_FAMILY = "1,2"; 277 | VALIDATE_PRODUCT = YES; 278 | VERSIONING_SYSTEM = "apple-generic"; 279 | VERSION_INFO_PREFIX = ""; 280 | }; 281 | name = Release; 282 | }; 283 | E01BB3AF1A890AA300F33C39 /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | APPLICATION_EXTENSION_API_ONLY = YES; 287 | CLANG_ENABLE_MODULES = YES; 288 | CODE_SIGN_IDENTITY = "Apple Development"; 289 | DEFINES_MODULE = YES; 290 | DEVELOPMENT_TEAM = YUAX44CNP6; 291 | DYLIB_COMPATIBILITY_VERSION = 1; 292 | DYLIB_CURRENT_VERSION = 1; 293 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 294 | INFOPLIST_FILE = AppExtensionCommunicator/Info.plist; 295 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 296 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 298 | PRODUCT_BUNDLE_IDENTIFIER = "com.lazyapps.$(PRODUCT_NAME:rfc1034identifier)"; 299 | PRODUCT_NAME = "$(TARGET_NAME)"; 300 | SKIP_INSTALL = YES; 301 | SWIFT_INCLUDE_PATHS = "$(SRCROOT)/AppExtensionCommunicator/AppExtensionCommunicatorHelper"; 302 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 303 | SWIFT_VERSION = 5.0; 304 | }; 305 | name = Debug; 306 | }; 307 | E01BB3B01A890AA300F33C39 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | APPLICATION_EXTENSION_API_ONLY = YES; 311 | CLANG_ENABLE_MODULES = YES; 312 | CODE_SIGN_IDENTITY = "Apple Development"; 313 | DEFINES_MODULE = YES; 314 | DEVELOPMENT_TEAM = YUAX44CNP6; 315 | DYLIB_COMPATIBILITY_VERSION = 1; 316 | DYLIB_CURRENT_VERSION = 1; 317 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 318 | INFOPLIST_FILE = AppExtensionCommunicator/Info.plist; 319 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 320 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 321 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 322 | PRODUCT_BUNDLE_IDENTIFIER = "com.lazyapps.$(PRODUCT_NAME:rfc1034identifier)"; 323 | PRODUCT_NAME = "$(TARGET_NAME)"; 324 | SKIP_INSTALL = YES; 325 | SWIFT_INCLUDE_PATHS = "$(SRCROOT)/AppExtensionCommunicator/AppExtensionCommunicatorHelper"; 326 | SWIFT_VERSION = 5.0; 327 | }; 328 | name = Release; 329 | }; 330 | /* End XCBuildConfiguration section */ 331 | 332 | /* Begin XCConfigurationList section */ 333 | E01BB3921A890AA300F33C39 /* Build configuration list for PBXProject "AppExtensionCommunicator" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | E01BB3AC1A890AA300F33C39 /* Debug */, 337 | E01BB3AD1A890AA300F33C39 /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | E01BB3AE1A890AA300F33C39 /* Build configuration list for PBXNativeTarget "AppExtensionCommunicator" */ = { 343 | isa = XCConfigurationList; 344 | buildConfigurations = ( 345 | E01BB3AF1A890AA300F33C39 /* Debug */, 346 | E01BB3B01A890AA300F33C39 /* Release */, 347 | ); 348 | defaultConfigurationIsVisible = 0; 349 | defaultConfigurationName = Release; 350 | }; 351 | /* End XCConfigurationList section */ 352 | }; 353 | rootObject = E01BB38F1A890AA300F33C39 /* Project object */; 354 | } 355 | -------------------------------------------------------------------------------- /AppExtensionCommunicator/AppExtensionCommunicator.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppExtensionCommunicator.h 3 | // AppExtensionCommunicator 4 | // 5 | // Created by CHEN Xian’an on 2/9/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AppExtensionCommunicator. 12 | FOUNDATION_EXPORT double AppExtensionCommunicatorVersionNumber; 13 | 14 | //! Project version string for AppExtensionCommunicator. 15 | FOUNDATION_EXPORT const unsigned char AppExtensionCommunicatorVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AppExtensionCommunicator/AppExtensionCommunicator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppExtensionCommunicator.swift 3 | // AppExtensionCommunicator 4 | // 5 | // Created by CHEN Xian’an on 2/9/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AppExtensionCommunicatorHelper 11 | 12 | /// message values accept only plist data types: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html 13 | public typealias AppExtensionMessage = [String: AnyObject] 14 | 15 | public typealias AppExtensionMessageHandler = (AppExtensionMessage?) -> Void 16 | 17 | public class AppExtensionCommunicator { 18 | 19 | let containerURL: URL 20 | 21 | /// `containerURL` Application group container directory, usually you can get it by `containerURLForSecurityApplicationGroupIdentifier` of `NSFileManager` 22 | public init(containerURL theURL: URL) { 23 | containerURL = theURL 24 | _userInfoDir = containerURL.appendingPathComponent(".AppExtensionCommunicator", isDirectory: true) 25 | _checkAndCreateUserInfoDir() 26 | } 27 | 28 | deinit { 29 | let center = CFNotificationCenterGetDarwinNotifyCenter() 30 | CFNotificationCenterRemoveEveryObserver(center, unsafeBitCast(self, to: UnsafeRawPointer.self)) 31 | } 32 | 33 | /// Deliver `message` with `identifier` 34 | public func deliver(message: AppExtensionMessage? = nil, withIdentifier identifier: String) { 35 | let target = _userInfoDir.appendingPathComponent(identifier) 36 | if let info = message as? NSDictionary { 37 | try? info.write(to: target) 38 | } else { 39 | try? FileManager().removeItem(at: target) 40 | } 41 | 42 | let center = CFNotificationCenterGetDarwinNotifyCenter() 43 | let identifierCF = CFNotificationName(identifier as CFString) 44 | CFNotificationCenterPostNotification(center, identifierCF, nil, nil, true) 45 | } 46 | 47 | /// observe message with `identifier` using `messageHandler` 48 | public func observeMessage(forIdentifier identifier: String, usingHandler messageHandler: @escaping AppExtensionMessageHandler) { 49 | if _registeredHandlers[identifier] == nil { 50 | addObserverWithNameForDarwinNotifyCenter(unsafeBitCast(self, to: UnsafeRawPointer.self), identifier) 51 | } 52 | 53 | _registeredHandlers[identifier] = messageHandler 54 | } 55 | 56 | // MARK: private properties 57 | 58 | private let _userInfoDir: URL 59 | 60 | private lazy var _registeredHandlers = [String: AppExtensionMessageHandler]() 61 | 62 | } 63 | 64 | // MARK: private methods 65 | private extension AppExtensionCommunicator { 66 | 67 | @objc func _handleNotificationCallbackWithName(_ name: String) { 68 | if let handler = _registeredHandlers[name] { 69 | let target = _userInfoDir.appendingPathComponent(name) 70 | let userInfo = NSDictionary(contentsOf: target) as? AppExtensionMessage 71 | handler(userInfo) 72 | } 73 | } 74 | 75 | func _checkAndCreateUserInfoDir() { 76 | let fm = FileManager() 77 | let dirExists: Bool = { 78 | var isDir = ObjCBool(true) 79 | let e = fm.fileExists(atPath: self._userInfoDir.path, isDirectory: &isDir) 80 | if !isDir.boolValue { 81 | try? fm.removeItem(at: self._userInfoDir) 82 | return false 83 | } 84 | 85 | return e 86 | }() 87 | 88 | if !dirExists { 89 | try? fm.createDirectory(at: _userInfoDir, withIntermediateDirectories: true) 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /AppExtensionCommunicator/AppExtensionCommunicatorHelper/DarwinNotifyCenterCallback.h: -------------------------------------------------------------------------------- 1 | // 2 | // DarwinNotifyCenterCallback.h 3 | // AppExtensionCommunicator 4 | // 5 | // Created by CHEN Xian’an on 2/9/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | @class NSString; 10 | 11 | void addObserverWithNameForDarwinNotifyCenter(const void *observer, NSString *name); 12 | -------------------------------------------------------------------------------- /AppExtensionCommunicator/AppExtensionCommunicatorHelper/DarwinNotifyCenterCallback.m: -------------------------------------------------------------------------------- 1 | // 2 | // DarwinNotifyCenterCallback.m 3 | // AppExtensionCommunicator 4 | // 5 | // Created by CHEN Xian’an on 2/9/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | #import "DarwinNotifyCenterCallback.h" 10 | #import 11 | 12 | static void notificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { 13 | id aen = (__bridge id)observer; 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" 16 | [aen performSelector:NSSelectorFromString(@"_handleNotificationCallbackWithName:") withObject:(__bridge NSString *)name]; 17 | #pragma clang diagnostic pop 18 | } 19 | 20 | void addObserverWithNameForDarwinNotifyCenter(const void *observer, NSString *name) { 21 | CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter(); 22 | CFNotificationCenterAddObserver(center, observer, notificationCallback, (__bridge CFStringRef)name, nil, CFNotificationSuspensionBehaviorDeliverImmediately); 23 | } 24 | -------------------------------------------------------------------------------- /AppExtensionCommunicator/AppExtensionCommunicatorHelper/module.modulemap: -------------------------------------------------------------------------------- 1 | /* 2 | This is the private module which is used to make private ObjC headers available to Swift code. 3 | Note how all header files need to be specified with paths relative to this file. 4 | 5 | This file lives inside a folder, and that folder is the actual module. In Xcode the SWIFT_INCLUDE_PATHS needs to include the partent directory to that folder. 6 | */ 7 | module AppExtensionCommunicatorHelper { 8 | header "DarwinNotifyCenterCallback.h" 9 | export * 10 | } 11 | -------------------------------------------------------------------------------- /AppExtensionCommunicator/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.lazyapps.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 205417E92998F87100E3D58A /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E01BB40B1A891C3F00F33C39 /* NotificationCenter.framework */; }; 11 | 207BF38E2998E6E7002873EE /* AppExtensionCommunicator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E001CA8B1A89268B00F70556 /* AppExtensionCommunicator.framework */; }; 12 | 207BF38F2998E6E7002873EE /* AppExtensionCommunicator.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E001CA8B1A89268B00F70556 /* AppExtensionCommunicator.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 13 | 207BF3912998E6EA002873EE /* TodayWidget.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E01BB4091A891C3F00F33C39 /* TodayWidget.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 14 | 207BF3972998ECBD002873EE /* AppExtensionCommunicator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E001CA8B1A89268B00F70556 /* AppExtensionCommunicator.framework */; }; 15 | 207BF3982998ECBD002873EE /* AppExtensionCommunicator.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E001CA8B1A89268B00F70556 /* AppExtensionCommunicator.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | E01BB3D41A89188100F33C39 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E01BB3D31A89188100F33C39 /* AppDelegate.swift */; }; 17 | E01BB3D61A89188100F33C39 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E01BB3D51A89188100F33C39 /* ViewController.swift */; }; 18 | E01BB3DB1A89188100F33C39 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E01BB3DA1A89188100F33C39 /* Images.xcassets */; }; 19 | E01BB3DE1A89188100F33C39 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = E01BB3DC1A89188100F33C39 /* LaunchScreen.xib */; }; 20 | E01BB4111A891C3F00F33C39 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E01BB4101A891C3F00F33C39 /* TodayViewController.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXContainerItemProxy section */ 24 | 207BF3922998E6EA002873EE /* PBXContainerItemProxy */ = { 25 | isa = PBXContainerItemProxy; 26 | containerPortal = E01BB3C61A89188100F33C39 /* Project object */; 27 | proxyType = 1; 28 | remoteGlobalIDString = E01BB4081A891C3F00F33C39; 29 | remoteInfo = TodayWidget; 30 | }; 31 | E001CA8A1A89268B00F70556 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = E001CA861A89268B00F70556 /* AppExtensionCommunicator.xcodeproj */; 34 | proxyType = 2; 35 | remoteGlobalIDString = E01BB3981A890AA300F33C39; 36 | remoteInfo = AppExtensionCommunicator; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXCopyFilesBuildPhase section */ 41 | 207BF3902998E6E7002873EE /* Embed Frameworks */ = { 42 | isa = PBXCopyFilesBuildPhase; 43 | buildActionMask = 2147483647; 44 | dstPath = ""; 45 | dstSubfolderSpec = 10; 46 | files = ( 47 | 207BF38F2998E6E7002873EE /* AppExtensionCommunicator.framework in Embed Frameworks */, 48 | ); 49 | name = "Embed Frameworks"; 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | 207BF3942998E6EA002873EE /* Embed Foundation Extensions */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = ""; 56 | dstSubfolderSpec = 13; 57 | files = ( 58 | 207BF3912998E6EA002873EE /* TodayWidget.appex in Embed Foundation Extensions */, 59 | ); 60 | name = "Embed Foundation Extensions"; 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | 207BF3992998ECBD002873EE /* Embed Frameworks */ = { 64 | isa = PBXCopyFilesBuildPhase; 65 | buildActionMask = 2147483647; 66 | dstPath = ""; 67 | dstSubfolderSpec = 10; 68 | files = ( 69 | 207BF3982998ECBD002873EE /* AppExtensionCommunicator.framework in Embed Frameworks */, 70 | ); 71 | name = "Embed Frameworks"; 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | /* End PBXCopyFilesBuildPhase section */ 75 | 76 | /* Begin PBXFileReference section */ 77 | E001CA801A89258A00F70556 /* AppExtensionCommunicator.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppExtensionCommunicator.framework; path = "../build/Debug-iphoneos/AppExtensionCommunicator.framework"; sourceTree = ""; }; 78 | E001CA851A89266E00F70556 /* AppExtensionCommunicator Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "AppExtensionCommunicator Example.entitlements"; sourceTree = ""; }; 79 | E001CA861A89268B00F70556 /* AppExtensionCommunicator.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = AppExtensionCommunicator.xcodeproj; path = ../AppExtensionCommunicator.xcodeproj; sourceTree = ""; }; 80 | E01BB3CE1A89188100F33C39 /* AppExtensionCommunicator Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AppExtensionCommunicator Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | E01BB3D21A89188100F33C39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | E01BB3D31A89188100F33C39 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 83 | E01BB3D51A89188100F33C39 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 84 | E01BB3DA1A89188100F33C39 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 85 | E01BB3DD1A89188100F33C39 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 86 | E01BB4091A891C3F00F33C39 /* TodayWidget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TodayWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | E01BB40B1A891C3F00F33C39 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; 88 | E01BB40F1A891C3F00F33C39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89 | E01BB4101A891C3F00F33C39 /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = ""; }; 90 | E01BB41C1A891F9200F33C39 /* TodayWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TodayWidget.entitlements; sourceTree = ""; }; 91 | /* End PBXFileReference section */ 92 | 93 | /* Begin PBXFrameworksBuildPhase section */ 94 | E01BB3CB1A89188100F33C39 /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | 207BF38E2998E6E7002873EE /* AppExtensionCommunicator.framework in Frameworks */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | E01BB4061A891C3F00F33C39 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | 205417E92998F87100E3D58A /* NotificationCenter.framework in Frameworks */, 107 | 207BF3972998ECBD002873EE /* AppExtensionCommunicator.framework in Frameworks */, 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXFrameworksBuildPhase section */ 112 | 113 | /* Begin PBXGroup section */ 114 | E001CA871A89268B00F70556 /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | E001CA8B1A89268B00F70556 /* AppExtensionCommunicator.framework */, 118 | ); 119 | name = Products; 120 | sourceTree = ""; 121 | }; 122 | E01BB3C51A89188100F33C39 = { 123 | isa = PBXGroup; 124 | children = ( 125 | E001CA861A89268B00F70556 /* AppExtensionCommunicator.xcodeproj */, 126 | E01BB3D01A89188100F33C39 /* Example */, 127 | E01BB40D1A891C3F00F33C39 /* TodayWidget */, 128 | E01BB40A1A891C3F00F33C39 /* Frameworks */, 129 | E01BB3CF1A89188100F33C39 /* Products */, 130 | ); 131 | sourceTree = ""; 132 | }; 133 | E01BB3CF1A89188100F33C39 /* Products */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | E01BB3CE1A89188100F33C39 /* AppExtensionCommunicator Example.app */, 137 | E01BB4091A891C3F00F33C39 /* TodayWidget.appex */, 138 | ); 139 | name = Products; 140 | sourceTree = ""; 141 | }; 142 | E01BB3D01A89188100F33C39 /* Example */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | E01BB3D31A89188100F33C39 /* AppDelegate.swift */, 146 | E01BB3D51A89188100F33C39 /* ViewController.swift */, 147 | E01BB3D11A89188100F33C39 /* Supporting Files */, 148 | ); 149 | path = Example; 150 | sourceTree = ""; 151 | }; 152 | E01BB3D11A89188100F33C39 /* Supporting Files */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | E01BB3DC1A89188100F33C39 /* LaunchScreen.xib */, 156 | E01BB3DA1A89188100F33C39 /* Images.xcassets */, 157 | E001CA851A89266E00F70556 /* AppExtensionCommunicator Example.entitlements */, 158 | E01BB3D21A89188100F33C39 /* Info.plist */, 159 | ); 160 | name = "Supporting Files"; 161 | sourceTree = ""; 162 | }; 163 | E01BB40A1A891C3F00F33C39 /* Frameworks */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | E001CA801A89258A00F70556 /* AppExtensionCommunicator.framework */, 167 | E01BB40B1A891C3F00F33C39 /* NotificationCenter.framework */, 168 | ); 169 | name = Frameworks; 170 | sourceTree = ""; 171 | }; 172 | E01BB40D1A891C3F00F33C39 /* TodayWidget */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | E01BB4101A891C3F00F33C39 /* TodayViewController.swift */, 176 | E01BB40E1A891C3F00F33C39 /* Supporting Files */, 177 | ); 178 | path = TodayWidget; 179 | sourceTree = ""; 180 | }; 181 | E01BB40E1A891C3F00F33C39 /* Supporting Files */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | E01BB41C1A891F9200F33C39 /* TodayWidget.entitlements */, 185 | E01BB40F1A891C3F00F33C39 /* Info.plist */, 186 | ); 187 | name = "Supporting Files"; 188 | sourceTree = ""; 189 | }; 190 | /* End PBXGroup section */ 191 | 192 | /* Begin PBXNativeTarget section */ 193 | E01BB3CD1A89188100F33C39 /* AppExtensionCommunicator Example */ = { 194 | isa = PBXNativeTarget; 195 | buildConfigurationList = E01BB3ED1A89188100F33C39 /* Build configuration list for PBXNativeTarget "AppExtensionCommunicator Example" */; 196 | buildPhases = ( 197 | E01BB3CA1A89188100F33C39 /* Sources */, 198 | E01BB3CB1A89188100F33C39 /* Frameworks */, 199 | E01BB3CC1A89188100F33C39 /* Resources */, 200 | 207BF3902998E6E7002873EE /* Embed Frameworks */, 201 | 207BF3942998E6EA002873EE /* Embed Foundation Extensions */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | 207BF3932998E6EA002873EE /* PBXTargetDependency */, 207 | ); 208 | name = "AppExtensionCommunicator Example"; 209 | productName = Example; 210 | productReference = E01BB3CE1A89188100F33C39 /* AppExtensionCommunicator Example.app */; 211 | productType = "com.apple.product-type.application"; 212 | }; 213 | E01BB4081A891C3F00F33C39 /* TodayWidget */ = { 214 | isa = PBXNativeTarget; 215 | buildConfigurationList = E01BB4171A891C3F00F33C39 /* Build configuration list for PBXNativeTarget "TodayWidget" */; 216 | buildPhases = ( 217 | E01BB4051A891C3F00F33C39 /* Sources */, 218 | E01BB4061A891C3F00F33C39 /* Frameworks */, 219 | E01BB4071A891C3F00F33C39 /* Resources */, 220 | 207BF3992998ECBD002873EE /* Embed Frameworks */, 221 | ); 222 | buildRules = ( 223 | ); 224 | dependencies = ( 225 | ); 226 | name = TodayWidget; 227 | productName = TodayWidget; 228 | productReference = E01BB4091A891C3F00F33C39 /* TodayWidget.appex */; 229 | productType = "com.apple.product-type.app-extension"; 230 | }; 231 | /* End PBXNativeTarget section */ 232 | 233 | /* Begin PBXProject section */ 234 | E01BB3C61A89188100F33C39 /* Project object */ = { 235 | isa = PBXProject; 236 | attributes = { 237 | LastUpgradeCheck = 1420; 238 | ORGANIZATIONNAME = "CHEN Xian’an"; 239 | TargetAttributes = { 240 | E01BB3CD1A89188100F33C39 = { 241 | CreatedOnToolsVersion = 6.2; 242 | DevelopmentTeam = YUAX44CNP6; 243 | SystemCapabilities = { 244 | com.apple.ApplicationGroups.iOS = { 245 | enabled = 1; 246 | }; 247 | }; 248 | }; 249 | E01BB4081A891C3F00F33C39 = { 250 | CreatedOnToolsVersion = 6.2; 251 | DevelopmentTeam = YUAX44CNP6; 252 | SystemCapabilities = { 253 | com.apple.ApplicationGroups.iOS = { 254 | enabled = 1; 255 | }; 256 | }; 257 | }; 258 | }; 259 | }; 260 | buildConfigurationList = E01BB3C91A89188100F33C39 /* Build configuration list for PBXProject "Example" */; 261 | compatibilityVersion = "Xcode 3.2"; 262 | developmentRegion = en; 263 | hasScannedForEncodings = 0; 264 | knownRegions = ( 265 | en, 266 | Base, 267 | ); 268 | mainGroup = E01BB3C51A89188100F33C39; 269 | productRefGroup = E01BB3CF1A89188100F33C39 /* Products */; 270 | projectDirPath = ""; 271 | projectReferences = ( 272 | { 273 | ProductGroup = E001CA871A89268B00F70556 /* Products */; 274 | ProjectRef = E001CA861A89268B00F70556 /* AppExtensionCommunicator.xcodeproj */; 275 | }, 276 | ); 277 | projectRoot = ""; 278 | targets = ( 279 | E01BB3CD1A89188100F33C39 /* AppExtensionCommunicator Example */, 280 | E01BB4081A891C3F00F33C39 /* TodayWidget */, 281 | ); 282 | }; 283 | /* End PBXProject section */ 284 | 285 | /* Begin PBXReferenceProxy section */ 286 | E001CA8B1A89268B00F70556 /* AppExtensionCommunicator.framework */ = { 287 | isa = PBXReferenceProxy; 288 | fileType = wrapper.framework; 289 | path = AppExtensionCommunicator.framework; 290 | remoteRef = E001CA8A1A89268B00F70556 /* PBXContainerItemProxy */; 291 | sourceTree = BUILT_PRODUCTS_DIR; 292 | }; 293 | /* End PBXReferenceProxy section */ 294 | 295 | /* Begin PBXResourcesBuildPhase section */ 296 | E01BB3CC1A89188100F33C39 /* Resources */ = { 297 | isa = PBXResourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | E01BB3DE1A89188100F33C39 /* LaunchScreen.xib in Resources */, 301 | E01BB3DB1A89188100F33C39 /* Images.xcassets in Resources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | E01BB4071A891C3F00F33C39 /* Resources */ = { 306 | isa = PBXResourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | /* End PBXResourcesBuildPhase section */ 313 | 314 | /* Begin PBXSourcesBuildPhase section */ 315 | E01BB3CA1A89188100F33C39 /* Sources */ = { 316 | isa = PBXSourcesBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | E01BB3D61A89188100F33C39 /* ViewController.swift in Sources */, 320 | E01BB3D41A89188100F33C39 /* AppDelegate.swift in Sources */, 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | E01BB4051A891C3F00F33C39 /* Sources */ = { 325 | isa = PBXSourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | E01BB4111A891C3F00F33C39 /* TodayViewController.swift in Sources */, 329 | ); 330 | runOnlyForDeploymentPostprocessing = 0; 331 | }; 332 | /* End PBXSourcesBuildPhase section */ 333 | 334 | /* Begin PBXTargetDependency section */ 335 | 207BF3932998E6EA002873EE /* PBXTargetDependency */ = { 336 | isa = PBXTargetDependency; 337 | target = E01BB4081A891C3F00F33C39 /* TodayWidget */; 338 | targetProxy = 207BF3922998E6EA002873EE /* PBXContainerItemProxy */; 339 | }; 340 | /* End PBXTargetDependency section */ 341 | 342 | /* Begin PBXVariantGroup section */ 343 | E01BB3DC1A89188100F33C39 /* LaunchScreen.xib */ = { 344 | isa = PBXVariantGroup; 345 | children = ( 346 | E01BB3DD1A89188100F33C39 /* Base */, 347 | ); 348 | name = LaunchScreen.xib; 349 | sourceTree = ""; 350 | }; 351 | /* End PBXVariantGroup section */ 352 | 353 | /* Begin XCBuildConfiguration section */ 354 | E01BB3EB1A89188100F33C39 /* Debug */ = { 355 | isa = XCBuildConfiguration; 356 | buildSettings = { 357 | ALWAYS_SEARCH_USER_PATHS = NO; 358 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 359 | CLANG_CXX_LIBRARY = "libc++"; 360 | CLANG_ENABLE_MODULES = YES; 361 | CLANG_ENABLE_OBJC_ARC = YES; 362 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 363 | CLANG_WARN_BOOL_CONVERSION = YES; 364 | CLANG_WARN_COMMA = YES; 365 | CLANG_WARN_CONSTANT_CONVERSION = YES; 366 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 367 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 368 | CLANG_WARN_EMPTY_BODY = YES; 369 | CLANG_WARN_ENUM_CONVERSION = YES; 370 | CLANG_WARN_INFINITE_RECURSION = YES; 371 | CLANG_WARN_INT_CONVERSION = YES; 372 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 373 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 374 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 375 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 376 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 377 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 378 | CLANG_WARN_STRICT_PROTOTYPES = YES; 379 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 380 | CLANG_WARN_UNREACHABLE_CODE = YES; 381 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 382 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 383 | COPY_PHASE_STRIP = NO; 384 | ENABLE_STRICT_OBJC_MSGSEND = YES; 385 | ENABLE_TESTABILITY = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_DYNAMIC_NO_PIC = NO; 388 | GCC_NO_COMMON_BLOCKS = YES; 389 | GCC_OPTIMIZATION_LEVEL = 0; 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "DEBUG=1", 392 | "$(inherited)", 393 | ); 394 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 402 | MTL_ENABLE_DEBUG_INFO = YES; 403 | ONLY_ACTIVE_ARCH = YES; 404 | SDKROOT = iphoneos; 405 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 406 | TARGETED_DEVICE_FAMILY = "1,2"; 407 | }; 408 | name = Debug; 409 | }; 410 | E01BB3EC1A89188100F33C39 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ALWAYS_SEARCH_USER_PATHS = NO; 414 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 415 | CLANG_CXX_LIBRARY = "libc++"; 416 | CLANG_ENABLE_MODULES = YES; 417 | CLANG_ENABLE_OBJC_ARC = YES; 418 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_COMMA = YES; 421 | CLANG_WARN_CONSTANT_CONVERSION = YES; 422 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 423 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 424 | CLANG_WARN_EMPTY_BODY = YES; 425 | CLANG_WARN_ENUM_CONVERSION = YES; 426 | CLANG_WARN_INFINITE_RECURSION = YES; 427 | CLANG_WARN_INT_CONVERSION = YES; 428 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 429 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 430 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 431 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 432 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 433 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 434 | CLANG_WARN_STRICT_PROTOTYPES = YES; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = NO; 440 | ENABLE_NS_ASSERTIONS = NO; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | GCC_C_LANGUAGE_STANDARD = gnu99; 443 | GCC_NO_COMMON_BLOCKS = YES; 444 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 445 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 446 | GCC_WARN_UNDECLARED_SELECTOR = YES; 447 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 448 | GCC_WARN_UNUSED_FUNCTION = YES; 449 | GCC_WARN_UNUSED_VARIABLE = YES; 450 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 451 | MTL_ENABLE_DEBUG_INFO = NO; 452 | SDKROOT = iphoneos; 453 | SWIFT_COMPILATION_MODE = wholemodule; 454 | TARGETED_DEVICE_FAMILY = "1,2"; 455 | VALIDATE_PRODUCT = YES; 456 | }; 457 | name = Release; 458 | }; 459 | E01BB3EE1A89188100F33C39 /* Debug */ = { 460 | isa = XCBuildConfiguration; 461 | buildSettings = { 462 | APPLICATION_EXTENSION_API_ONLY = NO; 463 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 464 | CODE_SIGN_ENTITLEMENTS = "Example/AppExtensionCommunicator Example.entitlements"; 465 | CODE_SIGN_IDENTITY = "iPhone Developer"; 466 | DEVELOPMENT_TEAM = YUAX44CNP6; 467 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 468 | INFOPLIST_FILE = Example/Info.plist; 469 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 470 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 471 | PRODUCT_BUNDLE_IDENTIFIER = com.lazyapps.AppExtensionCommunicatorExample; 472 | PRODUCT_NAME = "$(TARGET_NAME)"; 473 | PROVISIONING_PROFILE = ""; 474 | SWIFT_VERSION = 5.0; 475 | }; 476 | name = Debug; 477 | }; 478 | E01BB3EF1A89188100F33C39 /* Release */ = { 479 | isa = XCBuildConfiguration; 480 | buildSettings = { 481 | APPLICATION_EXTENSION_API_ONLY = NO; 482 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 483 | CODE_SIGN_ENTITLEMENTS = "Example/AppExtensionCommunicator Example.entitlements"; 484 | CODE_SIGN_IDENTITY = "Apple Development"; 485 | CODE_SIGN_STYLE = Automatic; 486 | DEVELOPMENT_TEAM = YUAX44CNP6; 487 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 488 | INFOPLIST_FILE = Example/Info.plist; 489 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 490 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 491 | PRODUCT_BUNDLE_IDENTIFIER = com.lazyapps.AppExtensionCommunicatorExample; 492 | PRODUCT_NAME = "$(TARGET_NAME)"; 493 | PROVISIONING_PROFILE = ""; 494 | PROVISIONING_PROFILE_SPECIFIER = ""; 495 | SWIFT_VERSION = 5.0; 496 | }; 497 | name = Release; 498 | }; 499 | E01BB4181A891C3F00F33C39 /* Debug */ = { 500 | isa = XCBuildConfiguration; 501 | buildSettings = { 502 | APPLICATION_EXTENSION_API_ONLY = YES; 503 | CODE_SIGN_ENTITLEMENTS = TodayWidget/TodayWidget.entitlements; 504 | CODE_SIGN_IDENTITY = "iPhone Developer"; 505 | DEVELOPMENT_TEAM = YUAX44CNP6; 506 | GCC_PREPROCESSOR_DEFINITIONS = ( 507 | "DEBUG=1", 508 | "$(inherited)", 509 | ); 510 | INFOPLIST_FILE = TodayWidget/Info.plist; 511 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 512 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; 513 | PRODUCT_BUNDLE_IDENTIFIER = com.lazyapps.AppExtensionCommunicatorExample.TodayWidget; 514 | PRODUCT_NAME = "$(TARGET_NAME)"; 515 | PROVISIONING_PROFILE = ""; 516 | SKIP_INSTALL = YES; 517 | SWIFT_VERSION = 5.0; 518 | }; 519 | name = Debug; 520 | }; 521 | E01BB4191A891C3F00F33C39 /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | APPLICATION_EXTENSION_API_ONLY = YES; 525 | CODE_SIGN_ENTITLEMENTS = TodayWidget/TodayWidget.entitlements; 526 | CODE_SIGN_IDENTITY = "Apple Development"; 527 | CODE_SIGN_STYLE = Automatic; 528 | DEVELOPMENT_TEAM = YUAX44CNP6; 529 | INFOPLIST_FILE = TodayWidget/Info.plist; 530 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 531 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; 532 | PRODUCT_BUNDLE_IDENTIFIER = com.lazyapps.AppExtensionCommunicatorExample.TodayWidget; 533 | PRODUCT_NAME = "$(TARGET_NAME)"; 534 | PROVISIONING_PROFILE = ""; 535 | PROVISIONING_PROFILE_SPECIFIER = ""; 536 | SKIP_INSTALL = YES; 537 | SWIFT_VERSION = 5.0; 538 | }; 539 | name = Release; 540 | }; 541 | /* End XCBuildConfiguration section */ 542 | 543 | /* Begin XCConfigurationList section */ 544 | E01BB3C91A89188100F33C39 /* Build configuration list for PBXProject "Example" */ = { 545 | isa = XCConfigurationList; 546 | buildConfigurations = ( 547 | E01BB3EB1A89188100F33C39 /* Debug */, 548 | E01BB3EC1A89188100F33C39 /* Release */, 549 | ); 550 | defaultConfigurationIsVisible = 0; 551 | defaultConfigurationName = Release; 552 | }; 553 | E01BB3ED1A89188100F33C39 /* Build configuration list for PBXNativeTarget "AppExtensionCommunicator Example" */ = { 554 | isa = XCConfigurationList; 555 | buildConfigurations = ( 556 | E01BB3EE1A89188100F33C39 /* Debug */, 557 | E01BB3EF1A89188100F33C39 /* Release */, 558 | ); 559 | defaultConfigurationIsVisible = 0; 560 | defaultConfigurationName = Release; 561 | }; 562 | E01BB4171A891C3F00F33C39 /* Build configuration list for PBXNativeTarget "TodayWidget" */ = { 563 | isa = XCConfigurationList; 564 | buildConfigurations = ( 565 | E01BB4181A891C3F00F33C39 /* Debug */, 566 | E01BB4191A891C3F00F33C39 /* Release */, 567 | ); 568 | defaultConfigurationIsVisible = 0; 569 | defaultConfigurationName = Release; 570 | }; 571 | /* End XCConfigurationList section */ 572 | }; 573 | rootObject = E01BB3C61A89188100F33C39 /* Project object */; 574 | } 575 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by CHEN Xian’an on 2/10/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 17 | window = UIWindow(frame: UIScreen.main.bounds) 18 | let vc = ViewController() 19 | window?.rootViewController = UINavigationController(rootViewController: vc) 20 | window?.makeKeyAndVisible() 21 | 22 | return true 23 | } 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /Example/Example/AppExtensionCommunicator Example.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.lazyapps.AppExtensionCommunicatorExample 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "2x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "1x", 51 | "size" : "29x29" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "2x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "1x", 61 | "size" : "40x40" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "2x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "1x", 71 | "size" : "76x76" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "2x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "83.5x83.5" 82 | }, 83 | { 84 | "idiom" : "ios-marketing", 85 | "scale" : "1x", 86 | "size" : "1024x1024" 87 | } 88 | ], 89 | "info" : { 90 | "author" : "xcode", 91 | "version" : 1 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Example/Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.lazyapps.AppExtensionCommunicatorExample 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Example 4 | // 5 | // Created by CHEN Xian’an on 2/10/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AppExtensionCommunicator 11 | 12 | class ViewController: UIViewController { 13 | 14 | var communicator: AppExtensionCommunicator? 15 | 16 | override func loadView() { 17 | super.loadView() 18 | navigationItem.title = "AppExtensionCommunicator Example" 19 | view.backgroundColor = UIColor.white 20 | view.addSubview(_textView) 21 | if let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.lazyapps.AppExtensionCommunicatorExample") { 22 | communicator = AppExtensionCommunicator(containerURL: containerURL) 23 | communicator?.observeMessage(forIdentifier: "AppExtensionCommunicatorExample") { message in 24 | self._textView.text = "Received Notification: \n\n\(String(describing: message))" 25 | } 26 | } else { 27 | _textView.text = "Setup App Groups Required" 28 | } 29 | } 30 | 31 | override func viewDidLayoutSubviews() { 32 | _textView.frame = self.view.bounds 33 | _textView.scrollIndicatorInsets = UIEdgeInsets(top: self.view.safeAreaInsets.top, left: 0, bottom: self.view.safeAreaInsets.bottom, right: 0) 34 | _textView.contentOffset = CGPointMake(0, -self.view.safeAreaInsets.top) 35 | } 36 | 37 | private lazy var _textView: UITextView = { 38 | let tv = UITextView(frame: CGRectZero) 39 | tv.text = "Swipe down Today View to install extension and test notification" 40 | tv.font = UIFont.systemFont(ofSize: 27) 41 | tv.isEditable = false 42 | 43 | return tv 44 | }() 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Example/TodayWidget/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AppExtensionCommunicator Example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | com.lazyapps.AppExtensionCommunicatorExample.TodayWidget 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSExtension 26 | 27 | NSExtensionPointIdentifier 28 | com.apple.widget-extension 29 | NSExtensionPrincipalClass 30 | $(PRODUCT_NAME).TodayViewController 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Example/TodayWidget/TodayViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TodayViewController.swift 3 | // TodayWidget 4 | // 5 | // Created by CHEN Xian’an on 2/10/15. 6 | // Copyright (c) 2015 CHEN Xian’an. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AppExtensionCommunicator 11 | 12 | class TodayViewController: UIViewController { 13 | 14 | var communicator: AppExtensionCommunicator? 15 | 16 | override func loadView() { 17 | super.loadView() 18 | preferredContentSize = CGSizeMake(self.view.bounds.width, 44) 19 | view.addSubview(_button) 20 | if let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.lazyapps.AppExtensionCommunicatorExample") { 21 | communicator = AppExtensionCommunicator(containerURL: containerURL) 22 | } else { 23 | _button.setTitle("Setup App Groups Required", for: .normal) 24 | _button.setTitleColor(UIColor.red, for: .normal) 25 | } 26 | } 27 | 28 | override func viewDidLayoutSubviews() { 29 | _button.frame = view.bounds 30 | } 31 | 32 | private lazy var _button: UIButton = { 33 | let b = UIButton(frame: CGRectZero) 34 | b.setTitle("Tap to Diliver Message", for: .normal) 35 | b.setTitleColor(UIColor.white, for: .normal) 36 | b.setTitleColor(UIColor.blue, for: .highlighted) 37 | b.addTarget(self, action: #selector(_buttonTouchUpInside(btn:)), for: .touchUpInside) 38 | 39 | return b 40 | }() 41 | 42 | @objc private func _buttonTouchUpInside(btn: UIButton) { 43 | let r = arc4random_uniform(UInt32(Int32.max)) 44 | communicator?.deliver(message: ["random" : NSNumber(value: Int32(r))], withIdentifier: "AppExtensionCommunicatorExample") 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Example/TodayWidget/TodayWidget.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.lazyapps.AppExtensionCommunicatorExample 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 — Present 2 | CHEN Xian’an 3 | http://lazyapps.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AppExtensionCommunicator 2 | 3 | Communicate between app extension and its containing app. 4 | 5 | 6 | ## Usage Example 7 | 8 | You must enable app groups for containing app and extension before using `AppExtensionCommunicator`. 9 | 10 | 1. Make an instance with app group container URL: `AppExtensionCommunicator(containerURL: containerURL)` 11 | 2. Deliver message: `communicator.deliverMessage(message: MSG_AS_DICTIONARY, withIdentifier: ID_AS_STRING)` 12 | 3. Observe message: `communicator.observeMessageForIdentifier(ID_AS_STRING) { message in 13 | ...}` 14 | 15 | That's all. 16 | 17 | Check the example project for a real world usage. 18 | 19 | ## Special Thanks 20 | I learned how to mix C into Swift framework thanks to created by [danieleggert](https://github.com/danieleggert). 21 | 22 | ## Creator 23 | 24 | * GitHub: 25 | * Twitter: [@_cxa](https://twitter.com/_cxa) 26 | * Apps available in App Store: 27 | 28 | ## License 29 | 30 | Under the MIT license. See the LICENSE file for more information. --------------------------------------------------------------------------------