├── .gitignore ├── Example ├── QuickActionsExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── QuickActionsExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── Info.plist │ └── MainViewController.swift ├── LICENSE ├── Package.swift ├── QuickActions.podspec ├── QuickActions.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── QuickActions.xcscheme ├── QuickActions ├── Info.plist └── QuickActions.h ├── README.md ├── Source └── QuickActions.swift └── fastlane ├── Fastfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/swift,xcode 3 | 4 | ### Swift ### 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | ## Build generated 10 | build/ 11 | DerivedData/ 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata/ 23 | xcshareddata/ 24 | 25 | ## Other 26 | *.moved-aside 27 | *.xcuserstate 28 | *.xcscmblueprint 29 | 30 | ## Obj-C/Swift specific 31 | *.hmap 32 | *.ipa 33 | *.dSYM.zip 34 | *.dSYM 35 | 36 | ## Playgrounds 37 | timeline.xctimeline 38 | playground.xcworkspace 39 | 40 | # Swift Package Manager 41 | # 42 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 43 | # Packages/ 44 | .build/ 45 | 46 | # CocoaPods 47 | # 48 | # We recommend against adding the Pods directory to your .gitignore. However 49 | # you should judge for yourself, the pros and cons are mentioned at: 50 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 51 | # 52 | # Pods/ 53 | 54 | # Carthage 55 | # 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # fastlane 62 | # 63 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 64 | # screenshots whenever they are needed. 65 | # For more information about the recommended setup visit: 66 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 67 | 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots 71 | fastlane/test_output 72 | -------------------------------------------------------------------------------- /Example/QuickActionsExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D701EF2D1C85B956000DBF13 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D701EF2C1C85B956000DBF13 /* AppDelegate.swift */; }; 11 | D701EF2F1C85B956000DBF13 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D701EF2E1C85B956000DBF13 /* MainViewController.swift */; }; 12 | D701EF341C85B956000DBF13 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D701EF331C85B956000DBF13 /* Assets.xcassets */; }; 13 | D701EF481C85BB27000DBF13 /* QuickActions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D701EF441C85BAC1000DBF13 /* QuickActions.framework */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXContainerItemProxy section */ 17 | D701EF431C85BAC1000DBF13 /* PBXContainerItemProxy */ = { 18 | isa = PBXContainerItemProxy; 19 | containerPortal = D701EF3E1C85BAC1000DBF13 /* QuickActions.xcodeproj */; 20 | proxyType = 2; 21 | remoteGlobalIDString = D7CCECA71C82A35F001B07AB; 22 | remoteInfo = QuickActions; 23 | }; 24 | /* End PBXContainerItemProxy section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | D701EF291C85B956000DBF13 /* QuickActionsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuickActionsExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | D701EF2C1C85B956000DBF13 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 29 | D701EF2E1C85B956000DBF13 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 30 | D701EF331C85B956000DBF13 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | D701EF381C85B956000DBF13 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | D701EF3E1C85BAC1000DBF13 /* QuickActions.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = QuickActions.xcodeproj; path = ../QuickActions.xcodeproj; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | D701EF261C85B956000DBF13 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | D701EF481C85BB27000DBF13 /* QuickActions.framework in Frameworks */, 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | D701EF201C85B956000DBF13 = { 48 | isa = PBXGroup; 49 | children = ( 50 | D701EF2B1C85B956000DBF13 /* QuickActionsExample */, 51 | D701EF2A1C85B956000DBF13 /* Products */, 52 | D701EF3E1C85BAC1000DBF13 /* QuickActions.xcodeproj */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | D701EF2A1C85B956000DBF13 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | D701EF291C85B956000DBF13 /* QuickActionsExample.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | D701EF2B1C85B956000DBF13 /* QuickActionsExample */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | D701EF2C1C85B956000DBF13 /* AppDelegate.swift */, 68 | D701EF2E1C85B956000DBF13 /* MainViewController.swift */, 69 | D701EF331C85B956000DBF13 /* Assets.xcassets */, 70 | D701EF381C85B956000DBF13 /* Info.plist */, 71 | ); 72 | path = QuickActionsExample; 73 | sourceTree = ""; 74 | }; 75 | D701EF3F1C85BAC1000DBF13 /* Products */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | D701EF441C85BAC1000DBF13 /* QuickActions.framework */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | /* End PBXGroup section */ 84 | 85 | /* Begin PBXNativeTarget section */ 86 | D701EF281C85B956000DBF13 /* QuickActionsExample */ = { 87 | isa = PBXNativeTarget; 88 | buildConfigurationList = D701EF3B1C85B956000DBF13 /* Build configuration list for PBXNativeTarget "QuickActionsExample" */; 89 | buildPhases = ( 90 | D701EF251C85B956000DBF13 /* Sources */, 91 | D701EF261C85B956000DBF13 /* Frameworks */, 92 | D701EF271C85B956000DBF13 /* Resources */, 93 | ); 94 | buildRules = ( 95 | ); 96 | dependencies = ( 97 | ); 98 | name = QuickActionsExample; 99 | productName = QuickActionsExample; 100 | productReference = D701EF291C85B956000DBF13 /* QuickActionsExample.app */; 101 | productType = "com.apple.product-type.application"; 102 | }; 103 | /* End PBXNativeTarget section */ 104 | 105 | /* Begin PBXProject section */ 106 | D701EF211C85B956000DBF13 /* Project object */ = { 107 | isa = PBXProject; 108 | attributes = { 109 | LastSwiftUpdateCheck = 0720; 110 | LastUpgradeCheck = 1500; 111 | ORGANIZATIONNAME = "Ricardo Pereira"; 112 | TargetAttributes = { 113 | D701EF281C85B956000DBF13 = { 114 | CreatedOnToolsVersion = 7.2.1; 115 | LastSwiftMigration = 1020; 116 | }; 117 | }; 118 | }; 119 | buildConfigurationList = D701EF241C85B956000DBF13 /* Build configuration list for PBXProject "QuickActionsExample" */; 120 | compatibilityVersion = "Xcode 3.2"; 121 | developmentRegion = en; 122 | hasScannedForEncodings = 0; 123 | knownRegions = ( 124 | en, 125 | Base, 126 | ); 127 | mainGroup = D701EF201C85B956000DBF13; 128 | productRefGroup = D701EF2A1C85B956000DBF13 /* Products */; 129 | projectDirPath = ""; 130 | projectReferences = ( 131 | { 132 | ProductGroup = D701EF3F1C85BAC1000DBF13 /* Products */; 133 | ProjectRef = D701EF3E1C85BAC1000DBF13 /* QuickActions.xcodeproj */; 134 | }, 135 | ); 136 | projectRoot = ""; 137 | targets = ( 138 | D701EF281C85B956000DBF13 /* QuickActionsExample */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXReferenceProxy section */ 144 | D701EF441C85BAC1000DBF13 /* QuickActions.framework */ = { 145 | isa = PBXReferenceProxy; 146 | fileType = wrapper.framework; 147 | path = QuickActions.framework; 148 | remoteRef = D701EF431C85BAC1000DBF13 /* PBXContainerItemProxy */; 149 | sourceTree = BUILT_PRODUCTS_DIR; 150 | }; 151 | /* End PBXReferenceProxy section */ 152 | 153 | /* Begin PBXResourcesBuildPhase section */ 154 | D701EF271C85B956000DBF13 /* Resources */ = { 155 | isa = PBXResourcesBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | D701EF341C85B956000DBF13 /* Assets.xcassets in Resources */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXResourcesBuildPhase section */ 163 | 164 | /* Begin PBXSourcesBuildPhase section */ 165 | D701EF251C85B956000DBF13 /* Sources */ = { 166 | isa = PBXSourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | D701EF2F1C85B956000DBF13 /* MainViewController.swift in Sources */, 170 | D701EF2D1C85B956000DBF13 /* AppDelegate.swift in Sources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXSourcesBuildPhase section */ 175 | 176 | /* Begin XCBuildConfiguration section */ 177 | D701EF391C85B956000DBF13 /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | ALWAYS_SEARCH_USER_PATHS = NO; 181 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 182 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 183 | CLANG_CXX_LIBRARY = "libc++"; 184 | CLANG_ENABLE_MODULES = YES; 185 | CLANG_ENABLE_OBJC_ARC = YES; 186 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 187 | CLANG_WARN_BOOL_CONVERSION = YES; 188 | CLANG_WARN_COMMA = YES; 189 | CLANG_WARN_CONSTANT_CONVERSION = YES; 190 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 191 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 192 | CLANG_WARN_EMPTY_BODY = YES; 193 | CLANG_WARN_ENUM_CONVERSION = YES; 194 | CLANG_WARN_INFINITE_RECURSION = YES; 195 | CLANG_WARN_INT_CONVERSION = YES; 196 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 197 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 198 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 200 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 201 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 202 | CLANG_WARN_STRICT_PROTOTYPES = YES; 203 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 204 | CLANG_WARN_UNREACHABLE_CODE = YES; 205 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 206 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 207 | COPY_PHASE_STRIP = NO; 208 | DEBUG_INFORMATION_FORMAT = dwarf; 209 | ENABLE_STRICT_OBJC_MSGSEND = YES; 210 | ENABLE_TESTABILITY = YES; 211 | GCC_C_LANGUAGE_STANDARD = gnu99; 212 | GCC_DYNAMIC_NO_PIC = NO; 213 | GCC_NO_COMMON_BLOCKS = YES; 214 | GCC_OPTIMIZATION_LEVEL = 0; 215 | GCC_PREPROCESSOR_DEFINITIONS = ( 216 | "DEBUG=1", 217 | "$(inherited)", 218 | ); 219 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 220 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 221 | GCC_WARN_UNDECLARED_SELECTOR = YES; 222 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 223 | GCC_WARN_UNUSED_FUNCTION = YES; 224 | GCC_WARN_UNUSED_VARIABLE = YES; 225 | MTL_ENABLE_DEBUG_INFO = YES; 226 | ONLY_ACTIVE_ARCH = YES; 227 | SDKROOT = iphoneos; 228 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 229 | }; 230 | name = Debug; 231 | }; 232 | D701EF3A1C85B956000DBF13 /* Release */ = { 233 | isa = XCBuildConfiguration; 234 | buildSettings = { 235 | ALWAYS_SEARCH_USER_PATHS = NO; 236 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 237 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 238 | CLANG_CXX_LIBRARY = "libc++"; 239 | CLANG_ENABLE_MODULES = YES; 240 | CLANG_ENABLE_OBJC_ARC = YES; 241 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 242 | CLANG_WARN_BOOL_CONVERSION = YES; 243 | CLANG_WARN_COMMA = YES; 244 | CLANG_WARN_CONSTANT_CONVERSION = YES; 245 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 246 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 247 | CLANG_WARN_EMPTY_BODY = YES; 248 | CLANG_WARN_ENUM_CONVERSION = YES; 249 | CLANG_WARN_INFINITE_RECURSION = YES; 250 | CLANG_WARN_INT_CONVERSION = YES; 251 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 252 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 253 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 255 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 256 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 257 | CLANG_WARN_STRICT_PROTOTYPES = YES; 258 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 259 | CLANG_WARN_UNREACHABLE_CODE = YES; 260 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 261 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 262 | COPY_PHASE_STRIP = NO; 263 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 264 | ENABLE_NS_ASSERTIONS = NO; 265 | ENABLE_STRICT_OBJC_MSGSEND = YES; 266 | GCC_C_LANGUAGE_STANDARD = gnu99; 267 | GCC_NO_COMMON_BLOCKS = YES; 268 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 269 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 270 | GCC_WARN_UNDECLARED_SELECTOR = YES; 271 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 272 | GCC_WARN_UNUSED_FUNCTION = YES; 273 | GCC_WARN_UNUSED_VARIABLE = YES; 274 | MTL_ENABLE_DEBUG_INFO = NO; 275 | SDKROOT = iphoneos; 276 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 277 | VALIDATE_PRODUCT = YES; 278 | }; 279 | name = Release; 280 | }; 281 | D701EF3C1C85B956000DBF13 /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 285 | INFOPLIST_FILE = QuickActionsExample/Info.plist; 286 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 287 | PRODUCT_BUNDLE_IDENTIFIER = eu.ricardopereira.QuickActionsExample; 288 | PRODUCT_NAME = "$(TARGET_NAME)"; 289 | SWIFT_VERSION = 5.0; 290 | }; 291 | name = Debug; 292 | }; 293 | D701EF3D1C85B956000DBF13 /* Release */ = { 294 | isa = XCBuildConfiguration; 295 | buildSettings = { 296 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 297 | INFOPLIST_FILE = QuickActionsExample/Info.plist; 298 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 299 | PRODUCT_BUNDLE_IDENTIFIER = eu.ricardopereira.QuickActionsExample; 300 | PRODUCT_NAME = "$(TARGET_NAME)"; 301 | SWIFT_VERSION = 5.0; 302 | }; 303 | name = Release; 304 | }; 305 | /* End XCBuildConfiguration section */ 306 | 307 | /* Begin XCConfigurationList section */ 308 | D701EF241C85B956000DBF13 /* Build configuration list for PBXProject "QuickActionsExample" */ = { 309 | isa = XCConfigurationList; 310 | buildConfigurations = ( 311 | D701EF391C85B956000DBF13 /* Debug */, 312 | D701EF3A1C85B956000DBF13 /* Release */, 313 | ); 314 | defaultConfigurationIsVisible = 0; 315 | defaultConfigurationName = Release; 316 | }; 317 | D701EF3B1C85B956000DBF13 /* Build configuration list for PBXNativeTarget "QuickActionsExample" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | D701EF3C1C85B956000DBF13 /* Debug */, 321 | D701EF3D1C85B956000DBF13 /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | /* End XCConfigurationList section */ 327 | }; 328 | rootObject = D701EF211C85B956000DBF13 /* Project object */; 329 | } 330 | -------------------------------------------------------------------------------- /Example/QuickActionsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/QuickActionsExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // QuickActionsExample 4 | // 5 | // Created by Ricardo Pereira on 01/03/16. 6 | // Copyright © 2016 Ricardo Pereira. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import QuickActions 11 | 12 | enum AppShortcut: String, ShortcutType { 13 | case createExpense 14 | case lastItems 15 | } 16 | 17 | @UIApplicationMain 18 | class AppDelegate: UIResponder, UIApplicationDelegate { 19 | 20 | var window: UIWindow? 21 | var quickActions: QuickActions? 22 | 23 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { 24 | window = UIWindow(frame: UIScreen.main.bounds) 25 | window?.makeKeyAndVisible() 26 | window?.rootViewController = MainViewController() 27 | 28 | let shortcuts = [ 29 | Shortcut( 30 | type: AppShortcut.createExpense, 31 | title: NSLocalizedString("CreateExpenseTitle", comment: ""), 32 | subtitle: NSLocalizedString("CreateExpenseSubTitle", comment: ""), 33 | icon: .add 34 | ) 35 | ] 36 | 37 | if let actionHandler = window?.rootViewController as? QuickActionSupport, 38 | let bundleIdentifier = Bundle.main.bundleIdentifier { 39 | quickActions = QuickActions(application, actionHandler: actionHandler, bundleIdentifier: bundleIdentifier, shortcuts: shortcuts, launchOptions: launchOptions) 40 | } 41 | return true 42 | } 43 | 44 | func applicationDidEnterBackground(_ application: UIApplication) { 45 | let shortcuts = [Shortcut(type: AppShortcut.lastItems, title: "Last items", subtitle: nil, icon: nil)] 46 | quickActions?.add(shortcuts, toApplication: application) 47 | } 48 | 49 | @available(iOS 9, *) 50 | func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Swift.Void) { 51 | // This callback is used if your application is already launched in the background, if not application(_:,willFinishLaunchingWithOptions:) or application(_:didFinishLaunchingWithOptions) will be called (handle the shortcut in those callbacks and return `false`) 52 | guard let quickActions = quickActions else { 53 | return completionHandler(false) 54 | } 55 | guard let actionHandler = window?.rootViewController as? QuickActionSupport else { 56 | return completionHandler(false) 57 | } 58 | completionHandler(quickActions.handle(actionHandler, shortcutItem: shortcutItem)) 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /Example/QuickActionsExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Example/QuickActionsExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/QuickActionsExample/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "8.0", 8 | "subtype" : "736h", 9 | "scale" : "3x" 10 | }, 11 | { 12 | "orientation" : "landscape", 13 | "idiom" : "iphone", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "8.0", 16 | "subtype" : "736h", 17 | "scale" : "3x" 18 | }, 19 | { 20 | "orientation" : "portrait", 21 | "idiom" : "iphone", 22 | "extent" : "full-screen", 23 | "minimum-system-version" : "8.0", 24 | "subtype" : "667h", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "orientation" : "portrait", 29 | "idiom" : "iphone", 30 | "extent" : "full-screen", 31 | "minimum-system-version" : "7.0", 32 | "scale" : "2x" 33 | }, 34 | { 35 | "orientation" : "portrait", 36 | "idiom" : "iphone", 37 | "extent" : "full-screen", 38 | "minimum-system-version" : "7.0", 39 | "subtype" : "retina4", 40 | "scale" : "2x" 41 | }, 42 | { 43 | "orientation" : "portrait", 44 | "idiom" : "iphone", 45 | "extent" : "full-screen", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "orientation" : "portrait", 50 | "idiom" : "iphone", 51 | "extent" : "full-screen", 52 | "scale" : "2x" 53 | }, 54 | { 55 | "orientation" : "portrait", 56 | "idiom" : "iphone", 57 | "extent" : "full-screen", 58 | "subtype" : "retina4", 59 | "scale" : "2x" 60 | } 61 | ], 62 | "info" : { 63 | "version" : 1, 64 | "author" : "xcode" 65 | } 66 | } -------------------------------------------------------------------------------- /Example/QuickActionsExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 | LaunchImage 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Example/QuickActionsExample/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.swift 3 | // QuickActionsExample 4 | // 5 | // Created by Ricardo Pereira on 01/03/16. 6 | // Copyright © 2016 Ricardo Pereira. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import QuickActions 11 | 12 | class MainViewController: UIViewController, QuickActionSupport { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | view.backgroundColor = .red 17 | } 18 | 19 | func prepareForQuickAction(_ shortcutType: T) { 20 | if let shortcut = AppShortcut(rawValue: shortcutType.value), case .createExpense = shortcut { 21 | print("Prepare the view to create a new expense") 22 | } 23 | } 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Ricardo Pereira 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "QuickActions", 7 | platforms: [ 8 | .iOS(.v10) 9 | ], 10 | products: [ 11 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 12 | .library( 13 | name: "QuickActions", 14 | targets: ["QuickActions"] 15 | ) 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 24 | .target( 25 | name: "QuickActions", 26 | path: ".", 27 | sources: ["Source"] 28 | ) 29 | ] 30 | ) 31 | -------------------------------------------------------------------------------- /QuickActions.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "QuickActions" 3 | s.version = "7.0.0" 4 | s.summary = "Swift wrapper for iOS Home Screen Quick Actions" 5 | s.homepage = "https://github.com/ricardopereira/QuickActions" 6 | s.license = 'MIT' 7 | s.author = { "Ricardo Pereira" => "m@ricardopereira.eu" } 8 | s.source = { :git => "https://github.com/ricardopereira/QuickActions.git", :tag => s.version.to_s } 9 | s.social_media_url = 'https://mastodon.social/@ricardopereira' 10 | 11 | s.platform = :ios, '12.0' 12 | s.requires_arc = true 13 | s.swift_version = '5.0' 14 | 15 | s.source_files = 'QuickActions/*.{h}', 'Source/**/*.{h,swift}' 16 | s.frameworks = 'UIKit' 17 | end 18 | -------------------------------------------------------------------------------- /QuickActions.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D701EF1E1C85AE10000DBF13 /* QuickActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D701EF1D1C85AE10000DBF13 /* QuickActions.swift */; }; 11 | D7CCECAB1C82A35F001B07AB /* QuickActions.h in Headers */ = {isa = PBXBuildFile; fileRef = D7CCECAA1C82A35F001B07AB /* QuickActions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXFileReference section */ 15 | D701EF1D1C85AE10000DBF13 /* QuickActions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = QuickActions.swift; path = Source/QuickActions.swift; sourceTree = SOURCE_ROOT; }; 16 | D7CCECA71C82A35F001B07AB /* QuickActions.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = QuickActions.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 17 | D7CCECAA1C82A35F001B07AB /* QuickActions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QuickActions.h; sourceTree = ""; }; 18 | D7CCECAC1C82A35F001B07AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 19 | /* End PBXFileReference section */ 20 | 21 | /* Begin PBXFrameworksBuildPhase section */ 22 | D7CCECA31C82A35F001B07AB /* Frameworks */ = { 23 | isa = PBXFrameworksBuildPhase; 24 | buildActionMask = 2147483647; 25 | files = ( 26 | ); 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXFrameworksBuildPhase section */ 30 | 31 | /* Begin PBXGroup section */ 32 | D7CCEC9D1C82A35F001B07AB = { 33 | isa = PBXGroup; 34 | children = ( 35 | D7CCECA91C82A35F001B07AB /* QuickActions */, 36 | D7CCECA81C82A35F001B07AB /* Products */, 37 | ); 38 | sourceTree = ""; 39 | }; 40 | D7CCECA81C82A35F001B07AB /* Products */ = { 41 | isa = PBXGroup; 42 | children = ( 43 | D7CCECA71C82A35F001B07AB /* QuickActions.framework */, 44 | ); 45 | name = Products; 46 | sourceTree = ""; 47 | }; 48 | D7CCECA91C82A35F001B07AB /* QuickActions */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | D7CCECAA1C82A35F001B07AB /* QuickActions.h */, 52 | D701EF1D1C85AE10000DBF13 /* QuickActions.swift */, 53 | D7CCECAC1C82A35F001B07AB /* Info.plist */, 54 | ); 55 | path = QuickActions; 56 | sourceTree = ""; 57 | }; 58 | /* End PBXGroup section */ 59 | 60 | /* Begin PBXHeadersBuildPhase section */ 61 | D7CCECA41C82A35F001B07AB /* Headers */ = { 62 | isa = PBXHeadersBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | D7CCECAB1C82A35F001B07AB /* QuickActions.h in Headers */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXHeadersBuildPhase section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | D7CCECA61C82A35F001B07AB /* QuickActions */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = D7CCECBB1C82A35F001B07AB /* Build configuration list for PBXNativeTarget "QuickActions" */; 75 | buildPhases = ( 76 | D7CCECA21C82A35F001B07AB /* Sources */, 77 | D7CCECA31C82A35F001B07AB /* Frameworks */, 78 | D7CCECA41C82A35F001B07AB /* Headers */, 79 | D7CCECA51C82A35F001B07AB /* Resources */, 80 | ); 81 | buildRules = ( 82 | ); 83 | dependencies = ( 84 | ); 85 | name = QuickActions; 86 | productName = QuickActions; 87 | productReference = D7CCECA71C82A35F001B07AB /* QuickActions.framework */; 88 | productType = "com.apple.product-type.framework"; 89 | }; 90 | /* End PBXNativeTarget section */ 91 | 92 | /* Begin PBXProject section */ 93 | D7CCEC9E1C82A35F001B07AB /* Project object */ = { 94 | isa = PBXProject; 95 | attributes = { 96 | BuildIndependentTargetsInParallel = YES; 97 | LastSwiftUpdateCheck = 0720; 98 | LastUpgradeCheck = 1500; 99 | ORGANIZATIONNAME = "Ricardo Pereira"; 100 | TargetAttributes = { 101 | D7CCECA61C82A35F001B07AB = { 102 | CreatedOnToolsVersion = 7.2.1; 103 | LastSwiftMigration = 1020; 104 | }; 105 | }; 106 | }; 107 | buildConfigurationList = D7CCECA11C82A35F001B07AB /* Build configuration list for PBXProject "QuickActions" */; 108 | compatibilityVersion = "Xcode 3.2"; 109 | developmentRegion = en; 110 | hasScannedForEncodings = 0; 111 | knownRegions = ( 112 | en, 113 | Base, 114 | ); 115 | mainGroup = D7CCEC9D1C82A35F001B07AB; 116 | productRefGroup = D7CCECA81C82A35F001B07AB /* Products */; 117 | projectDirPath = ""; 118 | projectRoot = ""; 119 | targets = ( 120 | D7CCECA61C82A35F001B07AB /* QuickActions */, 121 | ); 122 | }; 123 | /* End PBXProject section */ 124 | 125 | /* Begin PBXResourcesBuildPhase section */ 126 | D7CCECA51C82A35F001B07AB /* Resources */ = { 127 | isa = PBXResourcesBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | /* End PBXResourcesBuildPhase section */ 134 | 135 | /* Begin PBXSourcesBuildPhase section */ 136 | D7CCECA21C82A35F001B07AB /* Sources */ = { 137 | isa = PBXSourcesBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | D701EF1E1C85AE10000DBF13 /* QuickActions.swift in Sources */, 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXSourcesBuildPhase section */ 145 | 146 | /* Begin XCBuildConfiguration section */ 147 | D7CCECB91C82A35F001B07AB /* Debug */ = { 148 | isa = XCBuildConfiguration; 149 | buildSettings = { 150 | ALWAYS_SEARCH_USER_PATHS = NO; 151 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 152 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 153 | CLANG_CXX_LIBRARY = "libc++"; 154 | CLANG_ENABLE_MODULES = YES; 155 | CLANG_ENABLE_OBJC_ARC = YES; 156 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 157 | CLANG_WARN_BOOL_CONVERSION = YES; 158 | CLANG_WARN_COMMA = YES; 159 | CLANG_WARN_CONSTANT_CONVERSION = YES; 160 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 161 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 162 | CLANG_WARN_EMPTY_BODY = YES; 163 | CLANG_WARN_ENUM_CONVERSION = YES; 164 | CLANG_WARN_INFINITE_RECURSION = YES; 165 | CLANG_WARN_INT_CONVERSION = YES; 166 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 167 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 168 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 169 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 170 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 171 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 172 | CLANG_WARN_STRICT_PROTOTYPES = YES; 173 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 174 | CLANG_WARN_UNREACHABLE_CODE = YES; 175 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 176 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 177 | COPY_PHASE_STRIP = NO; 178 | CURRENT_PROJECT_VERSION = 2023.10.12.16.44; 179 | DEBUG_INFORMATION_FORMAT = dwarf; 180 | ENABLE_STRICT_OBJC_MSGSEND = YES; 181 | ENABLE_TESTABILITY = YES; 182 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 183 | GCC_C_LANGUAGE_STANDARD = gnu99; 184 | GCC_DYNAMIC_NO_PIC = NO; 185 | GCC_NO_COMMON_BLOCKS = YES; 186 | GCC_OPTIMIZATION_LEVEL = 0; 187 | GCC_PREPROCESSOR_DEFINITIONS = ( 188 | "DEBUG=1", 189 | "$(inherited)", 190 | ); 191 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 192 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 193 | GCC_WARN_UNDECLARED_SELECTOR = YES; 194 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 195 | GCC_WARN_UNUSED_FUNCTION = YES; 196 | GCC_WARN_UNUSED_VARIABLE = YES; 197 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 198 | MTL_ENABLE_DEBUG_INFO = YES; 199 | ONLY_ACTIVE_ARCH = YES; 200 | SDKROOT = iphoneos; 201 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 202 | TARGETED_DEVICE_FAMILY = "1,2"; 203 | VERSIONING_SYSTEM = "apple-generic"; 204 | VERSION_INFO_PREFIX = ""; 205 | }; 206 | name = Debug; 207 | }; 208 | D7CCECBA1C82A35F001B07AB /* Release */ = { 209 | isa = XCBuildConfiguration; 210 | buildSettings = { 211 | ALWAYS_SEARCH_USER_PATHS = NO; 212 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 214 | CLANG_CXX_LIBRARY = "libc++"; 215 | CLANG_ENABLE_MODULES = YES; 216 | CLANG_ENABLE_OBJC_ARC = YES; 217 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_COMMA = YES; 220 | CLANG_WARN_CONSTANT_CONVERSION = YES; 221 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 223 | CLANG_WARN_EMPTY_BODY = YES; 224 | CLANG_WARN_ENUM_CONVERSION = YES; 225 | CLANG_WARN_INFINITE_RECURSION = YES; 226 | CLANG_WARN_INT_CONVERSION = YES; 227 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 228 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 229 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 230 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 231 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 232 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 233 | CLANG_WARN_STRICT_PROTOTYPES = YES; 234 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 235 | CLANG_WARN_UNREACHABLE_CODE = YES; 236 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 237 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 238 | COPY_PHASE_STRIP = NO; 239 | CURRENT_PROJECT_VERSION = 2023.10.12.16.44; 240 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 241 | ENABLE_NS_ASSERTIONS = NO; 242 | ENABLE_STRICT_OBJC_MSGSEND = YES; 243 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 244 | GCC_C_LANGUAGE_STANDARD = gnu99; 245 | GCC_NO_COMMON_BLOCKS = YES; 246 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 247 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 248 | GCC_WARN_UNDECLARED_SELECTOR = YES; 249 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 250 | GCC_WARN_UNUSED_FUNCTION = YES; 251 | GCC_WARN_UNUSED_VARIABLE = YES; 252 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 253 | MTL_ENABLE_DEBUG_INFO = NO; 254 | SDKROOT = iphoneos; 255 | SWIFT_COMPILATION_MODE = wholemodule; 256 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 257 | TARGETED_DEVICE_FAMILY = "1,2"; 258 | VALIDATE_PRODUCT = YES; 259 | VERSIONING_SYSTEM = "apple-generic"; 260 | VERSION_INFO_PREFIX = ""; 261 | }; 262 | name = Release; 263 | }; 264 | D7CCECBC1C82A35F001B07AB /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | CLANG_ENABLE_MODULES = YES; 268 | CODE_SIGN_IDENTITY = ""; 269 | DEFINES_MODULE = YES; 270 | DYLIB_COMPATIBILITY_VERSION = 1; 271 | DYLIB_CURRENT_VERSION = 2023.10.12.16.44; 272 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 273 | ENABLE_MODULE_VERIFIER = YES; 274 | INFOPLIST_FILE = QuickActions/Info.plist; 275 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 276 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 277 | LD_RUNPATH_SEARCH_PATHS = ( 278 | "$(inherited)", 279 | "@executable_path/Frameworks", 280 | "@loader_path/Frameworks", 281 | ); 282 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; 283 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 284 | PRODUCT_BUNDLE_IDENTIFIER = eu.ricardopereira.QuickActions; 285 | PRODUCT_NAME = "$(TARGET_NAME)"; 286 | SKIP_INSTALL = YES; 287 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 288 | SWIFT_VERSION = 5.0; 289 | }; 290 | name = Debug; 291 | }; 292 | D7CCECBD1C82A35F001B07AB /* Release */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | CLANG_ENABLE_MODULES = YES; 296 | CODE_SIGN_IDENTITY = ""; 297 | DEFINES_MODULE = YES; 298 | DYLIB_COMPATIBILITY_VERSION = 1; 299 | DYLIB_CURRENT_VERSION = 2023.10.12.16.44; 300 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 301 | ENABLE_MODULE_VERIFIER = YES; 302 | INFOPLIST_FILE = QuickActions/Info.plist; 303 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 304 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 305 | LD_RUNPATH_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "@executable_path/Frameworks", 308 | "@loader_path/Frameworks", 309 | ); 310 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; 311 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; 312 | PRODUCT_BUNDLE_IDENTIFIER = eu.ricardopereira.QuickActions; 313 | PRODUCT_NAME = "$(TARGET_NAME)"; 314 | SKIP_INSTALL = YES; 315 | SWIFT_VERSION = 5.0; 316 | }; 317 | name = Release; 318 | }; 319 | /* End XCBuildConfiguration section */ 320 | 321 | /* Begin XCConfigurationList section */ 322 | D7CCECA11C82A35F001B07AB /* Build configuration list for PBXProject "QuickActions" */ = { 323 | isa = XCConfigurationList; 324 | buildConfigurations = ( 325 | D7CCECB91C82A35F001B07AB /* Debug */, 326 | D7CCECBA1C82A35F001B07AB /* Release */, 327 | ); 328 | defaultConfigurationIsVisible = 0; 329 | defaultConfigurationName = Release; 330 | }; 331 | D7CCECBB1C82A35F001B07AB /* Build configuration list for PBXNativeTarget "QuickActions" */ = { 332 | isa = XCConfigurationList; 333 | buildConfigurations = ( 334 | D7CCECBC1C82A35F001B07AB /* Debug */, 335 | D7CCECBD1C82A35F001B07AB /* Release */, 336 | ); 337 | defaultConfigurationIsVisible = 0; 338 | defaultConfigurationName = Release; 339 | }; 340 | /* End XCConfigurationList section */ 341 | }; 342 | rootObject = D7CCEC9E1C82A35F001B07AB /* Project object */; 343 | } 344 | -------------------------------------------------------------------------------- /QuickActions.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /QuickActions.xcodeproj/xcshareddata/xcschemes/QuickActions.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /QuickActions/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 7.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 2023.10.12.16.44 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /QuickActions/QuickActions.h: -------------------------------------------------------------------------------- 1 | // 2 | // QuickActions.h 3 | // QuickActions 4 | // 5 | // Created by Ricardo Pereira on 20/02/16. 6 | // Copyright (c) 2015 Ricardo Pereira. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for QuickActions. 12 | FOUNDATION_EXPORT double QuickActionsVersionNumber; 13 | 14 | //! Project version string for QuickActions. 15 | FOUNDATION_EXPORT const unsigned char QuickActionsVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/QuickActions.svg)](https://cocoapods.org/pods/QuickActions) 2 | [![Swift 5.0](https://img.shields.io/badge/Swift-5.0-orange.svg?style=flat)](https://developer.apple.com/swift/) 3 | [![Platforms iOS](https://img.shields.io/badge/Platforms-iOS-lightgray.svg?style=flat)](http://www.apple.com/ios/) 4 | [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) 5 | 6 | 7 | # QuickActions 8 | Swift wrapper for [iOS Home Screen Quick Actions](https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/index.html#//apple_ref/doc/uid/TP40016543-CH1-SW2) 9 | 10 | This wrapper helps you create dynamic Quick Actions. It is possible to define static quick actions in your app’s `Info.plist` file and also add localizable shortcuts dynamically and handle them with type safety. 11 | 12 | ## Usage 13 | 14 | ```swift 15 | import QuickActions 16 | ``` 17 | 18 | Define your application shortcuts with an enum. Don't forget to declare the enum with `String` and `ShortcutType`: 19 | 20 | ```swift 21 | enum AppShortcut: String, ShortcutType { 22 | case createExpense 23 | case lastItems 24 | } 25 | ``` 26 | 27 | Install a list of shortcuts: 28 | 29 | 30 | ```swift 31 | var quickActions: QuickActions? 32 | 33 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { 34 | let shortcuts = [Shortcut(type: AppShortcut.CreateExpense, title: NSLocalizedString("CreateExpenseTitle", comment: ""), subtitle: NSLocalizedString("CreateExpenseSubTitle", comment: ""), icon: .Add)] 35 | 36 | if let actionHandler = window?.rootViewController as? QuickActionSupport, bundleIdentifier = Bundle.main.bundleIdentifier { 37 | quickActions = QuickActions(application, actionHandler: actionHandler, bundleIdentifier: bundleIdentifier, shortcuts: shortcuts, launchOptions: launchOptions) 38 | } 39 | } 40 | ``` 41 | 42 | Add more shortcuts: 43 | 44 | ```swift 45 | func applicationDidEnterBackground(application: UIApplication) { 46 | let shortcuts = [Shortcut(type: AppShortcut.lastItems, title: "Last items", subtitle: nil, icon: nil)] 47 | quickActions?.add(shortcuts, toApplication: application) 48 | } 49 | ``` 50 | 51 | Handle each shortcut: 52 | 53 | ```swift 54 | @available(iOS 9, *) 55 | func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Swift.Void) { 56 | // This callback is used if your application is already launched in the background, if not application(_:,willFinishLaunchingWithOptions:) or application(_:didFinishLaunchingWithOptions) will be called (handle the shortcut in those callbacks and return `false`) 57 | guard let quickActions = quickActions else { 58 | return completionHandler(false) 59 | } 60 | guard let actionHandler = window?.rootViewController as? QuickActionSupport else { 61 | return completionHandler(false) 62 | } 63 | completionHandler(quickActions.handle(actionHandler, shortcutItem: shortcutItem)) 64 | } 65 | ``` 66 | 67 | Prepare your view controller using the `QuickActionSupport` protocol: 68 | 69 | ```swift 70 | class MainViewController: UIViewController, QuickActionSupport { 71 | 72 | func prepareForQuickAction(_ shortcutType: T) { 73 | if let shortcut = AppShortcut(rawValue: shortcutType.value), case .createExpense = shortcut { 74 | print("Prepare the view to create a new expense") 75 | } 76 | 77 | //or 78 | 79 | if let shortcut = AppShortcut(rawValue: shortcutType.value) { 80 | switch shortcut { 81 | case .createExpense: 82 | print("Prepare the view to create a new expense") 83 | case .lastItems: 84 | print("Prepare the view to show last items") 85 | } 86 | } 87 | } 88 | 89 | } 90 | ``` 91 | 92 | ## Installation 93 | 94 | #### [CocoaPods] 95 | 96 | [CocoaPods]: http://cocoapods.org 97 | 98 | To install it, simply add the following line to your **Podfile**: 99 | 100 | ```ruby 101 | pod 'QuickActions' '~> 6.0.0' 102 | ``` 103 | 104 | You will also need to make sure you're opting into using frameworks: 105 | 106 | ```ruby 107 | use_frameworks! 108 | ``` 109 | 110 | Then run `pod install` with CocoaPods 1.8.0 or newer. 111 | 112 | #### Manually 113 | 1. Download and drop ```QuickActions.swift``` in your project. 114 | 2. Congratulations! 115 | 116 | ## Requirements 117 | 118 | * iOS 12+ 119 | * Xcode 13+ (Swift 5) 120 | 121 | ## Author 122 | 123 | Ricardo Pereira, [@ricardopereiraw](https://mastodon.social/@ricardopereira) 124 | 125 | ## License 126 | 127 | QuickActions is available under the MIT license. See the [LICENSE] file for more info. 128 | 129 | [LICENSE]: /LICENSE 130 | 131 | -------------------------------------------------------------------------------- /Source/QuickActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuickActions.swift 3 | // QuickActions 4 | // 5 | // Created by Ricardo Pereira on 20/02/16. 6 | // Copyright © 2016 Ricardo Pereira. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum ShortcutIcon: Int { 12 | case compose 13 | case play 14 | case pause 15 | case add 16 | case location 17 | case search 18 | case share 19 | case prohibit 20 | case contact 21 | case home 22 | case markLocation 23 | case favorite 24 | case love 25 | case cloud 26 | case invitation 27 | case confirmation 28 | case mail 29 | case message 30 | case date 31 | case time 32 | case capturePhoto 33 | case captureVideo 34 | case task 35 | case taskCompleted 36 | case alarm 37 | case bookmark 38 | case shuffle 39 | case audio 40 | case update 41 | case custom 42 | 43 | @available(iOS 9.0, *) 44 | func toApplicationShortcutIcon() -> UIApplicationShortcutIcon? { 45 | if self == .custom { 46 | NSException(name: NSExceptionName(rawValue: "Invalid option"), reason: "`Custom` type need to be used with `toApplicationShortcutIcon:imageName`", userInfo: nil).raise() 47 | return nil 48 | } 49 | let icon = UIApplicationShortcutIcon.IconType(rawValue: self.rawValue) ?? UIApplicationShortcutIcon.IconType.confirmation 50 | return UIApplicationShortcutIcon(type: icon) 51 | } 52 | 53 | @available(iOS 9.0, *) 54 | func toApplicationShortcutIcon(_ imageName: String) -> UIApplicationShortcutIcon? { 55 | if self == .custom { 56 | return UIApplicationShortcutIcon(templateImageName: imageName) 57 | } 58 | else { 59 | NSException(name: NSExceptionName(rawValue: "Invalid option"), reason: "Type need to be `Custom`", userInfo: nil).raise() 60 | return nil 61 | } 62 | } 63 | 64 | } 65 | 66 | public protocol ShortcutType: RawRepresentable {} 67 | 68 | public extension RawRepresentable where Self: ShortcutType { 69 | 70 | init?(type: String) { 71 | assert(type is RawValue) 72 | // FIXME: try another solution to restrain the RawRepresentable as String 73 | self.init(rawValue: type as! RawValue) 74 | } 75 | 76 | var value: String { 77 | return self.rawValue as? String ?? "" 78 | } 79 | 80 | } 81 | 82 | public struct Shortcut { 83 | 84 | public let type: String 85 | public let title: String 86 | public let subtitle: String? 87 | public let icon: ShortcutIcon? 88 | 89 | public init(type: T, title: String, subtitle: String?, icon: ShortcutIcon?) { 90 | self.type = type.value 91 | self.title = title 92 | self.subtitle = subtitle 93 | self.icon = icon 94 | } 95 | 96 | } 97 | 98 | public extension Shortcut { 99 | 100 | @available(iOS 9.0, *) 101 | init(shortcutItem: UIApplicationShortcutItem) { 102 | if let range = shortcutItem.type.rangeOfCharacter(from: CharacterSet(charactersIn: "."), options: .backwards) { 103 | type = String(shortcutItem.type[range.upperBound...]) 104 | } 105 | else { 106 | type = "unknown" 107 | } 108 | title = shortcutItem.localizedTitle 109 | subtitle = shortcutItem.localizedSubtitle 110 | // FIXME: shortcutItem.icon!.type isn't accessible 111 | icon = nil 112 | } 113 | 114 | @available(iOS 9.0, *) 115 | fileprivate func toApplicationShortcut(_ bundleIdentifier: String) -> UIApplicationShortcutItem { 116 | return UIMutableApplicationShortcutItem(type: bundleIdentifier + "." + type, localizedTitle: title, localizedSubtitle: subtitle, icon: icon?.toApplicationShortcutIcon(), userInfo: nil) 117 | } 118 | 119 | } 120 | 121 | @available(iOS 9.0, *) 122 | public extension UIApplicationShortcutItem { 123 | 124 | var toShortcut: Shortcut { 125 | return Shortcut(shortcutItem: self) 126 | } 127 | 128 | } 129 | 130 | public protocol QuickActionSupport { 131 | 132 | @available(iOS 9.0, *) 133 | func prepareForQuickAction(_ shortcutType: T) 134 | 135 | } 136 | 137 | open class QuickActions { 138 | 139 | fileprivate let bundleIdentifier: String 140 | 141 | public init(_ application: UIApplication, actionHandler: QuickActionSupport?, bundleIdentifier: String, shortcuts: [Shortcut], launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) { 142 | self.bundleIdentifier = bundleIdentifier 143 | 144 | if #available(iOS 9.0, *) { 145 | install(shortcuts, toApplication: application) 146 | } 147 | 148 | if #available(iOS 9.0, *), let shortcutItem = launchOptions?[.shortcutItem] as? UIApplicationShortcutItem { 149 | handle(actionHandler, shortcutItem: shortcutItem) 150 | } 151 | } 152 | 153 | /// Install initial Quick Actions (app shortcuts) 154 | @available(iOS 9.0, *) 155 | fileprivate func install(_ shortcuts: [Shortcut], toApplication application: UIApplication) { 156 | application.shortcutItems = shortcuts.map { $0.toApplicationShortcut(bundleIdentifier) } 157 | } 158 | 159 | @available(iOS 9.0, *) 160 | @discardableResult 161 | open func handle(_ actionHandler: QuickActionSupport?, shortcutItem: UIApplicationShortcutItem) -> Bool { 162 | return handle(actionHandler, shortcut: shortcutItem.toShortcut) 163 | } 164 | 165 | @discardableResult 166 | open func handle(_ actionHandler: QuickActionSupport?, shortcut: Shortcut) -> Bool { 167 | guard let viewController = actionHandler else { return false } 168 | if #available(iOS 9.0, *) { 169 | let shortcutType = T.init(type: shortcut.type)! 170 | viewController.prepareForQuickAction(shortcutType) 171 | return true 172 | } 173 | else { 174 | return false 175 | } 176 | } 177 | 178 | @discardableResult 179 | open func handle(_ actionHandler: QuickActionSupport?, shortcutType: T) -> Bool { 180 | guard let viewController = actionHandler else { return false } 181 | if #available(iOS 9.0, *) { 182 | viewController.prepareForQuickAction(shortcutType) 183 | return true 184 | } 185 | else { 186 | return false 187 | } 188 | } 189 | 190 | open func add(_ shortcuts: [Shortcut], toApplication application: UIApplication) { 191 | if #available(iOS 9.0, *) { 192 | var items = shortcuts.map { $0.toApplicationShortcut(bundleIdentifier) } 193 | items.append(contentsOf: application.shortcutItems ?? []) 194 | application.shortcutItems = items 195 | } 196 | } 197 | 198 | open func add(_ shortcut: Shortcut, toApplication application: UIApplication) { 199 | add([shortcut], toApplication: application) 200 | } 201 | 202 | open func remove(_ shortcut: Shortcut, toApplication application: UIApplication) { 203 | if #available(iOS 9.0, *) { 204 | if let index = application.shortcutItems?.firstIndex(of: shortcut.toApplicationShortcut(bundleIdentifier)) , index > -1 { 205 | application.shortcutItems?.remove(at: index) 206 | } 207 | } 208 | } 209 | 210 | open func clear(_ application: UIApplication) { 211 | if #available(iOS 9.0, *) { 212 | application.shortcutItems = nil 213 | } 214 | } 215 | 216 | } 217 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | fastlane_version "1.100.0" 2 | REQUIRED_XCODE_VERSION = "8.0" 3 | default_platform :ios 4 | 5 | platform :ios do 6 | desc "Runs all the tests" 7 | lane :test do 8 | scan project: "QuickActions.xcodeproj" 9 | end 10 | 11 | desc "Increment the verion and build number" 12 | lane :version_bump_project do |options| 13 | build_number = Time.new.strftime("%Y.%m.%d.%H.%M") 14 | increment_build_number build_number: build_number 15 | increment_version_number bump_type: options[:bump_type] 16 | end 17 | 18 | desc "Prepare a new Release version" 19 | lane :release do |options| 20 | version_bump_project bump_type: options[:bump] 21 | version_bump_podspec bump_type: options[:bump] 22 | clean_build_artifacts 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ---- 3 | 4 | # Installation 5 | 6 | Make sure you have the latest version of the Xcode command line tools installed: 7 | 8 | ```sh 9 | xcode-select --install 10 | ``` 11 | 12 | For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) 13 | 14 | # Available Actions 15 | 16 | ## iOS 17 | 18 | ### ios test 19 | 20 | ```sh 21 | [bundle exec] fastlane ios test 22 | ``` 23 | 24 | Runs all the tests 25 | 26 | ### ios version_bump_project 27 | 28 | ```sh 29 | [bundle exec] fastlane ios version_bump_project 30 | ``` 31 | 32 | Increment the verion and build number 33 | 34 | ### ios release 35 | 36 | ```sh 37 | [bundle exec] fastlane ios release 38 | ``` 39 | 40 | Prepare a new Release version 41 | 42 | ---- 43 | 44 | This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. 45 | 46 | More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). 47 | 48 | The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 49 | --------------------------------------------------------------------------------