├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE.txt ├── OpenWhisk.podspec ├── OpenWhisk.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ ├── OpenWhisk Tests.xcscheme │ │ ├── OpenWhisk iOS.xcscheme │ │ └── OpenWhisk watchOS.xcscheme └── xcuserdata │ └── pcastro.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── OpenWhisk ├── Config.swift ├── Info_iOS.plist ├── Info_watchOS.plist ├── OpenWhisk.h ├── OpenWhiskButton.swift ├── OpenWhiskConfig.plist └── OpenWhiskSDK.swift ├── OpenWhiskTests ├── Info.plist └── OpenWhiskTests.swift ├── Package.swift ├── README.md ├── mobile └── iOS │ └── starterapp │ ├── .gitignore │ ├── Cartfile │ ├── OpenWhiskStarterApp.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── OpenWhiskStarterApp.xcscheme │ ├── OpenWhiskStarterApp │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── FilterForecast.swift │ ├── Info.plist │ ├── ResultSetCell.swift │ ├── ResultSetTableController.swift │ ├── SelfSignedNetworkDelegate.swift │ ├── Utils.swift │ └── ViewController.swift │ └── Podfile └── tools └── travis ├── scancode.sh └── setupscan.sh /.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 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | 62 | **/.DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # https://docs.travis-ci.com/user/languages/python/ 2 | language: python 3 | 4 | install: 5 | - ./tools/travis/setupscan.sh 6 | 7 | script: 8 | - ./tools/travis/scancode.sh 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 18 | 19 | # Contributing to Apache OpenWhisk 20 | 21 | Anyone can contribute to the OpenWhisk project and we welcome your contributions. 22 | 23 | There are multiple ways to contribute: report bugs, improve the docs, and 24 | contribute code, but you must follow these prerequisites and guidelines: 25 | 26 | - [Contributor License Agreement](#contributor-license-agreement) 27 | - [Raising issues](#raising-issues) 28 | - [Coding Standards](#coding-standards) 29 | 30 | ### Contributor License Agreement 31 | 32 | All contributors must sign and submit an Apache CLA (Contributor License Agreement). 33 | 34 | Instructions on how to do this can be found here: 35 | [http://www.apache.org/licenses/#clas](http://www.apache.org/licenses/#clas) 36 | 37 | Once submitted, you will receive a confirmation email from the Apache Software Foundation (ASF) and be added to 38 | the following list: http://people.apache.org/unlistedclas.html. 39 | 40 | Project committers will use this list to verify pull requests (PRs) come from contributors that have signed a CLA. 41 | 42 | We look forward to your contributions! 43 | 44 | ## Raising issues 45 | 46 | Please raise any bug reports on the respective project repository's GitHub issue tracker. Be sure to search the 47 | list to see if your issue has already been raised. 48 | 49 | A good bug report is one that make it easy for us to understand what you were trying to do and what went wrong. 50 | Provide as much context as possible so we can try to recreate the issue. 51 | 52 | ### Discussion 53 | 54 | Please use the project's developer email list to engage our community: 55 | [dev@openwhisk.incubator.apache.org](dev@openwhisk.incubator.apache.org) 56 | 57 | In addition, we provide a "dev" Slack team channel for conversations at: 58 | https://openwhisk-team.slack.com/messages/dev/ 59 | 60 | ### Coding standards 61 | 62 | Please ensure you follow the coding standards used throughout the existing 63 | code base. Some basic rules include: 64 | 65 | - all files must have the Apache license in the header. 66 | - all PRs must have passing builds for all operating systems. 67 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2015-2016 IBM Corporation 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /OpenWhisk.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = 'OpenWhisk' 4 | s.version = '0.3.0' 5 | s.summary = 'Apache OpenWhisk Client SDK' 6 | s.homepage = 'https://apache.openwhisk.org' 7 | s.license = { :type => 'Apache License, Version 2.0' } 8 | s.authors = 'Apache OpenWhisk' 9 | 10 | s.description = <<-DESC 11 | OpenWhisk is a cloud-first distributed event-based programming service. OpenWhisk provides a programming model to upload event handlers to a cloud service, and register the handlers to respond to various events. 12 | 13 | DESC 14 | 15 | s.ios.deployment_target = '11.0' 16 | s.watchos.deployment_target = '4.0' 17 | 18 | s.source = { :git => 'https://github.com/apache/incubator-openwhisk-client-swift.git', :tag => "#{s.version}" } 19 | 20 | 21 | s.source_files = 'OpenWhisk/*.{swift,h}' 22 | s.watchos.exclude_files = 'OpenWhisk/OpenWhiskButton.swift' 23 | 24 | s.frameworks = 'Foundation', 'WatchConnectivity' 25 | s.resource_bundles = {'OpenWhiskResources' => ['OpenWhisk/OpenWhiskConfig.plist']} 26 | 27 | end 28 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D61CBB251D9205E600176E5D /* OpenWhiskConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = D6C9C3B51C8F53C9002BDB13 /* OpenWhiskConfig.plist */; }; 11 | D64559FC1C8F49A600AA6840 /* OpenWhiskButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E3E6511C72760C00843E16 /* OpenWhiskButton.swift */; }; 12 | D6C9C3B71C8F53C9002BDB13 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C9C3B41C8F53C9002BDB13 /* Config.swift */; }; 13 | D6C9C3B81C8F53C9002BDB13 /* OpenWhiskConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = D6C9C3B51C8F53C9002BDB13 /* OpenWhiskConfig.plist */; }; 14 | D6C9C3B91C8F53C9002BDB13 /* OpenWhiskSDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C9C3B61C8F53C9002BDB13 /* OpenWhiskSDK.swift */; }; 15 | D6C9C3BA1C8F53D3002BDB13 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C9C3B41C8F53C9002BDB13 /* Config.swift */; }; 16 | D6C9C3BB1C8F53D8002BDB13 /* OpenWhiskSDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C9C3B61C8F53C9002BDB13 /* OpenWhiskSDK.swift */; }; 17 | D6C9C3BC1C8F53DD002BDB13 /* OpenWhiskSDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C9C3B61C8F53C9002BDB13 /* OpenWhiskSDK.swift */; }; 18 | D6C9C3BD1C8F53E0002BDB13 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C9C3B41C8F53C9002BDB13 /* Config.swift */; }; 19 | D6E3E63A1C72592300843E16 /* OpenWhisk.h in Headers */ = {isa = PBXBuildFile; fileRef = D6E3E6391C72592300843E16 /* OpenWhisk.h */; settings = {ATTRIBUTES = (Public, ); }; }; 20 | D6E3E6411C72592300843E16 /* OpenWhisk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6E3E6361C72592300843E16 /* OpenWhisk.framework */; }; 21 | D6E3E6461C72592300843E16 /* OpenWhiskTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E3E6451C72592300843E16 /* OpenWhiskTests.swift */; }; 22 | D6E3E6551C72760C00843E16 /* OpenWhiskButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E3E6511C72760C00843E16 /* OpenWhiskButton.swift */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | D6E3E6421C72592300843E16 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = D6E3E62D1C72592300843E16 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = D6E3E6351C72592300843E16; 31 | remoteInfo = OpenWhisk; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 92BBA3EB1D64D69B0026EC66 /* Info_watchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info_watchOS.plist; sourceTree = ""; }; 37 | D6C9C3B41C8F53C9002BDB13 /* Config.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; 38 | D6C9C3B51C8F53C9002BDB13 /* OpenWhiskConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = OpenWhiskConfig.plist; sourceTree = ""; }; 39 | D6C9C3B61C8F53C9002BDB13 /* OpenWhiskSDK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenWhiskSDK.swift; sourceTree = ""; }; 40 | D6E3E6361C72592300843E16 /* OpenWhisk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenWhisk.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | D6E3E6391C72592300843E16 /* OpenWhisk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenWhisk.h; sourceTree = ""; }; 42 | D6E3E63B1C72592300843E16 /* Info_iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info_iOS.plist; sourceTree = ""; }; 43 | D6E3E6401C72592300843E16 /* OpenWhisk Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "OpenWhisk Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | D6E3E6451C72592300843E16 /* OpenWhiskTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenWhiskTests.swift; sourceTree = ""; }; 45 | D6E3E6471C72592300843E16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | D6E3E6511C72760C00843E16 /* OpenWhiskButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenWhiskButton.swift; sourceTree = ""; }; 47 | D6F56ADF1C76471B00F047B6 /* OpenWhisk.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenWhisk.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | D6E3E6321C72592300843E16 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | D6E3E63D1C72592300843E16 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | D6E3E6411C72592300843E16 /* OpenWhisk.framework in Frameworks */, 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | D6F56ADB1C76471B00F047B6 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXFrameworksBuildPhase section */ 74 | 75 | /* Begin PBXGroup section */ 76 | 92BBA3EC1D64D6EF0026EC66 /* Resources */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | D6C9C3B51C8F53C9002BDB13 /* OpenWhiskConfig.plist */, 80 | D6E3E6391C72592300843E16 /* OpenWhisk.h */, 81 | D6E3E63B1C72592300843E16 /* Info_iOS.plist */, 82 | 92BBA3EB1D64D69B0026EC66 /* Info_watchOS.plist */, 83 | ); 84 | name = Resources; 85 | sourceTree = ""; 86 | }; 87 | D6E3E62C1C72592300843E16 = { 88 | isa = PBXGroup; 89 | children = ( 90 | D6E3E6381C72592300843E16 /* OpenWhisk */, 91 | D6E3E6441C72592300843E16 /* OpenWhiskTests */, 92 | D6E3E6371C72592300843E16 /* Products */, 93 | ); 94 | sourceTree = ""; 95 | }; 96 | D6E3E6371C72592300843E16 /* Products */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | D6E3E6361C72592300843E16 /* OpenWhisk.framework */, 100 | D6E3E6401C72592300843E16 /* OpenWhisk Tests.xctest */, 101 | D6F56ADF1C76471B00F047B6 /* OpenWhisk.framework */, 102 | ); 103 | name = Products; 104 | sourceTree = ""; 105 | }; 106 | D6E3E6381C72592300843E16 /* OpenWhisk */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | D6C9C3B61C8F53C9002BDB13 /* OpenWhiskSDK.swift */, 110 | D6E3E6511C72760C00843E16 /* OpenWhiskButton.swift */, 111 | D6C9C3B41C8F53C9002BDB13 /* Config.swift */, 112 | 92BBA3EC1D64D6EF0026EC66 /* Resources */, 113 | ); 114 | path = OpenWhisk; 115 | sourceTree = ""; 116 | }; 117 | D6E3E6441C72592300843E16 /* OpenWhiskTests */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | D6E3E6451C72592300843E16 /* OpenWhiskTests.swift */, 121 | D6E3E6471C72592300843E16 /* Info.plist */, 122 | ); 123 | path = OpenWhiskTests; 124 | sourceTree = ""; 125 | }; 126 | /* End PBXGroup section */ 127 | 128 | /* Begin PBXHeadersBuildPhase section */ 129 | D6E3E6331C72592300843E16 /* Headers */ = { 130 | isa = PBXHeadersBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | D6E3E63A1C72592300843E16 /* OpenWhisk.h in Headers */, 134 | ); 135 | runOnlyForDeploymentPostprocessing = 0; 136 | }; 137 | D6F56ADC1C76471B00F047B6 /* Headers */ = { 138 | isa = PBXHeadersBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | ); 142 | runOnlyForDeploymentPostprocessing = 0; 143 | }; 144 | /* End PBXHeadersBuildPhase section */ 145 | 146 | /* Begin PBXNativeTarget section */ 147 | D6E3E6351C72592300843E16 /* OpenWhisk iOS */ = { 148 | isa = PBXNativeTarget; 149 | buildConfigurationList = D6E3E64A1C72592300843E16 /* Build configuration list for PBXNativeTarget "OpenWhisk iOS" */; 150 | buildPhases = ( 151 | D6E3E6311C72592300843E16 /* Sources */, 152 | D6E3E6321C72592300843E16 /* Frameworks */, 153 | D6E3E6331C72592300843E16 /* Headers */, 154 | D6E3E6341C72592300843E16 /* Resources */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = "OpenWhisk iOS"; 161 | productName = OpenWhisk; 162 | productReference = D6E3E6361C72592300843E16 /* OpenWhisk.framework */; 163 | productType = "com.apple.product-type.framework"; 164 | }; 165 | D6E3E63F1C72592300843E16 /* OpenWhisk Tests */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = D6E3E64D1C72592300843E16 /* Build configuration list for PBXNativeTarget "OpenWhisk Tests" */; 168 | buildPhases = ( 169 | D6E3E63C1C72592300843E16 /* Sources */, 170 | D6E3E63D1C72592300843E16 /* Frameworks */, 171 | D6E3E63E1C72592300843E16 /* Resources */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | D6E3E6431C72592300843E16 /* PBXTargetDependency */, 177 | ); 178 | name = "OpenWhisk Tests"; 179 | productName = OpenWhiskTests; 180 | productReference = D6E3E6401C72592300843E16 /* OpenWhisk Tests.xctest */; 181 | productType = "com.apple.product-type.bundle.unit-test"; 182 | }; 183 | D6F56ADE1C76471B00F047B6 /* OpenWhisk watchOS */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = D6F56AE61C76471B00F047B6 /* Build configuration list for PBXNativeTarget "OpenWhisk watchOS" */; 186 | buildPhases = ( 187 | D6F56ADA1C76471B00F047B6 /* Sources */, 188 | D6F56ADB1C76471B00F047B6 /* Frameworks */, 189 | D6F56ADC1C76471B00F047B6 /* Headers */, 190 | D6F56ADD1C76471B00F047B6 /* Resources */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | ); 196 | name = "OpenWhisk watchOS"; 197 | productName = OpenWhiskWatch; 198 | productReference = D6F56ADF1C76471B00F047B6 /* OpenWhisk.framework */; 199 | productType = "com.apple.product-type.framework"; 200 | }; 201 | /* End PBXNativeTarget section */ 202 | 203 | /* Begin PBXProject section */ 204 | D6E3E62D1C72592300843E16 /* Project object */ = { 205 | isa = PBXProject; 206 | attributes = { 207 | LastSwiftUpdateCheck = 0720; 208 | LastUpgradeCheck = 0930; 209 | ORGANIZATIONNAME = IBM; 210 | TargetAttributes = { 211 | D6E3E6351C72592300843E16 = { 212 | CreatedOnToolsVersion = 7.2.1; 213 | LastSwiftMigration = 0930; 214 | }; 215 | D6E3E63F1C72592300843E16 = { 216 | CreatedOnToolsVersion = 7.2.1; 217 | LastSwiftMigration = 0930; 218 | }; 219 | D6F56ADE1C76471B00F047B6 = { 220 | CreatedOnToolsVersion = 7.2.1; 221 | LastSwiftMigration = 0800; 222 | }; 223 | }; 224 | }; 225 | buildConfigurationList = D6E3E6301C72592300843E16 /* Build configuration list for PBXProject "OpenWhisk" */; 226 | compatibilityVersion = "Xcode 3.2"; 227 | developmentRegion = English; 228 | hasScannedForEncodings = 0; 229 | knownRegions = ( 230 | en, 231 | ); 232 | mainGroup = D6E3E62C1C72592300843E16; 233 | productRefGroup = D6E3E6371C72592300843E16 /* Products */; 234 | projectDirPath = ""; 235 | projectRoot = ""; 236 | targets = ( 237 | D6E3E6351C72592300843E16 /* OpenWhisk iOS */, 238 | D6F56ADE1C76471B00F047B6 /* OpenWhisk watchOS */, 239 | D6E3E63F1C72592300843E16 /* OpenWhisk Tests */, 240 | ); 241 | }; 242 | /* End PBXProject section */ 243 | 244 | /* Begin PBXResourcesBuildPhase section */ 245 | D6E3E6341C72592300843E16 /* Resources */ = { 246 | isa = PBXResourcesBuildPhase; 247 | buildActionMask = 2147483647; 248 | files = ( 249 | D6C9C3B81C8F53C9002BDB13 /* OpenWhiskConfig.plist in Resources */, 250 | ); 251 | runOnlyForDeploymentPostprocessing = 0; 252 | }; 253 | D6E3E63E1C72592300843E16 /* Resources */ = { 254 | isa = PBXResourcesBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | D61CBB251D9205E600176E5D /* OpenWhiskConfig.plist in Resources */, 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | D6F56ADD1C76471B00F047B6 /* Resources */ = { 262 | isa = PBXResourcesBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | /* End PBXResourcesBuildPhase section */ 269 | 270 | /* Begin PBXSourcesBuildPhase section */ 271 | D6E3E6311C72592300843E16 /* Sources */ = { 272 | isa = PBXSourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | D6C9C3B91C8F53C9002BDB13 /* OpenWhiskSDK.swift in Sources */, 276 | D6E3E6551C72760C00843E16 /* OpenWhiskButton.swift in Sources */, 277 | D6C9C3B71C8F53C9002BDB13 /* Config.swift in Sources */, 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | D6E3E63C1C72592300843E16 /* Sources */ = { 282 | isa = PBXSourcesBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | D6C9C3BC1C8F53DD002BDB13 /* OpenWhiskSDK.swift in Sources */, 286 | D6C9C3BD1C8F53E0002BDB13 /* Config.swift in Sources */, 287 | D64559FC1C8F49A600AA6840 /* OpenWhiskButton.swift in Sources */, 288 | D6E3E6461C72592300843E16 /* OpenWhiskTests.swift in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | D6F56ADA1C76471B00F047B6 /* Sources */ = { 293 | isa = PBXSourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | D6C9C3BA1C8F53D3002BDB13 /* Config.swift in Sources */, 297 | D6C9C3BB1C8F53D8002BDB13 /* OpenWhiskSDK.swift in Sources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | /* End PBXSourcesBuildPhase section */ 302 | 303 | /* Begin PBXTargetDependency section */ 304 | D6E3E6431C72592300843E16 /* PBXTargetDependency */ = { 305 | isa = PBXTargetDependency; 306 | target = D6E3E6351C72592300843E16 /* OpenWhisk iOS */; 307 | targetProxy = D6E3E6421C72592300843E16 /* PBXContainerItemProxy */; 308 | }; 309 | /* End PBXTargetDependency section */ 310 | 311 | /* Begin XCBuildConfiguration section */ 312 | D6E3E6481C72592300843E16 /* Debug */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ALWAYS_SEARCH_USER_PATHS = NO; 316 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 317 | CLANG_CXX_LIBRARY = "libc++"; 318 | CLANG_ENABLE_MODULES = YES; 319 | CLANG_ENABLE_OBJC_ARC = YES; 320 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 321 | CLANG_WARN_BOOL_CONVERSION = YES; 322 | CLANG_WARN_COMMA = YES; 323 | CLANG_WARN_CONSTANT_CONVERSION = YES; 324 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 325 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 326 | CLANG_WARN_EMPTY_BODY = YES; 327 | CLANG_WARN_ENUM_CONVERSION = YES; 328 | CLANG_WARN_INFINITE_RECURSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 331 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 332 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 333 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 334 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 335 | CLANG_WARN_STRICT_PROTOTYPES = YES; 336 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 337 | CLANG_WARN_UNREACHABLE_CODE = YES; 338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 339 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 340 | COPY_PHASE_STRIP = NO; 341 | CURRENT_PROJECT_VERSION = 1; 342 | DEBUG_INFORMATION_FORMAT = dwarf; 343 | ENABLE_STRICT_OBJC_MSGSEND = YES; 344 | ENABLE_TESTABILITY = YES; 345 | GCC_C_LANGUAGE_STANDARD = gnu99; 346 | GCC_DYNAMIC_NO_PIC = NO; 347 | GCC_NO_COMMON_BLOCKS = YES; 348 | GCC_OPTIMIZATION_LEVEL = 0; 349 | GCC_PREPROCESSOR_DEFINITIONS = ( 350 | "DEBUG=1", 351 | "$(inherited)", 352 | ); 353 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 354 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 355 | GCC_WARN_UNDECLARED_SELECTOR = YES; 356 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 357 | GCC_WARN_UNUSED_FUNCTION = YES; 358 | GCC_WARN_UNUSED_VARIABLE = YES; 359 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 360 | MTL_ENABLE_DEBUG_INFO = YES; 361 | ONLY_ACTIVE_ARCH = YES; 362 | SDKROOT = iphoneos; 363 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 364 | TARGETED_DEVICE_FAMILY = "1,2"; 365 | VERSIONING_SYSTEM = "apple-generic"; 366 | VERSION_INFO_PREFIX = ""; 367 | }; 368 | name = Debug; 369 | }; 370 | D6E3E6491C72592300843E16 /* Release */ = { 371 | isa = XCBuildConfiguration; 372 | buildSettings = { 373 | ALWAYS_SEARCH_USER_PATHS = NO; 374 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 375 | CLANG_CXX_LIBRARY = "libc++"; 376 | CLANG_ENABLE_MODULES = YES; 377 | CLANG_ENABLE_OBJC_ARC = YES; 378 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 379 | CLANG_WARN_BOOL_CONVERSION = YES; 380 | CLANG_WARN_COMMA = YES; 381 | CLANG_WARN_CONSTANT_CONVERSION = YES; 382 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 383 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 384 | CLANG_WARN_EMPTY_BODY = YES; 385 | CLANG_WARN_ENUM_CONVERSION = YES; 386 | CLANG_WARN_INFINITE_RECURSION = YES; 387 | CLANG_WARN_INT_CONVERSION = YES; 388 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 389 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 390 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 391 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 392 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 393 | CLANG_WARN_STRICT_PROTOTYPES = YES; 394 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 395 | CLANG_WARN_UNREACHABLE_CODE = YES; 396 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 397 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 398 | COPY_PHASE_STRIP = NO; 399 | CURRENT_PROJECT_VERSION = 1; 400 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 401 | ENABLE_NS_ASSERTIONS = NO; 402 | ENABLE_STRICT_OBJC_MSGSEND = YES; 403 | GCC_C_LANGUAGE_STANDARD = gnu99; 404 | GCC_NO_COMMON_BLOCKS = YES; 405 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 406 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 407 | GCC_WARN_UNDECLARED_SELECTOR = YES; 408 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 409 | GCC_WARN_UNUSED_FUNCTION = YES; 410 | GCC_WARN_UNUSED_VARIABLE = YES; 411 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 412 | MTL_ENABLE_DEBUG_INFO = NO; 413 | SDKROOT = iphoneos; 414 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 415 | TARGETED_DEVICE_FAMILY = "1,2"; 416 | VALIDATE_PRODUCT = YES; 417 | VERSIONING_SYSTEM = "apple-generic"; 418 | VERSION_INFO_PREFIX = ""; 419 | }; 420 | name = Release; 421 | }; 422 | D6E3E64B1C72592300843E16 /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | CLANG_ENABLE_MODULES = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 427 | DEFINES_MODULE = YES; 428 | DYLIB_COMPATIBILITY_VERSION = 1; 429 | DYLIB_CURRENT_VERSION = 1; 430 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 431 | INFOPLIST_FILE = OpenWhisk/Info_iOS.plist; 432 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 433 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 434 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 435 | PRODUCT_BUNDLE_IDENTIFIER = org.openwhisk.OpenWhisk; 436 | PRODUCT_NAME = OpenWhisk; 437 | SKIP_INSTALL = YES; 438 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 439 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 440 | SWIFT_VERSION = 4.0; 441 | }; 442 | name = Debug; 443 | }; 444 | D6E3E64C1C72592300843E16 /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | CLANG_ENABLE_MODULES = YES; 448 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 449 | DEFINES_MODULE = YES; 450 | DYLIB_COMPATIBILITY_VERSION = 1; 451 | DYLIB_CURRENT_VERSION = 1; 452 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 453 | INFOPLIST_FILE = OpenWhisk/Info_iOS.plist; 454 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 455 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 456 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 457 | PRODUCT_BUNDLE_IDENTIFIER = org.openwhisk.OpenWhisk; 458 | PRODUCT_NAME = OpenWhisk; 459 | SKIP_INSTALL = YES; 460 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 461 | SWIFT_VERSION = 4.0; 462 | }; 463 | name = Release; 464 | }; 465 | D6E3E64E1C72592300843E16 /* Debug */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | INFOPLIST_FILE = OpenWhiskTests/Info.plist; 469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 470 | PRODUCT_BUNDLE_IDENTIFIER = com.ibm.mobile.openwhisk.OpenWhiskTests; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 473 | SWIFT_VERSION = 4.0; 474 | }; 475 | name = Debug; 476 | }; 477 | D6E3E64F1C72592300843E16 /* Release */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | INFOPLIST_FILE = OpenWhiskTests/Info.plist; 481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 482 | PRODUCT_BUNDLE_IDENTIFIER = com.ibm.mobile.openwhisk.OpenWhiskTests; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 485 | SWIFT_VERSION = 4.0; 486 | }; 487 | name = Release; 488 | }; 489 | D6F56AE41C76471B00F047B6 /* Debug */ = { 490 | isa = XCBuildConfiguration; 491 | buildSettings = { 492 | APPLICATION_EXTENSION_API_ONLY = YES; 493 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 494 | DEFINES_MODULE = YES; 495 | DYLIB_COMPATIBILITY_VERSION = 1; 496 | DYLIB_CURRENT_VERSION = 1; 497 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 498 | INFOPLIST_FILE = OpenWhisk/Info_watchOS.plist; 499 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 500 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 501 | PRODUCT_BUNDLE_IDENTIFIER = com.ibm.mobile.openwhisk.OpenWhisk; 502 | PRODUCT_NAME = OpenWhisk; 503 | SDKROOT = watchos; 504 | SKIP_INSTALL = YES; 505 | SWIFT_VERSION = 3.0; 506 | TARGETED_DEVICE_FAMILY = 4; 507 | WATCHOS_DEPLOYMENT_TARGET = 4.0; 508 | }; 509 | name = Debug; 510 | }; 511 | D6F56AE51C76471B00F047B6 /* Release */ = { 512 | isa = XCBuildConfiguration; 513 | buildSettings = { 514 | APPLICATION_EXTENSION_API_ONLY = YES; 515 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 516 | DEFINES_MODULE = YES; 517 | DYLIB_COMPATIBILITY_VERSION = 1; 518 | DYLIB_CURRENT_VERSION = 1; 519 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 520 | INFOPLIST_FILE = OpenWhisk/Info_watchOS.plist; 521 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 522 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 523 | PRODUCT_BUNDLE_IDENTIFIER = com.ibm.mobile.openwhisk.OpenWhisk; 524 | PRODUCT_NAME = OpenWhisk; 525 | SDKROOT = watchos; 526 | SKIP_INSTALL = YES; 527 | SWIFT_VERSION = 3.0; 528 | TARGETED_DEVICE_FAMILY = 4; 529 | WATCHOS_DEPLOYMENT_TARGET = 4.0; 530 | }; 531 | name = Release; 532 | }; 533 | /* End XCBuildConfiguration section */ 534 | 535 | /* Begin XCConfigurationList section */ 536 | D6E3E6301C72592300843E16 /* Build configuration list for PBXProject "OpenWhisk" */ = { 537 | isa = XCConfigurationList; 538 | buildConfigurations = ( 539 | D6E3E6481C72592300843E16 /* Debug */, 540 | D6E3E6491C72592300843E16 /* Release */, 541 | ); 542 | defaultConfigurationIsVisible = 0; 543 | defaultConfigurationName = Release; 544 | }; 545 | D6E3E64A1C72592300843E16 /* Build configuration list for PBXNativeTarget "OpenWhisk iOS" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | D6E3E64B1C72592300843E16 /* Debug */, 549 | D6E3E64C1C72592300843E16 /* Release */, 550 | ); 551 | defaultConfigurationIsVisible = 0; 552 | defaultConfigurationName = Release; 553 | }; 554 | D6E3E64D1C72592300843E16 /* Build configuration list for PBXNativeTarget "OpenWhisk Tests" */ = { 555 | isa = XCConfigurationList; 556 | buildConfigurations = ( 557 | D6E3E64E1C72592300843E16 /* Debug */, 558 | D6E3E64F1C72592300843E16 /* Release */, 559 | ); 560 | defaultConfigurationIsVisible = 0; 561 | defaultConfigurationName = Release; 562 | }; 563 | D6F56AE61C76471B00F047B6 /* Build configuration list for PBXNativeTarget "OpenWhisk watchOS" */ = { 564 | isa = XCConfigurationList; 565 | buildConfigurations = ( 566 | D6F56AE41C76471B00F047B6 /* Debug */, 567 | D6F56AE51C76471B00F047B6 /* Release */, 568 | ); 569 | defaultConfigurationIsVisible = 0; 570 | defaultConfigurationName = Release; 571 | }; 572 | /* End XCConfigurationList section */ 573 | }; 574 | rootObject = D6E3E62D1C72592300843E16 /* Project object */; 575 | } 576 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/xcshareddata/xcschemes/OpenWhisk Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/xcshareddata/xcschemes/OpenWhisk iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 78 | 79 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/xcshareddata/xcschemes/OpenWhisk watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /OpenWhisk.xcodeproj/xcuserdata/pcastro.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | OpenWhisk.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | OpenWhiskWatch.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | D6E3E6351C72592300843E16 21 | 22 | primary 23 | 24 | 25 | D6E3E63F1C72592300843E16 26 | 27 | primary 28 | 29 | 30 | D6F56ADE1C76471B00F047B6 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /OpenWhisk/Config.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import Foundation 19 | 20 | /* 21 | Retrieves basic configuration information for the SDK specified in WhiskConfig.plist or environment variables 22 | */ 23 | public class Config { 24 | 25 | 26 | class func getHostAndPath(type:String) -> String? { 27 | var url: String? = nil 28 | if let dict = getConfigDictionary() { 29 | url = dict.value(forKey: type) as? String 30 | } else { 31 | print("Configuration file missing, cannot config network call") 32 | } 33 | 34 | return url 35 | } 36 | 37 | 38 | private class func getConfigDictionary() -> NSDictionary? { 39 | 40 | // Attempt 1, load the bundle from a local reference to this classes bundle 41 | // I'am assuming the WhiskResources bundle is in the framework's root bundle 42 | let frameworkBundle = Bundle(for: Config.self) 43 | 44 | if let bundlePath = frameworkBundle.path(forResource: "OpenWhiskResources", ofType: "bundle") { 45 | if let bundle = Bundle(path: bundlePath) { 46 | let configFile = bundle.path(forResource: "OpenWhiskConfig", ofType: "plist") 47 | 48 | if let configFile = configFile { 49 | let config = NSDictionary(contentsOfFile: configFile) as? [String: AnyObject] 50 | if let config = config { 51 | let urlConfig = config["Locations"] as? [String: String] 52 | return urlConfig as NSDictionary? 53 | } 54 | } 55 | } 56 | } else if let bundlePath = frameworkBundle.path(forResource: "OpenWhiskWatchResources", ofType: "bundle") { 57 | if let bundle = Bundle(path: bundlePath) { 58 | let configFile = bundle.path(forResource: "OpenWhiskConfig", ofType: "plist") 59 | 60 | if let configFile = configFile { 61 | let config = NSDictionary(contentsOfFile: configFile) as? [String: AnyObject] 62 | if let config = config { 63 | let urlConfig = config["Locations"] as? [String: String] 64 | return urlConfig as NSDictionary? 65 | } 66 | } 67 | } 68 | } else { 69 | if let configFile = frameworkBundle.path(forResource: "OpenWhiskConfig", ofType: "plist") { 70 | let config = NSDictionary(contentsOfFile: configFile) as? [String: AnyObject] 71 | if let config = config { 72 | let urlConfig = config["Locations"] as? [String: String] 73 | return urlConfig as NSDictionary? 74 | } 75 | } else { 76 | print("Can't find configuration information") 77 | } 78 | } 79 | 80 | return nil 81 | 82 | } 83 | 84 | 85 | 86 | /* 87 | Can be used to read authentication credentials from env variables. Useful for unit tests and maybe some build tasks 88 | but not much else? 89 | */ 90 | public class func getAuthToken() -> (apiKey: String?, apiSecret: String?)? { 91 | 92 | let dict = ProcessInfo.processInfo.environment 93 | let key = dict["OPENWHISK_TESTAPIKEY"] 94 | let secret = dict["OPENWHISK_TESTAPISECRET"] 95 | 96 | return(key, secret) 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /OpenWhisk/Info_iOS.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 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /OpenWhisk/Info_watchOS.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 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /OpenWhisk/OpenWhisk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | @import Foundation; 19 | 20 | //! Project version number for OpenWhisk. 21 | FOUNDATION_EXPORT double OpenWhiskVersionNumber; 22 | 23 | //! Project version string for OpenWhisk. 24 | FOUNDATION_EXPORT const unsigned char OpenWhiskVersionString[]; 25 | 26 | // In this header, you should import all the public headers of your framework using statements like #import 27 | 28 | 29 | -------------------------------------------------------------------------------- /OpenWhisk/OpenWhiskButton.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import UIKit 19 | 20 | /* 21 | 22 | Convenience UI element that allows you to invoke whisk actions. You can use like a normal UIButton and handle all the press events yourself, or you can have the button "self-contained". If you set listenForPressEvents = true it will listen for its own press events and invoke the the configured action. 23 | 24 | */ 25 | @objc(WhiskButton) public class WhiskButton: UIButton { 26 | 27 | var whisk: Whisk? 28 | var urlSession: URLSession? 29 | 30 | var actionParameters: Dictionary? 31 | var actionHasResult: Bool = false 32 | var actionName: String? 33 | var actionPackage: String? 34 | var actionNamespace: String? 35 | var isListeningToSelf: Bool? 36 | 37 | public required init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder) 39 | } 40 | 41 | public override init(frame: CGRect) { 42 | super.init(frame: frame) 43 | } 44 | 45 | public var listenForPressEvents: Bool? { 46 | get { 47 | return isListeningToSelf 48 | } 49 | 50 | set { 51 | if newValue == true { 52 | self.addTarget(self, action: #selector(WhiskButton.buttonPressed), for: .touchUpInside) 53 | } else { 54 | self.removeTarget(self, action: #selector(WhiskButton.buttonPressed), for: .touchUpInside) 55 | } 56 | 57 | isListeningToSelf = newValue 58 | } 59 | } 60 | public var actionButtonCallback: ((Dictionary?, WhiskError?) -> Void)? 61 | 62 | 63 | @objc func buttonPressed() { 64 | invokeAction(parameters: nil, actionCallback: actionButtonCallback) 65 | } 66 | 67 | public func setupWhiskAction(qualifiedName qName:String, credentials: WhiskCredentials, hasResult: Bool = false,parameters: Dictionary? = nil, urlSession: URLSession? = nil, baseUrl: String? = nil) throws { 68 | 69 | let pathParts = try Whisk.processQualifiedName(qName) 70 | 71 | setupWhiskAction(pathParts.name, package: pathParts.package, namespace: pathParts.namespace, credentials: credentials, hasResult: hasResult, parameters: parameters, urlSession: urlSession, baseUrl: baseUrl) 72 | } 73 | 74 | public func setupWhiskAction(_ name: String, package: String? = nil, namespace: String = "_", credentials: WhiskCredentials, hasResult: Bool = false,parameters: Dictionary? = nil, urlSession: URLSession? = nil, baseUrl: String? = nil) { 75 | 76 | whisk = Whisk(credentials: credentials) 77 | 78 | if let session = urlSession { 79 | whisk?.urlSession = session 80 | } 81 | 82 | if let baseUrl = baseUrl { 83 | whisk?.baseURL = baseUrl 84 | } 85 | 86 | actionParameters = parameters 87 | actionName = name 88 | actionPackage = package 89 | actionNamespace = namespace 90 | actionHasResult = hasResult 91 | } 92 | 93 | public func invokeAction(parameters: [String:AnyObject]? = nil, actionCallback: ((Dictionary?, WhiskError?) -> Void)?) { 94 | 95 | if let whisk = whisk, let actionName = actionName, let actionNamespace = actionNamespace { 96 | 97 | let queue = DispatchQueue(label:"com.ibm.mobilefirst.openwhisk.invokeAction") 98 | queue.async(qos: .userInitiated) { 99 | do { 100 | 101 | var params:[String:AnyObject]? 102 | 103 | if let parameters = parameters { 104 | params = parameters 105 | } else { 106 | params = self.actionParameters 107 | } 108 | 109 | try whisk.invokeAction(name: actionName, package: self.actionPackage, namespace: actionNamespace, parameters: params as AnyObject?, hasResult: self.actionHasResult, callback: {(reply, error) in 110 | 111 | 112 | // note callback is in main queue already we should be on the UI thread 113 | if let actionCallback = actionCallback { 114 | actionCallback(reply, error) 115 | } 116 | 117 | 118 | }) 119 | } catch { 120 | print("Error invoking action: \(error)") 121 | } 122 | } 123 | } else { 124 | print("WhiskButton action not initialized") 125 | } 126 | 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /OpenWhisk/OpenWhiskConfig.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Locations 6 | 7 | actions 8 | https://openwhisk.ng.bluemix.net/api/v1/ 9 | triggers 10 | https://openwhisk.ng.bluemix.net/api/v1/ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /OpenWhisk/OpenWhiskSDK.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import Foundation 19 | 20 | /* 21 | 22 | Hold the Whisk access key and access token. The session token and jwtToken can be used to implement 23 | custom authentication flows 24 | 25 | */ 26 | public struct WhiskCredentials { 27 | public init(accessKey: String?, accessToken: String?, sessionToken:String? = nil, jwtToken: String? = nil) { 28 | self.accessToken = accessToken 29 | self.accessKey = accessKey 30 | self.sessionToken = sessionToken 31 | self.jwtToken = jwtToken 32 | } 33 | 34 | // whisk credentials 35 | public var accessKey: String? 36 | public var accessToken: String? 37 | public var sessionToken: String? 38 | 39 | // optional app credentials 40 | public var appKey: String? 41 | public var appSecret: String? 42 | 43 | // optional token for custom authentication flow 44 | public var jwtToken: String? 45 | } 46 | 47 | /* Error types for Whisk calls */ 48 | public enum WhiskError: Error { 49 | case httpError(description: String, statusCode: Int) // something went wrong with the http call 50 | case jsonError(description: String) // json wasn't right 51 | case credentialError(description: String) // something is wrong with the whisk credentials 52 | case qualifiedNameFormat(description: String) // something is wrong in qualified name 53 | case whiskProcessingError(description: String, errorCode: Int) // something went wrong on the whisk side. 54 | } 55 | 56 | /* Type of Whisk operation requested */ 57 | enum WhiskType { 58 | case action 59 | case trigger 60 | } 61 | 62 | /* Main class to hold the calls to invoke Actions and fire Triggers */ 63 | public class Whisk { 64 | 65 | // Secrets needed to call Whisk API 66 | let AccessKey: String? // Whisk key 67 | let AccessToken: String? // Whisk token 68 | let AppKey: String? // application Key (currently not used) 69 | let AppSecret: String? // application Secret (curently not used) 70 | 71 | // api Host for Whisk backend 72 | public var whiskBaseURL: String? 73 | 74 | // set to non-nil if using a custom session 75 | public var urlSession: URLSession? 76 | 77 | public var verboseReplies: Bool = false 78 | 79 | // Set these if you want to run unit tests and mock 80 | // calls to Whisk backend. 81 | public var useMock: Bool = false 82 | public var mockReply: [String: AnyObject]? 83 | public var mockError: WhiskError? 84 | 85 | 86 | // return base URL of backend including common path for all API calls 87 | public var baseURL: String? { 88 | set { 89 | if let url = newValue { 90 | 91 | let c = url.last 92 | 93 | let separater = c == "/" ? "" : "/" 94 | 95 | whiskBaseURL = url + separater + "api/v1/" 96 | 97 | } else { 98 | whiskBaseURL = nil 99 | } 100 | } 101 | get { 102 | return whiskBaseURL 103 | } 104 | } 105 | 106 | // Initialize with credentials, region currently not used 107 | public init(credentials: WhiskCredentials, region: String = "US-East-1") { 108 | // initialize 109 | AccessKey = credentials.accessKey 110 | AccessToken = credentials.accessToken 111 | AppKey = credentials.appKey 112 | AppSecret = credentials.appSecret 113 | 114 | } 115 | 116 | 117 | /* Base function to fire Whisk Trigger identified by qualified name */ 118 | public func fireTrigger(qualifiedName: String, parameters: AnyObject? = nil, callback: @escaping (Dictionary?, WhiskError?)->Void) throws { 119 | 120 | let pathParts = try Whisk.processQualifiedName(qualifiedName) 121 | try fireTrigger(name: pathParts.name, package: pathParts.package, namespace: pathParts.namespace, parameters: parameters, callback: callback) 122 | } 123 | 124 | /* Base function to invoke Whisk Action identified by qualified name */ 125 | public func invokeAction(qualifiedName: String, parameters: AnyObject?, hasResult: Bool = false, callback: @escaping (Dictionary?, WhiskError?)->Void) throws { 126 | 127 | let pathParts = try Whisk.processQualifiedName(qualifiedName) 128 | try invokeAction(name: pathParts.name, package: pathParts.package, namespace: pathParts.namespace, parameters: parameters, hasResult: hasResult, callback: callback) 129 | } 130 | 131 | 132 | /* Base function to fire Whisk Trigger identified by components */ 133 | public func fireTrigger(name: String, package: String? = nil, namespace: String = "_", parameters: AnyObject? = nil, callback: @escaping (Dictionary?, WhiskError?)->Void) throws { 134 | 135 | if let accessKey = AccessKey, let accessToken = AccessToken { 136 | try httpRequestWhiskAPI(accessKey: accessKey, accessToken: accessToken, namespace: namespace, verb: "POST", type: .trigger, package: package, name:name, parameters: parameters, isSync: false, callback: { (jsonArray, error) in 137 | if let error = error { 138 | callback(nil, error) 139 | } else { 140 | callback(jsonArray, nil) 141 | } 142 | }) 143 | } else { 144 | throw WhiskError.credentialError(description: "Access key and token not set") 145 | } 146 | 147 | 148 | } 149 | 150 | /* Base function to invoke Whisk Action identified by components */ 151 | public func invokeAction(name: String, package: String? = nil, namespace: String = "_", parameters: AnyObject?, hasResult:Bool = false, callback: @escaping (Dictionary?, WhiskError?)-> Void) throws { 152 | if let accessKey = AccessKey, let accessToken = AccessToken { 153 | 154 | try httpRequestWhiskAPI(accessKey: accessKey, accessToken: accessToken, namespace: namespace, verb: "POST", type: .action, package: package, name: name, parameters: parameters, isSync: hasResult, callback: {(jsonDict, error) in 155 | if let error = error { 156 | callback(nil, error) 157 | } else { 158 | callback(jsonDict, nil) 159 | } 160 | 161 | }) 162 | } else { 163 | throw WhiskError.credentialError(description: "Access key and token not set") 164 | } 165 | 166 | } 167 | 168 | /* can redirect call here, e.g. if mocking */ 169 | func httpRequestWhiskAPI(accessKey: String, accessToken: String, namespace: String, verb: String, type: WhiskType, package: String?, name: String, parameters: AnyObject?, isSync: Bool, callback: @escaping (Dictionary?, WhiskError?) ->Void) throws { 170 | 171 | if useMock { 172 | callback(mockReply, mockError) 173 | 174 | } else { 175 | try whiskAPI(accessKey: accessKey, accessToken: accessToken, namespace: namespace, verb: verb, type: type, package: package, name: name, parameters: parameters, isSync: isSync, callback: callback) 176 | } 177 | } 178 | 179 | 180 | /* Network call */ 181 | func whiskAPI(accessKey: String, accessToken: String, namespace: String, verb: String, type: WhiskType, package: String?, name: String, parameters: AnyObject?, isSync: Bool, callback: @escaping (Dictionary?,WhiskError?) ->Void) throws { 182 | 183 | // set parameters 184 | var paramsIsDict = false 185 | if let parameters = parameters { 186 | if parameters is Dictionary { 187 | paramsIsDict = true 188 | } 189 | } 190 | 191 | // set authorization string 192 | let loginString = NSString(format: "%@:%@", accessKey, accessToken) 193 | let loginData: Data = loginString.data(using: String.Encoding.utf8.rawValue)! 194 | let base64LoginString = loginData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0)) 195 | 196 | let typeStr: String! 197 | 198 | // set type 199 | switch type { 200 | case .action: 201 | typeStr = "actions" 202 | case .trigger: 203 | typeStr = "triggers" 204 | } 205 | 206 | // get base URL 207 | guard let actionURL = baseURL != nil ? baseURL : Config.getHostAndPath(type: typeStr) else { 208 | callback(nil, WhiskError.httpError(description: "Base URL not set, try using whisk.baseUrl setting", statusCode: 400)) 209 | return 210 | } 211 | 212 | // append namespace and trigger/action path 213 | var syncName = "namespaces/" 214 | 215 | var namespaceStr = namespace 216 | 217 | if namespace.count == 0 { 218 | namespaceStr = "_" 219 | } 220 | 221 | if let package = package { 222 | if package.count == 0 { 223 | syncName = syncName + namespaceStr+"/"+typeStr+"/"+name 224 | } else { 225 | syncName = syncName + namespaceStr+"/"+typeStr+"/"+package+"/"+name 226 | } 227 | } else { 228 | syncName = syncName + namespaceStr+"/"+typeStr+"/"+name 229 | } 230 | 231 | // if action has results, specify as blocking 232 | if isSync == true { 233 | syncName += "?blocking=true" 234 | } 235 | 236 | // use this for verbose replies 237 | let restCall = actionURL+syncName 238 | 239 | guard let encodedPath = syncName.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else { 240 | callback(nil, WhiskError.httpError(description: "URL Encode error \(syncName)", statusCode: 400)) 241 | return 242 | } 243 | 244 | syncName = encodedPath 245 | 246 | // create request 247 | guard let url = URL(string:actionURL+syncName) else { 248 | // send back error on main queue 249 | 250 | callback(nil, WhiskError.httpError(description: "Malformed url \(actionURL+syncName)", statusCode: 400)) 251 | 252 | return 253 | 254 | } 255 | 256 | var request = URLRequest(url: url) 257 | request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type") 258 | request.addValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization") 259 | request.httpMethod = verb 260 | 261 | // create JSON from parameters dictionary 262 | do { 263 | 264 | if let parameters = parameters { 265 | if paramsIsDict { 266 | request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions()) 267 | } else { 268 | if parameters is String { 269 | let str = "{\"payload\":\"\(parameters as! String)\"}" 270 | request.httpBody = str.data(using: String.Encoding.utf8) 271 | } else { 272 | let str = "{\"payload\": \(parameters)}" 273 | request.httpBody = str.data(using: String.Encoding.utf8) 274 | } 275 | } 276 | } 277 | 278 | } catch { 279 | print("Error parsing JSON in Whisk request: \(error)") 280 | } 281 | 282 | 283 | // retrieve session as default or use developer specified session 284 | let sess: URLSession! 285 | if let _ = urlSession { 286 | sess = urlSession 287 | } else { 288 | let sessConfig = URLSessionConfiguration.default 289 | sess = URLSession(configuration: sessConfig) 290 | } 291 | 292 | // perform network request 293 | let task = sess.dataTask(with: request) { 294 | data, response, error in 295 | let statusCode: Int! 296 | 297 | if let error = error { 298 | 299 | if let httpResponse = response as? HTTPURLResponse { 300 | statusCode = httpResponse.statusCode 301 | } else { 302 | statusCode = -1 303 | } 304 | // return network transport error call on main queue 305 | DispatchQueue.main.async { 306 | callback(nil, WhiskError.httpError(description: "\(error.localizedDescription)", statusCode: statusCode)) 307 | } 308 | 309 | return 310 | 311 | } else { 312 | 313 | if let httpResponse = response as? HTTPURLResponse { 314 | statusCode = httpResponse.statusCode 315 | do { 316 | // success 317 | if statusCode < 300 { 318 | 319 | switch verb { 320 | // is an action invocation 321 | case "POST": 322 | var jsonDict = [String:AnyObject]() 323 | 324 | let respDict = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary 325 | jsonDict = respDict 326 | 327 | 328 | if let whiskError = jsonDict["error"] as? String { 329 | 330 | var errorCode = -1 331 | if let code = jsonDict["code"] as? Int { 332 | errorCode = code 333 | } 334 | // send back error on main queue 335 | DispatchQueue.main.async { 336 | callback(nil, WhiskError.whiskProcessingError(description: "errorCode:\(errorCode), \(whiskError)", errorCode: errorCode)) 337 | } 338 | 339 | } else { 340 | 341 | var whiskReply = [String:AnyObject]() 342 | 343 | if self.verboseReplies == true { 344 | whiskReply = jsonDict 345 | 346 | // add the rest call made to verbose replies for debugging 347 | switch type { 348 | case .action: 349 | whiskReply["actionUrl"] = restCall as AnyObject? 350 | case .trigger: 351 | whiskReply["triggerUrl"] = restCall as AnyObject? 352 | } 353 | 354 | } else { 355 | let reply = jsonDict 356 | whiskReply["activationId"] = reply["activationId"] 357 | 358 | if isSync == true { 359 | if let whiskResponse = reply["response"] as? [String:AnyObject] { 360 | 361 | if let actionResult = whiskResponse["result"] { 362 | 363 | //if let payload = actionResult["payload"] { 364 | 365 | let payload:AnyObject? = actionResult 366 | if payload is String { 367 | do { 368 | 369 | let payloadObj = try JSONSerialization.jsonObject(with: (payload as! String).data(using: String.Encoding.utf8)!, options: []) 370 | 371 | whiskReply["result"] = payloadObj as AnyObject 372 | } catch { 373 | print("Error parsing payload into JSON, defaulting to string") 374 | whiskReply = ["result" : "\(payload!)" as AnyObject] 375 | } 376 | } else { 377 | whiskReply["result"] = payload as AnyObject 378 | } 379 | //} 380 | } 381 | } 382 | } 383 | } 384 | 385 | // send back successful response on main queue 386 | DispatchQueue.main.async { 387 | callback(whiskReply, nil) 388 | } 389 | } 390 | 391 | // get info about actions/triggers 392 | // not used right now 393 | case "GET": 394 | let jsonArray = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray 395 | let jsonDict:Dictionary = ["array":jsonArray] 396 | 397 | DispatchQueue.main.async { 398 | callback(jsonDict, nil) 399 | } 400 | 401 | default: 402 | break 403 | 404 | } 405 | } else { 406 | DispatchQueue.main.async { 407 | callback(nil, WhiskError.httpError(description: "Whisk returned HTTP error code", statusCode: statusCode)) 408 | } 409 | } 410 | 411 | } catch { 412 | print("Error parsing JSON from Whisk response: \(error)") 413 | DispatchQueue.main.async { 414 | callback(nil, WhiskError.jsonError(description: "\(error)")) 415 | } 416 | } 417 | } 418 | } 419 | } 420 | 421 | task.resume() 422 | 423 | 424 | } 425 | 426 | /* Convert qualified name string into component parts of action or trigger call */ 427 | class func processQualifiedName(_ qName: String) throws -> (namespace:String, package: String?, name: String) { 428 | var namespace = "_" 429 | var package: String? = nil 430 | var name = "" 431 | var doesSpecifyNamespace = false 432 | 433 | if qName.first == "/" { 434 | doesSpecifyNamespace = true 435 | } 436 | 437 | let pathParts = qName.split { $0 == "/" }.map(String.init) 438 | 439 | if doesSpecifyNamespace == true { 440 | if pathParts.count == 2 { 441 | namespace = pathParts[0] 442 | name = pathParts[1] 443 | } else if pathParts.count == 3 { 444 | namespace = pathParts[0] 445 | package = pathParts[1] 446 | name = pathParts[2] 447 | } else { 448 | throw WhiskError.qualifiedNameFormat(description: "Cannot parse \(qName)") 449 | } 450 | } else { 451 | if pathParts.count == 1 { 452 | name = pathParts[0] 453 | } else if pathParts.count == 2 { 454 | package = pathParts[0] 455 | name = pathParts[1] 456 | } else { 457 | throw WhiskError.qualifiedNameFormat(description: "Cannot parse \(qName)") 458 | } 459 | } 460 | 461 | return (namespace, package, name) 462 | } 463 | 464 | } 465 | 466 | 467 | -------------------------------------------------------------------------------- /OpenWhiskTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /OpenWhiskTests/OpenWhiskTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import XCTest 19 | import OpenWhisk 20 | 21 | class NetworkUtilsDelegate: NSObject, URLSessionDelegate { 22 | 23 | func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { 24 | completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) 25 | } 26 | 27 | } 28 | 29 | class OpenWhiskTests: XCTestCase { 30 | 31 | let Timeout:TimeInterval = 100 // time to wait for whisk action to complete 32 | 33 | var apiKey: String? 34 | var apiSecret: String? 35 | 36 | override func setUp() { 37 | super.setUp() 38 | 39 | 40 | if let config = Config.getAuthToken() { 41 | apiKey = config.apiKey 42 | apiSecret = config.apiSecret 43 | } 44 | 45 | } 46 | 47 | override func tearDown() { 48 | super.tearDown() 49 | } 50 | 51 | 52 | 53 | func testWhiskParameterizedAction() { 54 | 55 | if let apiKey = apiKey, let apiSecret = apiSecret { 56 | // allow for self-signed certificates 57 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main) 58 | 59 | let credentials = WhiskCredentials(accessKey: apiKey, accessToken: apiSecret) 60 | let whisk = Whisk(credentials: credentials) 61 | whisk.urlSession = session 62 | 63 | // setup for async testing 64 | let expectation = self.expectation(description: "Whisk Callback") 65 | 66 | do { 67 | try whisk.invokeAction(name: "date", package: "utils", namespace: "whisk.system", parameters: nil, hasResult: true, 68 | callback: {(reply, error) in 69 | 70 | if let error = error { 71 | if case let WhiskError.httpError(description, statusCode) = error { 72 | 73 | print("Error: \(description) statusCode: \(statusCode))") 74 | 75 | if statusCode != 401 && statusCode != 404 && statusCode != 408 && statusCode != 500 { 76 | XCTFail("Error: \(description) statusCode: \(statusCode))") 77 | } 78 | 79 | } 80 | } 81 | 82 | if let reply = reply { 83 | 84 | print("Reply is \(reply)") 85 | XCTAssertNotNil(reply["activationId"]) 86 | let id = reply["activationId"] as! String 87 | print("Got id \(id)") 88 | } 89 | 90 | expectation.fulfill() 91 | 92 | 93 | }) 94 | } catch { 95 | print(error) 96 | XCTFail("Error invoking action \(error)") 97 | } 98 | 99 | waitForExpectations(timeout: Timeout, handler: { error in 100 | 101 | if let error = error { 102 | print("Error: \(error)") 103 | } 104 | }) 105 | } else { 106 | XCTFail("No credentials available to run test") 107 | } 108 | } 109 | 110 | func testWhiskQualifiedNameAction() { 111 | 112 | if let apiKey = apiKey, let apiSecret = apiSecret { 113 | // setup for async testing 114 | let expectation = self.expectation(description: "Whisk Callback") 115 | // allow for self-signed certificates 116 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main) 117 | 118 | let credentials = WhiskCredentials(accessKey: apiKey, accessToken: apiSecret) 119 | let whisk = Whisk(credentials: credentials) 120 | whisk.urlSession = session 121 | do { 122 | try whisk.invokeAction(qualifiedName: "/whisk.system/utils/date", parameters: nil, hasResult: true, callback: {(reply, error) in 123 | 124 | if let error = error { 125 | if case let WhiskError.httpError(description, statusCode) = error { 126 | 127 | print("Error: \(description) statusCode: \(statusCode))") 128 | 129 | if statusCode != 401 && statusCode != 404 && statusCode != 408 && statusCode != 500 { 130 | XCTFail("Error: \(description) statusCode: \(statusCode))") 131 | } 132 | 133 | } 134 | } 135 | 136 | if let reply = reply { 137 | 138 | print("Reply is \(reply)") 139 | XCTAssertNotNil(reply["activationId"]) 140 | let id = reply["activationId"] as! String 141 | print("Got id \(id)") 142 | } 143 | 144 | expectation.fulfill() 145 | 146 | 147 | }) 148 | } catch { 149 | print(error) 150 | XCTFail("Error invoking action \(error)") 151 | } 152 | 153 | waitForExpectations(timeout: Timeout, handler: { error in 154 | 155 | if let error = error { 156 | print("Error: \(error)") 157 | } 158 | }) 159 | } else { 160 | XCTFail("No credentials available to run test") 161 | } 162 | } 163 | 164 | func testWhiskSettingBaseUrl() { 165 | 166 | if let apiKey = apiKey, let apiSecret = apiSecret { 167 | // setup for async testing 168 | let expectation = self.expectation(description: "Whisk Callback") 169 | 170 | // allow for self-signed certificates 171 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main) 172 | 173 | let credentials = WhiskCredentials(accessKey: apiKey, accessToken: apiSecret) 174 | let whisk = Whisk(credentials: credentials) 175 | whisk.urlSession = session 176 | 177 | do { 178 | whisk.baseURL = "https://openwhisk.ng.bluemix.net" 179 | 180 | try whisk.invokeAction(qualifiedName: "/whisk.system/utils/date", parameters: nil, hasResult: true, callback: {(reply, error) in 181 | 182 | if let error = error { 183 | if case let WhiskError.httpError(description, statusCode) = error { 184 | 185 | print("Error: \(description) statusCode: \(statusCode))") 186 | 187 | if statusCode != 401 && statusCode != 404 && statusCode != 408 && statusCode != 500 { 188 | XCTFail("Error: \(description) statusCode: \(statusCode))") 189 | } 190 | 191 | } 192 | } 193 | 194 | if let reply = reply { 195 | 196 | print("Reply is \(reply)") 197 | XCTAssertNotNil(reply["activationId"]) 198 | let id = reply["activationId"] as! String 199 | print("Got id \(id)") 200 | } 201 | 202 | expectation.fulfill() 203 | 204 | 205 | }) 206 | } catch { 207 | print(error) 208 | XCTFail("Error invoking action \(error)") 209 | } 210 | 211 | waitForExpectations(timeout: Timeout, handler: { error in 212 | 213 | if let error = error { 214 | print("Error: \(error)") 215 | } 216 | }) 217 | 218 | } else { 219 | XCTFail("No credentials available to run test") 220 | } 221 | } 222 | 223 | func testWhiskVerboseReplies() { 224 | 225 | if let apiKey = apiKey, let apiSecret = apiSecret { 226 | // setup for async testing 227 | let expectation = self.expectation(description: "Whisk Callback") 228 | 229 | // allow for self-signed certificates 230 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main) 231 | 232 | let credentials = WhiskCredentials(accessKey: apiKey, accessToken: apiSecret) 233 | let whisk = Whisk(credentials: credentials) 234 | whisk.urlSession = session 235 | whisk.baseURL = "https://openwhisk.ng.bluemix.net" 236 | 237 | do { 238 | whisk.verboseReplies = true 239 | 240 | try whisk.invokeAction(qualifiedName: "/whisk.system/utils/date", parameters: nil, hasResult: true, callback: {(reply, error) in 241 | 242 | if let error = error { 243 | if case let WhiskError.httpError(description, statusCode) = error { 244 | 245 | print("Error: \(description) statusCode: \(statusCode))") 246 | 247 | if statusCode != 401 && statusCode != 404 && statusCode != 408 && statusCode != 500 { 248 | XCTFail("Error: \(description) statusCode: \(statusCode))") 249 | } 250 | 251 | } 252 | } 253 | 254 | if let reply = reply { 255 | 256 | print("Reply is \(reply)") 257 | XCTAssertNotNil(reply["activationId"]) 258 | let id = reply["activationId"] as! String 259 | print("Got id \(id)") 260 | } 261 | 262 | expectation.fulfill() 263 | 264 | 265 | }) 266 | } catch { 267 | print(error) 268 | XCTFail("Error invoking action \(error)") 269 | } 270 | 271 | waitForExpectations(timeout: Timeout, handler: { error in 272 | 273 | if let error = error { 274 | print("Error: \(error)") 275 | } 276 | }) 277 | 278 | } else { 279 | XCTFail("No credentials available to run test") 280 | } 281 | } 282 | 283 | func testWhiskTrigger() { 284 | 285 | if let apiKey = apiKey, let apiSecret = apiSecret { 286 | // setup for async testing 287 | let expectation = self.expectation(description: "Whisk Callback") 288 | 289 | // allow for self-signed certificates 290 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main) 291 | 292 | let credentials = WhiskCredentials(accessKey: apiKey, accessToken: apiSecret) 293 | let whisk = Whisk(credentials: credentials) 294 | whisk.urlSession = session 295 | whisk.baseURL = "https://openwhisk.ng.bluemix.net" 296 | 297 | do { 298 | 299 | try whisk.fireTrigger(name: "myTrigger", callback: { (reply, error) in 300 | 301 | if let error = error { 302 | if case let WhiskError.httpError(description, statusCode) = error { 303 | 304 | print("Error: \(description) statusCode: \(statusCode))") 305 | 306 | // actually any of these status codes are probably OK since the API call succeeded 307 | if statusCode != 401 && statusCode != 404 && statusCode != 408 && statusCode != 500 { 308 | XCTFail("Error: \(description) statusCode: \(statusCode))") 309 | } 310 | 311 | } 312 | } else if let reply = reply { 313 | print("\(reply)") 314 | } else { 315 | print("No error or response") 316 | } 317 | }) 318 | 319 | expectation.fulfill() 320 | 321 | } catch { 322 | print(error) 323 | XCTFail("Error invoking trigger \(error)") 324 | } 325 | 326 | waitForExpectations(timeout: Timeout, handler: { error in 327 | 328 | if let error = error { 329 | print("Error: \(error)") 330 | } 331 | }) 332 | 333 | } else { 334 | XCTFail("No credentials available to run test") 335 | } 336 | } 337 | 338 | } 339 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import PackageDescription 19 | 20 | let package = Package( 21 | name: "OpenWhisk", 22 | exclude: ["OpenWhiskWatch","OpenWhiskTests", "OpenWhisk/OpenWhiskButton.swift"] 23 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift Client SDK for OpenWhisk 2 | 3 | [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0) 4 | [![Build Status](https://api.travis-ci.org/apache/incubator-openwhisk-client-swift.svg?branch=master)](https://api.travis-ci.org/apache/incubator-openwhisk-client-swift) 5 | 6 | This is a Swift-based client SDK for OpenWhisk. You can use it to connect to the [IBM Cloud Functions service](https://www.ibm.com/cloud/functions), or you own installation of [Apache OpenWhisk](https://github.com/apache/incubator-openwhisk). It partially implements the OpenWhisk [REST API](https://github.com/apache/incubator-openwhisk/blob/master/docs/reference.md#rest-api) and allows you to invoke actions and fire triggers. The client SDK is compatible with Swift 4.x and runs on iOS 11, WatchOS 4, and Darwin. Since this code uses classes like URLSession, Linux support is linked to the current status of [Foundation on Linux](https://github.com/apple/swift-corelibs-foundation). 7 | 8 | ## Installation 9 | You can install the SDK using the source code in this repo, as a Cocoapod for iOS and WatchOS apps, Carthage, and as a package using the Swift Package Manager for Darwin CLI apps. 10 | 11 | ### Source Code Installation 12 | To build the source code: 13 | - Clone this repo. 14 | - Open the `OpenWhisk.xcodeproj` file in Xcode 9.x 15 | - Build the OpenWhisk target for an iOS app or the OpenWhiskWatch target for a WatchOS app. 16 | - Locate the binary framework file (usually in `debug` or `release` directories at `~/Library/Developer/Xcode/DerivedData/$projectName-*`) and add it to the "Embedded Binaries" list in the General settings of your apps' target. 17 | 18 | ### CocoaPods Installation 19 | The [official CocoaPods website](http://cocoapods.org) has detailed instructions on how to install and use CocoaPods. 20 | 21 | The following lines in a Podfile will install the SDK for an iOS app with a watch OS extension: 22 | 23 | ``` 24 | install! 'cocoapods', :deterministic_uuids => false 25 | use_frameworks! 26 | 27 | target 'MyApp' do 28 | pod 'OpenWhisk', :git => 'https://github.com/apache/incubator-openwhisk-client-swift.git', :tag => '0.3.0' 29 | end 30 | 31 | target 'MyApp WatchKit Extension' do 32 | pod 'OpenWhisk', :git => 'https://github.com/apache/incubator-openwhisk-client-swift.git', :tag => '0.3.0' 33 | end 34 | ``` 35 | You may get the warning 'target overrides the `EMBEDDED_CONTENT_CONTAINS_SWIFT` ' when you have a watch target. You can eliminate this warning by changing this setting in "Build Settings" to the value '$(inherited)'. 36 | 37 | After installation, open your project workspace. You may get the following warning when building: 38 | `Use Legacy Swift Language Version” (SWIFT_VERSION) is required to be configured correctly for targets which use Swift. Use the [Edit > Convert > To Current Swift Syntax…] menu to choose a Swift version or use the Build Settings editor to configure the build setting directly.` 39 | This is caused if Cocoapods does not update the Swift version in the Pods project. To fix, select the Pods project and the OpenWhisk target. Go to Build Settings and change the setting `Use Legacy Swift Language Version` to `no`. You can also add the following post installation instructions at the end of you Podfile: 40 | 41 | ``` 42 | post_install do |installer| 43 | installer.pods_project.targets.each do |target| 44 | target.build_configurations.each do |config| 45 | config.build_settings['SWIFT_VERSION'] = '4.0' 46 | end 47 | end 48 | end 49 | ``` 50 | 51 | ### Carthage Installation 52 | 53 | Visit the [official Carthage site on Github](https://github.com/Carthage/Carthage) for detailed instructions on installing and using Carthage. 54 | 55 | Here is an example Cartfile for iOS installation using Carthage: 56 | 57 | ``` 58 | github "openwhisk/openwhisk-client-swift.git" ~> 0.3.0 # Or latest version 59 | 60 | ``` 61 | 62 | ### Swift Package Manager 63 | Use the Swift Package Manager to install into a Darwin CLI app. Below is an example Package.swift manifest file you can use: 64 | 65 | ``` 66 | import PackageDescription 67 | 68 | let package = Package( 69 | name: "PackageTest", 70 | dependencies: [ 71 | .Package(url: "https://github.com/apache/incubator-openwhisk-client-swift.git", versions: Version(0,0,0)..() 106 | params["payload"] = "Hi from mobile" 107 | 108 | do { 109 | try whisk.invokeAction(name: "helloConsole", package: "mypackage", namespace: "mynamespace", parameters: params, hasResult: false, callback: {(reply, error) -> Void in 110 | if let error = error { 111 | //do something 112 | print("Error invoking action \(error.localizedDescription)") 113 | } else { 114 | print("Action invoked!") 115 | } 116 | 117 | }) 118 | } catch { 119 | print("Error \(error)") 120 | } 121 | ``` 122 | 123 | In the above example, we are invoking the "helloConsole" action using the default namespace. 124 | 125 | ### Fire an OpenWhisk Trigger 126 | To fire a remote OpenWhisk trigger, call the "fireTrigger" method. Pass in parameters as required using a dictionary. 127 | 128 | ```swift 129 | // In this example we are firing a trigger when our location has changed by a certain amount 130 | 131 | var locationParams = Dictionary() 132 | locationParams["payload"] = "{\"lat\":41.27093, \"lon\":-73.77763}" 133 | 134 | do { 135 | try whisk.fireTrigger(name: "locationChanged", package: "mypackage", namespace: "mynamespace", parameters: locationParams, callback: {(reply, error) -> Void in 136 | 137 | if let error = error { 138 | print("Error firing trigger \(error.localizedDescription)") 139 | } else { 140 | print("Trigger fired!") 141 | } 142 | }) 143 | } catch { 144 | print("Error \(error)") 145 | } 146 | ``` 147 | In the above example, we are firing a trigger "locationChanged". 148 | 149 | ### Actions that return a result 150 | If the action returns a result, set hasResult to true in the invokeAction call. The result of the action is returned in the reply dictionary, for example: 151 | 152 | ```swift 153 | do { 154 | try whisk.invokeAction(name: "actionWithResult", package: "mypackage", namespace: "mynamespace", parameters: params, hasResult: true, callback: {(reply, error) -> Void in 155 | 156 | if let error = error { 157 | //do something 158 | print("Error invoking action \(error.localizedDescription)") 159 | 160 | } else { 161 | var result = reply["result"] 162 | print("Got result \(result)") 163 | } 164 | 165 | 166 | }) 167 | } catch { 168 | print("Error \(error)") 169 | } 170 | ``` 171 | By default, the SDK will only return the activationId and any result produced by the invoked action. To get metadata of the entire response object, which includes the HTTP response status code and the REST API URL the SDK tried to call, use this setting: 172 | 173 | ``` 174 | whisk.verboseReplies = true 175 | ``` 176 | 177 | The REST API URL called will be in the actionUrl/triggerUrl fields of the response. 178 | 179 | ## SDK configuration 180 | 181 | You can configure the SDK to work with different installations of OpenWhisk using the baseURL parameter. For instance: 182 | 183 | ```swift 184 | whisk.baseURL = "http://localhost:8080" 185 | ``` 186 | will use an OpenWhisk running at localhost:8080. If you do not specify the baseUrl, the Mobile SDK will use the instance running at https://openwhisk.ng.bluemix.net 187 | 188 | You can pass in a custom URLSession in case you require special network handling. For example, you may have your own OpenWhisk installation that uses self-signed certificates: 189 | 190 | ```swift 191 | 192 | // create a network delegate that trusts everything 193 | class NetworkUtilsDelegate: NSObject, URLSessionDelegate { 194 | func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { 195 | 196 | completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) 197 | } 198 | } 199 | 200 | // create an URLSession that uses the trusting delegate 201 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: NetworkUtilsDelegate(), delegateQueue:OperationQueue.main) 202 | 203 | // set the SDK to use this urlSession instead of the default shared one 204 | whisk.urlSession = session 205 | ``` 206 | #### Support for Qualified Names 207 | All actions and triggers have a fully qualified name which is made up of a namespace, a package, and an action/trigger name. The SDK can accept these as parameters when invoking an action or firing a trigger. The SDK also provides a function that accepts a fully qualified name that looks like "/mynamespace/mypackage/nameOfActionOrTrigger". The qualified name string supports unnamed default values for namespaces and packages that all OpenWhisk users have, so the following parsing rules apply: 208 | 209 | 1. qName = "foo" will result in namespace = default, package = default, action/trigger = "foo" 210 | 2. qName = "mypackage/foo" will result in namespace = default, package = mypackage, action/trigger = "foo" 211 | 3. qName = "/mynamespace/foo" will result in namespace = mynamespace, package = default, action/trigger = "foo" 212 | 4. qName = "/mynamespace/mypackage/foo will result in namespace = mynamespace, package = mypackage, action/trigger = "foo" 213 | 214 | All other combinations will throw a WhiskError.QualifiedName error. When using qualified names, you must wrap the call in a do/try/catch block. 215 | 216 | #### SDK Button 217 | For convenience, the iOS version of the SDK includes a WhiskButton, which extends the UIButton to allow it to invoke OpenWhisk actions. To use this: 218 | 219 | ```swift 220 | var whiskButton = WhiskButton(frame: CGRectMake(0,0,20,20)) 221 | 222 | whiskButton.setupWhiskAction("helloConsole", package: "mypackage", namespace: "_", credentials: credentialsConfiguration!, hasResult: false, parameters: nil, urlSession: nil) 223 | 224 | let myParams = ["name":"value"] 225 | 226 | // Call this when you detect a press event, e.g. in an IBAction, to invoke the action 227 | whiskButton.invokeAction(parameters: myParams, callback: { reply, error in 228 | if let error = error { 229 | print("Oh no, error: \(error)") 230 | } else { 231 | print("Success: \(reply)") 232 | } 233 | }) 234 | 235 | // or alternatively you can setup a "self contained" button that listens for press events on itself and invokes an action 236 | 237 | var whiskButtonSelfContained = WhiskButton(frame: CGRectMake(0,0,20,20)) 238 | whiskButtonSelfContained.listenForPressEvents = true 239 | do { 240 | 241 | // use qualified name API which requires do/try/catch 242 | try whiskButtonSelfContained.setupWhiskAction("mypackage/helloConsole", credentials: credentialsConfiguration!, hasResult: false, parameters: nil, urlSession: nil) 243 | whiskButtonSelfContained.actionButtonCallback = { reply, error in 244 | 245 | if let error = error { 246 | print("Oh no, error: \(error)") 247 | } else { 248 | print("Success: \(reply)") 249 | } 250 | } 251 | } catch { 252 | print("Error setting up button \(error)") 253 | } 254 | 255 | ``` 256 | 257 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/.gitignore: -------------------------------------------------------------------------------- 1 | OpenWhiskStarterApp.xcodeproj/xcuserdata/ 2 | OpenWhiskStarterApp.xcworkspace/ 3 | Podfile.lock 4 | Pods/ -------------------------------------------------------------------------------- /mobile/iOS/starterapp/Cartfile: -------------------------------------------------------------------------------- 1 | github "apache/incubator-openwhisk-client-swift.git" ~> 0.3.0 # Or latest version -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A876F95BF11B6113CAFD9683 /* Pods_OpenWhiskStarterApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C18E934BAB74A8F669FB576 /* Pods_OpenWhiskStarterApp.framework */; }; 11 | D65844461C727BBC001581F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65844451C727BBC001581F3 /* AppDelegate.swift */; }; 12 | D65844481C727BBC001581F3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65844471C727BBC001581F3 /* ViewController.swift */; }; 13 | D658444B1C727BBC001581F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D65844491C727BBC001581F3 /* Main.storyboard */; }; 14 | D658444D1C727BBC001581F3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D658444C1C727BBC001581F3 /* Assets.xcassets */; }; 15 | D65844501C727BBC001581F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D658444E1C727BBC001581F3 /* LaunchScreen.storyboard */; }; 16 | D658445D1C727C2D001581F3 /* FilterForecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65844571C727C2D001581F3 /* FilterForecast.swift */; }; 17 | D658445F1C727C2D001581F3 /* ResultSetCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D65844591C727C2D001581F3 /* ResultSetCell.swift */; }; 18 | D65844601C727C2D001581F3 /* ResultSetTableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D658445A1C727C2D001581F3 /* ResultSetTableController.swift */; }; 19 | D65844611C727C2D001581F3 /* SelfSignedNetworkDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D658445B1C727C2D001581F3 /* SelfSignedNetworkDelegate.swift */; }; 20 | D65844621C727C2D001581F3 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D658445C1C727C2D001581F3 /* Utils.swift */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXCopyFilesBuildPhase section */ 24 | D648FD291C72804F0088C7C1 /* Embed Frameworks */ = { 25 | isa = PBXCopyFilesBuildPhase; 26 | buildActionMask = 2147483647; 27 | dstPath = ""; 28 | dstSubfolderSpec = 10; 29 | files = ( 30 | ); 31 | name = "Embed Frameworks"; 32 | runOnlyForDeploymentPostprocessing = 0; 33 | }; 34 | /* End PBXCopyFilesBuildPhase section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 2959AF4398B3AA80564C2D04 /* Pods-OpenWhiskStarterApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenWhiskStarterApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OpenWhiskStarterApp/Pods-OpenWhiskStarterApp.debug.xcconfig"; sourceTree = ""; }; 38 | 8C18E934BAB74A8F669FB576 /* Pods_OpenWhiskStarterApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OpenWhiskStarterApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | D65844421C727BBC001581F3 /* OpenWhiskStarterApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenWhiskStarterApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | D65844451C727BBC001581F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | D65844471C727BBC001581F3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 42 | D658444A1C727BBC001581F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43 | D658444C1C727BBC001581F3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 44 | D658444F1C727BBC001581F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 45 | D65844511C727BBC001581F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | D65844571C727C2D001581F3 /* FilterForecast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterForecast.swift; sourceTree = ""; }; 47 | D65844591C727C2D001581F3 /* ResultSetCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultSetCell.swift; sourceTree = ""; }; 48 | D658445A1C727C2D001581F3 /* ResultSetTableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultSetTableController.swift; sourceTree = ""; }; 49 | D658445B1C727C2D001581F3 /* SelfSignedNetworkDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfSignedNetworkDelegate.swift; sourceTree = ""; }; 50 | D658445C1C727C2D001581F3 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 51 | FAF80DAB673A9E7E8AC1D44E /* Pods-OpenWhiskStarterApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OpenWhiskStarterApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-OpenWhiskStarterApp/Pods-OpenWhiskStarterApp.release.xcconfig"; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | D658443F1C727BBC001581F3 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | A876F95BF11B6113CAFD9683 /* Pods_OpenWhiskStarterApp.framework in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 19C2AB47312D7E18E83745BD /* Pods */ = { 67 | isa = PBXGroup; 68 | children = ( 69 | 2959AF4398B3AA80564C2D04 /* Pods-OpenWhiskStarterApp.debug.xcconfig */, 70 | FAF80DAB673A9E7E8AC1D44E /* Pods-OpenWhiskStarterApp.release.xcconfig */, 71 | ); 72 | name = Pods; 73 | sourceTree = ""; 74 | }; 75 | 23725AC2F19C7559B0E0A283 /* Frameworks */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 8C18E934BAB74A8F669FB576 /* Pods_OpenWhiskStarterApp.framework */, 79 | ); 80 | name = Frameworks; 81 | sourceTree = ""; 82 | }; 83 | D65844391C727BBC001581F3 = { 84 | isa = PBXGroup; 85 | children = ( 86 | D65844441C727BBC001581F3 /* OpenWhiskStarterApp */, 87 | D65844431C727BBC001581F3 /* Products */, 88 | 19C2AB47312D7E18E83745BD /* Pods */, 89 | 23725AC2F19C7559B0E0A283 /* Frameworks */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | D65844431C727BBC001581F3 /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | D65844421C727BBC001581F3 /* OpenWhiskStarterApp.app */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | D65844441C727BBC001581F3 /* OpenWhiskStarterApp */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | D65844451C727BBC001581F3 /* AppDelegate.swift */, 105 | D65844471C727BBC001581F3 /* ViewController.swift */, 106 | D65844571C727C2D001581F3 /* FilterForecast.swift */, 107 | D65844591C727C2D001581F3 /* ResultSetCell.swift */, 108 | D658445A1C727C2D001581F3 /* ResultSetTableController.swift */, 109 | D658445B1C727C2D001581F3 /* SelfSignedNetworkDelegate.swift */, 110 | D658445C1C727C2D001581F3 /* Utils.swift */, 111 | D65844491C727BBC001581F3 /* Main.storyboard */, 112 | D658444C1C727BBC001581F3 /* Assets.xcassets */, 113 | D658444E1C727BBC001581F3 /* LaunchScreen.storyboard */, 114 | D65844511C727BBC001581F3 /* Info.plist */, 115 | ); 116 | path = OpenWhiskStarterApp; 117 | sourceTree = ""; 118 | }; 119 | /* End PBXGroup section */ 120 | 121 | /* Begin PBXNativeTarget section */ 122 | D65844411C727BBC001581F3 /* OpenWhiskStarterApp */ = { 123 | isa = PBXNativeTarget; 124 | buildConfigurationList = D65844541C727BBC001581F3 /* Build configuration list for PBXNativeTarget "OpenWhiskStarterApp" */; 125 | buildPhases = ( 126 | 0D555FCCEFEA3E092AB6381A /* [CP] Check Pods Manifest.lock */, 127 | D658443E1C727BBC001581F3 /* Sources */, 128 | D658443F1C727BBC001581F3 /* Frameworks */, 129 | D65844401C727BBC001581F3 /* Resources */, 130 | D648FD291C72804F0088C7C1 /* Embed Frameworks */, 131 | 17B39CA85AFF9440A7860D2E /* [CP] Embed Pods Frameworks */, 132 | ); 133 | buildRules = ( 134 | ); 135 | dependencies = ( 136 | ); 137 | name = OpenWhiskStarterApp; 138 | productName = OpenWhiskStarterApp; 139 | productReference = D65844421C727BBC001581F3 /* OpenWhiskStarterApp.app */; 140 | productType = "com.apple.product-type.application"; 141 | }; 142 | /* End PBXNativeTarget section */ 143 | 144 | /* Begin PBXProject section */ 145 | D658443A1C727BBC001581F3 /* Project object */ = { 146 | isa = PBXProject; 147 | attributes = { 148 | LastSwiftUpdateCheck = 0720; 149 | LastUpgradeCheck = 0930; 150 | ORGANIZATIONNAME = IBM; 151 | TargetAttributes = { 152 | D65844411C727BBC001581F3 = { 153 | CreatedOnToolsVersion = 7.2.1; 154 | DevelopmentTeam = 76CMF53Q35; 155 | LastSwiftMigration = 0930; 156 | }; 157 | }; 158 | }; 159 | buildConfigurationList = D658443D1C727BBC001581F3 /* Build configuration list for PBXProject "OpenWhiskStarterApp" */; 160 | compatibilityVersion = "Xcode 3.2"; 161 | developmentRegion = English; 162 | hasScannedForEncodings = 0; 163 | knownRegions = ( 164 | en, 165 | Base, 166 | ); 167 | mainGroup = D65844391C727BBC001581F3; 168 | productRefGroup = D65844431C727BBC001581F3 /* Products */; 169 | projectDirPath = ""; 170 | projectRoot = ""; 171 | targets = ( 172 | D65844411C727BBC001581F3 /* OpenWhiskStarterApp */, 173 | ); 174 | }; 175 | /* End PBXProject section */ 176 | 177 | /* Begin PBXResourcesBuildPhase section */ 178 | D65844401C727BBC001581F3 /* Resources */ = { 179 | isa = PBXResourcesBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | D65844501C727BBC001581F3 /* LaunchScreen.storyboard in Resources */, 183 | D658444D1C727BBC001581F3 /* Assets.xcassets in Resources */, 184 | D658444B1C727BBC001581F3 /* Main.storyboard in Resources */, 185 | ); 186 | runOnlyForDeploymentPostprocessing = 0; 187 | }; 188 | /* End PBXResourcesBuildPhase section */ 189 | 190 | /* Begin PBXShellScriptBuildPhase section */ 191 | 0D555FCCEFEA3E092AB6381A /* [CP] Check Pods Manifest.lock */ = { 192 | isa = PBXShellScriptBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | ); 196 | inputPaths = ( 197 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 198 | "${PODS_ROOT}/Manifest.lock", 199 | ); 200 | name = "[CP] Check Pods Manifest.lock"; 201 | outputPaths = ( 202 | "$(DERIVED_FILE_DIR)/Pods-OpenWhiskStarterApp-checkManifestLockResult.txt", 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | shellPath = /bin/sh; 206 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 207 | showEnvVarsInLog = 0; 208 | }; 209 | 17B39CA85AFF9440A7860D2E /* [CP] Embed Pods Frameworks */ = { 210 | isa = PBXShellScriptBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | ); 214 | inputPaths = ( 215 | "${SRCROOT}/Pods/Target Support Files/Pods-OpenWhiskStarterApp/Pods-OpenWhiskStarterApp-frameworks.sh", 216 | "${BUILT_PRODUCTS_DIR}/OpenWhisk/OpenWhisk.framework", 217 | ); 218 | name = "[CP] Embed Pods Frameworks"; 219 | outputPaths = ( 220 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenWhisk.framework", 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | shellPath = /bin/sh; 224 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OpenWhiskStarterApp/Pods-OpenWhiskStarterApp-frameworks.sh\"\n"; 225 | showEnvVarsInLog = 0; 226 | }; 227 | /* End PBXShellScriptBuildPhase section */ 228 | 229 | /* Begin PBXSourcesBuildPhase section */ 230 | D658443E1C727BBC001581F3 /* Sources */ = { 231 | isa = PBXSourcesBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | D65844481C727BBC001581F3 /* ViewController.swift in Sources */, 235 | D658445D1C727C2D001581F3 /* FilterForecast.swift in Sources */, 236 | D658445F1C727C2D001581F3 /* ResultSetCell.swift in Sources */, 237 | D65844601C727C2D001581F3 /* ResultSetTableController.swift in Sources */, 238 | D65844611C727C2D001581F3 /* SelfSignedNetworkDelegate.swift in Sources */, 239 | D65844461C727BBC001581F3 /* AppDelegate.swift in Sources */, 240 | D65844621C727C2D001581F3 /* Utils.swift in Sources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXSourcesBuildPhase section */ 245 | 246 | /* Begin PBXVariantGroup section */ 247 | D65844491C727BBC001581F3 /* Main.storyboard */ = { 248 | isa = PBXVariantGroup; 249 | children = ( 250 | D658444A1C727BBC001581F3 /* Base */, 251 | ); 252 | name = Main.storyboard; 253 | sourceTree = ""; 254 | }; 255 | D658444E1C727BBC001581F3 /* LaunchScreen.storyboard */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | D658444F1C727BBC001581F3 /* Base */, 259 | ); 260 | name = LaunchScreen.storyboard; 261 | sourceTree = ""; 262 | }; 263 | /* End PBXVariantGroup section */ 264 | 265 | /* Begin XCBuildConfiguration section */ 266 | D65844521C727BBC001581F3 /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 275 | CLANG_WARN_BOOL_CONVERSION = YES; 276 | CLANG_WARN_COMMA = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 280 | CLANG_WARN_EMPTY_BODY = YES; 281 | CLANG_WARN_ENUM_CONVERSION = YES; 282 | CLANG_WARN_INFINITE_RECURSION = YES; 283 | CLANG_WARN_INT_CONVERSION = YES; 284 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 285 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 286 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 289 | CLANG_WARN_STRICT_PROTOTYPES = YES; 290 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 294 | COPY_PHASE_STRIP = NO; 295 | DEBUG_INFORMATION_FORMAT = dwarf; 296 | ENABLE_STRICT_OBJC_MSGSEND = YES; 297 | ENABLE_TESTABILITY = YES; 298 | GCC_C_LANGUAGE_STANDARD = gnu99; 299 | GCC_DYNAMIC_NO_PIC = NO; 300 | GCC_NO_COMMON_BLOCKS = YES; 301 | GCC_OPTIMIZATION_LEVEL = 0; 302 | GCC_PREPROCESSOR_DEFINITIONS = ( 303 | "DEBUG=1", 304 | "$(inherited)", 305 | ); 306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 307 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 308 | GCC_WARN_UNDECLARED_SELECTOR = YES; 309 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 310 | GCC_WARN_UNUSED_FUNCTION = YES; 311 | GCC_WARN_UNUSED_VARIABLE = YES; 312 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 313 | MTL_ENABLE_DEBUG_INFO = YES; 314 | ONLY_ACTIVE_ARCH = YES; 315 | SDKROOT = iphoneos; 316 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 317 | TARGETED_DEVICE_FAMILY = "1,2"; 318 | }; 319 | name = Debug; 320 | }; 321 | D65844531C727BBC001581F3 /* Release */ = { 322 | isa = XCBuildConfiguration; 323 | buildSettings = { 324 | ALWAYS_SEARCH_USER_PATHS = NO; 325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 326 | CLANG_CXX_LIBRARY = "libc++"; 327 | CLANG_ENABLE_MODULES = YES; 328 | CLANG_ENABLE_OBJC_ARC = YES; 329 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 330 | CLANG_WARN_BOOL_CONVERSION = YES; 331 | CLANG_WARN_COMMA = YES; 332 | CLANG_WARN_CONSTANT_CONVERSION = YES; 333 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 335 | CLANG_WARN_EMPTY_BODY = YES; 336 | CLANG_WARN_ENUM_CONVERSION = YES; 337 | CLANG_WARN_INFINITE_RECURSION = YES; 338 | CLANG_WARN_INT_CONVERSION = YES; 339 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 340 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 341 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 343 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 344 | CLANG_WARN_STRICT_PROTOTYPES = YES; 345 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 346 | CLANG_WARN_UNREACHABLE_CODE = YES; 347 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 348 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 349 | COPY_PHASE_STRIP = NO; 350 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 351 | ENABLE_NS_ASSERTIONS = NO; 352 | ENABLE_STRICT_OBJC_MSGSEND = YES; 353 | GCC_C_LANGUAGE_STANDARD = gnu99; 354 | GCC_NO_COMMON_BLOCKS = YES; 355 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 356 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 357 | GCC_WARN_UNDECLARED_SELECTOR = YES; 358 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 359 | GCC_WARN_UNUSED_FUNCTION = YES; 360 | GCC_WARN_UNUSED_VARIABLE = YES; 361 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 362 | MTL_ENABLE_DEBUG_INFO = NO; 363 | SDKROOT = iphoneos; 364 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 365 | TARGETED_DEVICE_FAMILY = "1,2"; 366 | VALIDATE_PRODUCT = YES; 367 | }; 368 | name = Release; 369 | }; 370 | D65844551C727BBC001581F3 /* Debug */ = { 371 | isa = XCBuildConfiguration; 372 | baseConfigurationReference = 2959AF4398B3AA80564C2D04 /* Pods-OpenWhiskStarterApp.debug.xcconfig */; 373 | buildSettings = { 374 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CODE_SIGN_IDENTITY = "iPhone Developer"; 377 | FRAMEWORK_SEARCH_PATHS = ( 378 | "$(inherited)", 379 | "$(PROJECT_DIR)", 380 | ); 381 | INFOPLIST_FILE = OpenWhiskStarterApp/Info.plist; 382 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 383 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 384 | PRODUCT_BUNDLE_IDENTIFIER = com.ibm.mobile.openwhisk.OpenWhiskStarterApp; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 387 | SWIFT_VERSION = 4.0; 388 | }; 389 | name = Debug; 390 | }; 391 | D65844561C727BBC001581F3 /* Release */ = { 392 | isa = XCBuildConfiguration; 393 | baseConfigurationReference = FAF80DAB673A9E7E8AC1D44E /* Pods-OpenWhiskStarterApp.release.xcconfig */; 394 | buildSettings = { 395 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 396 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 397 | CODE_SIGN_IDENTITY = "iPhone Developer"; 398 | FRAMEWORK_SEARCH_PATHS = ( 399 | "$(inherited)", 400 | "$(PROJECT_DIR)", 401 | ); 402 | INFOPLIST_FILE = OpenWhiskStarterApp/Info.plist; 403 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 404 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 405 | PRODUCT_BUNDLE_IDENTIFIER = com.ibm.mobile.openwhisk.OpenWhiskStarterApp; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 408 | SWIFT_VERSION = 4.0; 409 | }; 410 | name = Release; 411 | }; 412 | /* End XCBuildConfiguration section */ 413 | 414 | /* Begin XCConfigurationList section */ 415 | D658443D1C727BBC001581F3 /* Build configuration list for PBXProject "OpenWhiskStarterApp" */ = { 416 | isa = XCConfigurationList; 417 | buildConfigurations = ( 418 | D65844521C727BBC001581F3 /* Debug */, 419 | D65844531C727BBC001581F3 /* Release */, 420 | ); 421 | defaultConfigurationIsVisible = 0; 422 | defaultConfigurationName = Release; 423 | }; 424 | D65844541C727BBC001581F3 /* Build configuration list for PBXNativeTarget "OpenWhiskStarterApp" */ = { 425 | isa = XCConfigurationList; 426 | buildConfigurations = ( 427 | D65844551C727BBC001581F3 /* Debug */, 428 | D65844561C727BBC001581F3 /* Release */, 429 | ); 430 | defaultConfigurationIsVisible = 0; 431 | defaultConfigurationName = Release; 432 | }; 433 | /* End XCConfigurationList section */ 434 | }; 435 | rootObject = D658443A1C727BBC001581F3 /* Project object */; 436 | } 437 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp.xcodeproj/xcshareddata/xcschemes/OpenWhiskStarterApp.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | import UIKit 20 | 21 | @UIApplicationMain 22 | class AppDelegate: UIResponder, UIApplicationDelegate { 23 | 24 | var window: UIWindow? 25 | 26 | 27 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 28 | // Override point for customization after application launch. 29 | return true 30 | } 31 | 32 | func applicationWillResignActive(_ application: UIApplication) { 33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 34 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 35 | } 36 | 37 | func applicationDidEnterBackground(_ application: UIApplication) { 38 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | func applicationWillEnterForeground(_ application: UIApplication) { 43 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 44 | } 45 | 46 | func applicationDidBecomeActive(_ application: UIApplication) { 47 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 48 | } 49 | 50 | func applicationWillTerminate(_ application: UIApplication) { 51 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 52 | } 53 | 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/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 | 27 | 28 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 97 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/FilterForecast.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | import Foundation 20 | 21 | func main(args:[String:Any]) -> [String:Any] { 22 | let NumDays = 2 23 | var filteredForecasts = [[String:Any]]() 24 | #if os(Linux) 25 | if let forecasts = args["forecasts"] as? [Any] { 26 | for day in 0...(NumDays - 1) { 27 | if let forecast = forecasts[day] as? [String:Any] { 28 | var terse = [String:Any]() 29 | terse["dow"] = forecast["dow"] 30 | terse["narrative"] = forecast["narrative"] 31 | terse["min_temp"] = forecast["min_temp"] 32 | terse["max_temp"] = forecast["max_temp"] 33 | filteredForecasts.append(terse) 34 | } 35 | } 36 | } 37 | #else 38 | if let forecasts = args["forecasts"] as? [[String:AnyObject]] { 39 | for day in 0...(NumDays - 1) { 40 | let forecast = forecasts[day] as [String:AnyObject] 41 | var terse = [String:Any]() 42 | terse["dow"] = forecast["dow"] 43 | terse["narrative"] = forecast["narrative"] 44 | terse["min_temp"] = forecast["min_temp"] 45 | terse["max_temp"] = forecast["max_temp"] 46 | filteredForecasts.append(terse) 47 | 48 | } 49 | } 50 | 51 | #endif 52 | return [ "forecasts": filteredForecasts ] 53 | } 54 | 55 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSLocationWhenInUseUsageDescription 6 | Location used for demo purposes. 7 | CFBundleDisplayName 8 | 9 | NSBluetoothPeripheralUsageDescription 10 | 11 | LSApplicationCategoryType 12 | 13 | CFBundleDevelopmentRegion 14 | en 15 | CFBundleExecutable 16 | $(EXECUTABLE_NAME) 17 | CFBundleIdentifier 18 | $(PRODUCT_BUNDLE_IDENTIFIER) 19 | CFBundleInfoDictionaryVersion 20 | 6.0 21 | CFBundleName 22 | $(PRODUCT_NAME) 23 | CFBundlePackageType 24 | APPL 25 | CFBundleShortVersionString 26 | 1.0 27 | CFBundleSignature 28 | ???? 29 | CFBundleVersion 30 | 1 31 | LSRequiresIPhoneOS 32 | 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UIRequiredDeviceCapabilities 38 | 39 | armv7 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UISupportedInterfaceOrientations~ipad 48 | 49 | UIInterfaceOrientationPortrait 50 | UIInterfaceOrientationPortraitUpsideDown 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/ResultSetCell.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | import UIKit 20 | 21 | class ResultSetCell: UITableViewCell { 22 | 23 | @IBOutlet weak var valueLabel: UILabel! 24 | @IBOutlet weak var nameLabel: UILabel! 25 | 26 | } 27 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/ResultSetTableController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import UIKit 19 | 20 | class ResultSetTableController: UITableViewController { 21 | 22 | var resultSet: [String: AnyObject]! 23 | var names = [String]() 24 | var values = [String]() 25 | var isComplex = [Bool]() 26 | 27 | override func viewDidLoad() { 28 | super.viewDidLoad() 29 | 30 | 31 | tableView.estimatedRowHeight = 44 32 | tableView.rowHeight = UITableViewAutomaticDimension 33 | 34 | navigationItem.title = "Action Results" 35 | 36 | reloadTable() 37 | } 38 | 39 | func reloadTable() { 40 | 41 | names = [String]() 42 | values = [String]() 43 | 44 | if let resultSet = resultSet , resultSet.count > 0 { 45 | for (name, value) in resultSet { 46 | names.append(name) 47 | 48 | if let value = (value as? String) { 49 | values.append(value) 50 | isComplex.append(false) 51 | } else { 52 | if value is Bool { 53 | if (value as! Bool) == true { 54 | values.append("true") 55 | } else { 56 | values.append("false") 57 | } 58 | isComplex.append(false) 59 | } else if value is NSNumber { 60 | values.append(value.stringValue) 61 | isComplex.append(false) 62 | } else { 63 | do { 64 | let theJSONData = try JSONSerialization.data( 65 | withJSONObject: value , 66 | options: JSONSerialization.WritingOptions(rawValue: 0)) 67 | let theJSONText = NSString(data: theJSONData, 68 | encoding: String.Encoding.ascii.rawValue) 69 | values.append(theJSONText! as String) 70 | isComplex.append(true) 71 | } catch { 72 | print("Error converting value to JSON") 73 | values.append("Unknown type") 74 | isComplex.append(false) 75 | } 76 | } 77 | } 78 | } 79 | } 80 | 81 | 82 | } 83 | 84 | 85 | // MARK UITableViewDataSource 86 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 87 | return resultSet.count 88 | } 89 | 90 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 91 | let cell = tableView.dequeueReusableCell(withIdentifier: "resultCell") as! ResultSetCell 92 | 93 | cell.nameLabel.text = names[(indexPath as NSIndexPath).row] 94 | cell.valueLabel.text = values[(indexPath as NSIndexPath).row] 95 | 96 | if isComplex[(indexPath as NSIndexPath).row] == true { 97 | cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator 98 | } 99 | 100 | 101 | return cell 102 | 103 | } 104 | 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/SelfSignedNetworkDelegate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | import Foundation 20 | 21 | class SelfSignedNetworkDelegate: NSObject, URLSessionDelegate { 22 | func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { 23 | 24 | completionHandler(Foundation.URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/Utils.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | import Foundation 20 | 21 | func convertReply(input: [String:AnyObject]) -> [String:Any] { 22 | 23 | var output = [String:Any]() 24 | 25 | for (key, value) in input { 26 | if let value = value as? [[String: AnyObject]] { 27 | var newValue = [[String:Any]]() 28 | for dict in value { 29 | var newDict = [String:Any]() 30 | for (key2, value2) in dict { 31 | newDict[key2] = value2 32 | } 33 | newValue.append(newDict) 34 | } 35 | output[key] = newValue 36 | } 37 | } 38 | 39 | return output 40 | } 41 | 42 | func filterForecast(args:[String:Any]) -> [String:Any] { 43 | let NumDays = 2 44 | var filteredForecasts = [[String:Any]]() 45 | if let forecasts = args["forecasts"] as? [[String:Any]] { 46 | for day in 0...(NumDays - 1) { 47 | let forecast = forecasts[day] as [String:Any] 48 | var terse = [String:Any]() 49 | terse["dow"] = forecast["dow"] 50 | terse["narrative"] = forecast["narrative"] 51 | terse["min_temp"] = forecast["min_temp"] 52 | terse["max_temp"] = forecast["max_temp"] 53 | filteredForecasts.append(terse) 54 | } 55 | } 56 | return [ "forecasts": filteredForecasts ] 57 | } 58 | 59 | 60 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/OpenWhiskStarterApp/ViewController.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | import UIKit 20 | import OpenWhisk 21 | import CoreLocation 22 | 23 | class ViewController: UIViewController, CLLocationManagerDelegate { 24 | 25 | @IBOutlet weak var whiskButton: WhiskButton! 26 | @IBOutlet weak var outputText: UITextView! 27 | @IBOutlet weak var statusLabel: UILabel! 28 | 29 | // Change to your whisk app key and secret. 30 | let WhiskAppKey: String = "MyAppKey" 31 | let WhiskAppSecret: String = "MyAppSecret" 32 | 33 | // the URL for Whisk backend 34 | let baseUrl: String? = "https://openwhisk.ng.bluemix.net" 35 | 36 | // The action to invoke. 37 | 38 | // Choice: specify components 39 | let MyNamespace: String = "whisk.system" 40 | let MyPackage: String? = "utils" 41 | let MyWhiskAction: String = "date" 42 | 43 | var MyActionParameters: [String:AnyObject]? = nil 44 | let HasResult: Bool = true // true if the action returns a result 45 | 46 | var session: URLSession! 47 | 48 | let locationManager = CLLocationManager() 49 | var currentLocation: [CLLocation]? 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | // create custom session that allows self-signed certificates 55 | let session = URLSession(configuration: URLSessionConfiguration.default, delegate: SelfSignedNetworkDelegate(), delegateQueue:OperationQueue.main) 56 | 57 | // create whisk credentials token 58 | let creds = WhiskCredentials(accessKey: WhiskAppKey,accessToken: WhiskAppSecret) 59 | 60 | // Setup action using components 61 | whiskButton.setupWhiskAction(MyWhiskAction, package: MyPackage, namespace: MyNamespace, credentials: creds, hasResult: HasResult, parameters: MyActionParameters, urlSession: session, baseUrl: baseUrl) 62 | 63 | // setup location 64 | locationManager.delegate = self 65 | locationManager.requestWhenInUseAuthorization() 66 | 67 | navigationItem.title = "Whisk" 68 | 69 | } 70 | 71 | @IBAction func whiskButtonPressed(sender: AnyObject) { 72 | // Set latitude and longitude parameters. 73 | if let currentLocation = currentLocation { 74 | MyActionParameters = ["latitude": currentLocation[0].coordinate.latitude as AnyObject, "longitude": currentLocation[0].coordinate.longitude as AnyObject] 75 | } 76 | 77 | // Invoke action with parameters. 78 | whiskButton.invokeAction(parameters: MyActionParameters, actionCallback: { reply, error in 79 | if let error = error { 80 | print("Oh no! \(error)") 81 | if case let WhiskError.httpError(description, statusCode) = error { 82 | print("HttpError: \(description) statusCode:\(statusCode)") 83 | } 84 | } else if let reply = reply { 85 | let str = "\(reply)" 86 | print("reply: \(str)") 87 | self.statusLabel.text = "Action \(self.MyNamespace)/\(self.MyWhiskAction) returned \(str.count) characters" 88 | if let result = reply["result"] as? [String:AnyObject] { 89 | self.displayOutput(reply: result) 90 | } 91 | } else { 92 | print("Success") 93 | } 94 | }) 95 | } 96 | 97 | 98 | func displayOutput(reply: [String:AnyObject]) { 99 | if let date = reply["date"] as? String{ 100 | self.outputText.text = "The date is \(reformatDate(dateStr: date))" 101 | } 102 | } 103 | 104 | // Optional, can be used to display results in a UITableView 105 | func displayResultView(reply: [String: AnyObject]) { 106 | let storyboard = UIStoryboard(name: "Main", bundle: nil) 107 | let vc = storyboard.instantiateViewController(withIdentifier: "resultSetTable") as! ResultSetTableController 108 | vc.resultSet = reply 109 | self.navigationController?.pushViewController(vc, animated: true) 110 | } 111 | 112 | 113 | // CLLocationDelegate Functions 114 | func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 115 | print("Got location manager authorization status \(status)") 116 | locationManager.startUpdatingLocation() 117 | 118 | } 119 | 120 | func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 121 | currentLocation = locations 122 | } 123 | 124 | 125 | override func didReceiveMemoryWarning() { 126 | super.didReceiveMemoryWarning() 127 | // Dispose of any resources that can be recreated. 128 | } 129 | 130 | // Convert string timestamp to a display format 131 | func reformatDate(dateStr: String) -> String { 132 | 133 | var newDateStr = dateStr 134 | let formatter = DateFormatter() 135 | formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" 136 | 137 | formatter.timeZone = TimeZone(abbreviation: "UTC") //NSTimeZone(name: "UTC") 138 | 139 | if let date = formatter.date(from: dateStr) { 140 | formatter.dateFormat = "MMM dd EEEE yyyy HH:mm" 141 | formatter.timeZone = TimeZone(abbreviation: "UTC") 142 | newDateStr = formatter.string(from: date) 143 | } 144 | 145 | return newDateStr 146 | } 147 | 148 | 149 | } 150 | 151 | -------------------------------------------------------------------------------- /mobile/iOS/starterapp/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'OpenWhiskStarterApp' do 4 | platform :ios, '11.0' 5 | pod 'OpenWhisk', :git => 'https://github.com/apache/incubator-openwhisk-client-swift.git', :tag => '0.3.0' 6 | end 7 | 8 | post_install do |installer| 9 | installer.pods_project.targets.each do |target| 10 | target.build_configurations.each do |config| 11 | config.build_settings['SWIFT_VERSION'] = '4.0' 12 | end 13 | end 14 | end -------------------------------------------------------------------------------- /tools/travis/scancode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Build script for Travis-CI. 5 | SCRIPTDIR=$(cd $(dirname "$0") && pwd) 6 | ROOTDIR="$SCRIPTDIR/../.." 7 | UTIL_DIR="$ROOTDIR/../incubator-openwhisk-utilities" 8 | 9 | # run scancode 10 | cd $UTIL_DIR 11 | scancode/scanCode.py $ROOTDIR -------------------------------------------------------------------------------- /tools/travis/setupscan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPTDIR=$(cd $(dirname "$0") && pwd) 4 | HOMEDIR="$SCRIPTDIR/../../../" 5 | 6 | # clone OpenWhisk utilities repo. in order to run scanCode.py 7 | cd $HOMEDIR 8 | git clone https://github.com/apache/incubator-openwhisk-utilities.git 9 | --------------------------------------------------------------------------------