├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .nojekyll ├── .swift-version ├── .travis.yml ├── Demo ├── Demo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── Demo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── PluginsTableViewController.swift │ └── ViewController.swift ├── LICENSE ├── Package.swift ├── PluginScripts ├── bing.js ├── getter_setter.js ├── google.js ├── kkbox.js └── youtube.js ├── README.md ├── Sources └── ZBSimplePluginManager │ └── ZBSimplePluginManager.swift ├── Tests ├── LinuxMain.swift └── ZBSimplePluginManagerTests │ └── ZBSimplePluginManagerTests.swift ├── ZBSimplePluginManager.podspec ├── ZBSimplePluginManager.xcodeproj ├── ZBSimplePluginManagerTests_Info.plist ├── ZBSimplePluginManager_Info.plist ├── ZBSimplePuginManagerTests_Info.plist ├── ZBSimplePuginManager_Info.plist ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── ZBSimplePluginManager.xcscheme │ ├── ZBSimplePluginManagerTests.xcscheme │ └── xcschememanagement.plist ├── docs ├── .nojekyll ├── Classes.html ├── Classes │ ├── ZBPlugin.html │ └── ZBSimplePluginManager.html ├── badge.svg ├── css │ ├── highlight.css │ └── jazzy.css ├── docsets │ ├── ZBSimplePluginManager.docset │ │ └── Contents │ │ │ ├── Info.plist │ │ │ └── Resources │ │ │ ├── Documents │ │ │ ├── Classes.html │ │ │ ├── Classes │ │ │ │ ├── ZBPlugin.html │ │ │ │ └── ZBSimplePluginManager.html │ │ │ ├── badge.svg │ │ │ ├── css │ │ │ │ ├── highlight.css │ │ │ │ └── jazzy.css │ │ │ ├── img │ │ │ │ ├── carat.png │ │ │ │ ├── dash.png │ │ │ │ └── gh.png │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── jazzy.js │ │ │ │ └── jquery.min.js │ │ │ ├── search.json │ │ │ └── undocumented.json │ │ │ └── docSet.dsidx │ └── ZBSimplePluginManager.tgz ├── img │ ├── carat.png │ ├── dash.png │ └── gh.png ├── index.html ├── js │ ├── jazzy.js │ └── jquery.min.js ├── search.json └── undocumented.json └── jazzy.sh /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [push] 3 | 4 | jobs: 5 | build: 6 | name: Build 7 | runs-on: macOS-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | - name: Build 11 | run: swift build -Xswiftc "-sdk" -Xswiftc "`xcrun --sdk iphonesimulator --show-sdk-path`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios12.1-simulator" 12 | - name: Test 13 | run: xcodebuild -project ZBSimplePluginManager.xcodeproj -scheme ZBSimplePluginManagerTests test -destination 'platform=iOS Simulator,name=iPhone X,OS=12.4' 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | .idea 70 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/.nojekyll -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | sudo: required 3 | dist: trusty 4 | osx_image: xcode9.2 5 | script: 6 | - swift build 7 | - xcodebuild -scheme ZBSimplePluginManagerTests test 8 | notifications: 9 | email: 10 | on_success: never 11 | on_failure: change 12 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D414849E2010D7880017C9B0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D414849D2010D7880017C9B0 /* AppDelegate.swift */; }; 11 | D41484A02010D7880017C9B0 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D414849F2010D7880017C9B0 /* ViewController.swift */; }; 12 | D41484A32010D7880017C9B0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D41484A12010D7880017C9B0 /* Main.storyboard */; }; 13 | D41484A52010D7880017C9B0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D41484A42010D7880017C9B0 /* Assets.xcassets */; }; 14 | D41484A82010D7880017C9B0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D41484A62010D7880017C9B0 /* LaunchScreen.storyboard */; }; 15 | D41484FA2010EAE40017C9B0 /* ZBSimplePluginManager.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D41484F92010EAD80017C9B0 /* ZBSimplePluginManager.framework */; }; 16 | D41484FB2010EAE40017C9B0 /* ZBSimplePluginManager.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D41484F92010EAD80017C9B0 /* ZBSimplePluginManager.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | D41485102010F0700017C9B0 /* PluginScripts in Resources */ = {isa = PBXBuildFile; fileRef = D414850F2010F0700017C9B0 /* PluginScripts */; }; 18 | D41485122010F4860017C9B0 /* PluginsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41485112010F4860017C9B0 /* PluginsTableViewController.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | D41484F62010EAD80017C9B0 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = D41484EF2010EAD80017C9B0 /* ZBSimplePluginManager.xcodeproj */; 25 | proxyType = 2; 26 | remoteGlobalIDString = "ZBSimplePluginManager::ZBSimplePluginManagerTests::Product"; 27 | remoteInfo = ZBSimplePluginManagerTests; 28 | }; 29 | D41484F82010EAD80017C9B0 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = D41484EF2010EAD80017C9B0 /* ZBSimplePluginManager.xcodeproj */; 32 | proxyType = 2; 33 | remoteGlobalIDString = "ZBSimplePluginManager::ZBSimplePluginManager::Product"; 34 | remoteInfo = ZBSimplePluginManager; 35 | }; 36 | D41484FC2010EAE40017C9B0 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = D41484EF2010EAD80017C9B0 /* ZBSimplePluginManager.xcodeproj */; 39 | proxyType = 1; 40 | remoteGlobalIDString = "ZBSimplePluginManager::ZBSimplePluginManager"; 41 | remoteInfo = ZBSimplePluginManager; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXCopyFilesBuildPhase section */ 46 | D41484EB2010E9600017C9B0 /* Embed Frameworks */ = { 47 | isa = PBXCopyFilesBuildPhase; 48 | buildActionMask = 2147483647; 49 | dstPath = ""; 50 | dstSubfolderSpec = 10; 51 | files = ( 52 | D41484FB2010EAE40017C9B0 /* ZBSimplePluginManager.framework in Embed Frameworks */, 53 | ); 54 | name = "Embed Frameworks"; 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXCopyFilesBuildPhase section */ 58 | 59 | /* Begin PBXFileReference section */ 60 | D414849A2010D7880017C9B0 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | D414849D2010D7880017C9B0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 62 | D414849F2010D7880017C9B0 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 63 | D41484A22010D7880017C9B0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 64 | D41484A42010D7880017C9B0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 65 | D41484A72010D7880017C9B0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 66 | D41484A92010D7880017C9B0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | D41484EF2010EAD80017C9B0 /* ZBSimplePluginManager.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ZBSimplePluginManager.xcodeproj; path = ../ZBSimplePluginManager.xcodeproj; sourceTree = ""; }; 68 | D414850F2010F0700017C9B0 /* PluginScripts */ = {isa = PBXFileReference; lastKnownFileType = folder; name = PluginScripts; path = ../../PluginScripts; sourceTree = ""; }; 69 | D41485112010F4860017C9B0 /* PluginsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginsTableViewController.swift; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | D41484972010D7880017C9B0 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | D41484FA2010EAE40017C9B0 /* ZBSimplePluginManager.framework in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | D41484912010D7880017C9B0 = { 85 | isa = PBXGroup; 86 | children = ( 87 | D41484EF2010EAD80017C9B0 /* ZBSimplePluginManager.xcodeproj */, 88 | D414849C2010D7880017C9B0 /* Demo */, 89 | D414849B2010D7880017C9B0 /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | D414849B2010D7880017C9B0 /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | D414849A2010D7880017C9B0 /* Demo.app */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | D414849C2010D7880017C9B0 /* Demo */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | D414850F2010F0700017C9B0 /* PluginScripts */, 105 | D414849D2010D7880017C9B0 /* AppDelegate.swift */, 106 | D41485112010F4860017C9B0 /* PluginsTableViewController.swift */, 107 | D414849F2010D7880017C9B0 /* ViewController.swift */, 108 | D41484A12010D7880017C9B0 /* Main.storyboard */, 109 | D41484A42010D7880017C9B0 /* Assets.xcassets */, 110 | D41484A62010D7880017C9B0 /* LaunchScreen.storyboard */, 111 | D41484A92010D7880017C9B0 /* Info.plist */, 112 | ); 113 | path = Demo; 114 | sourceTree = ""; 115 | }; 116 | D41484F02010EAD80017C9B0 /* Products */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | D41484F72010EAD80017C9B0 /* ZBSimplePluginManagerTests.xctest */, 120 | D41484F92010EAD80017C9B0 /* ZBSimplePluginManager.framework */, 121 | ); 122 | name = Products; 123 | sourceTree = ""; 124 | }; 125 | /* End PBXGroup section */ 126 | 127 | /* Begin PBXNativeTarget section */ 128 | D41484992010D7880017C9B0 /* Demo */ = { 129 | isa = PBXNativeTarget; 130 | buildConfigurationList = D41484AC2010D7880017C9B0 /* Build configuration list for PBXNativeTarget "Demo" */; 131 | buildPhases = ( 132 | D41484962010D7880017C9B0 /* Sources */, 133 | D41484972010D7880017C9B0 /* Frameworks */, 134 | D41484982010D7880017C9B0 /* Resources */, 135 | D41484EB2010E9600017C9B0 /* Embed Frameworks */, 136 | ); 137 | buildRules = ( 138 | ); 139 | dependencies = ( 140 | D41484FD2010EAE40017C9B0 /* PBXTargetDependency */, 141 | ); 142 | name = Demo; 143 | productName = Demo; 144 | productReference = D414849A2010D7880017C9B0 /* Demo.app */; 145 | productType = "com.apple.product-type.application"; 146 | }; 147 | /* End PBXNativeTarget section */ 148 | 149 | /* Begin PBXProject section */ 150 | D41484922010D7880017C9B0 /* Project object */ = { 151 | isa = PBXProject; 152 | attributes = { 153 | LastSwiftUpdateCheck = 0920; 154 | LastUpgradeCheck = 0920; 155 | ORGANIZATIONNAME = "Weizhong Yang"; 156 | TargetAttributes = { 157 | D41484992010D7880017C9B0 = { 158 | CreatedOnToolsVersion = 9.2; 159 | ProvisioningStyle = Automatic; 160 | }; 161 | }; 162 | }; 163 | buildConfigurationList = D41484952010D7880017C9B0 /* Build configuration list for PBXProject "Demo" */; 164 | compatibilityVersion = "Xcode 8.0"; 165 | developmentRegion = en; 166 | hasScannedForEncodings = 0; 167 | knownRegions = ( 168 | en, 169 | Base, 170 | ); 171 | mainGroup = D41484912010D7880017C9B0; 172 | productRefGroup = D414849B2010D7880017C9B0 /* Products */; 173 | projectDirPath = ""; 174 | projectReferences = ( 175 | { 176 | ProductGroup = D41484F02010EAD80017C9B0 /* Products */; 177 | ProjectRef = D41484EF2010EAD80017C9B0 /* ZBSimplePluginManager.xcodeproj */; 178 | }, 179 | ); 180 | projectRoot = ""; 181 | targets = ( 182 | D41484992010D7880017C9B0 /* Demo */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXReferenceProxy section */ 188 | D41484F72010EAD80017C9B0 /* ZBSimplePluginManagerTests.xctest */ = { 189 | isa = PBXReferenceProxy; 190 | fileType = file; 191 | path = ZBSimplePluginManagerTests.xctest; 192 | remoteRef = D41484F62010EAD80017C9B0 /* PBXContainerItemProxy */; 193 | sourceTree = BUILT_PRODUCTS_DIR; 194 | }; 195 | D41484F92010EAD80017C9B0 /* ZBSimplePluginManager.framework */ = { 196 | isa = PBXReferenceProxy; 197 | fileType = wrapper.framework; 198 | path = ZBSimplePluginManager.framework; 199 | remoteRef = D41484F82010EAD80017C9B0 /* PBXContainerItemProxy */; 200 | sourceTree = BUILT_PRODUCTS_DIR; 201 | }; 202 | /* End PBXReferenceProxy section */ 203 | 204 | /* Begin PBXResourcesBuildPhase section */ 205 | D41484982010D7880017C9B0 /* Resources */ = { 206 | isa = PBXResourcesBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | D41485102010F0700017C9B0 /* PluginScripts in Resources */, 210 | D41484A82010D7880017C9B0 /* LaunchScreen.storyboard in Resources */, 211 | D41484A52010D7880017C9B0 /* Assets.xcassets in Resources */, 212 | D41484A32010D7880017C9B0 /* Main.storyboard in Resources */, 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | /* End PBXResourcesBuildPhase section */ 217 | 218 | /* Begin PBXSourcesBuildPhase section */ 219 | D41484962010D7880017C9B0 /* Sources */ = { 220 | isa = PBXSourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | D41485122010F4860017C9B0 /* PluginsTableViewController.swift in Sources */, 224 | D41484A02010D7880017C9B0 /* ViewController.swift in Sources */, 225 | D414849E2010D7880017C9B0 /* AppDelegate.swift in Sources */, 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXSourcesBuildPhase section */ 230 | 231 | /* Begin PBXTargetDependency section */ 232 | D41484FD2010EAE40017C9B0 /* PBXTargetDependency */ = { 233 | isa = PBXTargetDependency; 234 | name = ZBSimplePluginManager; 235 | targetProxy = D41484FC2010EAE40017C9B0 /* PBXContainerItemProxy */; 236 | }; 237 | /* End PBXTargetDependency section */ 238 | 239 | /* Begin PBXVariantGroup section */ 240 | D41484A12010D7880017C9B0 /* Main.storyboard */ = { 241 | isa = PBXVariantGroup; 242 | children = ( 243 | D41484A22010D7880017C9B0 /* Base */, 244 | ); 245 | name = Main.storyboard; 246 | sourceTree = ""; 247 | }; 248 | D41484A62010D7880017C9B0 /* LaunchScreen.storyboard */ = { 249 | isa = PBXVariantGroup; 250 | children = ( 251 | D41484A72010D7880017C9B0 /* Base */, 252 | ); 253 | name = LaunchScreen.storyboard; 254 | sourceTree = ""; 255 | }; 256 | /* End PBXVariantGroup section */ 257 | 258 | /* Begin XCBuildConfiguration section */ 259 | D41484AA2010D7880017C9B0 /* Debug */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ALWAYS_SEARCH_USER_PATHS = NO; 263 | CLANG_ANALYZER_NONNULL = YES; 264 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 266 | CLANG_CXX_LIBRARY = "libc++"; 267 | CLANG_ENABLE_MODULES = YES; 268 | CLANG_ENABLE_OBJC_ARC = YES; 269 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 270 | CLANG_WARN_BOOL_CONVERSION = YES; 271 | CLANG_WARN_COMMA = YES; 272 | CLANG_WARN_CONSTANT_CONVERSION = YES; 273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 274 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INFINITE_RECURSION = YES; 278 | CLANG_WARN_INT_CONVERSION = YES; 279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 282 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 283 | CLANG_WARN_STRICT_PROTOTYPES = YES; 284 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 285 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 286 | CLANG_WARN_UNREACHABLE_CODE = YES; 287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 288 | CODE_SIGN_IDENTITY = "iPhone Developer"; 289 | COPY_PHASE_STRIP = NO; 290 | DEBUG_INFORMATION_FORMAT = dwarf; 291 | ENABLE_STRICT_OBJC_MSGSEND = YES; 292 | ENABLE_TESTABILITY = YES; 293 | GCC_C_LANGUAGE_STANDARD = gnu11; 294 | GCC_DYNAMIC_NO_PIC = NO; 295 | GCC_NO_COMMON_BLOCKS = YES; 296 | GCC_OPTIMIZATION_LEVEL = 0; 297 | GCC_PREPROCESSOR_DEFINITIONS = ( 298 | "DEBUG=1", 299 | "$(inherited)", 300 | ); 301 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 302 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 303 | GCC_WARN_UNDECLARED_SELECTOR = YES; 304 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 305 | GCC_WARN_UNUSED_FUNCTION = YES; 306 | GCC_WARN_UNUSED_VARIABLE = YES; 307 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 308 | MTL_ENABLE_DEBUG_INFO = YES; 309 | ONLY_ACTIVE_ARCH = YES; 310 | SDKROOT = iphoneos; 311 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 312 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 313 | }; 314 | name = Debug; 315 | }; 316 | D41484AB2010D7880017C9B0 /* Release */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ALWAYS_SEARCH_USER_PATHS = NO; 320 | CLANG_ANALYZER_NONNULL = YES; 321 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 322 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 323 | CLANG_CXX_LIBRARY = "libc++"; 324 | CLANG_ENABLE_MODULES = YES; 325 | CLANG_ENABLE_OBJC_ARC = YES; 326 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 327 | CLANG_WARN_BOOL_CONVERSION = YES; 328 | CLANG_WARN_COMMA = YES; 329 | CLANG_WARN_CONSTANT_CONVERSION = YES; 330 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 331 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 332 | CLANG_WARN_EMPTY_BODY = YES; 333 | CLANG_WARN_ENUM_CONVERSION = YES; 334 | CLANG_WARN_INFINITE_RECURSION = YES; 335 | CLANG_WARN_INT_CONVERSION = YES; 336 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 337 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 338 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 339 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 340 | CLANG_WARN_STRICT_PROTOTYPES = YES; 341 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 342 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 345 | CODE_SIGN_IDENTITY = "iPhone Developer"; 346 | COPY_PHASE_STRIP = NO; 347 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 348 | ENABLE_NS_ASSERTIONS = NO; 349 | ENABLE_STRICT_OBJC_MSGSEND = YES; 350 | GCC_C_LANGUAGE_STANDARD = gnu11; 351 | GCC_NO_COMMON_BLOCKS = YES; 352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 354 | GCC_WARN_UNDECLARED_SELECTOR = YES; 355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 356 | GCC_WARN_UNUSED_FUNCTION = YES; 357 | GCC_WARN_UNUSED_VARIABLE = YES; 358 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 359 | MTL_ENABLE_DEBUG_INFO = NO; 360 | SDKROOT = iphoneos; 361 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 362 | VALIDATE_PRODUCT = YES; 363 | }; 364 | name = Release; 365 | }; 366 | D41484AD2010D7880017C9B0 /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 370 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 371 | CODE_SIGN_STYLE = Automatic; 372 | DEVELOPMENT_TEAM = X29ZB2LBKB; 373 | INFOPLIST_FILE = Demo/Info.plist; 374 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 375 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 376 | PRODUCT_BUNDLE_IDENTIFIER = net.zonble.Demo; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | SWIFT_VERSION = 4.0; 379 | TARGETED_DEVICE_FAMILY = "1,2"; 380 | }; 381 | name = Debug; 382 | }; 383 | D41484AE2010D7880017C9B0 /* Release */ = { 384 | isa = XCBuildConfiguration; 385 | buildSettings = { 386 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 387 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 388 | CODE_SIGN_STYLE = Automatic; 389 | DEVELOPMENT_TEAM = X29ZB2LBKB; 390 | INFOPLIST_FILE = Demo/Info.plist; 391 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 392 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 393 | PRODUCT_BUNDLE_IDENTIFIER = net.zonble.Demo; 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | SWIFT_VERSION = 4.0; 396 | TARGETED_DEVICE_FAMILY = "1,2"; 397 | }; 398 | name = Release; 399 | }; 400 | /* End XCBuildConfiguration section */ 401 | 402 | /* Begin XCConfigurationList section */ 403 | D41484952010D7880017C9B0 /* Build configuration list for PBXProject "Demo" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | D41484AA2010D7880017C9B0 /* Debug */, 407 | D41484AB2010D7880017C9B0 /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | D41484AC2010D7880017C9B0 /* Build configuration list for PBXNativeTarget "Demo" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | D41484AD2010D7880017C9B0 /* Debug */, 416 | D41484AE2010D7880017C9B0 /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | defaultConfigurationName = Release; 420 | }; 421 | /* End XCConfigurationList section */ 422 | }; 423 | rootObject = D41484922010D7880017C9B0 /* Project object */; 424 | } 425 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ZBSimplePluginManager 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | var window: UIWindow? 7 | var pluginManager: ZBSimplePluginManager? 8 | 9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 10 | let resourceURL = URL(fileURLWithPath: Bundle.main.resourcePath!) 11 | let pluginFolder = resourceURL.appendingPathComponent("PluginScripts") 12 | pluginManager = ZBSimplePluginManager(pluginFolderURL: pluginFolder, defaultsNamespace: "plugins") 13 | pluginManager?.loadAllPlugins() 14 | return true 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Demo/Demo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Demo/Demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 44 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Demo/Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 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 | -------------------------------------------------------------------------------- /Demo/Demo/PluginsTableViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ZBSimplePluginManager 3 | 4 | class PluginsTableViewController: UITableViewController { 5 | 6 | override func viewDidLoad() { 7 | super.viewDidLoad() 8 | self.title = "Plug-ins" 9 | self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseIdentifier") 10 | } 11 | 12 | override func didReceiveMemoryWarning() { 13 | super.didReceiveMemoryWarning() 14 | } 15 | 16 | // MARK: - Table view data source 17 | 18 | var pluginManager: ZBSimplePluginManager? { 19 | guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { 20 | return nil 21 | } 22 | return appDelegate.pluginManager 23 | } 24 | 25 | override func numberOfSections(in tableView: UITableView) -> Int { 26 | return 1 27 | } 28 | 29 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 30 | return pluginManager?.plugins.count ?? 0 31 | } 32 | 33 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 34 | let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) 35 | guard let plugin = pluginManager?.plugins[indexPath.row] else { 36 | return cell 37 | } 38 | cell.textLabel?.text = plugin.title 39 | cell.accessoryType = plugin.enabled ? .checkmark : .none 40 | return cell 41 | } 42 | 43 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 44 | guard let plugin = pluginManager?.plugins[indexPath.row] else { 45 | return 46 | } 47 | pluginManager?.toggle(plugin: plugin, enabled: !plugin.enabled) 48 | self.tableView.reloadData() 49 | tableView.deselectRow(at: indexPath, animated: true) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Demo/Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import ZBSimplePluginManager 3 | 4 | class ViewController: UIViewController { 5 | 6 | override func viewDidLoad() { 7 | super.viewDidLoad() 8 | self.title = "Demo" 9 | } 10 | 11 | override func didReceiveMemoryWarning() { 12 | super.didReceiveMemoryWarning() 13 | } 14 | 15 | @IBAction func promptMenu() { 16 | guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { 17 | return 18 | } 19 | guard let manager = appDelegate.pluginManager else { 20 | return 21 | } 22 | 23 | if manager.enabledPlugins.count == 0 { 24 | return 25 | } 26 | 27 | let contoller = UIAlertController(title: "You choice", message: "Select one from the items below.", preferredStyle: UIAlertControllerStyle.actionSheet) 28 | 29 | for plugin in manager.enabledPlugins { 30 | let action = UIAlertAction(title: plugin.title, style: .default) { action in 31 | _ = plugin.call(args: ["Nirvana"]) 32 | } 33 | contoller.addAction(action) 34 | } 35 | contoller.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in 36 | }) 37 | self.present(contoller, animated: true, completion: nil) 38 | } 39 | 40 | @IBAction func managePlugins() { 41 | self.navigationController?.pushViewController(PluginsTableViewController(), animated: true) 42 | } 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Weizhong Yang 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 10 | furnished 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "ZBSimplePluginManager", 6 | products: [ 7 | .library( 8 | name: "ZBSimplePluginManager", 9 | targets: ["ZBSimplePluginManager"]), 10 | ], 11 | dependencies: [ 12 | ], 13 | targets: [ 14 | .target( 15 | name: "ZBSimplePluginManager", 16 | dependencies: []), 17 | .testTarget( 18 | name: "ZBSimplePluginManagerTests", 19 | dependencies: ["ZBSimplePluginManager"]), 20 | ] 21 | ) 22 | -------------------------------------------------------------------------------- /PluginScripts/bing.js: -------------------------------------------------------------------------------- 1 | var youtubePlugin = { 2 | id: 'plugin.bing.search', 3 | title: 'Search in Bing...', 4 | action: function (keyword) { 5 | var url = 'https://bing.com/search?q=' + encodeURIComponent(keyword) 6 | openURL(url) 7 | } 8 | } 9 | 10 | registerPlugin(youtubePlugin) 11 | -------------------------------------------------------------------------------- /PluginScripts/getter_setter.js: -------------------------------------------------------------------------------- 1 | var kkboxPlugin = { 2 | id: 'plugin.getter_setter', 3 | title: 'Getter/Setter', 4 | action: function (keyword) { 5 | var key = 'artist' 6 | set(key, keyword) 7 | var result = get(key) 8 | log(result) 9 | } 10 | } 11 | 12 | registerPlugin(kkboxPlugin) 13 | -------------------------------------------------------------------------------- /PluginScripts/google.js: -------------------------------------------------------------------------------- 1 | var kkboxPlugin = { 2 | id: 'plugin.google.search', 3 | title: 'Search in Google...', 4 | action: function (keyword) { 5 | var url = 'https://google.com/search?q=' + encodeURIComponent(keyword) 6 | openURL(url) 7 | } 8 | } 9 | 10 | registerPlugin(kkboxPlugin) 11 | -------------------------------------------------------------------------------- /PluginScripts/kkbox.js: -------------------------------------------------------------------------------- 1 | var kkboxPlugin = { 2 | id: 'plugin.kkbox.search', 3 | title: 'Search in KKBOX...', 4 | action: function (keyword) { 5 | var url = 'https://www.kkbox.com/tw/tc/search.php?word=' + encodeURIComponent(keyword) 6 | openURL(url) 7 | } 8 | } 9 | 10 | registerPlugin(kkboxPlugin) 11 | -------------------------------------------------------------------------------- /PluginScripts/youtube.js: -------------------------------------------------------------------------------- 1 | var youtubePlugin = { 2 | id: 'plugin.youtube.search', 3 | title: 'Search in Youtube...', 4 | action: function (keyword) { 5 | var url = 'https://www.youtube.com/results?search_query=' + encodeURIComponent(keyword) 6 | openURL(url) 7 | } 8 | } 9 | 10 | registerPlugin(youtubePlugin) 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZBSimplePluginManager 2 | 3 | A simple plug-in system by using JavaScriptCore. 4 | 5 | [![Support](https://img.shields.io/badge/macOS-10.10-blue.svg)](https://www.apple.com/tw/macos)  6 | [![Support](https://img.shields.io/badge/iOS-8-blue.svg)](https://www.apple.com/tw/ios)  7 | [![Support](https://img.shields.io/badge/tvOS-9-blue.svg)](https://www.apple.com/tw/tvos)  8 | 9 | Copyright (c) 2018 Weizhong Yang a.k.a zonble 10 | 11 | ## Introduction 12 | 13 | A plug-in system helps to make your app more flexible. 14 | 15 | Users may not need all of the functions in your app, and you may want to update the implementation of a function anytime. If you make these functions as plug-ins, users can enable or disable them when they need them or not, and you can let users to download new plug-ins if you hope so. 16 | 17 | Apple introduced JavaScriptCore framework, a JavaScript interpreter, in iOS 7. It is a great tool and we could leverage it to build a simple plug-in system in your app easily. It is also quite easy to write new plug-ins, since they are just simple JavaScript code. 18 | 19 | ## Requirement 20 | 21 | ZBSimplePluginManager runs on iOS, macOS and tvOS. 22 | 23 | * Swift 4 24 | * iOS 8 or above. 25 | * macOS 10.10 or above. 26 | * tvOS 9 or above. 27 | 28 | ## Installation 29 | 30 | The SDK supports CocoaPods. Please add pod 'ZBSimplePluginManager' to your Podfile, and then call pod install. 31 | 32 | ## Usage 33 | 34 | Please create an instance of *ZBSimplePluginManager* by giving the folder where your plug-in files are, and a namespace for storing plug-in settings. A namespace here is a key that is used in NSUserDefaults to manage how a plug-in is enabled or disabled. 35 | 36 | Then, ask the manager to load all of the plug-ins in th given folder. 37 | 38 | ``` swift 39 | let resourceURL = URL(fileURLWithPath: Bundle.main.resourcePath!) 40 | let pluginFolder = resourceURL.appendingPathComponent("PluginScripts") 41 | let pluginManager = ZBSimplePluginManager(pluginFolderURL: pluginFolder, defaultsNameSpace: "plugins") 42 | pluginManager?.loadAllPlugins() 43 | ``` 44 | 45 | Once the plug-ins are loaded, you can obtain a list of plug-ins from the manager. 46 | 47 | ``` swift 48 | let plugins = pluginManager.plugins 49 | ``` 50 | 51 | A plug-in that we defined in *ZBSimplePluginManager* has an identifier, a name and an action. You can call the action of a plug-in by passing specific parameters. 52 | 53 | ``` 54 | let plugins = pluginManager.plugins 55 | Let plugin = plugins[0] 56 | _ = plugin.call(args: ["Hello World!"]) 57 | ``` 58 | 59 | ## Plug-in Files 60 | 61 | A plug-in may looks like: 62 | 63 | ``` js 64 | var youtubePlugin = { 65 | id: 'plugin.google.search', 66 | title: 'Search in Google...', 67 | action: function (keyword) { 68 | var url = 'https://google.com/search?q=' + encodeURIComponent(keyword) 69 | openURL(url) 70 | } 71 | } 72 | 73 | registerPlugin(youtubePlugin) 74 | ``` 75 | 76 | What the plug-in does is: 77 | 78 | * Creating a JavaScript object with attributes including id, title, and action. 79 | * Call `registerPlugin` by passing the object to register it. 80 | 81 | If there is already a plug-in registered with the same ID, you cannot register the plug-in. 82 | 83 | ## JavaScript APIs 84 | 85 | *ZBSimplePluginManager* has only a few APIs that you can call from your JavaScript code right now, but it is also easy to extend the APIs. 86 | 87 | * `registerPlugin`: Register a new plug-in. 88 | * `log`: Print debug messages. 89 | * `openURL`: Open a given URL. 90 | 91 | *ZBSimplePluginManager* also provides a simple shared key/value storage in memory. You can use following functions to access it. 92 | 93 | * `set`: Set a value to the shared storage by giving a key. 94 | * `get`: Get a value by giving a key. 95 | 96 | You can add your own functions to be called by your JavaScript code by simply calling `addJavaScriptAPI(functionName:, block:)`. For example, if you want to replace the existing `log` function, you can do this in your code: 97 | 98 | ``` swift 99 | try? self.addJavaScriptAPI(functionName: "log") { log in 100 | if let log = log as? String { 101 | print("[My Log]" + log) 102 | } 103 | return nil 104 | } 105 | ``` 106 | 107 | The body of your custom function is a Swift closure that has a simple input value and returns a value. Type of both of input and output value is optional any (written in "Any?"). You can cast the value by your self to satisfy your needs. By the way, you cannot replace the 'registerPlugin' function, otherwise we cannot register plug-ins. 108 | 109 | Enjoy! 110 | 111 | ## License 112 | 113 | **LFLiveKit is released under the MIT license. See 114 | [LICENSE](https://github.com/zonble/ZBSimplePluginManager/blob/master/LICENSE) for details.** -------------------------------------------------------------------------------- /Sources/ZBSimplePluginManager/ZBSimplePluginManager.swift: -------------------------------------------------------------------------------- 1 | #if os(iOS) 2 | import UIKit 3 | #endif 4 | 5 | #if os(OSX) 6 | import AppKit 7 | #endif 8 | 9 | import JavaScriptCore 10 | 11 | /// A class that represents a plug-in. 12 | public class ZBPlugin { 13 | /// ID of the plug-in. 14 | public private(set) var ID: String 15 | /// Title of the plug-in. 16 | public private(set) var title: String 17 | /// What the plugin actually does. 18 | public private(set) var action: JSValue? 19 | /// Is the plugin enabled or not. 20 | public fileprivate(set) var enabled: Bool = false 21 | 22 | fileprivate init(ID: String, title: String, action: JSValue?, enabled: Bool) { 23 | self.ID = ID 24 | self.title = title 25 | self.action = action 26 | self.enabled = enabled 27 | } 28 | 29 | /// Call the action of the plugin. 30 | /// 31 | /// - Parameter args: The arguments. 32 | /// - Returns: The results. 33 | public func call(args: [Any]) -> Any? { 34 | return self.action?.call(withArguments: args) 35 | } 36 | } 37 | 38 | // MARK: - 39 | 40 | extension Notification.Name { 41 | /// A notification that is fired when a plug-in manager completes loading plug-ins. 42 | static let pluginManagerDidLoadPlugins = Notification.Name("pluginManagerDidLoadPlugins") 43 | /// A notification that is fired when a plug-in manager resets all plug-ins. 44 | static let pluginManagerDidResetPlugins = Notification.Name("pluginManagerDidLoadPlugins") 45 | /// A notification that is fired when a plug-in manager resets all settings. 46 | static let pluginManagerDidResetSettings = Notification.Name("pluginManagerDidResetSettings") 47 | } 48 | 49 | enum ZBSimplePluginManagerError: Error { 50 | case overrideRegisterPluginAPI 51 | 52 | var localizedDescription: String { 53 | switch self { 54 | case .overrideRegisterPluginAPI: 55 | return NSLocalizedString("You cannot replace the \"registerPlugin\" function", comment: "error message") 56 | } 57 | } 58 | } 59 | 60 | // MARK: - 61 | 62 | /// ZBSimplePluginManager helps to load and manage JavaScript plug-ins. 63 | public class ZBSimplePluginManager { 64 | /// All of the loaded plug-ins. 65 | public private(set) var plugins = [ZBPlugin]() 66 | /// A filtered list of enabled plug-ins. 67 | public var enabledPlugins: [ZBPlugin] { 68 | return self.plugins.filter { $0.enabled } 69 | } 70 | 71 | fileprivate var jsContext: JSContext = JSContext() 72 | private var pluginFolderURL: URL 73 | private var defaultsNamespace: String 74 | 75 | /// A public property that helps to store values. 76 | public var valueStorage:[String: Any] = [String: Any]() 77 | 78 | // MARK: - 79 | 80 | /// Create an instance by given parameters. 81 | /// 82 | /// - Parameters: 83 | /// - pluginFolderURL: Where are the JavaScript plug-ins located at. 84 | /// - defaultsNamespace: A name space for setting user defaults. 85 | public init(pluginFolderURL: URL, defaultsNamespace: String = "plug-ins") { 86 | self.pluginFolderURL = pluginFolderURL 87 | self.defaultsNamespace = defaultsNamespace 88 | jsContext.name = "ZBSimplePluginManager" 89 | self.buildPluginRegisterationAPI() 90 | self.buildJavaScriptAPIs() 91 | } 92 | 93 | // MARK: - Methods related with creating JavaScript APIs. 94 | 95 | /// Add new JavsScript function to the manager. 96 | /// 97 | /// Note: You cannot override the "registerPlugin" function. 98 | /// 99 | /// - Parameters: 100 | /// - functionName: Name of the function. 101 | /// - block: Implementation of the function. 102 | /// - input: Input value of the function. 103 | /// - Throws: Errors that cuase you cannot add new functions. 104 | public func addJavaScriptAPI(functionName: String, blockWithArgument: @escaping (_ input: Any?) -> (Any?)) throws { 105 | if functionName == "registerPlugin" { 106 | throw ZBSimplePluginManagerError.overrideRegisterPluginAPI 107 | } 108 | let objcBlock: @convention (block) (Any?) -> (Any?) = { input in 109 | return blockWithArgument(input) 110 | } 111 | self.jsContext.setObject(unsafeBitCast(objcBlock, to: AnyObject.self), forKeyedSubscript: functionName as NSString) 112 | } 113 | 114 | /// Add new JavsScript function to the manager. 115 | /// 116 | /// Note: You cannot override the "registerPlugin" function. 117 | /// 118 | /// - Parameters: 119 | /// - functionName: Name of the function. 120 | /// - block: Implementation of the function. 121 | /// - arg1: The first argument. 122 | /// - arg2: The second argument. 123 | /// - Throws: Errors that cuase you cannot add new functions. 124 | public func addJavaScriptAPI(functionName: String, blockWithTwoArguments: @escaping (_ arg1: Any?, _ arg2: Any?) -> (Any?)) throws { 125 | if functionName == "registerPlugin" { 126 | throw ZBSimplePluginManagerError.overrideRegisterPluginAPI 127 | } 128 | let objcBlock: @convention (block) (Any?, Any?) -> (Any?) = { arg1, arg2 in 129 | return blockWithTwoArguments(arg1, arg2) 130 | } 131 | self.jsContext.setObject(unsafeBitCast(objcBlock, to: AnyObject.self), forKeyedSubscript: functionName as NSString) 132 | } 133 | 134 | fileprivate func buildPluginRegisterationAPI() { 135 | 136 | func checkIfPluginEnabledInUserDefaults(pluginID: String) -> Bool { 137 | let settingMap = UserDefaults.standard.dictionary(forKey: defaultsNamespace) as? [String: Bool] ?? [String: Bool]() 138 | return settingMap[pluginID] ?? true 139 | } 140 | 141 | let registerPlugin: @convention (block) (JSValue?) -> Bool = { pluginJSObject in 142 | guard let pluginJSObject = pluginJSObject, 143 | let pluginID = pluginJSObject.forProperty("id").toString() else { 144 | return false 145 | } 146 | let exitingPluginIDs = self.plugins.map { 147 | $0.ID 148 | } 149 | if exitingPluginIDs.contains(pluginID) { 150 | return false 151 | } 152 | guard let title = pluginJSObject.forProperty("title").toString() else { 153 | return false 154 | } 155 | let action = pluginJSObject.forProperty("action") 156 | let enabled = checkIfPluginEnabledInUserDefaults(pluginID: pluginID) 157 | let plugin = ZBPlugin(ID: pluginID, title: title, action: action, enabled: enabled) 158 | self.plugins.append(plugin) 159 | return true 160 | } 161 | self.jsContext.setObject(unsafeBitCast(registerPlugin, to: AnyObject.self), forKeyedSubscript: "registerPlugin" as NSString) 162 | } 163 | 164 | fileprivate func buildJavaScriptAPIs() { 165 | 166 | // MARK: log 167 | try? self.addJavaScriptAPI(functionName: "log") { log in 168 | if let log = log as? String { 169 | print(log) 170 | } 171 | return nil 172 | } 173 | 174 | // MARK: openURL 175 | try? self.addJavaScriptAPI(functionName:"openURL") { urlString in 176 | guard let urlString = urlString as? String, 177 | let url = URL(string:urlString) else { 178 | return nil 179 | } 180 | #if os(iOS) 181 | if #available(iOS 10.0, *) { 182 | UIApplication.shared.open(url, options: [:], completionHandler:nil) 183 | } else { 184 | UIApplication.shared.openURL(url) 185 | } 186 | #endif 187 | #if os(OSX) 188 | NSWorkspace.shared.open(url) 189 | #endif 190 | return nil 191 | } 192 | 193 | // MARK: set 194 | try? self.addJavaScriptAPI(functionName:"set") { key, value in 195 | guard let key = key as? String else { 196 | return nil 197 | } 198 | self.valueStorage[key] = value 199 | return nil 200 | } 201 | 202 | // MARK: get 203 | try? self.addJavaScriptAPI(functionName:"get") { key in 204 | guard let key = key as? String else { 205 | return nil 206 | } 207 | return self.valueStorage[key] 208 | } 209 | 210 | } 211 | 212 | // MARK: - Methods related with loading plug-ins. 213 | 214 | /// Load all plug-ins from the given folder path. 215 | public func loadAllPlugins() { 216 | plugins.removeAll() 217 | let pluginFolder = self.pluginFolderURL.path 218 | guard let enumerator = FileManager.default.enumerator(atPath: pluginFolder) else { 219 | NotificationCenter.default.post(name: .pluginManagerDidLoadPlugins, object: self) 220 | return 221 | } 222 | for path in enumerator { 223 | let fullpath = (pluginFolder as NSString).appendingPathComponent(path as! String) 224 | _ = self.loadJavaScript(fileURL: URL(fileURLWithPath: fullpath)) 225 | } 226 | plugins.sort { $0.title < $1.title } 227 | NotificationCenter.default.post(name: .pluginManagerDidLoadPlugins, object: self) 228 | } 229 | 230 | /// Remove all plug-ins. 231 | public func resetPlugins() { 232 | plugins.removeAll() 233 | NotificationCenter.default.post(name: .pluginManagerDidResetPlugins, object: self) 234 | } 235 | 236 | /// Enable or disable a plugin. 237 | /// 238 | /// - Parameters: 239 | /// - plugin: The plugin. 240 | /// - enabled: Enabled or not. 241 | public func toggle(plugin: ZBPlugin, enabled: Bool) { 242 | plugin.enabled = enabled 243 | var settingMap = UserDefaults.standard.dictionary(forKey: defaultsNamespace) as? [String: Bool] ?? [String: Bool]() 244 | settingMap[plugin.title] = enabled 245 | UserDefaults.standard.set(settingMap, forKey: self.defaultsNamespace) 246 | } 247 | 248 | /// Remove all of the plug-in enable/disable settings. 249 | public func resetSettings() { 250 | UserDefaults.standard.removeObject(forKey: self.defaultsNamespace) 251 | for plugin in self.plugins { 252 | plugin.enabled = true 253 | } 254 | NotificationCenter.default.post(name: .pluginManagerDidResetSettings, object: self) 255 | } 256 | 257 | // MARK: - 258 | 259 | /// Evaluate JavaScript code. 260 | /// 261 | /// - Parameter string: The Javascript code to evaluate. 262 | /// - Returns: The result. 263 | public func loadJavaScript(string: String) -> Any? { 264 | return self.jsContext.evaluateScript(string) 265 | } 266 | 267 | /// Evaluate JavaScript code from a text file. 268 | /// 269 | /// - Parameter fileURL: The file to evaluate. 270 | /// - Returns: The result. 271 | public func loadJavaScript(fileURL: URL) -> Any? { 272 | if !fileURL.isFileURL { 273 | return nil 274 | } 275 | guard let text = try? String(contentsOf: fileURL) else { 276 | return nil 277 | } 278 | return self.jsContext.evaluateScript(text, withSourceURL: fileURL) 279 | } 280 | 281 | } 282 | 283 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import ZBSimplePuginManagerTests 3 | 4 | XCTMain([ 5 | testCase(ZBSimplePuginManagerTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Tests/ZBSimplePluginManagerTests/ZBSimplePluginManagerTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import JavaScriptCore 3 | @testable import ZBSimplePluginManager 4 | 5 | class ZBSimplePluginManagerTests: XCTestCase { 6 | 7 | func createManager() -> ZBSimplePluginManager { 8 | let bundle = Bundle(for: ZBSimplePluginManagerTests.self) 9 | let resourceURL = URL(fileURLWithPath: bundle.resourcePath!) 10 | let pluginFolder = resourceURL.appendingPathComponent("PluginScripts") 11 | let manager = ZBSimplePluginManager(pluginFolderURL: pluginFolder, defaultsNamespace: "test") 12 | return manager 13 | } 14 | 15 | func testLoadPlugin() { 16 | let manager = createManager() 17 | XCTAssertTrue(manager.plugins.count == 0) 18 | manager.loadAllPlugins() 19 | XCTAssertTrue(manager.plugins.count > 0) 20 | } 21 | 22 | func testResetPlugin() { 23 | let manager = createManager() 24 | manager.loadAllPlugins() 25 | XCTAssertTrue(manager.plugins.count > 0) 26 | manager.resetPlugins() 27 | XCTAssertTrue(manager.plugins.count == 0) 28 | } 29 | 30 | func testRegisterPlugin() { 31 | let script = 32 | """ 33 | var printPlugin = { 34 | id: 'plugin.print', 35 | title: 'Print', 36 | action: function (keyword) { 37 | print(keyword) 38 | } 39 | } 40 | registerPlugin(printPlugin) 41 | """ 42 | let manager = createManager() 43 | _ = manager.loadJavaScript(string: script) 44 | XCTAssertTrue(manager.plugins.count == 1) 45 | let plugin = manager.plugins[0] 46 | XCTAssertTrue(plugin.ID == "plugin.print") 47 | XCTAssertTrue(plugin.title == "Print") 48 | let result = plugin.call(args: ["Hi"]) 49 | XCTAssertTrue(result as? String == nil) 50 | } 51 | 52 | func testArray() { 53 | let script = 54 | """ 55 | var arrayPlugin = { 56 | id: 'plugin.Array', 57 | title: 'Array', 58 | action: function (key) { 59 | return [1, 2] 60 | } 61 | } 62 | registerPlugin(arrayPlugin) 63 | """ 64 | let manager = createManager() 65 | _ = manager.loadJavaScript(string: script) 66 | XCTAssertTrue(manager.plugins.count == 1) 67 | let plugin = manager.plugins[0] 68 | let result = (plugin.call(args: []) as? JSValue)?.toArray() 69 | XCTAssertTrue(result?.count == 2) 70 | XCTAssertTrue(result?[0] as? Int == 1) 71 | XCTAssertTrue(result?[1] as? Int == 2) 72 | } 73 | 74 | func testSet() { 75 | let script = 76 | """ 77 | var setPlugin = { 78 | id: 'plugin.set', 79 | title: 'Set', 80 | action: function (keyword) { 81 | set("key", "value") 82 | } 83 | } 84 | registerPlugin(setPlugin) 85 | """ 86 | let manager = createManager() 87 | _ = manager.loadJavaScript(string: script) 88 | XCTAssertTrue(manager.plugins.count == 1) 89 | let plugin = manager.plugins[0] 90 | _ = plugin.call(args: []) 91 | XCTAssertTrue(manager.valueStorage["key"] as? String == "value") 92 | } 93 | 94 | func testGet() { 95 | let script = 96 | """ 97 | var getPlugin = { 98 | id: 'plugin.get', 99 | title: 'Get', 100 | action: function (key) { 101 | return get(key) 102 | } 103 | } 104 | registerPlugin(getPlugin) 105 | """ 106 | let manager = createManager() 107 | _ = manager.loadJavaScript(string: script) 108 | XCTAssertTrue(manager.plugins.count == 1) 109 | let key = "key" 110 | let value = "value" 111 | manager.valueStorage[key] = value 112 | let plugin = manager.plugins[0] 113 | let result = (plugin.call(args: [key]) as? JSValue)?.toString() 114 | XCTAssertTrue(result == value) 115 | } 116 | 117 | func testDisablePugin() { 118 | let manager = createManager() 119 | manager.loadAllPlugins() 120 | manager.resetSettings() 121 | let plugin = manager.plugins[0] 122 | manager.toggle(plugin: plugin, enabled: false) 123 | XCTAssertTrue(manager.plugins.count == manager.enabledPlugins.count + 1) 124 | manager.toggle(plugin: plugin, enabled: true) 125 | XCTAssertTrue(manager.plugins.count == manager.enabledPlugins.count) 126 | } 127 | 128 | static var allTests = [ 129 | ("testLoadPlugin", testLoadPlugin), 130 | ("testResetPlugin", testResetPlugin), 131 | ("testRegisterPlugin", testRegisterPlugin), 132 | ("testArray", testArray), 133 | ("testSet", testSet), 134 | ("testGet", testGet), 135 | ("testDisablePugin", testDisablePugin), 136 | ] 137 | } 138 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'ZBSimplePluginManager' 3 | s.version = '0.0.2' 4 | s.summary = 'A simple plug-in system by using JavaScriptCore.' 5 | s.description = <<-DESC 6 | Apple introduced JavaScriptCore framework, a JavaScript interpreter, in iOS 7. 7 | It is a great tool and we leverage it to build a simple plug-in system to extend 8 | flexibility of your app easily. 9 | DESC 10 | 11 | s.homepage = 'https://github.com/zonble/ZBSimplePluginManager' 12 | s.license = { :type => 'MIT', :file => 'LICENSE' } 13 | s.author = { 'zonble' => 'zonble@gmail.com' } 14 | s.source = { :git => 'https://github.com/zonble/ZBSimplePluginManager.git', :tag => s.version.to_s } 15 | s.social_media_url = 'https://twitter.com/zonble' 16 | s.documentation_url = 'https://zonble.github.io/ZBSimplePluginManager/' 17 | 18 | s.ios.deployment_target = '8.0' 19 | s.osx.deployment_target = '10.10' 20 | s.tvos.deployment_target = '9.0' 21 | s.source_files = 'Sources/ZBSimplePluginManager/**/*' 22 | end 23 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/ZBSimplePluginManagerTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/ZBSimplePluginManager_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 | 0.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/ZBSimplePuginManagerTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/ZBSimplePuginManager_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | "ZBSimplePluginManager::ZBSimplePluginManagerPackageTests::ProductTarget" /* ZBSimplePluginManagerPackageTests */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = OBJ_40 /* Build configuration list for PBXAggregateTarget "ZBSimplePluginManagerPackageTests" */; 13 | buildPhases = ( 14 | ); 15 | dependencies = ( 16 | OBJ_43 /* PBXTargetDependency */, 17 | ); 18 | name = ZBSimplePluginManagerPackageTests; 19 | productName = ZBSimplePluginManagerPackageTests; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | D4B63499201197A500588435 /* PluginScripts in CopyFiles */ = {isa = PBXBuildFile; fileRef = D4B634972011966800588435 /* PluginScripts */; }; 25 | OBJ_22 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; 26 | OBJ_28 /* ZBSimplePluginManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* ZBSimplePluginManagerTests.swift */; }; 27 | OBJ_30 /* ZBSimplePluginManager.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "ZBSimplePluginManager::ZBSimplePluginManager::Product" /* ZBSimplePluginManager.framework */; }; 28 | OBJ_37 /* ZBSimplePluginManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* ZBSimplePluginManager.swift */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | D41484EC2010EAC00017C9B0 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = OBJ_1 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = "ZBSimplePluginManager::ZBSimplePluginManager"; 37 | remoteInfo = ZBSimplePluginManager; 38 | }; 39 | D41484ED2010EAC00017C9B0 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = OBJ_1 /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = "ZBSimplePluginManager::ZBSimplePluginManagerTests"; 44 | remoteInfo = ZBSimplePluginManagerTests; 45 | }; 46 | /* End PBXContainerItemProxy section */ 47 | 48 | /* Begin PBXCopyFilesBuildPhase section */ 49 | D4B634982011979C00588435 /* CopyFiles */ = { 50 | isa = PBXCopyFilesBuildPhase; 51 | buildActionMask = 2147483647; 52 | dstPath = ""; 53 | dstSubfolderSpec = 7; 54 | files = ( 55 | D4B63499201197A500588435 /* PluginScripts in CopyFiles */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXCopyFilesBuildPhase section */ 60 | 61 | /* Begin PBXFileReference section */ 62 | D4B634972011966800588435 /* PluginScripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = PluginScripts; sourceTree = ""; }; 63 | OBJ_12 /* ZBSimplePluginManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZBSimplePluginManagerTests.swift; sourceTree = ""; }; 64 | OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 65 | OBJ_9 /* ZBSimplePluginManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZBSimplePluginManager.swift; sourceTree = ""; }; 66 | "ZBSimplePluginManager::ZBSimplePluginManager::Product" /* ZBSimplePluginManager.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ZBSimplePluginManager.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | "ZBSimplePluginManager::ZBSimplePluginManagerTests::Product" /* ZBSimplePluginManagerTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = ZBSimplePluginManagerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | OBJ_29 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 0; 74 | files = ( 75 | OBJ_30 /* ZBSimplePluginManager.framework in Frameworks */, 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | OBJ_38 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 0; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | /* End PBXFrameworksBuildPhase section */ 87 | 88 | /* Begin PBXGroup section */ 89 | OBJ_10 /* Tests */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | D4B634972011966800588435 /* PluginScripts */, 93 | OBJ_11 /* ZBSimplePluginManagerTests */, 94 | ); 95 | name = Tests; 96 | sourceTree = SOURCE_ROOT; 97 | }; 98 | OBJ_11 /* ZBSimplePluginManagerTests */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | OBJ_12 /* ZBSimplePluginManagerTests.swift */, 102 | ); 103 | name = ZBSimplePluginManagerTests; 104 | path = Tests/ZBSimplePluginManagerTests; 105 | sourceTree = SOURCE_ROOT; 106 | }; 107 | OBJ_14 /* Products */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | "ZBSimplePluginManager::ZBSimplePluginManagerTests::Product" /* ZBSimplePluginManagerTests.xctest */, 111 | "ZBSimplePluginManager::ZBSimplePluginManager::Product" /* ZBSimplePluginManager.framework */, 112 | ); 113 | name = Products; 114 | sourceTree = BUILT_PRODUCTS_DIR; 115 | }; 116 | OBJ_5 = { 117 | isa = PBXGroup; 118 | children = ( 119 | OBJ_6 /* Package.swift */, 120 | OBJ_7 /* Sources */, 121 | OBJ_10 /* Tests */, 122 | OBJ_14 /* Products */, 123 | ); 124 | sourceTree = ""; 125 | }; 126 | OBJ_7 /* Sources */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | OBJ_8 /* ZBSimplePluginManager */, 130 | ); 131 | name = Sources; 132 | sourceTree = SOURCE_ROOT; 133 | }; 134 | OBJ_8 /* ZBSimplePluginManager */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | OBJ_9 /* ZBSimplePluginManager.swift */, 138 | ); 139 | name = ZBSimplePluginManager; 140 | path = Sources/ZBSimplePluginManager; 141 | sourceTree = SOURCE_ROOT; 142 | }; 143 | /* End PBXGroup section */ 144 | 145 | /* Begin PBXNativeTarget section */ 146 | "ZBSimplePluginManager::SwiftPMPackageDescription" /* ZBSimplePluginManagerPackageDescription */ = { 147 | isa = PBXNativeTarget; 148 | buildConfigurationList = OBJ_18 /* Build configuration list for PBXNativeTarget "ZBSimplePluginManagerPackageDescription" */; 149 | buildPhases = ( 150 | OBJ_21 /* Sources */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = ZBSimplePluginManagerPackageDescription; 157 | productName = ZBSimplePluginManagerPackageDescription; 158 | productType = "com.apple.product-type.framework"; 159 | }; 160 | "ZBSimplePluginManager::ZBSimplePluginManager" /* ZBSimplePluginManager */ = { 161 | isa = PBXNativeTarget; 162 | buildConfigurationList = OBJ_33 /* Build configuration list for PBXNativeTarget "ZBSimplePluginManager" */; 163 | buildPhases = ( 164 | OBJ_36 /* Sources */, 165 | OBJ_38 /* Frameworks */, 166 | ); 167 | buildRules = ( 168 | ); 169 | dependencies = ( 170 | ); 171 | name = ZBSimplePluginManager; 172 | productName = ZBSimplePluginManager; 173 | productReference = "ZBSimplePluginManager::ZBSimplePluginManager::Product" /* ZBSimplePluginManager.framework */; 174 | productType = "com.apple.product-type.framework"; 175 | }; 176 | "ZBSimplePluginManager::ZBSimplePluginManagerTests" /* ZBSimplePluginManagerTests */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = OBJ_24 /* Build configuration list for PBXNativeTarget "ZBSimplePluginManagerTests" */; 179 | buildPhases = ( 180 | OBJ_27 /* Sources */, 181 | OBJ_29 /* Frameworks */, 182 | D4B634982011979C00588435 /* CopyFiles */, 183 | ); 184 | buildRules = ( 185 | ); 186 | dependencies = ( 187 | OBJ_31 /* PBXTargetDependency */, 188 | ); 189 | name = ZBSimplePluginManagerTests; 190 | productName = ZBSimplePluginManagerTests; 191 | productReference = "ZBSimplePluginManager::ZBSimplePluginManagerTests::Product" /* ZBSimplePluginManagerTests.xctest */; 192 | productType = "com.apple.product-type.bundle.unit-test"; 193 | }; 194 | /* End PBXNativeTarget section */ 195 | 196 | /* Begin PBXProject section */ 197 | OBJ_1 /* Project object */ = { 198 | isa = PBXProject; 199 | attributes = { 200 | LastUpgradeCheck = 9999; 201 | }; 202 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "ZBSimplePluginManager" */; 203 | compatibilityVersion = "Xcode 3.2"; 204 | developmentRegion = English; 205 | hasScannedForEncodings = 0; 206 | knownRegions = ( 207 | en, 208 | ); 209 | mainGroup = OBJ_5; 210 | productRefGroup = OBJ_14 /* Products */; 211 | projectDirPath = ""; 212 | projectRoot = ""; 213 | targets = ( 214 | "ZBSimplePluginManager::SwiftPMPackageDescription" /* ZBSimplePluginManagerPackageDescription */, 215 | "ZBSimplePluginManager::ZBSimplePluginManagerTests" /* ZBSimplePluginManagerTests */, 216 | "ZBSimplePluginManager::ZBSimplePluginManager" /* ZBSimplePluginManager */, 217 | "ZBSimplePluginManager::ZBSimplePluginManagerPackageTests::ProductTarget" /* ZBSimplePluginManagerPackageTests */, 218 | ); 219 | }; 220 | /* End PBXProject section */ 221 | 222 | /* Begin PBXSourcesBuildPhase section */ 223 | OBJ_21 /* Sources */ = { 224 | isa = PBXSourcesBuildPhase; 225 | buildActionMask = 0; 226 | files = ( 227 | OBJ_22 /* Package.swift in Sources */, 228 | ); 229 | runOnlyForDeploymentPostprocessing = 0; 230 | }; 231 | OBJ_27 /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 0; 234 | files = ( 235 | OBJ_28 /* ZBSimplePluginManagerTests.swift in Sources */, 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | OBJ_36 /* Sources */ = { 240 | isa = PBXSourcesBuildPhase; 241 | buildActionMask = 0; 242 | files = ( 243 | OBJ_37 /* ZBSimplePluginManager.swift in Sources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | /* End PBXSourcesBuildPhase section */ 248 | 249 | /* Begin PBXTargetDependency section */ 250 | OBJ_31 /* PBXTargetDependency */ = { 251 | isa = PBXTargetDependency; 252 | target = "ZBSimplePluginManager::ZBSimplePluginManager" /* ZBSimplePluginManager */; 253 | targetProxy = D41484EC2010EAC00017C9B0 /* PBXContainerItemProxy */; 254 | }; 255 | OBJ_43 /* PBXTargetDependency */ = { 256 | isa = PBXTargetDependency; 257 | target = "ZBSimplePluginManager::ZBSimplePluginManagerTests" /* ZBSimplePluginManagerTests */; 258 | targetProxy = D41484ED2010EAC00017C9B0 /* PBXContainerItemProxy */; 259 | }; 260 | /* End PBXTargetDependency section */ 261 | 262 | /* Begin XCBuildConfiguration section */ 263 | OBJ_19 /* Debug */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | LD = /usr/bin/true; 267 | OTHER_SWIFT_FLAGS = "-swift-version 4 -I /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk"; 268 | SWIFT_VERSION = 4.0; 269 | }; 270 | name = Debug; 271 | }; 272 | OBJ_20 /* Release */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | LD = /usr/bin/true; 276 | OTHER_SWIFT_FLAGS = "-swift-version 4 -I /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk"; 277 | SWIFT_VERSION = 4.0; 278 | }; 279 | name = Release; 280 | }; 281 | OBJ_25 /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 285 | FRAMEWORK_SEARCH_PATHS = ( 286 | "$(inherited)", 287 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 288 | ); 289 | HEADER_SEARCH_PATHS = "$(inherited)"; 290 | INFOPLIST_FILE = ZBSimplePluginManager.xcodeproj/ZBSimplePluginManagerTests_Info.plist; 291 | LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; 292 | OTHER_LDFLAGS = "$(inherited)"; 293 | OTHER_SWIFT_FLAGS = "$(inherited)"; 294 | SWIFT_VERSION = 4.0; 295 | TARGET_NAME = ZBSimplePluginManagerTests; 296 | }; 297 | name = Debug; 298 | }; 299 | OBJ_26 /* Release */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 303 | FRAMEWORK_SEARCH_PATHS = ( 304 | "$(inherited)", 305 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 306 | ); 307 | HEADER_SEARCH_PATHS = "$(inherited)"; 308 | INFOPLIST_FILE = ZBSimplePluginManager.xcodeproj/ZBSimplePluginManagerTests_Info.plist; 309 | LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; 310 | OTHER_LDFLAGS = "$(inherited)"; 311 | OTHER_SWIFT_FLAGS = "$(inherited)"; 312 | SWIFT_VERSION = 4.0; 313 | TARGET_NAME = ZBSimplePluginManagerTests; 314 | }; 315 | name = Release; 316 | }; 317 | OBJ_3 /* Debug */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | CLANG_ENABLE_OBJC_ARC = YES; 321 | COMBINE_HIDPI_IMAGES = YES; 322 | COPY_PHASE_STRIP = NO; 323 | DEBUG_INFORMATION_FORMAT = dwarf; 324 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 325 | ENABLE_NS_ASSERTIONS = YES; 326 | GCC_OPTIMIZATION_LEVEL = 0; 327 | MACOSX_DEPLOYMENT_TARGET = 10.10; 328 | ONLY_ACTIVE_ARCH = YES; 329 | OTHER_SWIFT_FLAGS = "-DXcode"; 330 | PRODUCT_NAME = "$(TARGET_NAME)"; 331 | SDKROOT = iphoneos; 332 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; 333 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; 334 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 335 | USE_HEADERMAP = NO; 336 | }; 337 | name = Debug; 338 | }; 339 | OBJ_34 /* Debug */ = { 340 | isa = XCBuildConfiguration; 341 | buildSettings = { 342 | ENABLE_TESTABILITY = YES; 343 | FRAMEWORK_SEARCH_PATHS = ( 344 | "$(inherited)", 345 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 346 | ); 347 | HEADER_SEARCH_PATHS = "$(inherited)"; 348 | INFOPLIST_FILE = ZBSimplePluginManager.xcodeproj/ZBSimplePluginManager_Info.plist; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; 351 | OTHER_LDFLAGS = "$(inherited)"; 352 | OTHER_SWIFT_FLAGS = "$(inherited)"; 353 | PRODUCT_BUNDLE_IDENTIFIER = ZBSimplePluginManager; 354 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 355 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 356 | SKIP_INSTALL = YES; 357 | SWIFT_VERSION = 4.0; 358 | TARGET_NAME = ZBSimplePluginManager; 359 | }; 360 | name = Debug; 361 | }; 362 | OBJ_35 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ENABLE_TESTABILITY = YES; 366 | FRAMEWORK_SEARCH_PATHS = ( 367 | "$(inherited)", 368 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 369 | ); 370 | HEADER_SEARCH_PATHS = "$(inherited)"; 371 | INFOPLIST_FILE = ZBSimplePluginManager.xcodeproj/ZBSimplePluginManager_Info.plist; 372 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 373 | LD_RUNPATH_SEARCH_PATHS = "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"; 374 | OTHER_LDFLAGS = "$(inherited)"; 375 | OTHER_SWIFT_FLAGS = "$(inherited)"; 376 | PRODUCT_BUNDLE_IDENTIFIER = ZBSimplePluginManager; 377 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 378 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 379 | SKIP_INSTALL = YES; 380 | SWIFT_VERSION = 4.0; 381 | TARGET_NAME = ZBSimplePluginManager; 382 | }; 383 | name = Release; 384 | }; 385 | OBJ_4 /* Release */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | CLANG_ENABLE_OBJC_ARC = YES; 389 | COMBINE_HIDPI_IMAGES = YES; 390 | COPY_PHASE_STRIP = YES; 391 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 392 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 393 | GCC_OPTIMIZATION_LEVEL = s; 394 | MACOSX_DEPLOYMENT_TARGET = 10.10; 395 | OTHER_SWIFT_FLAGS = "-DXcode"; 396 | PRODUCT_NAME = "$(TARGET_NAME)"; 397 | SDKROOT = iphoneos; 398 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; 399 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; 400 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 401 | USE_HEADERMAP = NO; 402 | }; 403 | name = Release; 404 | }; 405 | OBJ_41 /* Debug */ = { 406 | isa = XCBuildConfiguration; 407 | buildSettings = { 408 | }; 409 | name = Debug; 410 | }; 411 | OBJ_42 /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | }; 415 | name = Release; 416 | }; 417 | /* End XCBuildConfiguration section */ 418 | 419 | /* Begin XCConfigurationList section */ 420 | OBJ_18 /* Build configuration list for PBXNativeTarget "ZBSimplePluginManagerPackageDescription" */ = { 421 | isa = XCConfigurationList; 422 | buildConfigurations = ( 423 | OBJ_19 /* Debug */, 424 | OBJ_20 /* Release */, 425 | ); 426 | defaultConfigurationIsVisible = 0; 427 | defaultConfigurationName = Debug; 428 | }; 429 | OBJ_2 /* Build configuration list for PBXProject "ZBSimplePluginManager" */ = { 430 | isa = XCConfigurationList; 431 | buildConfigurations = ( 432 | OBJ_3 /* Debug */, 433 | OBJ_4 /* Release */, 434 | ); 435 | defaultConfigurationIsVisible = 0; 436 | defaultConfigurationName = Debug; 437 | }; 438 | OBJ_24 /* Build configuration list for PBXNativeTarget "ZBSimplePluginManagerTests" */ = { 439 | isa = XCConfigurationList; 440 | buildConfigurations = ( 441 | OBJ_25 /* Debug */, 442 | OBJ_26 /* Release */, 443 | ); 444 | defaultConfigurationIsVisible = 0; 445 | defaultConfigurationName = Debug; 446 | }; 447 | OBJ_33 /* Build configuration list for PBXNativeTarget "ZBSimplePluginManager" */ = { 448 | isa = XCConfigurationList; 449 | buildConfigurations = ( 450 | OBJ_34 /* Debug */, 451 | OBJ_35 /* Release */, 452 | ); 453 | defaultConfigurationIsVisible = 0; 454 | defaultConfigurationName = Debug; 455 | }; 456 | OBJ_40 /* Build configuration list for PBXAggregateTarget "ZBSimplePluginManagerPackageTests" */ = { 457 | isa = XCConfigurationList; 458 | buildConfigurations = ( 459 | OBJ_41 /* Debug */, 460 | OBJ_42 /* Release */, 461 | ); 462 | defaultConfigurationIsVisible = 0; 463 | defaultConfigurationName = Debug; 464 | }; 465 | /* End XCConfigurationList section */ 466 | }; 467 | rootObject = OBJ_1 /* Project object */; 468 | } 469 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/xcshareddata/xcschemes/ZBSimplePluginManager.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/xcshareddata/xcschemes/ZBSimplePluginManagerTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 41 | 42 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /ZBSimplePluginManager.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SchemeUserState 5 | 6 | ZBSimplePluginManager-Package.xcscheme 7 | 8 | 9 | SuppressBuildableAutocreation 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/.nojekyll -------------------------------------------------------------------------------- /docs/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ZBSimplePluginManager Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 43 |
44 |
45 |
46 |

Classes

47 |

The following classes are available globally.

48 | 49 |
50 |
51 |
52 |
    53 |
  • 54 |
    55 | 56 | 57 | 58 | ZBPlugin 59 | 60 |
    61 |
    62 |
    63 |
    64 |
    65 |
    66 |

    A class that represents a plug-in.

    67 | 68 | See more 69 |
    70 |
    71 |

    Declaration

    72 |
    73 |

    Swift

    74 |
    public class ZBPlugin
    75 | 76 |
    77 |
    78 |
    79 | Show on GitHub 80 |
    81 |
    82 |
    83 |
  • 84 |
85 |
86 |
87 |
    88 |
  • 89 |
    90 | 91 | 92 | 93 | ZBSimplePluginManager 94 | 95 |
    96 |
    97 |
    98 |
    99 |
    100 |
    101 |

    ZBSimplePluginManager helps to load and manage JavaScript plug-ins.

    102 | 103 | See more 104 |
    105 |
    106 |

    Declaration

    107 |
    108 |

    Swift

    109 |
    public class ZBSimplePluginManager
    110 | 111 |
    112 |
    113 |
    114 | Show on GitHub 115 |
    116 |
    117 |
    118 |
  • 119 |
120 |
121 |
122 |
123 | 127 |
128 |
129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /docs/Classes/ZBPlugin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ZBPlugin Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ZBSimplePluginManager Docs (100% documented)

18 |

View on GitHub

19 |
20 |
21 |
22 | 27 |
28 |
29 | 44 |
45 |
46 |
47 |

ZBPlugin

48 |
49 |
50 |
public class ZBPlugin
51 | 52 |
53 |
54 |

A class that represents a plug-in.

55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 |
    62 | 63 | 64 | 65 | ID 66 | 67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |

    ID of the plug-in.

    74 | 75 |
    76 |
    77 |

    Declaration

    78 |
    79 |

    Swift

    80 |
    public private(set) var ID: String
    81 | 82 |
    83 |
    84 |
    85 | Show on GitHub 86 |
    87 |
    88 |
    89 |
  • 90 |
  • 91 |
    92 | 93 | 94 | 95 | title 96 | 97 |
    98 |
    99 |
    100 |
    101 |
    102 |
    103 |

    Title of the plug-in.

    104 | 105 |
    106 |
    107 |

    Declaration

    108 |
    109 |

    Swift

    110 |
    public private(set) var title: String
    111 | 112 |
    113 |
    114 |
    115 | Show on GitHub 116 |
    117 |
    118 |
    119 |
  • 120 |
  • 121 |
    122 | 123 | 124 | 125 | action 126 | 127 |
    128 |
    129 |
    130 |
    131 |
    132 |
    133 |

    What the plugin actually does.

    134 | 135 |
    136 |
    137 |

    Declaration

    138 |
    139 |

    Swift

    140 |
    public private(set) var action: JSValue?
    141 | 142 |
    143 |
    144 |
    145 | Show on GitHub 146 |
    147 |
    148 |
    149 |
  • 150 |
  • 151 |
    152 | 153 | 154 | 155 | enabled 156 | 157 |
    158 |
    159 |
    160 |
    161 |
    162 |
    163 |

    Is the plugin enabled or not.

    164 | 165 |
    166 |
    167 |

    Declaration

    168 |
    169 |

    Swift

    170 |
    public fileprivate(set) var enabled: Bool = false
    171 | 172 |
    173 |
    174 |
    175 | Show on GitHub 176 |
    177 |
    178 |
    179 |
  • 180 |
  • 181 |
    182 | 183 | 184 | 185 | call(args:) 186 | 187 |
    188 |
    189 |
    190 |
    191 |
    192 |
    193 |

    Call the action of the plugin.

    194 | 195 |
    196 |
    197 |

    Declaration

    198 |
    199 |

    Swift

    200 |
    public func call(args: [Any]) -> Any?
    201 | 202 |
    203 |
    204 |
    205 |

    Parameters

    206 | 207 | 208 | 209 | 214 | 219 | 220 | 221 |
    210 | 211 | args 212 | 213 | 215 |
    216 |

    The arguments.

    217 |
    218 |
    222 |
    223 |
    224 |

    Return Value

    225 |

    The results.

    226 |
    227 |
    228 | Show on GitHub 229 |
    230 |
    231 |
    232 |
  • 233 |
234 |
235 |
236 |
237 | 241 |
242 |
243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 100% 23 | 24 | 25 | 100% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/css/jazzy.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { 2 | background: transparent; 3 | border: 0; 4 | margin: 0; 5 | outline: 0; 6 | padding: 0; 7 | vertical-align: baseline; } 8 | 9 | body { 10 | background-color: #f2f2f2; 11 | font-family: Helvetica, freesans, Arial, sans-serif; 12 | font-size: 14px; 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | word-wrap: break-word; } 15 | 16 | h1, h2, h3 { 17 | margin-top: 0.8em; 18 | margin-bottom: 0.3em; 19 | font-weight: 100; 20 | color: black; } 21 | 22 | h1 { 23 | font-size: 2.5em; } 24 | 25 | h2 { 26 | font-size: 2em; 27 | border-bottom: 1px solid #e2e2e2; } 28 | 29 | h4 { 30 | font-size: 13px; 31 | line-height: 1.5; 32 | margin-top: 21px; } 33 | 34 | h5 { 35 | font-size: 1.1em; } 36 | 37 | h6 { 38 | font-size: 1.1em; 39 | color: #777; } 40 | 41 | .section-name { 42 | color: gray; 43 | display: block; 44 | font-family: Helvetica; 45 | font-size: 22px; 46 | font-weight: 100; 47 | margin-bottom: 15px; } 48 | 49 | pre, code { 50 | font: 0.95em Menlo, monospace; 51 | color: #777; 52 | word-wrap: normal; } 53 | 54 | p code, li code { 55 | background-color: #eee; 56 | padding: 2px 4px; 57 | border-radius: 4px; } 58 | 59 | a { 60 | color: #0088cc; 61 | text-decoration: none; } 62 | 63 | ul { 64 | padding-left: 15px; } 65 | 66 | li { 67 | line-height: 1.8em; } 68 | 69 | img { 70 | max-width: 100%; } 71 | 72 | blockquote { 73 | margin-left: 0; 74 | padding: 0 10px; 75 | border-left: 4px solid #ccc; } 76 | 77 | .content-wrapper { 78 | margin: 0 auto; 79 | width: 980px; } 80 | 81 | header { 82 | font-size: 0.85em; 83 | line-height: 26px; 84 | background-color: #414141; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 1; } 88 | header img { 89 | padding-right: 6px; 90 | vertical-align: -4px; 91 | height: 16px; } 92 | header a { 93 | color: #fff; } 94 | header p { 95 | float: left; 96 | color: #999; } 97 | header .header-right { 98 | float: right; 99 | margin-left: 16px; } 100 | 101 | #breadcrumbs { 102 | background-color: #f2f2f2; 103 | height: 27px; 104 | padding-top: 17px; 105 | position: fixed; 106 | width: 100%; 107 | z-index: 1; 108 | margin-top: 26px; } 109 | #breadcrumbs #carat { 110 | height: 10px; 111 | margin: 0 5px; } 112 | 113 | .sidebar { 114 | background-color: #f9f9f9; 115 | border: 1px solid #e2e2e2; 116 | overflow-y: auto; 117 | overflow-x: hidden; 118 | position: fixed; 119 | top: 70px; 120 | bottom: 0; 121 | width: 230px; 122 | word-wrap: normal; } 123 | 124 | .nav-groups { 125 | list-style-type: none; 126 | background: #fff; 127 | padding-left: 0; } 128 | 129 | .nav-group-name { 130 | border-bottom: 1px solid #e2e2e2; 131 | font-size: 1.1em; 132 | font-weight: 100; 133 | padding: 15px 0 15px 20px; } 134 | .nav-group-name > a { 135 | color: #333; } 136 | 137 | .nav-group-tasks { 138 | margin-top: 5px; } 139 | 140 | .nav-group-task { 141 | font-size: 0.9em; 142 | list-style-type: none; 143 | white-space: nowrap; } 144 | .nav-group-task a { 145 | color: #888; } 146 | 147 | .main-content { 148 | background-color: #fff; 149 | border: 1px solid #e2e2e2; 150 | margin-left: 246px; 151 | position: absolute; 152 | overflow: hidden; 153 | padding-bottom: 60px; 154 | top: 70px; 155 | width: 734px; } 156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { 157 | margin-bottom: 1em; } 158 | .main-content p { 159 | line-height: 1.8em; } 160 | .main-content section .section:first-child { 161 | margin-top: 0; 162 | padding-top: 0; } 163 | .main-content section .task-group-section .task-group:first-of-type { 164 | padding-top: 10px; } 165 | .main-content section .task-group-section .task-group:first-of-type .section-name { 166 | padding-top: 15px; } 167 | .main-content section .heading:before { 168 | content: ""; 169 | display: block; 170 | padding-top: 70px; 171 | margin: -70px 0 0; } 172 | 173 | .section { 174 | padding: 0 25px; } 175 | 176 | .highlight { 177 | background-color: #eee; 178 | padding: 10px 12px; 179 | border: 1px solid #e2e2e2; 180 | border-radius: 4px; 181 | overflow-x: auto; } 182 | 183 | .declaration .highlight { 184 | overflow-x: initial; 185 | padding: 0 40px 40px 0; 186 | margin-bottom: -25px; 187 | background-color: transparent; 188 | border: none; } 189 | 190 | .section-name { 191 | margin: 0; 192 | margin-left: 18px; } 193 | 194 | .task-group-section { 195 | padding-left: 6px; 196 | border-top: 1px solid #e2e2e2; } 197 | 198 | .task-group { 199 | padding-top: 0px; } 200 | 201 | .task-name-container a[name]:before { 202 | content: ""; 203 | display: block; 204 | padding-top: 70px; 205 | margin: -70px 0 0; } 206 | 207 | .item { 208 | padding-top: 8px; 209 | width: 100%; 210 | list-style-type: none; } 211 | .item a[name]:before { 212 | content: ""; 213 | display: block; 214 | padding-top: 70px; 215 | margin: -70px 0 0; } 216 | .item code { 217 | background-color: transparent; 218 | padding: 0; } 219 | .item .token { 220 | padding-left: 3px; 221 | margin-left: 15px; 222 | font-size: 11.9px; } 223 | .item .declaration-note { 224 | font-size: .85em; 225 | color: gray; 226 | font-style: italic; } 227 | 228 | .pointer-container { 229 | border-bottom: 1px solid #e2e2e2; 230 | left: -23px; 231 | padding-bottom: 13px; 232 | position: relative; 233 | width: 110%; } 234 | 235 | .pointer { 236 | background: #f9f9f9; 237 | border-left: 1px solid #e2e2e2; 238 | border-top: 1px solid #e2e2e2; 239 | height: 12px; 240 | left: 21px; 241 | top: -7px; 242 | -webkit-transform: rotate(45deg); 243 | -moz-transform: rotate(45deg); 244 | -o-transform: rotate(45deg); 245 | transform: rotate(45deg); 246 | position: absolute; 247 | width: 12px; } 248 | 249 | .height-container { 250 | display: none; 251 | left: -25px; 252 | padding: 0 25px; 253 | position: relative; 254 | width: 100%; 255 | overflow: hidden; } 256 | .height-container .section { 257 | background: #f9f9f9; 258 | border-bottom: 1px solid #e2e2e2; 259 | left: -25px; 260 | position: relative; 261 | width: 100%; 262 | padding-top: 10px; 263 | padding-bottom: 5px; } 264 | 265 | .aside, .language { 266 | padding: 6px 12px; 267 | margin: 12px 0; 268 | border-left: 5px solid #dddddd; 269 | overflow-y: hidden; } 270 | .aside .aside-title, .language .aside-title { 271 | font-size: 9px; 272 | letter-spacing: 2px; 273 | text-transform: uppercase; 274 | padding-bottom: 0; 275 | margin: 0; 276 | color: #aaa; 277 | -webkit-user-select: none; } 278 | .aside p:last-child, .language p:last-child { 279 | margin-bottom: 0; } 280 | 281 | .language { 282 | border-left: 5px solid #cde9f4; } 283 | .language .aside-title { 284 | color: #4b8afb; } 285 | 286 | .aside-warning { 287 | border-left: 5px solid #ff6666; } 288 | .aside-warning .aside-title { 289 | color: #ff0000; } 290 | 291 | .graybox { 292 | border-collapse: collapse; 293 | width: 100%; } 294 | .graybox p { 295 | margin: 0; 296 | word-break: break-word; 297 | min-width: 50px; } 298 | .graybox td { 299 | border: 1px solid #e2e2e2; 300 | padding: 5px 25px 5px 10px; 301 | vertical-align: middle; } 302 | .graybox tr td:first-of-type { 303 | text-align: right; 304 | padding: 7px; 305 | vertical-align: top; 306 | word-break: normal; 307 | width: 40px; } 308 | 309 | .slightly-smaller { 310 | font-size: 0.9em; } 311 | 312 | #footer { 313 | position: absolute; 314 | bottom: 10px; 315 | margin-left: 25px; } 316 | #footer p { 317 | margin: 0; 318 | color: #aaa; 319 | font-size: 0.8em; } 320 | 321 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar { 322 | display: none; } 323 | html.dash .main-content { 324 | width: 980px; 325 | margin-left: 0; 326 | border: none; 327 | width: 100%; 328 | top: 0; 329 | padding-bottom: 0; } 330 | html.dash .height-container { 331 | display: block; } 332 | html.dash .item .token { 333 | margin-left: 0; } 334 | html.dash .content-wrapper { 335 | width: auto; } 336 | html.dash #footer { 337 | position: static; } 338 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.zbsimplepluginmanager 7 | CFBundleName 8 | ZBSimplePluginManager 9 | DocSetPlatformFamily 10 | zbsimplepluginmanager 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/Classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Classes Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ZBSimplePluginManager Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 43 |
44 |
45 |
46 |

Classes

47 |

The following classes are available globally.

48 | 49 |
50 |
51 |
52 |
    53 |
  • 54 |
    55 | 56 | 57 | 58 | ZBPlugin 59 | 60 |
    61 |
    62 |
    63 |
    64 |
    65 |
    66 |

    A class that represents a plug-in.

    67 | 68 | See more 69 |
    70 |
    71 |

    Declaration

    72 |
    73 |

    Swift

    74 |
    public class ZBPlugin
    75 | 76 |
    77 |
    78 |
    79 | Show on GitHub 80 |
    81 |
    82 |
    83 |
  • 84 |
85 |
86 |
87 |
    88 |
  • 89 |
    90 | 91 | 92 | 93 | ZBSimplePluginManager 94 | 95 |
    96 |
    97 |
    98 |
    99 |
    100 |
    101 |

    ZBSimplePluginManager helps to load and manage JavaScript plug-ins.

    102 | 103 | See more 104 |
    105 |
    106 |

    Declaration

    107 |
    108 |

    Swift

    109 |
    public class ZBSimplePluginManager
    110 | 111 |
    112 |
    113 |
    114 | Show on GitHub 115 |
    116 |
    117 |
    118 |
  • 119 |
120 |
121 |
122 |
123 | 127 |
128 |
129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/Classes/ZBPlugin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ZBPlugin Class Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |

ZBSimplePluginManager Docs (100% documented)

18 |

View on GitHub

19 |
20 |
21 |
22 | 27 |
28 |
29 | 44 |
45 |
46 |
47 |

ZBPlugin

48 |
49 |
50 |
public class ZBPlugin
51 | 52 |
53 |
54 |

A class that represents a plug-in.

55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 |
    62 | 63 | 64 | 65 | ID 66 | 67 |
    68 |
    69 |
    70 |
    71 |
    72 |
    73 |

    ID of the plug-in.

    74 | 75 |
    76 |
    77 |

    Declaration

    78 |
    79 |

    Swift

    80 |
    public private(set) var ID: String
    81 | 82 |
    83 |
    84 |
    85 | Show on GitHub 86 |
    87 |
    88 |
    89 |
  • 90 |
  • 91 |
    92 | 93 | 94 | 95 | title 96 | 97 |
    98 |
    99 |
    100 |
    101 |
    102 |
    103 |

    Title of the plug-in.

    104 | 105 |
    106 |
    107 |

    Declaration

    108 |
    109 |

    Swift

    110 |
    public private(set) var title: String
    111 | 112 |
    113 |
    114 |
    115 | Show on GitHub 116 |
    117 |
    118 |
    119 |
  • 120 |
  • 121 |
    122 | 123 | 124 | 125 | action 126 | 127 |
    128 |
    129 |
    130 |
    131 |
    132 |
    133 |

    What the plugin actually does.

    134 | 135 |
    136 |
    137 |

    Declaration

    138 |
    139 |

    Swift

    140 |
    public private(set) var action: JSValue?
    141 | 142 |
    143 |
    144 |
    145 | Show on GitHub 146 |
    147 |
    148 |
    149 |
  • 150 |
  • 151 |
    152 | 153 | 154 | 155 | enabled 156 | 157 |
    158 |
    159 |
    160 |
    161 |
    162 |
    163 |

    Is the plugin enabled or not.

    164 | 165 |
    166 |
    167 |

    Declaration

    168 |
    169 |

    Swift

    170 |
    public fileprivate(set) var enabled: Bool = false
    171 | 172 |
    173 |
    174 |
    175 | Show on GitHub 176 |
    177 |
    178 |
    179 |
  • 180 |
  • 181 |
    182 | 183 | 184 | 185 | call(args:) 186 | 187 |
    188 |
    189 |
    190 |
    191 |
    192 |
    193 |

    Call the action of the plugin.

    194 | 195 |
    196 |
    197 |

    Declaration

    198 |
    199 |

    Swift

    200 |
    public func call(args: [Any]) -> Any?
    201 | 202 |
    203 |
    204 |
    205 |

    Parameters

    206 | 207 | 208 | 209 | 214 | 219 | 220 | 221 |
    210 | 211 | args 212 | 213 | 215 |
    216 |

    The arguments.

    217 |
    218 |
    222 |
    223 |
    224 |

    Return Value

    225 |

    The results.

    226 |
    227 |
    228 | Show on GitHub 229 |
    230 |
    231 |
    232 |
  • 233 |
234 |
235 |
236 |
237 | 241 |
242 |
243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 100% 23 | 24 | 25 | 100% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* Credit to https://gist.github.com/wataru420/2048287 */ 2 | .highlight { 3 | /* Comment */ 4 | /* Error */ 5 | /* Keyword */ 6 | /* Operator */ 7 | /* Comment.Multiline */ 8 | /* Comment.Preproc */ 9 | /* Comment.Single */ 10 | /* Comment.Special */ 11 | /* Generic.Deleted */ 12 | /* Generic.Deleted.Specific */ 13 | /* Generic.Emph */ 14 | /* Generic.Error */ 15 | /* Generic.Heading */ 16 | /* Generic.Inserted */ 17 | /* Generic.Inserted.Specific */ 18 | /* Generic.Output */ 19 | /* Generic.Prompt */ 20 | /* Generic.Strong */ 21 | /* Generic.Subheading */ 22 | /* Generic.Traceback */ 23 | /* Keyword.Constant */ 24 | /* Keyword.Declaration */ 25 | /* Keyword.Pseudo */ 26 | /* Keyword.Reserved */ 27 | /* Keyword.Type */ 28 | /* Literal.Number */ 29 | /* Literal.String */ 30 | /* Name.Attribute */ 31 | /* Name.Builtin */ 32 | /* Name.Class */ 33 | /* Name.Constant */ 34 | /* Name.Entity */ 35 | /* Name.Exception */ 36 | /* Name.Function */ 37 | /* Name.Namespace */ 38 | /* Name.Tag */ 39 | /* Name.Variable */ 40 | /* Operator.Word */ 41 | /* Text.Whitespace */ 42 | /* Literal.Number.Float */ 43 | /* Literal.Number.Hex */ 44 | /* Literal.Number.Integer */ 45 | /* Literal.Number.Oct */ 46 | /* Literal.String.Backtick */ 47 | /* Literal.String.Char */ 48 | /* Literal.String.Doc */ 49 | /* Literal.String.Double */ 50 | /* Literal.String.Escape */ 51 | /* Literal.String.Heredoc */ 52 | /* Literal.String.Interpol */ 53 | /* Literal.String.Other */ 54 | /* Literal.String.Regex */ 55 | /* Literal.String.Single */ 56 | /* Literal.String.Symbol */ 57 | /* Name.Builtin.Pseudo */ 58 | /* Name.Variable.Class */ 59 | /* Name.Variable.Global */ 60 | /* Name.Variable.Instance */ 61 | /* Literal.Number.Integer.Long */ } 62 | .highlight .c { 63 | color: #999988; 64 | font-style: italic; } 65 | .highlight .err { 66 | color: #a61717; 67 | background-color: #e3d2d2; } 68 | .highlight .k { 69 | color: #000000; 70 | font-weight: bold; } 71 | .highlight .o { 72 | color: #000000; 73 | font-weight: bold; } 74 | .highlight .cm { 75 | color: #999988; 76 | font-style: italic; } 77 | .highlight .cp { 78 | color: #999999; 79 | font-weight: bold; } 80 | .highlight .c1 { 81 | color: #999988; 82 | font-style: italic; } 83 | .highlight .cs { 84 | color: #999999; 85 | font-weight: bold; 86 | font-style: italic; } 87 | .highlight .gd { 88 | color: #000000; 89 | background-color: #ffdddd; } 90 | .highlight .gd .x { 91 | color: #000000; 92 | background-color: #ffaaaa; } 93 | .highlight .ge { 94 | color: #000000; 95 | font-style: italic; } 96 | .highlight .gr { 97 | color: #aa0000; } 98 | .highlight .gh { 99 | color: #999999; } 100 | .highlight .gi { 101 | color: #000000; 102 | background-color: #ddffdd; } 103 | .highlight .gi .x { 104 | color: #000000; 105 | background-color: #aaffaa; } 106 | .highlight .go { 107 | color: #888888; } 108 | .highlight .gp { 109 | color: #555555; } 110 | .highlight .gs { 111 | font-weight: bold; } 112 | .highlight .gu { 113 | color: #aaaaaa; } 114 | .highlight .gt { 115 | color: #aa0000; } 116 | .highlight .kc { 117 | color: #000000; 118 | font-weight: bold; } 119 | .highlight .kd { 120 | color: #000000; 121 | font-weight: bold; } 122 | .highlight .kp { 123 | color: #000000; 124 | font-weight: bold; } 125 | .highlight .kr { 126 | color: #000000; 127 | font-weight: bold; } 128 | .highlight .kt { 129 | color: #445588; } 130 | .highlight .m { 131 | color: #009999; } 132 | .highlight .s { 133 | color: #d14; } 134 | .highlight .na { 135 | color: #008080; } 136 | .highlight .nb { 137 | color: #0086B3; } 138 | .highlight .nc { 139 | color: #445588; 140 | font-weight: bold; } 141 | .highlight .no { 142 | color: #008080; } 143 | .highlight .ni { 144 | color: #800080; } 145 | .highlight .ne { 146 | color: #990000; 147 | font-weight: bold; } 148 | .highlight .nf { 149 | color: #990000; } 150 | .highlight .nn { 151 | color: #555555; } 152 | .highlight .nt { 153 | color: #000080; } 154 | .highlight .nv { 155 | color: #008080; } 156 | .highlight .ow { 157 | color: #000000; 158 | font-weight: bold; } 159 | .highlight .w { 160 | color: #bbbbbb; } 161 | .highlight .mf { 162 | color: #009999; } 163 | .highlight .mh { 164 | color: #009999; } 165 | .highlight .mi { 166 | color: #009999; } 167 | .highlight .mo { 168 | color: #009999; } 169 | .highlight .sb { 170 | color: #d14; } 171 | .highlight .sc { 172 | color: #d14; } 173 | .highlight .sd { 174 | color: #d14; } 175 | .highlight .s2 { 176 | color: #d14; } 177 | .highlight .se { 178 | color: #d14; } 179 | .highlight .sh { 180 | color: #d14; } 181 | .highlight .si { 182 | color: #d14; } 183 | .highlight .sx { 184 | color: #d14; } 185 | .highlight .sr { 186 | color: #009926; } 187 | .highlight .s1 { 188 | color: #d14; } 189 | .highlight .ss { 190 | color: #990073; } 191 | .highlight .bp { 192 | color: #999999; } 193 | .highlight .vc { 194 | color: #008080; } 195 | .highlight .vg { 196 | color: #008080; } 197 | .highlight .vi { 198 | color: #008080; } 199 | .highlight .il { 200 | color: #009999; } 201 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/css/jazzy.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { 2 | background: transparent; 3 | border: 0; 4 | margin: 0; 5 | outline: 0; 6 | padding: 0; 7 | vertical-align: baseline; } 8 | 9 | body { 10 | background-color: #f2f2f2; 11 | font-family: Helvetica, freesans, Arial, sans-serif; 12 | font-size: 14px; 13 | -webkit-font-smoothing: subpixel-antialiased; 14 | word-wrap: break-word; } 15 | 16 | h1, h2, h3 { 17 | margin-top: 0.8em; 18 | margin-bottom: 0.3em; 19 | font-weight: 100; 20 | color: black; } 21 | 22 | h1 { 23 | font-size: 2.5em; } 24 | 25 | h2 { 26 | font-size: 2em; 27 | border-bottom: 1px solid #e2e2e2; } 28 | 29 | h4 { 30 | font-size: 13px; 31 | line-height: 1.5; 32 | margin-top: 21px; } 33 | 34 | h5 { 35 | font-size: 1.1em; } 36 | 37 | h6 { 38 | font-size: 1.1em; 39 | color: #777; } 40 | 41 | .section-name { 42 | color: gray; 43 | display: block; 44 | font-family: Helvetica; 45 | font-size: 22px; 46 | font-weight: 100; 47 | margin-bottom: 15px; } 48 | 49 | pre, code { 50 | font: 0.95em Menlo, monospace; 51 | color: #777; 52 | word-wrap: normal; } 53 | 54 | p code, li code { 55 | background-color: #eee; 56 | padding: 2px 4px; 57 | border-radius: 4px; } 58 | 59 | a { 60 | color: #0088cc; 61 | text-decoration: none; } 62 | 63 | ul { 64 | padding-left: 15px; } 65 | 66 | li { 67 | line-height: 1.8em; } 68 | 69 | img { 70 | max-width: 100%; } 71 | 72 | blockquote { 73 | margin-left: 0; 74 | padding: 0 10px; 75 | border-left: 4px solid #ccc; } 76 | 77 | .content-wrapper { 78 | margin: 0 auto; 79 | width: 980px; } 80 | 81 | header { 82 | font-size: 0.85em; 83 | line-height: 26px; 84 | background-color: #414141; 85 | position: fixed; 86 | width: 100%; 87 | z-index: 1; } 88 | header img { 89 | padding-right: 6px; 90 | vertical-align: -4px; 91 | height: 16px; } 92 | header a { 93 | color: #fff; } 94 | header p { 95 | float: left; 96 | color: #999; } 97 | header .header-right { 98 | float: right; 99 | margin-left: 16px; } 100 | 101 | #breadcrumbs { 102 | background-color: #f2f2f2; 103 | height: 27px; 104 | padding-top: 17px; 105 | position: fixed; 106 | width: 100%; 107 | z-index: 1; 108 | margin-top: 26px; } 109 | #breadcrumbs #carat { 110 | height: 10px; 111 | margin: 0 5px; } 112 | 113 | .sidebar { 114 | background-color: #f9f9f9; 115 | border: 1px solid #e2e2e2; 116 | overflow-y: auto; 117 | overflow-x: hidden; 118 | position: fixed; 119 | top: 70px; 120 | bottom: 0; 121 | width: 230px; 122 | word-wrap: normal; } 123 | 124 | .nav-groups { 125 | list-style-type: none; 126 | background: #fff; 127 | padding-left: 0; } 128 | 129 | .nav-group-name { 130 | border-bottom: 1px solid #e2e2e2; 131 | font-size: 1.1em; 132 | font-weight: 100; 133 | padding: 15px 0 15px 20px; } 134 | .nav-group-name > a { 135 | color: #333; } 136 | 137 | .nav-group-tasks { 138 | margin-top: 5px; } 139 | 140 | .nav-group-task { 141 | font-size: 0.9em; 142 | list-style-type: none; 143 | white-space: nowrap; } 144 | .nav-group-task a { 145 | color: #888; } 146 | 147 | .main-content { 148 | background-color: #fff; 149 | border: 1px solid #e2e2e2; 150 | margin-left: 246px; 151 | position: absolute; 152 | overflow: hidden; 153 | padding-bottom: 60px; 154 | top: 70px; 155 | width: 734px; } 156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { 157 | margin-bottom: 1em; } 158 | .main-content p { 159 | line-height: 1.8em; } 160 | .main-content section .section:first-child { 161 | margin-top: 0; 162 | padding-top: 0; } 163 | .main-content section .task-group-section .task-group:first-of-type { 164 | padding-top: 10px; } 165 | .main-content section .task-group-section .task-group:first-of-type .section-name { 166 | padding-top: 15px; } 167 | .main-content section .heading:before { 168 | content: ""; 169 | display: block; 170 | padding-top: 70px; 171 | margin: -70px 0 0; } 172 | 173 | .section { 174 | padding: 0 25px; } 175 | 176 | .highlight { 177 | background-color: #eee; 178 | padding: 10px 12px; 179 | border: 1px solid #e2e2e2; 180 | border-radius: 4px; 181 | overflow-x: auto; } 182 | 183 | .declaration .highlight { 184 | overflow-x: initial; 185 | padding: 0 40px 40px 0; 186 | margin-bottom: -25px; 187 | background-color: transparent; 188 | border: none; } 189 | 190 | .section-name { 191 | margin: 0; 192 | margin-left: 18px; } 193 | 194 | .task-group-section { 195 | padding-left: 6px; 196 | border-top: 1px solid #e2e2e2; } 197 | 198 | .task-group { 199 | padding-top: 0px; } 200 | 201 | .task-name-container a[name]:before { 202 | content: ""; 203 | display: block; 204 | padding-top: 70px; 205 | margin: -70px 0 0; } 206 | 207 | .item { 208 | padding-top: 8px; 209 | width: 100%; 210 | list-style-type: none; } 211 | .item a[name]:before { 212 | content: ""; 213 | display: block; 214 | padding-top: 70px; 215 | margin: -70px 0 0; } 216 | .item code { 217 | background-color: transparent; 218 | padding: 0; } 219 | .item .token { 220 | padding-left: 3px; 221 | margin-left: 15px; 222 | font-size: 11.9px; } 223 | .item .declaration-note { 224 | font-size: .85em; 225 | color: gray; 226 | font-style: italic; } 227 | 228 | .pointer-container { 229 | border-bottom: 1px solid #e2e2e2; 230 | left: -23px; 231 | padding-bottom: 13px; 232 | position: relative; 233 | width: 110%; } 234 | 235 | .pointer { 236 | background: #f9f9f9; 237 | border-left: 1px solid #e2e2e2; 238 | border-top: 1px solid #e2e2e2; 239 | height: 12px; 240 | left: 21px; 241 | top: -7px; 242 | -webkit-transform: rotate(45deg); 243 | -moz-transform: rotate(45deg); 244 | -o-transform: rotate(45deg); 245 | transform: rotate(45deg); 246 | position: absolute; 247 | width: 12px; } 248 | 249 | .height-container { 250 | display: none; 251 | left: -25px; 252 | padding: 0 25px; 253 | position: relative; 254 | width: 100%; 255 | overflow: hidden; } 256 | .height-container .section { 257 | background: #f9f9f9; 258 | border-bottom: 1px solid #e2e2e2; 259 | left: -25px; 260 | position: relative; 261 | width: 100%; 262 | padding-top: 10px; 263 | padding-bottom: 5px; } 264 | 265 | .aside, .language { 266 | padding: 6px 12px; 267 | margin: 12px 0; 268 | border-left: 5px solid #dddddd; 269 | overflow-y: hidden; } 270 | .aside .aside-title, .language .aside-title { 271 | font-size: 9px; 272 | letter-spacing: 2px; 273 | text-transform: uppercase; 274 | padding-bottom: 0; 275 | margin: 0; 276 | color: #aaa; 277 | -webkit-user-select: none; } 278 | .aside p:last-child, .language p:last-child { 279 | margin-bottom: 0; } 280 | 281 | .language { 282 | border-left: 5px solid #cde9f4; } 283 | .language .aside-title { 284 | color: #4b8afb; } 285 | 286 | .aside-warning { 287 | border-left: 5px solid #ff6666; } 288 | .aside-warning .aside-title { 289 | color: #ff0000; } 290 | 291 | .graybox { 292 | border-collapse: collapse; 293 | width: 100%; } 294 | .graybox p { 295 | margin: 0; 296 | word-break: break-word; 297 | min-width: 50px; } 298 | .graybox td { 299 | border: 1px solid #e2e2e2; 300 | padding: 5px 25px 5px 10px; 301 | vertical-align: middle; } 302 | .graybox tr td:first-of-type { 303 | text-align: right; 304 | padding: 7px; 305 | vertical-align: top; 306 | word-break: normal; 307 | width: 40px; } 308 | 309 | .slightly-smaller { 310 | font-size: 0.9em; } 311 | 312 | #footer { 313 | position: absolute; 314 | bottom: 10px; 315 | margin-left: 25px; } 316 | #footer p { 317 | margin: 0; 318 | color: #aaa; 319 | font-size: 0.8em; } 320 | 321 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar { 322 | display: none; } 323 | html.dash .main-content { 324 | width: 980px; 325 | margin-left: 0; 326 | border: none; 327 | width: 100%; 328 | top: 0; 329 | padding-bottom: 0; } 330 | html.dash .height-container { 331 | display: block; } 332 | html.dash .item .token { 333 | margin-left: 0; } 334 | html.dash .content-wrapper { 335 | width: auto; } 336 | html.dash #footer { 337 | position: static; } 338 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ZBSimplePluginManager Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ZBSimplePluginManager Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 43 |
44 |
45 |
46 | 47 |

ZBSimplePluginManager

48 | 49 |

A simple plug-in system by using JavaScriptCore.

50 | 51 |

Support  52 | Support  53 | Support 

54 | 55 |

Copyright © 2018 Weizhong Yang a.k.a zonble

56 |

Introduction

57 | 58 |

A plug-in system helps to make your app more flexible.

59 | 60 |

Users may not need all of the functions in your app, and you may want to update the implementation of a function anytime. If you make these functions as plug-ins, users can enable or disable them when they need them or not, and you can let users to download new plug-ins if you hope so.

61 | 62 |

Apple introduced JavaScriptCore framework, a JavaScript interpreter, in iOS 7. It is a great tool and we could leverage it to build a simple plug-in system in your app easily. It is also quite easy to write new plug-ins, since they are just simple JavaScript code.

63 |

Requirement

64 | 65 |

ZBSimplePluginManager runs on iOS, macOS and tvOS.

66 | 67 |
    68 |
  • Swift 4
  • 69 |
  • iOS 8 or above.
  • 70 |
  • macOS 10.10 or above.
  • 71 |
  • tvOS 9 or above.
  • 72 |
73 |

Installation

74 | 75 |

The SDK supports CocoaPods. Please add pod ‘ZBSimplePluginManager’ to your Podfile, and then call pod install.

76 |

Usage

77 | 78 |

Please create an instance of ZBSimplePluginManager by giving the folder where your plug-in files are, and a namespace for storing plug-in settings. A namespace here is a key that is used in NSUserDefaults to manage how a plug-in is enabled or disabled.

79 | 80 |

Then, ask the manager to load all of the plug-ins in th given folder.

81 |
let resourceURL = URL(fileURLWithPath: Bundle.main.resourcePath!)
 82 | let pluginFolder = resourceURL.appendingPathComponent("PluginScripts")
 83 | let pluginManager = ZBSimplePluginManager(pluginFolderURL: pluginFolder, defaultsNameSpace: "plugins")
 84 | pluginManager?.loadAllPlugins()
 85 | 
86 | 87 |

Once the plug-ins are loaded, you can obtain a list of plug-ins from the manager.

88 |
let plugins = pluginManager.plugins
 89 | 
90 | 91 |

A plug-in that we defined in ZBSimplePluginManager has an identifier, a name and an action. You can call the action of a plug-in by passing specific parameters.

92 |
let plugins = pluginManager.plugins
 93 | Let plugin = plugins[0]
 94 | _ = plugin.call(args: ["Hello World!"])
 95 | 
96 |

Plug-in Files

97 | 98 |

A plug-in may looks like:

99 |
var youtubePlugin = {
100 |   id: 'plugin.google.search',
101 |   title: 'Search in Google...',
102 |   action: function (keyword) {
103 |     var url = 'https://google.com/search?q=' + encodeURIComponent(keyword)
104 |     openURL(url)
105 |   }
106 | }
107 | 
108 | registerPlugin(youtubePlugin)
109 | 
110 | 111 |

What the plug-in does is:

112 | 113 |
    114 |
  • Creating a JavaScript object with attributes including id, title, and action.
  • 115 |
  • Call registerPlugin by passing the object to register it.
  • 116 |
117 | 118 |

If there is already a plug-in registered with the same ID, you cannot register the plug-in.

119 |

JavaScript APIs

120 | 121 |

ZBSimplePluginManager has only a few APIs that you can call from your JavaScript code right now, but it is also easy to extend the APIs.

122 | 123 |
    124 |
  • registerPlugin: Register a new plug-in.
  • 125 |
  • log: Print debug messages.
  • 126 |
  • openURL: Open a given URL.
  • 127 |
128 | 129 |

ZBSimplePluginManager also provides a simple shared key/value storage in memory. You can use following functions to access it.

130 | 131 |
    132 |
  • set: Set a value to the shared storage by giving a key.
  • 133 |
  • get: Get a value by giving a key.
  • 134 |
135 | 136 |

You can add your own functions to be called by your JavaScript code by simply calling addJavaScriptAPI(functionName:, block:). For example, if you want to replace the existing log function, you can do this in your code:

137 |
try? self.addJavaScriptAPI(functionName: "log") { log in
138 |   if let log = log as? String {
139 |     print("[My Log]" + log)
140 |   }
141 |   return nil
142 | }
143 | 
144 | 145 |

The body of your custom function is a Swift closure that has a simple input value and returns a value. Type of both of input and output value is optional any (written in Any?). You can cast the value by your self to satisfy your needs. By the way, you cannot replace the ‘registerPlugin’ function, otherwise we cannot register plug-ins.

146 | 147 |

Enjoy!

148 |

License

149 | 150 |

LFLiveKit is released under the MIT license. See 151 | LICENSE for details.

152 | 153 |
154 |
155 | 159 |
160 |
161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/search.json: -------------------------------------------------------------------------------- 1 | {"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC7pluginsSayAA8ZBPluginCGv":{"name":"plugins","abstract":"

All of the loaded plug-ins.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14enabledPluginsSayAA8ZBPluginCGv":{"name":"enabledPlugins","abstract":"

A filtered list of enabled plug-ins.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC12valueStorages10DictionaryVySSypGv":{"name":"valueStorage","abstract":"

A public property that helps to store values.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAACAB10Foundation3URLV012pluginFolderE0_SS17defaultsNamespacetcfc":{"name":"init(pluginFolderURL:defaultsNamespace:)","abstract":"

Create an instance by given parameters.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC16addJavaScriptAPIySS12functionName_ypSgAEc17blockWithArgumenttKF":{"name":"addJavaScriptAPI(functionName:blockWithArgument:)","abstract":"

Add new JavsScript function to the manager.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC16addJavaScriptAPIySS12functionName_ypSgAE_AEtc21blockWithTwoArgumentstKF":{"name":"addJavaScriptAPI(functionName:blockWithTwoArguments:)","abstract":"

Add new JavsScript function to the manager.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14loadAllPluginsyyF":{"name":"loadAllPlugins()","abstract":"

Load all plug-ins from the given folder path.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC12resetPluginsyyF":{"name":"resetPlugins()","abstract":"

Remove all plug-ins.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC6toggleyAA8ZBPluginC6plugin_Sb7enabledtF":{"name":"toggle(plugin:enabled:)","abstract":"

Enable or disable a plugin.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC13resetSettingsyyF":{"name":"resetSettings()","abstract":"

Remove all of the plug-in enable/disable settings.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14loadJavaScriptypSgSS6string_tF":{"name":"loadJavaScript(string:)","abstract":"

Evaluate JavaScript code.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14loadJavaScriptypSg10Foundation3URLV04fileH0_tF":{"name":"loadJavaScript(fileURL:)","abstract":"

Evaluate JavaScript code from a text file.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC2IDSSv":{"name":"ID","abstract":"

ID of the plug-in.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC5titleSSv":{"name":"title","abstract":"

Title of the plug-in.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC6actionSo7JSValueCSgv":{"name":"action","abstract":"

What the plugin actually does.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC7enabledSbv":{"name":"enabled","abstract":"

Is the plugin enabled or not.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC4callypSgSayypG4args_tF":{"name":"call(args:)","abstract":"

Call the action of the plugin.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html":{"name":"ZBPlugin","abstract":"

A class that represents a plug-in.

"},"Classes/ZBSimplePluginManager.html":{"name":"ZBSimplePluginManager","abstract":"

ZBSimplePluginManager helps to load and manage JavaScript plug-ins.

"},"Classes.html":{"name":"Classes","abstract":"

The following classes are available globally.

"}} -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/Documents/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | 4 | ], 5 | "source_directory": "/Users/zonble/Work/ZBSimplePluginManager" 6 | } -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/docsets/ZBSimplePluginManager.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/ZBSimplePluginManager.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/docsets/ZBSimplePluginManager.tgz -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zonble/ZBSimplePluginManager/1b97e26988884f7ae29e2a92038540d7ca9ea5e0/docs/img/gh.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ZBSimplePluginManager Reference 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

ZBSimplePluginManager Docs (100% documented)

17 |

View on GitHub

18 |
19 |
20 |
21 | 26 |
27 |
28 | 43 |
44 |
45 |
46 | 47 |

ZBSimplePluginManager

48 | 49 |

A simple plug-in system by using JavaScriptCore.

50 | 51 |

Support  52 | Support  53 | Support 

54 | 55 |

Copyright © 2018 Weizhong Yang a.k.a zonble

56 |

Introduction

57 | 58 |

A plug-in system helps to make your app more flexible.

59 | 60 |

Users may not need all of the functions in your app, and you may want to update the implementation of a function anytime. If you make these functions as plug-ins, users can enable or disable them when they need them or not, and you can let users to download new plug-ins if you hope so.

61 | 62 |

Apple introduced JavaScriptCore framework, a JavaScript interpreter, in iOS 7. It is a great tool and we could leverage it to build a simple plug-in system in your app easily. It is also quite easy to write new plug-ins, since they are just simple JavaScript code.

63 |

Requirement

64 | 65 |

ZBSimplePluginManager runs on iOS, macOS and tvOS.

66 | 67 |
    68 |
  • Swift 4
  • 69 |
  • iOS 8 or above.
  • 70 |
  • macOS 10.10 or above.
  • 71 |
  • tvOS 9 or above.
  • 72 |
73 |

Installation

74 | 75 |

The SDK supports CocoaPods. Please add pod ‘ZBSimplePluginManager’ to your Podfile, and then call pod install.

76 |

Usage

77 | 78 |

Please create an instance of ZBSimplePluginManager by giving the folder where your plug-in files are, and a namespace for storing plug-in settings. A namespace here is a key that is used in NSUserDefaults to manage how a plug-in is enabled or disabled.

79 | 80 |

Then, ask the manager to load all of the plug-ins in th given folder.

81 |
let resourceURL = URL(fileURLWithPath: Bundle.main.resourcePath!)
 82 | let pluginFolder = resourceURL.appendingPathComponent("PluginScripts")
 83 | let pluginManager = ZBSimplePluginManager(pluginFolderURL: pluginFolder, defaultsNameSpace: "plugins")
 84 | pluginManager?.loadAllPlugins()
 85 | 
86 | 87 |

Once the plug-ins are loaded, you can obtain a list of plug-ins from the manager.

88 |
let plugins = pluginManager.plugins
 89 | 
90 | 91 |

A plug-in that we defined in ZBSimplePluginManager has an identifier, a name and an action. You can call the action of a plug-in by passing specific parameters.

92 |
let plugins = pluginManager.plugins
 93 | Let plugin = plugins[0]
 94 | _ = plugin.call(args: ["Hello World!"])
 95 | 
96 |

Plug-in Files

97 | 98 |

A plug-in may looks like:

99 |
var youtubePlugin = {
100 |   id: 'plugin.google.search',
101 |   title: 'Search in Google...',
102 |   action: function (keyword) {
103 |     var url = 'https://google.com/search?q=' + encodeURIComponent(keyword)
104 |     openURL(url)
105 |   }
106 | }
107 | 
108 | registerPlugin(youtubePlugin)
109 | 
110 | 111 |

What the plug-in does is:

112 | 113 |
    114 |
  • Creating a JavaScript object with attributes including id, title, and action.
  • 115 |
  • Call registerPlugin by passing the object to register it.
  • 116 |
117 | 118 |

If there is already a plug-in registered with the same ID, you cannot register the plug-in.

119 |

JavaScript APIs

120 | 121 |

ZBSimplePluginManager has only a few APIs that you can call from your JavaScript code right now, but it is also easy to extend the APIs.

122 | 123 |
    124 |
  • registerPlugin: Register a new plug-in.
  • 125 |
  • log: Print debug messages.
  • 126 |
  • openURL: Open a given URL.
  • 127 |
128 | 129 |

ZBSimplePluginManager also provides a simple shared key/value storage in memory. You can use following functions to access it.

130 | 131 |
    132 |
  • set: Set a value to the shared storage by giving a key.
  • 133 |
  • get: Get a value by giving a key.
  • 134 |
135 | 136 |

You can add your own functions to be called by your JavaScript code by simply calling addJavaScriptAPI(functionName:, block:). For example, if you want to replace the existing log function, you can do this in your code:

137 |
try? self.addJavaScriptAPI(functionName: "log") { log in
138 |   if let log = log as? String {
139 |     print("[My Log]" + log)
140 |   }
141 |   return nil
142 | }
143 | 
144 | 145 |

The body of your custom function is a Swift closure that has a simple input value and returns a value. Type of both of input and output value is optional any (written in Any?). You can cast the value by your self to satisfy your needs. By the way, you cannot replace the ‘registerPlugin’ function, otherwise we cannot register plug-ins.

146 | 147 |

Enjoy!

148 |

License

149 | 150 |

LFLiveKit is released under the MIT license. See 151 | LICENSE for details.

152 | 153 |
154 |
155 | 159 |
160 |
161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/search.json: -------------------------------------------------------------------------------- 1 | {"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC7pluginsSayAA8ZBPluginCGv":{"name":"plugins","abstract":"

All of the loaded plug-ins.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14enabledPluginsSayAA8ZBPluginCGv":{"name":"enabledPlugins","abstract":"

A filtered list of enabled plug-ins.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC12valueStorages10DictionaryVySSypGv":{"name":"valueStorage","abstract":"

A public property that helps to store values.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAACAB10Foundation3URLV012pluginFolderE0_SS17defaultsNamespacetcfc":{"name":"init(pluginFolderURL:defaultsNamespace:)","abstract":"

Create an instance by given parameters.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC16addJavaScriptAPIySS12functionName_ypSgAEc17blockWithArgumenttKF":{"name":"addJavaScriptAPI(functionName:blockWithArgument:)","abstract":"

Add new JavsScript function to the manager.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC16addJavaScriptAPIySS12functionName_ypSgAE_AEtc21blockWithTwoArgumentstKF":{"name":"addJavaScriptAPI(functionName:blockWithTwoArguments:)","abstract":"

Add new JavsScript function to the manager.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14loadAllPluginsyyF":{"name":"loadAllPlugins()","abstract":"

Load all plug-ins from the given folder path.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC12resetPluginsyyF":{"name":"resetPlugins()","abstract":"

Remove all plug-ins.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC6toggleyAA8ZBPluginC6plugin_Sb7enabledtF":{"name":"toggle(plugin:enabled:)","abstract":"

Enable or disable a plugin.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC13resetSettingsyyF":{"name":"resetSettings()","abstract":"

Remove all of the plug-in enable/disable settings.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14loadJavaScriptypSgSS6string_tF":{"name":"loadJavaScript(string:)","abstract":"

Evaluate JavaScript code.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBSimplePluginManager.html#/s:21ZBSimplePluginManagerAAC14loadJavaScriptypSg10Foundation3URLV04fileH0_tF":{"name":"loadJavaScript(fileURL:)","abstract":"

Evaluate JavaScript code from a text file.

","parent_name":"ZBSimplePluginManager"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC2IDSSv":{"name":"ID","abstract":"

ID of the plug-in.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC5titleSSv":{"name":"title","abstract":"

Title of the plug-in.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC6actionSo7JSValueCSgv":{"name":"action","abstract":"

What the plugin actually does.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC7enabledSbv":{"name":"enabled","abstract":"

Is the plugin enabled or not.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html#/s:21ZBSimplePluginManager8ZBPluginC4callypSgSayypG4args_tF":{"name":"call(args:)","abstract":"

Call the action of the plugin.

","parent_name":"ZBPlugin"},"Classes/ZBPlugin.html":{"name":"ZBPlugin","abstract":"

A class that represents a plug-in.

"},"Classes/ZBSimplePluginManager.html":{"name":"ZBSimplePluginManager","abstract":"

ZBSimplePluginManager helps to load and manage JavaScript plug-ins.

"},"Classes.html":{"name":"Classes","abstract":"

The following classes are available globally.

"}} -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | 4 | ], 5 | "source_directory": "/Users/zonble/Work/ZBSimplePluginManager" 6 | } -------------------------------------------------------------------------------- /jazzy.sh: -------------------------------------------------------------------------------- 1 | jazzy \ 2 | --author zonble \ 3 | --author_url https://zonble.net \ 4 | --github_url https://github.com/zonble/ZBSimplePluginManager \ 5 | --github-file-prefix https://github.com/zonble/ZBSimplePluginManager/tree/0.0.2 \ 6 | --module-version 0.0.2 \ 7 | --xcodebuild-arguments -scheme,ZBSimplePluginManager \ 8 | --module ZBSimplePluginManager 9 | --------------------------------------------------------------------------------