├── .github ├── FUNDING.yml └── workflows │ ├── cla.yaml │ ├── publish.yml │ └── test.yaml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── index.js ├── lib ├── certs.js ├── device.js ├── env.js ├── provisioning.js ├── sim_focus.scpt ├── sim_hide.scpt ├── simctl.js ├── simulator.js ├── teams.js ├── utilities.js └── xcode.js ├── package-lock.json ├── package.json └── test ├── TestApp ├── TestApp.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── TestApp.xcscheme └── TestApp │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ ├── Main_iPad.storyboard │ └── Main_iPhone.storyboard │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── TestApp-Info.plist │ ├── TestApp-Prefix.pch │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── TestWatchApp ├── TestWatchApp WatchKit App │ ├── Base.lproj │ │ └── Interface.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ └── Info.plist ├── TestWatchApp WatchKit Extension │ ├── GlanceController.h │ ├── GlanceController.m │ ├── Images.xcassets │ │ └── README__ignoredByTemplate__ │ ├── Info.plist │ ├── InterfaceController.h │ ├── InterfaceController.m │ ├── NotificationController.h │ ├── NotificationController.m │ └── PushNotificationPayload.apns ├── TestWatchApp.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── Glance - TestWatchApp WatchKit App.xcscheme │ │ ├── Notification - TestWatchApp WatchKit App.xcscheme │ │ ├── TestWatchApp WatchKit App.xcscheme │ │ └── TestWatchApp.xcscheme └── TestWatchApp │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ ├── Main_iPad.storyboard │ └── Main_iPhone.storyboard │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── TestWatchApp-Info.plist │ ├── TestWatchApp-Prefix.pch │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── TestWatchApp2 ├── TestWatchApp2 WatchKit App │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Interface.storyboard │ └── Info.plist ├── TestWatchApp2 WatchKit Extension │ ├── Assets.xcassets │ │ └── README__ignoredByTemplate__ │ ├── ExtensionDelegate.h │ ├── ExtensionDelegate.m │ ├── Info.plist │ ├── InterfaceController.h │ ├── InterfaceController.m │ ├── NotificationController.h │ ├── NotificationController.m │ └── PushNotificationPayload.apns ├── TestWatchApp2.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── Notification - TestWatchApp2 WatchKit App.xcscheme │ │ ├── TestWatchApp2 WatchKit App.xcscheme │ │ └── TestWatchApp2.xcscheme └── TestWatchApp2 │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── init.js ├── test-certs.js ├── test-device.js ├── test-env.js ├── test-ioslib.js ├── test-provisioning.js ├── test-simulator.js ├── test-teams.js └── test-xcode.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: tidev 2 | liberapay: tidev 3 | -------------------------------------------------------------------------------- /.github/workflows/cla.yaml: -------------------------------------------------------------------------------- 1 | name: Check CLA 2 | on: 3 | - pull_request 4 | 5 | jobs: 6 | check-cla: 7 | runs-on: ubuntu-latest 8 | name: Verify contributor 9 | 10 | steps: 11 | - uses: tidev/tidev-cla-action@v2 12 | with: 13 | repo-token: ${{ secrets.GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | release: 4 | types: [ published ] 5 | 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | name: Publish 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup node 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: 20 19 | registry-url: 'https://registry.npmjs.org' 20 | 21 | - name: Install dependencies 22 | run: npm ci 23 | if: steps.node-cache.outputs.cache-hit != 'true' 24 | 25 | - name: Publish to npm 26 | env: 27 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | run: npm publish --tag ${{ github.event.release.prerelease && 'next' || 'latest' }} 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | - pull_request 4 | - push 5 | 6 | jobs: 7 | test: 8 | runs-on: macos-latest 9 | name: Test 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Setup node 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: 20 19 | registry-url: 'https://registry.npmjs.org' 20 | 21 | - name: Install dependencies 22 | run: npm ci 23 | if: steps.node-cache.outputs.cache-hit != 'true' 24 | 25 | - name: Run tests 26 | run: npm test 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .DS_Store 3 | dist 4 | npm-debug.log 5 | node_modules 6 | env.properties 7 | junit_report.xml 8 | 9 | test/TestApp/info.plist 10 | test/TestApp/build 11 | test/TestApp/index 12 | test/TestApp/Logs 13 | test/TestApp/ModuleCache 14 | test/TestApp/ModuleCache.noindex 15 | test/TestApp/TestApp.xcodeproj/xcuserdata 16 | test/TestApp/TestApp.xcodeproj/project.xcworkspace 17 | 18 | test/TestWatchApp/info.plist 19 | test/TestWatchApp/build 20 | test/TestWatchApp/index 21 | test/TestWatchApp/Logs 22 | test/TestWatchApp/ModuleCache 23 | test/TestWatchApp/ModuleCache.noindex 24 | test/TestWatchApp/TestWatchApp.xcodeproj/xcuserdata 25 | test/TestWatchApp/TestWatchApp.xcodeproj/project.xcworkspace 26 | 27 | test/TestWatchApp2/info.plist 28 | test/TestWatchApp2/build 29 | test/TestWatchApp2/index 30 | test/TestWatchApp2/Logs 31 | test/TestWatchApp2/ModuleCache 32 | test/TestWatchApp2/ModuleCache.noindex 33 | test/TestWatchApp2/TestWatchApp2.xcodeproj/xcuserdata 34 | test/TestWatchApp2/TestWatchApp2.xcodeproj/project.xcworkspace 35 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .DS_Store 3 | .git* 4 | /dist 5 | /node_modules 6 | /npm-debug.log 7 | /env.properties 8 | 9 | test/TestApp/info.plist 10 | test/TestApp/build 11 | test/TestApp/Build 12 | test/TestApp/Logs 13 | test/TestApp/ModuleCache 14 | test/TestApp/TestApp.xcodeproj/xcuserdata 15 | test/TestApp/TestApp.xcodeproj/project.xcworkspace 16 | 17 | test/TestWatchApp/info.plist 18 | test/TestWatchApp/build 19 | test/TestWatchApp/Build 20 | test/TestWatchApp/Logs 21 | test/TestWatchApp/ModuleCache 22 | test/TestWatchApp/TestWatchApp.xcodeproj/xcuserdata 23 | test/TestWatchApp/TestWatchApp.xcodeproj/project.xcworkspace 24 | 25 | test/TestWatchApp2/info.plist 26 | test/TestWatchApp2/build 27 | test/TestWatchApp2/Build 28 | test/TestWatchApp2/Logs 29 | test/TestWatchApp2/ModuleCache 30 | test/TestWatchApp2/TestWatchApp2.xcodeproj/xcuserdata 31 | test/TestWatchApp2/TestWatchApp2.xcodeproj/project.xcworkspace 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright TiDev, Inc. 4/7/2022-Present 2 | Copyright 2014-2020 by Appcelerator, Inc. 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 | 16 | ------------------------------------------------------------------------------- 17 | 18 | lib/certs.js contains code from the "forge" project. 19 | https://github.com/digitalbazaar/forge 20 | 21 | New BSD License (3-clause) 22 | Copyright (c) 2010, Digital Bazaar, Inc. 23 | All rights reserved. 24 | 25 | Redistribution and use in source and binary forms, with or without 26 | modification, are permitted provided that the following conditions are met: 27 | * Redistributions of source code must retain the above copyright 28 | notice, this list of conditions and the following disclaimer. 29 | * Redistributions in binary form must reproduce the above copyright 30 | notice, this list of conditions and the following disclaimer in the 31 | documentation and/or other materials provided with the distribution. 32 | * Neither the name of Digital Bazaar, Inc. nor the 33 | names of its contributors may be used to endorse or promote products 34 | derived from this software without specific prior written permission. 35 | 36 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 37 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 38 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 | DISCLAIMED. IN NO EVENT SHALL DIGITAL BAZAAR BE LIABLE FOR ANY 40 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 41 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 45 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS Utility Library 2 | 3 | > This is a library of utilities for dealing programmatically with iOS applications, 4 | used namely for tools like [Hyperloop](https://github.com/tidev/hyperloop) 5 | and [Titanium SDK](https://github.com/tidev/titanium-sdk). 6 | 7 | ioslib supports Xcode 6 and newer. 8 | 9 | ## Installation 10 | 11 | From NPM: 12 | 13 | npm install ioslib 14 | 15 | ## Examples 16 | 17 | ### Detect all the connected iOS devices: 18 | 19 | ```javascript 20 | var ioslib = require('ioslib'); 21 | 22 | ioslib.device.detect(function (err, devices) { 23 | if (err) { 24 | console.error(err); 25 | } else { 26 | console.log(devices); 27 | } 28 | }); 29 | ``` 30 | 31 | ### Install an application on device 32 | 33 | ```javascript 34 | var deviceUDID = null; // string or null to pick first device 35 | 36 | ioslib.device.install(deviceUDID, '/path/to/name.app', 'com.company.appname') 37 | .on('installed', function () { 38 | console.log('App successfully installed on device'); 39 | }) 40 | .on('appStarted', function () { 41 | console.log('App has started'); 42 | }) 43 | .on('log', function (msg) { 44 | console.log('[LOG] ' + msg); 45 | }) 46 | .on('appQuit', function () { 47 | console.log('App has quit'); 48 | }) 49 | .on('error', function (err) { 50 | console.error(err); 51 | }); 52 | ``` 53 | 54 | ### Launch the iOS Simulator 55 | 56 | ```javascript 57 | ioslib.simulator.launch(null, function (err, simHandle) { 58 | console.log('Simulator launched'); 59 | ioslib.simulator.stop(simHandle, function () { 60 | console.log('Simulator stopped'); 61 | }); 62 | }); 63 | ``` 64 | 65 | ### Launch, install, and run an application on simulator 66 | 67 | ```javascript 68 | var simUDID = null; // string or null to pick a simulator 69 | 70 | ioslib.simulator.launch(simUDID, { 71 | appPath: '/path/to/name.app' 72 | }) 73 | .on('launched', function (msg) { 74 | console.log('Simulator has launched'); 75 | }) 76 | .on('appStarted', function (msg) { 77 | console.log('App has started'); 78 | }) 79 | .on('log', function (msg) { 80 | console.log('[LOG] ' + msg); 81 | }) 82 | .on('error', function (err) { 83 | console.error(err); 84 | }); 85 | ``` 86 | 87 | ### Force stop an application running on simulator 88 | 89 | ```javascript 90 | ioslib.simulator.launch(simUDID, { 91 | appPath: '/path/to/name.app' 92 | }) 93 | .on('launched', function (simHandle) { 94 | console.log('Simulator launched'); 95 | ioslib.simulator.stop(simHandle).on('stopped', function () { 96 | console.log('Simulator stopped'); 97 | }); 98 | }); 99 | ``` 100 | 101 | ### Find a valid device/cert/provisioning profile combination 102 | 103 | ```javascript 104 | ioslib.findValidDeviceCertProfileCombos({ 105 | appId: 'com.company.appname' 106 | }, function (err, results) { 107 | if (err) { 108 | console.error(err); 109 | } else { 110 | console.log(results); 111 | } 112 | }); 113 | ``` 114 | 115 | ### Detect everything 116 | 117 | ```javascript 118 | ioslib.detect(function (err, info) { 119 | if (err) { 120 | console.error(err); 121 | } else { 122 | console.log(info); 123 | } 124 | }); 125 | ``` 126 | 127 | ### Detect iOS certificates 128 | 129 | ```javascript 130 | ioslib.certs.detect(function (err, certs) { 131 | if (err) { 132 | console.error(err); 133 | } else { 134 | console.log(certs); 135 | } 136 | }); 137 | ``` 138 | 139 | ### Detect provisioning profiles 140 | 141 | ```javascript 142 | ioslib.provisioning.detect(function (err, profiles) { 143 | if (err) { 144 | console.error(err); 145 | } else { 146 | console.log(profiles); 147 | } 148 | }); 149 | ``` 150 | 151 | ### Detect Xcode installations 152 | 153 | ```javascript 154 | ioslib.xcode.detect(function (err, xcodeInfo) { 155 | if (err) { 156 | console.error(err); 157 | } else { 158 | console.log(xcodeInfo); 159 | } 160 | }); 161 | ``` 162 | 163 | ## Running Tests 164 | 165 | For best results, connect an iOS device. 166 | 167 | To run all tests: 168 | 169 | ``` 170 | npm test 171 | ``` 172 | 173 | To see debug logging, set the `DEBUG` environment variable: 174 | 175 | ``` 176 | DEBUG=1 npm test 177 | ``` 178 | 179 | To run a specific test suite: 180 | 181 | ``` 182 | npm run-script test-certs 183 | 184 | npm run-script test-device 185 | 186 | npm run-script test-env 187 | 188 | npm run-script test-ioslib 189 | 190 | npm run-script test-provisioning 191 | 192 | npm run-script test-simulator 193 | 194 | npm run-script test-xcode 195 | ``` 196 | 197 | ## Contributing 198 | 199 | Interested in contributing? There are several ways you can help contribute to this project. 200 | 201 | ### New Features, Improvements, Bug Fixes, & Documentation 202 | 203 | Source code contributions are always welcome! Before we can accept your pull request, you must sign a Contributor License Agreement (CLA). Please visit https://tidev.io/contribute for more information. 204 | 205 | ### Donations 206 | 207 | Please consider supporting this project by making a charitable [donation](https://tidev.io/donate). The money you donate goes to compensate the skilled engineeers and maintainers that keep this project going. 208 | 209 | ### Code of Conduct 210 | 211 | TiDev wants to provide a safe and welcoming community for everyone to participate. Please see our [Code of Conduct](https://tidev.io/code-of-conduct) that applies to all contributors. 212 | 213 | ## Security 214 | 215 | If you find a security related issue, please send an email to [security@tidev.io](mailto:security@tidev.io) instead of publicly creating a ticket. 216 | 217 | ## Stay Connected 218 | 219 | For the latest information, please find us on Twitter: [Titanium SDK](https://twitter.com/titaniumsdk) and [TiDev](https://twitter.com/tidevio). 220 | 221 | Join our growing Slack community by visiting https://slack.tidev.io! 222 | 223 | ## Legal 224 | 225 | Titanium is a registered trademark of TiDev Inc. All Titanium trademark and patent rights were transferred and assigned to TiDev Inc. on 4/7/2022. Please see the LEGAL information about using our trademarks, privacy policy, terms of usage and other legal information at https://tidev.io/legal. -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Main namespace for the ioslib. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014-2016 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | const 13 | async = require('async'), 14 | 15 | certs = exports.certs = require('./lib/certs'), 16 | device = exports.device = require('./lib/device'), 17 | env = exports.env = require('./lib/env'), 18 | magik = exports.magik = require('./lib/utilities').magik, 19 | provisioning = exports.provisioning = require('./lib/provisioning'), 20 | simulator = exports.simulator = require('./lib/simulator'), 21 | teams = exports.teams = require('./lib/teams'), 22 | utilities = exports.utilities = require('./lib/utilities'), 23 | xcode = exports.xcode = require('./lib/xcode'); 24 | 25 | var cache; 26 | 27 | exports.detect = detect; 28 | exports.findValidDeviceCertProfileCombos = findValidDeviceCertProfileCombos; 29 | 30 | /** 31 | * Detects the entire iOS environment information. 32 | * 33 | * @param {Object} [options] - An object containing various settings. 34 | * @param {Boolean} [options.bypassCache=false] - When true, re-detects the all iOS information. 35 | * @param {String} [options.minIosVersion] - The minimum iOS SDK to detect. 36 | * @param {String} [options.minWatchosVersion] - The minimum WatchOS SDK to detect. 37 | * @param {String} [options.profileDir=~/Library/Developer/Xcode/UserData/Provisioning Profiles] - The path to search for provisioning profiles. 38 | * @param {String} [options.security] - Path to the security executable 39 | * @param {String} [options.supportedVersions] - A string with a version number or range to check if an Xcode install is supported. 40 | * @param {String} [options.type] - The type of emulators to return. Can be either "iphone" or "ipad". Defaults to all types. 41 | * @param {Boolean} [options.validOnly=true] - When true, only returns non-expired, valid certificates. 42 | * @param {String} [options.xcodeSelect] - Path to the xcode-select executable 43 | * @param {Function} [callback(err, info)] - A function to call when all detection tasks have completed. 44 | */ 45 | function detect(options, callback) { 46 | return magik(options, callback, function (emitter, options, callback) { 47 | if (cache && !options.bypassCache) { 48 | emitter.emit('detected', cache); 49 | return callback(null, cache); 50 | } 51 | 52 | var results = { 53 | detectVersion: '5.0', 54 | issues: [] 55 | }; 56 | 57 | function mix(src, dest) { 58 | Object.keys(src).forEach(function (name) { 59 | if (Array.isArray(src[name])) { 60 | if (Array.isArray(dest[name])) { 61 | dest[name] = dest[name].concat(src[name]); 62 | } else { 63 | dest[name] = src[name]; 64 | } 65 | } else if (src[name] !== null && typeof src[name] === 'object') { 66 | dest[name] || (dest[name] = {}); 67 | Object.keys(src[name]).forEach(function (key) { 68 | dest[name][key] = src[name][key]; 69 | }); 70 | } else { 71 | dest[name] = src[name]; 72 | } 73 | }); 74 | } 75 | 76 | async.parallel([ 77 | function detectCertificates(done) { 78 | certs.detect(options, function (err, result) { 79 | err || mix(result, results); 80 | done(err); 81 | }); 82 | }, 83 | function detectDevices(done) { 84 | device.detect(options, function (err, result) { 85 | err || mix(result, results); 86 | done(err); 87 | }); 88 | }, 89 | function detectEnvironment(done) { 90 | env.detect(options, function (err, result) { 91 | err || mix(result, results); 92 | done(err); 93 | }); 94 | }, 95 | function detectProvisioning(done) { 96 | provisioning.detect(options, function (err, result) { 97 | err || mix(result, results); 98 | done(err); 99 | }); 100 | }, 101 | function detectSimulator(done) { 102 | simulator.detect(options, function (err, result) { 103 | err || mix(result, results); 104 | done(err); 105 | }); 106 | }, 107 | function detectTeams(done) { 108 | teams.detect(options, function (err, result) { 109 | err || mix(result, results); 110 | done(err); 111 | }); 112 | }, 113 | function detectXcode(done) { 114 | xcode.detect(options, function (err, result) { 115 | err || mix(result, results); 116 | done(err); 117 | }); 118 | } 119 | ], function (err) { 120 | if (err) { 121 | emitter.emit('error', err); 122 | return callback(err); 123 | } else { 124 | cache = results; 125 | emitter.emit('detected', results); 126 | return callback(null, results); 127 | } 128 | }); 129 | }); 130 | }; 131 | 132 | /** 133 | * Finds all valid device/cert/provisioning profile combinations. This is handy for quickly 134 | * finding valid parameters for building an app for an iOS device. 135 | * 136 | * @param {Object} [options] - An object containing various settings. 137 | * @param {String} [options.appId] - The app identifier (com.domain.app) to filter provisioning profiles by. 138 | * @param {Boolean} [options.bypassCache=false] - When true, re-detects the all iOS information. 139 | * @param {Boolean} [options.unmanagedProvisioningProfile] - When true, selects an unmanaged provisioning profile. 140 | * @param {Function} [callback(err, info)] - A function to call when the simulator has launched. 141 | */ 142 | function findValidDeviceCertProfileCombos(options, callback) { 143 | if (typeof options === 'function') { 144 | callback = options; 145 | options = {}; 146 | } else if (!options) { 147 | options = {}; 148 | } 149 | typeof callback === 'function' || (callback = function () {}); 150 | 151 | // find us a device 152 | device.detect(function (err, deviceResults) { 153 | if (!deviceResults.devices.length) { 154 | // no devices connected 155 | return callback(new Error('No iOS devices connected')); 156 | } 157 | 158 | // next find us some certs 159 | certs.detect(function (err, certResults) { 160 | var certs = []; 161 | Object.keys(certResults.certs.keychains).forEach(function (keychain) { 162 | var types = certResults.certs.keychains[keychain]; 163 | Object.keys(types).forEach(function (type) { 164 | certs = certs.concat(types[type]); 165 | }); 166 | }); 167 | 168 | if (!certs.length) { 169 | return callback(new Error('No iOS certificates')); 170 | } 171 | 172 | // find us a provisioning profile 173 | provisioning.find({ 174 | appId: options.appId, 175 | certs: certs, 176 | devicesUDIDs: deviceResults.devices.map(function (device) { return device.udid; }), 177 | unmanaged: options.unmanagedProvisioningProfile 178 | }, function (err, profiles) { 179 | if (!profiles.length) { 180 | return callback(new Error('No provisioning profiles found')); 181 | 182 | } 183 | 184 | var combos = []; 185 | profiles.forEach(function (profile) { 186 | deviceResults.devices.forEach(function (device) { 187 | if (profile.devices && profile.devices.indexOf(device.udid) !== -1) { 188 | certs.forEach(function (cert) { 189 | var prefix = cert.pem.replace(/^-----BEGIN CERTIFICATE-----\n/, '').substring(0, 60); 190 | profile.certs.forEach(function (pcert) { 191 | if (pcert.indexOf(prefix) === 0) { 192 | combos.push({ 193 | ppUUID: profile.uuid, 194 | certName: cert.name, 195 | deviceUDID: device.udid 196 | }); 197 | } 198 | }); 199 | }); 200 | } 201 | }); 202 | }); 203 | 204 | callback(null, combos); 205 | }); 206 | }); 207 | }); 208 | } 209 | -------------------------------------------------------------------------------- /lib/device.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Detects iOS developer and distribution certificates and the WWDC certificate. 3 | * 4 | * @module device 5 | * 6 | * @copyright 7 | * Copyright (c) 2014-2016 by Appcelerator, Inc. All Rights Reserved. 8 | * 9 | * @license 10 | * Licensed under the terms of the Apache Public License. 11 | * Please see the LICENSE included with this distribution for details. 12 | */ 13 | 14 | 'use strict'; 15 | 16 | const appc = require('node-appc'); 17 | const async = require('async'); 18 | const magik = require('./utilities').magik; 19 | const fs = require('fs'); 20 | const iosDevice = require('node-ios-device'); 21 | const path = require('path'); 22 | const __ = appc.i18n(__dirname).__; 23 | 24 | var cache; 25 | 26 | exports.detect = detect; 27 | exports.install = install; 28 | 29 | /** 30 | * Detects connected iOS devices. 31 | * 32 | * @param {Object} [options] - An object containing various settings. 33 | * @param {Boolean} [options.bypassCache=false] - When true, re-detects all connected iOS devices. 34 | * @param {Function} [callback(err, results)] - A function to call with the device information. 35 | * 36 | * @emits module:device#detected 37 | * @emits module:device#error 38 | * 39 | * @returns {Handle} 40 | */ 41 | function detect(options, callback) { 42 | return magik(options, callback, function (handle, options, callback) { 43 | if (cache && !options.bypassCache) { 44 | var dupe = JSON.parse(JSON.stringify(cache)); 45 | handle.emit('detected', dupe); 46 | return callback(null, dupe); 47 | } 48 | 49 | iosDevice.devices(function (err, devices) { 50 | if (err) { 51 | handle.emit('error', err); 52 | return callback(err); 53 | } 54 | 55 | var results = { 56 | devices: devices, 57 | issues: [] 58 | }; 59 | 60 | // the cache must be a clean copy that we'll clone for subsequent detect() calls 61 | // because we can't allow the cache to be modified by reference 62 | cache = JSON.parse(JSON.stringify(results)); 63 | 64 | handle.emit('detected', results); 65 | return callback(null, results); 66 | }); 67 | }); 68 | }; 69 | 70 | /** 71 | * Installs the specified app to an iOS device. 72 | * 73 | * @param {String} udid - The UDID of the device to install the app to or null if you want ioslib to pick one. 74 | * @param {String} appPath - The path to the iOS app to install after launching the iOS Simulator. 75 | * @param {Object} [options] - An object containing various settings. 76 | * @param {Boolean} [options.bypassCache=false] - When true, re-detects all iOS simulators. 77 | * @param {Number} [options.logPort] - A port to connect to in the iOS app and relay log messages from. 78 | * @param {Number} [options.timeout] - Number of milliseconds to wait before timing out. 79 | * 80 | * @emits module:device#app-quit - Only omitted when `options.logPort` is specified and app starts a TCP server. 81 | * @emits module:device#app-started - Only omitted when `options.logPort` is specified and app starts a TCP server. 82 | * @emits module:device#disconnect - Only omitted when `options.logPort` is specified and app starts a TCP server. 83 | * @emits module:device#error 84 | * @emits module:device#installed 85 | * @emits module:device#log - Only omitted when `options.logPort` is specified and app starts a TCP server. 86 | * 87 | * @returns {Handle} 88 | */ 89 | function install(udid, appPath, options) { 90 | return magik(options, null, function (handle, options) { 91 | if (!appPath) { 92 | return handle.emit('error', new Error(__('Missing app path argument'))); 93 | } 94 | 95 | if (!fs.existsSync(appPath)) { 96 | return handle.emit('error', new Error(__('App path does not exist: ' + appPath))); 97 | } 98 | 99 | handle.stop = function () {}; // for stopping logging 100 | 101 | iosDevice.installApp(udid, appPath, function (err) { 102 | if (err) { 103 | return handle.emit('error', err); 104 | } 105 | 106 | handle.emit('installed'); 107 | 108 | if (options.logPort) { 109 | var logHandle = iosDevice 110 | .log(udid, options.logPort) 111 | .on('log', function (msg) { 112 | handle.emit('log', msg); 113 | }) 114 | .on('app-started', function () { 115 | handle.emit('app-started'); 116 | }) 117 | .on('app-quit', function () { 118 | handle.emit('app-quit'); 119 | }) 120 | .on('disconnect', function () { 121 | handle.emit('disconnect'); 122 | }) 123 | .on('error', function (err) { 124 | handle.emit('log-error', err); 125 | }); 126 | 127 | handle.stop = function () { 128 | logHandle.stop(); 129 | }; 130 | } 131 | }); 132 | }); 133 | } 134 | -------------------------------------------------------------------------------- /lib/env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Detects the iOS development environment. 3 | * 4 | * @module env 5 | * 6 | * @copyright 7 | * Copyright (c) 2014-2017 by Appcelerator, Inc. All Rights Reserved. 8 | * 9 | * @license 10 | * Licensed under the terms of the Apache Public License. 11 | * Please see the LICENSE included with this distribution for details. 12 | */ 13 | 14 | const 15 | appc = require('node-appc'), 16 | async = require('async'), 17 | magik = require('./utilities').magik, 18 | __ = appc.i18n(__dirname).__; 19 | 20 | var cache = null; 21 | 22 | /** 23 | * Fired when the developer profiles have been updated. 24 | * @event module:env#detected 25 | * @type {Object} 26 | */ 27 | 28 | /** 29 | * Fired when there was an error retreiving the provisioning profiles. 30 | * @event module:env#error 31 | * @type {Error} 32 | */ 33 | 34 | /** 35 | * Detects the iOS development enviroment dependencies. 36 | * 37 | * @param {Object} [options] - An object containing various settings 38 | * @param {Boolean} [options.bypassCache=false] - When true, re-detects the development environment dependencies 39 | * @param {String} [options.security] - Path to the security executable 40 | * @param {String} [options.xcodeSelect] - Path to the xcode-select executable 41 | * @param {Function} [callback(err, results)] - A function to call with the development environment information 42 | * 43 | * @emits module:env#detected 44 | * @emits module:env#error 45 | * 46 | * @returns {Handle} 47 | */ 48 | exports.detect = function detect(options, callback) { 49 | return magik(options, callback, function (emitter, options, callback) { 50 | if (cache && !options.bypassCache) { 51 | return callback(null, cache); 52 | } 53 | 54 | var results = { 55 | executables: { 56 | xcodeSelect: null, 57 | security: null 58 | }, 59 | issues: [] 60 | }; 61 | 62 | async.parallel({ 63 | security: function (next) { 64 | appc.subprocess.findExecutable([options.security, '/usr/bin/security', 'security'], function (err, result) { 65 | if (err) { 66 | results.issues.push({ 67 | id: 'IOS_SECURITY_EXECUTABLE_NOT_FOUND', 68 | type: 'error', 69 | message: __("Unable to find the 'security' executable.") + '\n' 70 | + __('Please verify your system path.') + '\n' 71 | + __("This program is distributed with macOS and if it's missing, you'll have to restore it from a backup or another computer, or reinstall macOS.") 72 | }); 73 | } else { 74 | results.executables.security = result; 75 | } 76 | next(); 77 | }); 78 | }, 79 | 80 | xcodeSelect: function (next) { 81 | appc.subprocess.findExecutable([options.xcodeSelect, '/usr/bin/xcode-select', 'xcode-select'], function (err, result) { 82 | if (err) { 83 | results.issues.push({ 84 | id: 'IOS_XCODE_SELECT_EXECUTABLE_NOT_FOUND', 85 | type: 'error', 86 | message: __("Unable to find the 'xcode-select' executable.") + '\n' 87 | + __('Perhaps Xcode is not installed, your Xcode installation is corrupt, or your system path is incomplete.') 88 | }); 89 | } else { 90 | results.executables.xcodeSelect = result; 91 | } 92 | next(); 93 | }); 94 | } 95 | }, function () { 96 | cache = results; 97 | emitter.emit('detected', results); 98 | callback(null, results); 99 | }); 100 | }); 101 | }; 102 | -------------------------------------------------------------------------------- /lib/provisioning.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Detects provisioning profiles. 3 | * 4 | * @module provisioning 5 | * 6 | * @copyright 7 | * Copyright (c) 2014-2016 by Appcelerator, Inc. All Rights Reserved. 8 | * 9 | * @license 10 | * Licensed under the terms of the Apache Public License. 11 | * Please see the LICENSE included with this distribution for details. 12 | * 13 | * @requires certs 14 | */ 15 | 16 | const 17 | appc = require('node-appc'), 18 | certs = require('./certs'), 19 | magik = require('./utilities').magik, 20 | fs = require('fs'), 21 | path = require('path'), 22 | __ = appc.i18n(__dirname).__, 23 | provisioningProfilesDirectories = [ 24 | '~/Library/Developer/Xcode/UserData/Provisioning Profiles', 25 | '~/Library/MobileDevice/Provisioning Profiles' 26 | ] 27 | 28 | var cache = null, 29 | watchers = {}; 30 | 31 | /** 32 | * Fired when the provisioning profiles have been detected or updated. 33 | * @event module:provisioning#detected 34 | * @type {Object} 35 | */ 36 | 37 | /** 38 | * Fired when there was an error retreiving the provisioning profiles. 39 | * @event module:provisioning#error 40 | * @type {Error} 41 | */ 42 | 43 | exports.detect = detect; 44 | exports.find = find; 45 | exports.watch = watch; 46 | exports.unwatch = unwatch; 47 | 48 | /** 49 | * Detects installed provisioning profiles. 50 | * 51 | * @param {Object} [options] - An object containing various settings. 52 | * @param {Boolean} [options.bypassCache=false] - When true, re-detects all provisioning profiles. 53 | * @param {String} [options.profileDir=~/Library/Developer/Xcode/UserData/Provisioning Profiles] - The path to search for provisioning profiles. 54 | * @param {Boolean} [options.unmanaged] - When true, excludes managed provisioning profiles. 55 | * @param {Boolean} [options.validOnly=true] - When true, only returns non-expired, valid provisioning profiles. 56 | * @param {Boolean} [options.watch=false] - If true, watches the specified provisioning profile directory for updates. 57 | * @param {Function} [callback(err, results)] - A function to call with the provisioning profile information. 58 | * 59 | * @emits module:provisioning#detected 60 | * @emits module:provisioning#error 61 | * 62 | * @returns {Handle} 63 | */ 64 | function detect(options, callback) { 65 | return magik(options, callback, function (emitter, options, callback) { 66 | var files = {}, 67 | validOnly = options.validOnly === undefined || options.validOnly === true, 68 | profileDirs = getExistingProvisioningProfileDirectories(options.profileDir), 69 | results = { 70 | provisioning: { 71 | profileDir: profileDirs[0], 72 | development: [], 73 | adhoc: [], 74 | enterprise: [], 75 | distribution: [], 76 | }, 77 | issues: [] 78 | }, 79 | valid = { 80 | development: 0, 81 | adhoc: 0, 82 | enterprise: 0, 83 | distribution: 0 84 | }, 85 | 86 | ppRegExp = /.*\.(mobileprovision|provisionprofile)$/; 87 | 88 | 89 | if (options.watch) { 90 | var throttleTimer = null; 91 | 92 | for (const profileDir of profileDirs) { 93 | if (!watchers[profileDir]) { 94 | watchers[profileDir] = { 95 | handle: fs.watch(profileDir, { persistent: false }, function (event, filename) { 96 | if (!ppRegExp.test(filename)) { 97 | // if it's not a provisioning profile, we don't care about it 98 | return; 99 | } 100 | 101 | var file = path.join(profileDir, filename); 102 | 103 | if (event === 'rename') { 104 | if (files[file]) { 105 | if (fs.existsSync(file)) { 106 | // change, reload the provisioning profile 107 | parseProfile(file); 108 | } else { 109 | // delete 110 | removeProfile(file); 111 | } 112 | } else { 113 | // add 114 | parseProfile(file); 115 | } 116 | } else if (event === 'change') { 117 | // updated 118 | parseProfile(file); 119 | } 120 | 121 | clearTimeout(throttleTimer); 122 | 123 | throttleTimer = setTimeout(function () { 124 | detectIssues(); 125 | emitter.emit('detected', results); 126 | }, 250); 127 | }), 128 | count: 0 129 | }; 130 | } 131 | 132 | watchers[profileDir].count++; 133 | } 134 | } 135 | 136 | if (cache && !options.bypassCache) { 137 | emitter.emit('detected', cache); 138 | return callback(null, cache); 139 | } 140 | 141 | function detectIssues() { 142 | results.issues = []; 143 | 144 | if (results.provisioning.development.length > 0 && !valid.development) { 145 | results.issues.push({ 146 | id: 'IOS_NO_VALID_DEVELOPMENT_PROVISIONING_PROFILES', 147 | type: 'warning', 148 | message: __('Unable to find any valid iOS development provisioning profiles.') + '\n' + 149 | __('This will prevent you from building apps for testing on iOS devices.') 150 | }); 151 | } 152 | 153 | if (results.provisioning.adhoc.length > 0 && !valid.adhoc) { 154 | results.issues.push({ 155 | id: 'IOS_NO_VALID_ADHOC_PROVISIONING_PROFILES', 156 | type: 'warning', 157 | message: __('Unable to find any valid iOS adhoc provisioning profiles.') + '\n' + 158 | __('This will prevent you from packaging apps for adhoc distribution.') 159 | }); 160 | } 161 | 162 | if (results.provisioning.distribution.length > 0 && !valid.distribution) { 163 | results.issues.push({ 164 | id: 'IOS_NO_VALID_DISTRIBUTION_PROVISIONING_PROFILES', 165 | type: 'warning', 166 | message: __('Unable to find any valid iOS distribution provisioning profiles.') + '\n' + 167 | __('This will prevent you from packaging apps for AppStore distribution.') 168 | }); 169 | } 170 | } 171 | 172 | function removeProfile(file) { 173 | var r = results[files[file]], 174 | i = 0, 175 | l = r.length; 176 | for (; i < l; i++) { 177 | if (r[i].file === file) { 178 | r.splice(i, 1); 179 | break; 180 | } 181 | } 182 | delete files[file]; 183 | } 184 | 185 | function parseProfile(file) { 186 | if (!fs.existsSync(file)) { 187 | return; 188 | } 189 | 190 | var contents = fs.readFileSync(file).toString(), 191 | i = contents.indexOf(''); 193 | 194 | if (j === -1) return; 195 | 196 | var plist = new appc.plist().parse(contents.substring(i, j + 8)), 197 | dest = 'development', // debug 198 | appPrefix = (plist.ApplicationIdentifierPrefix || []).shift(), 199 | entitlements = plist.Entitlements || {}, 200 | expired = false; 201 | 202 | if (plist.ProvisionedDevices) { 203 | if (!entitlements['get-task-allow']) { 204 | dest = 'adhoc'; 205 | } 206 | } else if (plist.ProvisionsAllDevices) { 207 | dest = 'enterprise'; 208 | } else { 209 | dest = 'distribution'; // app store 210 | } 211 | 212 | try { 213 | if (plist.ExpirationDate) { 214 | expired = new Date(plist.ExpirationDate) < new Date; 215 | } 216 | } catch (e) {} 217 | 218 | if (!expired) { 219 | valid[dest]++; 220 | } 221 | 222 | // store which bucket the provisioning profile is in 223 | files[file] && removeProfile(file); 224 | files[file] = dest; 225 | 226 | var managed = plist.Name.indexOf('iOS Team Provisioning Profile') !== -1; 227 | 228 | if ((!validOnly || !expired) && (!options.unmanaged || !managed)) { 229 | results.provisioning[dest].push({ 230 | file: file, 231 | uuid: plist.UUID, 232 | name: plist.Name, 233 | managed: managed, 234 | appPrefix: appPrefix, 235 | creationDate: plist.CreationDate, 236 | expirationDate: plist.ExpirationDate, 237 | expired: expired, 238 | certs: Array.isArray(plist.DeveloperCertificates) 239 | ? plist.DeveloperCertificates.map(function (cert) { return cert.value; }) 240 | : null, 241 | devices: plist.ProvisionedDevices || null, 242 | team: plist.TeamIdentifier || null, 243 | entitlements: entitlements, 244 | // TODO: remove all of the entitlements below and just use the `entitlements` property 245 | appId: (entitlements['application-identifier'] || entitlements['com.apple.application-identifier'] || '').replace(appPrefix + '.', ''), 246 | getTaskAllow: !!entitlements['get-task-allow'], 247 | apsEnvironment: entitlements['aps-environment'] || '' 248 | }); 249 | } 250 | } 251 | 252 | for (const profileDir of profileDirs) { 253 | fs.readdirSync(profileDir).forEach(function (name) { 254 | ppRegExp.test(name) && parseProfile(path.join(profileDir, name)); 255 | }); 256 | } 257 | 258 | detectIssues(); 259 | cache = results; 260 | emitter.emit('detected', results); 261 | return callback(null, results); 262 | }); 263 | }; 264 | 265 | /** 266 | * Finds all provisioning profiles that match the specified developer cert name 267 | * and iOS device UDID. 268 | * 269 | * @param {Object} [options] - An object containing various settings. 270 | * @param {String} [options.appId] - The app identifier (com.domain.app) to filter by. 271 | * @param {Object|Array} [options.certs] - One or more certificate descriptors to filter by. 272 | * @param {String|Array} [options.deviceUDIDs] - One or more iOS device UDIDs to filter by. 273 | * @param {Boolean} [options.unmanaged] - When true, excludes managed provisioning profiles. 274 | * @param {Boolean} [options.validOnly=true] - When true, only returns valid profiles. 275 | * @param {Function} callback(err, results) - A function to call with an array of matching provisioning profiles. 276 | */ 277 | function find(options, callback) { 278 | if (typeof options === 'function') { 279 | callback = options; 280 | options = {}; 281 | } else if (!options) { 282 | options = {}; 283 | } 284 | typeof callback === 'function' || (callback = function () {}); 285 | 286 | var deviceUDIDs = (Array.isArray(options.deviceUDIDs) ? options.deviceUDIDs : [ options.deviceUDIDs ]).filter(function (a) { return a; }), 287 | certs = (Array.isArray(options.certs) ? options.certs : [ options.certs ]).filter(function (a) { return a; }); 288 | 289 | options.validOnly = options.validOnly === undefined || options.validOnly === true; 290 | 291 | exports.detect(options, function (err, results) { 292 | if (err) { 293 | return callback(err); 294 | } else { 295 | var profiles = []; 296 | 297 | function check(scope) { 298 | scope.forEach(function (pp) { 299 | // check app id 300 | if (options.appId && !(new RegExp('^' + pp.appId.replace(/\./g, '\\.').replace(/\*/g, '.*') + '$')).test(options.appId)) { 301 | return; 302 | } 303 | 304 | // check certs 305 | if (certs.length) { 306 | var match = false; 307 | for (var i = 0, l = certs.length; i < l; i++) { 308 | var prefix = certs[i].pem.replace(/^-----BEGIN CERTIFICATE-----\n/, '').substring(0, 60); 309 | if (pp.certs.some(function (cert) { return cert.indexOf(prefix) === 0; })) { 310 | match = true; 311 | break; 312 | } 313 | } 314 | if (!match) return; 315 | } 316 | 317 | // check device uuids 318 | if (deviceUDIDs.length && (pp.devices === null || !deviceUDIDs.some(function (d) { return pp.devices.indexOf(d) !== -1; }))) { 319 | return; 320 | } 321 | 322 | profiles.push(pp); 323 | }); 324 | } 325 | 326 | check(results.provisioning.development); 327 | check(results.provisioning.distribution); 328 | check(results.provisioning.adhoc); 329 | 330 | return callback(null, profiles); 331 | } 332 | }); 333 | }; 334 | 335 | /** 336 | * Watches a provisioning profile directory for file changes. 337 | * 338 | * @param {Object} [options] - An object containing various settings. 339 | * @param {String} [options.profileDir=~/Library/Developer/Xcode/UserData/Provisioning Profiles] - The path to search for provisioning profiles. 340 | * @param {Function} [callback(err, results)] - A function to call with the provisioning profile information. 341 | * 342 | * @returns {Function} A function that unwatches changes. 343 | */ 344 | function watch(options, callback) { 345 | if (typeof options === 'function') { 346 | callback = options; 347 | options = {}; 348 | } else if (!options) { 349 | options = {}; 350 | } 351 | 352 | options.watch = true; 353 | options.bypassCache = true; 354 | 355 | exports.detect(options, callback); 356 | 357 | return function () { 358 | unwatch(options.profileDir); 359 | }; 360 | }; 361 | 362 | /** 363 | * Stops watching the specified provisioning profile directory. 364 | * 365 | * @param {String} [profileDir=~/Library/Developer/Xcode/UserData/Provisioning Profiles] - The path to the provisioning profile directory. 366 | */ 367 | function unwatch(profileDir) { 368 | var profileDirs = getExistingProvisioningProfileDirectories(profileDir); 369 | 370 | for (const profileDir of profileDirs) { 371 | if (!watchers[profileDir]) continue; 372 | 373 | if (--watchers[profileDir].count <= 0) { 374 | watchers[profileDir].handle.close(); 375 | delete watchers[profileDir]; 376 | } 377 | } 378 | }; 379 | 380 | /** 381 | * Searches for existing provisioning profile directories. 382 | * 383 | * @throws 384 | * @param {string | undefined} profileDir A custom directory set by the developer. 385 | * @returns {string[]} The directories that exist on the filesystem. 386 | */ 387 | function getExistingProvisioningProfileDirectories(profileDir) { 388 | const profileDirectories = []; 389 | 390 | for (const directory of [profileDir, ...provisioningProfilesDirectories]) { 391 | if (!directory) { 392 | continue; 393 | } 394 | 395 | const resolvedDirectory = appc.fs.resolvePath(directory); 396 | 397 | if (fs.existsSync(resolvedDirectory)) { 398 | profileDirectories.push(resolvedDirectory); 399 | } 400 | } 401 | 402 | return profileDirectories; 403 | } 404 | 405 | /* 406 | * If the app exits, close all filesystem watchers. 407 | */ 408 | process.on('exit', function () { 409 | Object.keys(watchers).forEach(function (w) { 410 | watchers[w].handle.close(); 411 | delete watchers[w]; 412 | }); 413 | }); 414 | -------------------------------------------------------------------------------- /lib/sim_focus.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidev/ioslib/32190337789f377007b870c2a6bcbb310c71dd7c/lib/sim_focus.scpt -------------------------------------------------------------------------------- /lib/sim_hide.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidev/ioslib/32190337789f377007b870c2a6bcbb310c71dd7c/lib/sim_hide.scpt -------------------------------------------------------------------------------- /lib/teams.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Detects the Apple developer teams. 3 | * 4 | * @module teams 5 | * 6 | * @copyright 7 | * Copyright (c) 2014-2016 by Appcelerator, Inc. All Rights Reserved. 8 | * 9 | * @license 10 | * Licensed under the terms of the Apache Public License. 11 | * Please see the LICENSE included with this distribution for details. 12 | */ 13 | 14 | const 15 | async = require('async'), 16 | magik = require('./utilities').magik, 17 | provisioning = require('./provisioning'), 18 | xcode = require('./xcode'); 19 | 20 | /** 21 | * Fired when the developer profiles have been updated. 22 | * @event module:env#detected 23 | * @type {Object} 24 | */ 25 | 26 | /** 27 | * Fired when there was an error retreiving the provisioning profiles. 28 | * @event module:env#error 29 | * @type {Error} 30 | */ 31 | 32 | /** 33 | * Detects the Apple developer teams from the provisioning profiles and Xcodes. 34 | * 35 | * @param {Object} [options] - An object containing various settings 36 | * @param {Function} [callback(err, results)] - A function to call with the development environment information 37 | * 38 | * @emits module:env#detected 39 | * @emits module:env#error 40 | * 41 | * @returns {Handle} 42 | */ 43 | exports.detect = function detect(options, callback) { 44 | return magik(options, callback, function (emitter, options, callback) { 45 | async.parallel({ 46 | provisioning: function (next) { 47 | provisioning.detect(options, next); 48 | }, 49 | xcode: function (next) { 50 | xcode.detect(options, next); 51 | } 52 | }, function (err, iosInfo) { 53 | if (err) { 54 | return callback(err); 55 | } 56 | 57 | var provisioning = iosInfo.provisioning.provisioning; 58 | var xcodes = iosInfo.xcode.xcode; 59 | var teams = {}; 60 | 61 | ['development', 'adhoc', 'distribution'].forEach(function (type) { 62 | provisioning[type].forEach(function (pp) { 63 | if (Array.isArray(pp.team)) { 64 | pp.team.forEach(function (id) { 65 | teams[id] = id; 66 | }); 67 | } 68 | }); 69 | }); 70 | 71 | Object.keys(xcodes).forEach(function (xcodeId) { 72 | var t = xcodes[xcodeId].teams; 73 | Object.keys(t).forEach(function (id) { 74 | teams[id] = t[id]; 75 | }); 76 | }); 77 | 78 | var results = { 79 | teams: Object.keys(teams).map(function (id) { 80 | var team = teams[id]; 81 | if (typeof team === 'string') { 82 | return { 83 | id: team, 84 | name: 'Unknown', 85 | }; 86 | } 87 | 88 | return { 89 | id: id, 90 | name: team.name 91 | }; 92 | }) 93 | }; 94 | 95 | emitter.emit('detected', results); 96 | callback(null, results); 97 | }); 98 | }); 99 | }; 100 | -------------------------------------------------------------------------------- /lib/utilities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility functions used by ioslib. 3 | * 4 | * @module utilities 5 | * 6 | * @copyright 7 | * Copyright (c) 2015-2016 by Appcelerator, Inc. All Rights Reserved. 8 | * 9 | * @license 10 | * Licensed under the terms of the Apache Public License. 11 | * Please see the LICENSE included with this distribution for details. 12 | */ 13 | 14 | 'use strict'; 15 | 16 | const appc = require('node-appc'); 17 | const bplist = require('bplist-parser'); 18 | const crypto = require('crypto'); 19 | const EventEmitter = require('events').EventEmitter; 20 | const fs = require('fs'); 21 | const __ = appc.i18n(__dirname).__; 22 | const util = require('util'); 23 | 24 | exports.Handle = Handle; 25 | exports.magik = magik; 26 | exports.hash = hash; 27 | exports.readPlist = readPlist; 28 | 29 | /** 30 | * Exposes both an event emitter API and a `stop()` method for canceling long 31 | * running functions such as `trackDevices()` and `log()`. 32 | */ 33 | function Handle() {} 34 | util.inherits(Handle, EventEmitter); 35 | 36 | /** 37 | * Creates an event emitting handle, validates that the platform is OS X, 38 | * normalizes the 'options' and 'callback' arguments, and passes all 39 | * these goodies to the 'body' function. It's magik! 40 | * 41 | * @param {Object} [options] - An object containing various settings. 42 | * @param {Function} [callback(err, ...)] - A function to call with the task is complete. This is guaranteed to be called asynchronously. 43 | * @param {Function} [body] - A function to call with the 44 | * 45 | * @returns {Handle} 46 | */ 47 | function magik(options, callback, body) { 48 | var handle = new Handle; 49 | handle.on('error', function () {}); 50 | 51 | process.nextTick(function () { 52 | if (typeof options === 'function') { 53 | callback = options; 54 | options = {}; 55 | } else if (!options) { 56 | options = {}; 57 | } 58 | typeof callback === 'function' || (callback = function () {}); 59 | 60 | if (process.platform !== 'darwin') { 61 | var err = new Error(__('Unsupported platform "%s"', process.platform)); 62 | handle.emit('error', err); 63 | return callback(err); 64 | } 65 | 66 | body && body(handle, options, callback); 67 | }); 68 | 69 | return handle; 70 | }; 71 | 72 | /** 73 | * MD5 hashes the specified string. 74 | * 75 | * @param {String|Buffer} str - The string to hash. 76 | * 77 | * @returns {String} The MD5 hash. 78 | */ 79 | function hash(str) { 80 | return crypto.createHash('md5').update(str || '').digest('hex'); 81 | }; 82 | 83 | /** 84 | * Parses both ascii and binary plist files and returns a JSON representation. 85 | * 86 | * @param {String} file - The path to the plist file. 87 | * 88 | * @returns {Object|null} - Returns a JSON representation of the plist file or null if the file does not exist or unable to parse. 89 | */ 90 | function readPlist(file) { 91 | try { 92 | if (fs.existsSync(file)) { 93 | var buffer = fs.readFileSync(file), 94 | header = buffer.slice(0, 'bplist'.length).toString('utf8'); 95 | if (header === 'bplist') { 96 | return bplist.parseBuffer(buffer)[0]; 97 | } else { 98 | return (new appc.plist()).parse(buffer.toString()); 99 | } 100 | } 101 | } catch (ex) {} 102 | return null; 103 | } 104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ioslib", 3 | "version": "5.0.0", 4 | "description": "iOS Utility Library", 5 | "keywords": [ 6 | "appcelerator", 7 | "ios", 8 | "iphone", 9 | "ipad", 10 | "xcode", 11 | "apple" 12 | ], 13 | "author": "TiDev, Inc. ", 14 | "repository": "https://github.com/tidev/ioslib", 15 | "license": "Apache-2.0", 16 | "main": "./index", 17 | "bugs": "https://github.com/tidev/ioslib/issues", 18 | "directories": { 19 | "lib": "./lib" 20 | }, 21 | "dependencies": { 22 | "always-tail": "0.2.0", 23 | "async": "^3.2.6", 24 | "bplist-parser": "0.3.2", 25 | "debug": "^4.3.4", 26 | "node-appc": "^1.1.7", 27 | "node-ios-device": "^1.12.1" 28 | }, 29 | "devDependencies": { 30 | "mocha": "^8.2.0", 31 | "should": "^13.2.3" 32 | }, 33 | "scripts": { 34 | "test": "mocha --require test/init --check-leaks test/", 35 | "test-certs": "mocha --require test/init --reporter spec --check-leaks test/test-certs", 36 | "test-device": "mocha --require test/init --reporter spec --check-leaks test/test-device", 37 | "test-env": "mocha --require test/init --reporter spec --check-leaks test/test-env", 38 | "test-ioslib": "mocha --require test/init --reporter spec --check-leaks test/test-ioslib", 39 | "test-provisioning": "mocha --require test/init --reporter spec --check-leaks test/test-provisioning", 40 | "test-simulator": "mocha --require test/init --reporter spec --check-leaks test/test-simulator", 41 | "test-teams": "mocha --require test/init --reporter spec --check-leaks test/test-teams", 42 | "test-xcode": "mocha --require test/init --reporter spec --check-leaks test/test-xcode" 43 | }, 44 | "engines": { 45 | "node": ">=18" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/TestApp/TestApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 83D658AA19A00323009A9C56 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D658A919A00323009A9C56 /* Foundation.framework */; }; 11 | 83D658AC19A00323009A9C56 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D658AB19A00323009A9C56 /* CoreGraphics.framework */; }; 12 | 83D658AE19A00323009A9C56 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83D658AD19A00323009A9C56 /* UIKit.framework */; }; 13 | 83D658B419A00323009A9C56 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83D658B219A00323009A9C56 /* InfoPlist.strings */; }; 14 | 83D658B619A00323009A9C56 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 83D658B519A00323009A9C56 /* main.m */; }; 15 | 83D658BA19A00323009A9C56 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 83D658B919A00323009A9C56 /* AppDelegate.m */; }; 16 | 83D658BD19A00323009A9C56 /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 83D658BB19A00323009A9C56 /* Main_iPhone.storyboard */; }; 17 | 83D658C019A00323009A9C56 /* Main_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 83D658BE19A00323009A9C56 /* Main_iPad.storyboard */; }; 18 | 83D658C319A00323009A9C56 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83D658C219A00323009A9C56 /* ViewController.m */; }; 19 | 83D658C519A00323009A9C56 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 83D658C419A00323009A9C56 /* Images.xcassets */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXCopyFilesBuildPhase section */ 23 | CE877F041AE038AE0048B8B6 /* Embed App Extensions */ = { 24 | isa = PBXCopyFilesBuildPhase; 25 | buildActionMask = 2147483647; 26 | dstPath = ""; 27 | dstSubfolderSpec = 13; 28 | files = ( 29 | ); 30 | name = "Embed App Extensions"; 31 | runOnlyForDeploymentPostprocessing = 0; 32 | }; 33 | /* End PBXCopyFilesBuildPhase section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 83D658A619A00323009A9C56 /* TestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 83D658A919A00323009A9C56 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 38 | 83D658AB19A00323009A9C56 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 39 | 83D658AD19A00323009A9C56 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 40 | 83D658B119A00323009A9C56 /* TestApp-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TestApp-Info.plist"; sourceTree = ""; }; 41 | 83D658B319A00323009A9C56 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 42 | 83D658B519A00323009A9C56 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 43 | 83D658B719A00323009A9C56 /* TestApp-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TestApp-Prefix.pch"; sourceTree = ""; }; 44 | 83D658B819A00323009A9C56 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 45 | 83D658B919A00323009A9C56 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 46 | 83D658BC19A00323009A9C56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPhone.storyboard; sourceTree = ""; }; 47 | 83D658BF19A00323009A9C56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPad.storyboard; sourceTree = ""; }; 48 | 83D658C119A00323009A9C56 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 49 | 83D658C219A00323009A9C56 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 50 | 83D658C419A00323009A9C56 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | 83D658A319A00323009A9C56 /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | 83D658AC19A00323009A9C56 /* CoreGraphics.framework in Frameworks */, 59 | 83D658AE19A00323009A9C56 /* UIKit.framework in Frameworks */, 60 | 83D658AA19A00323009A9C56 /* Foundation.framework in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | 83D6589D19A00322009A9C56 = { 68 | isa = PBXGroup; 69 | children = ( 70 | 83D658AF19A00323009A9C56 /* TestApp */, 71 | 83D658A819A00323009A9C56 /* Frameworks */, 72 | 83D658A719A00323009A9C56 /* Products */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 83D658A719A00323009A9C56 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 83D658A619A00323009A9C56 /* TestApp.app */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 83D658A819A00323009A9C56 /* Frameworks */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 83D658A919A00323009A9C56 /* Foundation.framework */, 88 | 83D658AB19A00323009A9C56 /* CoreGraphics.framework */, 89 | 83D658AD19A00323009A9C56 /* UIKit.framework */, 90 | ); 91 | name = Frameworks; 92 | sourceTree = ""; 93 | }; 94 | 83D658AF19A00323009A9C56 /* TestApp */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 83D658B819A00323009A9C56 /* AppDelegate.h */, 98 | 83D658B919A00323009A9C56 /* AppDelegate.m */, 99 | 83D658BB19A00323009A9C56 /* Main_iPhone.storyboard */, 100 | 83D658BE19A00323009A9C56 /* Main_iPad.storyboard */, 101 | 83D658C119A00323009A9C56 /* ViewController.h */, 102 | 83D658C219A00323009A9C56 /* ViewController.m */, 103 | 83D658C419A00323009A9C56 /* Images.xcassets */, 104 | 83D658B019A00323009A9C56 /* Supporting Files */, 105 | ); 106 | path = TestApp; 107 | sourceTree = ""; 108 | }; 109 | 83D658B019A00323009A9C56 /* Supporting Files */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 83D658B119A00323009A9C56 /* TestApp-Info.plist */, 113 | 83D658B219A00323009A9C56 /* InfoPlist.strings */, 114 | 83D658B519A00323009A9C56 /* main.m */, 115 | 83D658B719A00323009A9C56 /* TestApp-Prefix.pch */, 116 | ); 117 | name = "Supporting Files"; 118 | sourceTree = ""; 119 | }; 120 | /* End PBXGroup section */ 121 | 122 | /* Begin PBXNativeTarget section */ 123 | 83D658A519A00323009A9C56 /* TestApp */ = { 124 | isa = PBXNativeTarget; 125 | buildConfigurationList = 83D658DB19A00323009A9C56 /* Build configuration list for PBXNativeTarget "TestApp" */; 126 | buildPhases = ( 127 | 83D658A219A00323009A9C56 /* Sources */, 128 | 83D658A319A00323009A9C56 /* Frameworks */, 129 | 83D658A419A00323009A9C56 /* Resources */, 130 | CE877F041AE038AE0048B8B6 /* Embed App Extensions */, 131 | ); 132 | buildRules = ( 133 | ); 134 | dependencies = ( 135 | ); 136 | name = TestApp; 137 | productName = TestApp; 138 | productReference = 83D658A619A00323009A9C56 /* TestApp.app */; 139 | productType = "com.apple.product-type.application"; 140 | }; 141 | /* End PBXNativeTarget section */ 142 | 143 | /* Begin PBXProject section */ 144 | 83D6589E19A00323009A9C56 /* Project object */ = { 145 | isa = PBXProject; 146 | attributes = { 147 | LastUpgradeCheck = 0510; 148 | ORGANIZATIONNAME = Appcelerator; 149 | TargetAttributes = { 150 | 83D658A519A00323009A9C56 = { 151 | DevelopmentTeam = WY35J6ST95; 152 | ProvisioningStyle = Manual; 153 | }; 154 | }; 155 | }; 156 | buildConfigurationList = 83D658A119A00323009A9C56 /* Build configuration list for PBXProject "TestApp" */; 157 | compatibilityVersion = "Xcode 3.2"; 158 | developmentRegion = English; 159 | hasScannedForEncodings = 0; 160 | knownRegions = ( 161 | English, 162 | en, 163 | Base, 164 | ); 165 | mainGroup = 83D6589D19A00322009A9C56; 166 | productRefGroup = 83D658A719A00323009A9C56 /* Products */; 167 | projectDirPath = ""; 168 | projectRoot = ""; 169 | targets = ( 170 | 83D658A519A00323009A9C56 /* TestApp */, 171 | ); 172 | }; 173 | /* End PBXProject section */ 174 | 175 | /* Begin PBXResourcesBuildPhase section */ 176 | 83D658A419A00323009A9C56 /* Resources */ = { 177 | isa = PBXResourcesBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | 83D658C019A00323009A9C56 /* Main_iPad.storyboard in Resources */, 181 | 83D658C519A00323009A9C56 /* Images.xcassets in Resources */, 182 | 83D658BD19A00323009A9C56 /* Main_iPhone.storyboard in Resources */, 183 | 83D658B419A00323009A9C56 /* InfoPlist.strings in Resources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXResourcesBuildPhase section */ 188 | 189 | /* Begin PBXSourcesBuildPhase section */ 190 | 83D658A219A00323009A9C56 /* Sources */ = { 191 | isa = PBXSourcesBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | 83D658C319A00323009A9C56 /* ViewController.m in Sources */, 195 | 83D658BA19A00323009A9C56 /* AppDelegate.m in Sources */, 196 | 83D658B619A00323009A9C56 /* main.m in Sources */, 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | }; 200 | /* End PBXSourcesBuildPhase section */ 201 | 202 | /* Begin PBXVariantGroup section */ 203 | 83D658B219A00323009A9C56 /* InfoPlist.strings */ = { 204 | isa = PBXVariantGroup; 205 | children = ( 206 | 83D658B319A00323009A9C56 /* en */, 207 | ); 208 | name = InfoPlist.strings; 209 | sourceTree = ""; 210 | }; 211 | 83D658BB19A00323009A9C56 /* Main_iPhone.storyboard */ = { 212 | isa = PBXVariantGroup; 213 | children = ( 214 | 83D658BC19A00323009A9C56 /* Base */, 215 | ); 216 | name = Main_iPhone.storyboard; 217 | sourceTree = ""; 218 | }; 219 | 83D658BE19A00323009A9C56 /* Main_iPad.storyboard */ = { 220 | isa = PBXVariantGroup; 221 | children = ( 222 | 83D658BF19A00323009A9C56 /* Base */, 223 | ); 224 | name = Main_iPad.storyboard; 225 | sourceTree = ""; 226 | }; 227 | /* End PBXVariantGroup section */ 228 | 229 | /* Begin XCBuildConfiguration section */ 230 | 83D658D919A00323009A9C56 /* Debug */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | ALWAYS_SEARCH_USER_PATHS = NO; 234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 235 | CLANG_CXX_LIBRARY = "libc++"; 236 | CLANG_ENABLE_MODULES = YES; 237 | CLANG_ENABLE_OBJC_ARC = YES; 238 | CLANG_WARN_BOOL_CONVERSION = YES; 239 | CLANG_WARN_CONSTANT_CONVERSION = YES; 240 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 241 | CLANG_WARN_EMPTY_BODY = YES; 242 | CLANG_WARN_ENUM_CONVERSION = YES; 243 | CLANG_WARN_INT_CONVERSION = YES; 244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 245 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 246 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 247 | COPY_PHASE_STRIP = NO; 248 | GCC_C_LANGUAGE_STANDARD = gnu99; 249 | GCC_DYNAMIC_NO_PIC = NO; 250 | GCC_OPTIMIZATION_LEVEL = 0; 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 256 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 257 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 258 | GCC_WARN_UNDECLARED_SELECTOR = YES; 259 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 260 | GCC_WARN_UNUSED_FUNCTION = YES; 261 | GCC_WARN_UNUSED_VARIABLE = YES; 262 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 263 | ONLY_ACTIVE_ARCH = YES; 264 | SDKROOT = iphoneos; 265 | TARGETED_DEVICE_FAMILY = "1,2"; 266 | }; 267 | name = Debug; 268 | }; 269 | 83D658DA19A00323009A9C56 /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | ALWAYS_SEARCH_USER_PATHS = NO; 273 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 274 | CLANG_CXX_LIBRARY = "libc++"; 275 | CLANG_ENABLE_MODULES = YES; 276 | CLANG_ENABLE_OBJC_ARC = YES; 277 | CLANG_WARN_BOOL_CONVERSION = YES; 278 | CLANG_WARN_CONSTANT_CONVERSION = 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_INT_CONVERSION = YES; 283 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 284 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 285 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 286 | COPY_PHASE_STRIP = YES; 287 | ENABLE_NS_ASSERTIONS = NO; 288 | GCC_C_LANGUAGE_STANDARD = gnu99; 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 296 | SDKROOT = iphoneos; 297 | TARGETED_DEVICE_FAMILY = "1,2"; 298 | VALIDATE_PRODUCT = YES; 299 | }; 300 | name = Release; 301 | }; 302 | 83D658DC19A00323009A9C56 /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 306 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 307 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 308 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 309 | GCC_PREFIX_HEADER = "TestApp/TestApp-Prefix.pch"; 310 | INFOPLIST_FILE = "TestApp/TestApp-Info.plist"; 311 | PRODUCT_BUNDLE_IDENTIFIER = com.appcelerator.testapp3; 312 | PRODUCT_NAME = "$(TARGET_NAME)"; 313 | WRAPPER_EXTENSION = app; 314 | }; 315 | name = Debug; 316 | }; 317 | 83D658DD19A00323009A9C56 /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 321 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 322 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; 323 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 324 | GCC_PREFIX_HEADER = "TestApp/TestApp-Prefix.pch"; 325 | INFOPLIST_FILE = "TestApp/TestApp-Info.plist"; 326 | PRODUCT_BUNDLE_IDENTIFIER = com.appcelerator.testapp3; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | WRAPPER_EXTENSION = app; 329 | }; 330 | name = Release; 331 | }; 332 | /* End XCBuildConfiguration section */ 333 | 334 | /* Begin XCConfigurationList section */ 335 | 83D658A119A00323009A9C56 /* Build configuration list for PBXProject "TestApp" */ = { 336 | isa = XCConfigurationList; 337 | buildConfigurations = ( 338 | 83D658D919A00323009A9C56 /* Debug */, 339 | 83D658DA19A00323009A9C56 /* Release */, 340 | ); 341 | defaultConfigurationIsVisible = 0; 342 | defaultConfigurationName = Release; 343 | }; 344 | 83D658DB19A00323009A9C56 /* Build configuration list for PBXNativeTarget "TestApp" */ = { 345 | isa = XCConfigurationList; 346 | buildConfigurations = ( 347 | 83D658DC19A00323009A9C56 /* Debug */, 348 | 83D658DD19A00323009A9C56 /* Release */, 349 | ); 350 | defaultConfigurationIsVisible = 0; 351 | defaultConfigurationName = Release; 352 | }; 353 | /* End XCConfigurationList section */ 354 | }; 355 | rootObject = 83D6589E19A00323009A9C56 /* Project object */; 356 | } 357 | -------------------------------------------------------------------------------- /test/TestApp/TestApp.xcodeproj/xcshareddata/xcschemes/TestApp.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 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TestApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TestApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 16 | NSString *documentsDirectory = [paths objectAtIndex:0]; 17 | NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"TestApp.log"]; 18 | freopen([logPath cStringUsingEncoding:NSUTF8StringEncoding], "w+", stderr); 19 | fprintf(stderr, "[INFO] Application started\n"); 20 | 21 | #ifdef TEST_BASIC_LOGGING 22 | NSLog(@"[INFO] info test"); 23 | NSLog(@"[DEBUG] debug test"); 24 | NSLog(@"[DEBUG] line 1 test\n[DEBUG] line 2 test"); 25 | NSLog(@"[DEBUG] AUTO_EXIT"); 26 | #endif 27 | 28 | #ifdef TEST_TIMOCHA 29 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_START"); 30 | NSLog(@"[DEBUG] {\"foo\":\"bar\"}"); 31 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_STOP"); 32 | #endif 33 | 34 | #ifdef TEST_TIMOCHA_MULTIPLE_LINES 35 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_START"); 36 | NSLog(@"[DEBUG] {"); 37 | NSLog(@"[DEBUG] \"foo\":\"bar\""); 38 | NSLog(@"[DEBUG] }"); 39 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_STOP"); 40 | #endif 41 | 42 | #ifdef TEST_TIMEOUT 43 | // do nothing, we want to time out explicitly here 44 | #endif 45 | 46 | #ifdef TEST_OBJC_CRASH 47 | // force a crash (unrecognized selector) 48 | SEL selector = NSSelectorFromString(@"pleaseCrash"); 49 | [NSObject performSelector:selector]; 50 | #endif 51 | 52 | #ifdef TEST_C_CRASH 53 | // force a crash (divide by zero) 54 | int *x = NULL; 55 | *x = 99; 56 | #endif 57 | 58 | // Override point for customization after application launch. 59 | return YES; 60 | } 61 | 62 | - (void)applicationWillResignActive:(UIApplication *)application 63 | { 64 | // 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. 65 | // 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. 66 | } 67 | 68 | - (void)applicationDidEnterBackground:(UIApplication *)application 69 | { 70 | // 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. 71 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 72 | } 73 | 74 | - (void)applicationWillEnterForeground:(UIApplication *)application 75 | { 76 | // 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. 77 | } 78 | 79 | - (void)applicationDidBecomeActive:(UIApplication *)application 80 | { 81 | // 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. 82 | } 83 | 84 | - (void)applicationWillTerminate:(UIApplication *)application 85 | { 86 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/Base.lproj/Main_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/Base.lproj/Main_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/Images.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" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /test/TestApp/TestApp/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /test/TestApp/TestApp/TestApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main_iPhone 29 | UIMainStoryboardFile~ipad 30 | Main_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/TestApp-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TestApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TestApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad 18 | { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view, typically from a nib. 21 | } 22 | 23 | - (void)didReceiveMemoryWarning 24 | { 25 | [super didReceiveMemoryWarning]; 26 | // Dispose of any resources that can be recreated. 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /test/TestApp/TestApp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TestApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit App/Base.lproj/Interface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit App/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "24x24", 5 | "idiom" : "watch", 6 | "scale" : "2x", 7 | "role" : "notificationCenter", 8 | "subtype" : "38mm" 9 | }, 10 | { 11 | "size" : "27.5x27.5", 12 | "idiom" : "watch", 13 | "scale" : "2x", 14 | "role" : "notificationCenter", 15 | "subtype" : "42mm" 16 | }, 17 | { 18 | "size" : "29x29", 19 | "idiom" : "watch", 20 | "role" : "companionSettings", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "size" : "29x29", 25 | "idiom" : "watch", 26 | "role" : "companionSettings", 27 | "scale" : "3x" 28 | }, 29 | { 30 | "size" : "40x40", 31 | "idiom" : "watch", 32 | "scale" : "2x", 33 | "role" : "appLauncher", 34 | "subtype" : "38mm" 35 | }, 36 | { 37 | "size" : "44x44", 38 | "idiom" : "watch", 39 | "scale" : "2x", 40 | "role" : "longLook", 41 | "subtype" : "42mm" 42 | }, 43 | { 44 | "size" : "86x86", 45 | "idiom" : "watch", 46 | "scale" : "2x", 47 | "role" : "quickLook", 48 | "subtype" : "38mm" 49 | }, 50 | { 51 | "size" : "98x98", 52 | "idiom" : "watch", 53 | "scale" : "2x", 54 | "role" : "quickLook", 55 | "subtype" : "42mm" 56 | } 57 | ], 58 | "info" : { 59 | "version" : 1, 60 | "author" : "xcode" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | TestWatchApp 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | com.appcelerator.TestWatchApp.watchkitapp 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | UISupportedInterfaceOrientations 26 | 27 | UIInterfaceOrientationPortrait 28 | UIInterfaceOrientationPortraitUpsideDown 29 | 30 | WKCompanionAppBundleIdentifier 31 | com.appcelerator.TestWatchApp 32 | WKWatchKitApp 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/GlanceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // GlanceController.h 3 | // TestWatchApp WatchKit Extension 4 | // 5 | // Created by Jonathan Alter on 4/16/15. 6 | // Copyright (c) 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface GlanceController : WKInterfaceController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/GlanceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // GlanceController.m 3 | // TestWatchApp WatchKit Extension 4 | // 5 | // Created by Jonathan Alter on 4/16/15. 6 | // Copyright (c) 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "GlanceController.h" 10 | 11 | 12 | @interface GlanceController() 13 | 14 | @end 15 | 16 | 17 | @implementation GlanceController 18 | 19 | - (void)awakeWithContext:(id)context { 20 | [super awakeWithContext:context]; 21 | 22 | // Configure interface objects here. 23 | } 24 | 25 | - (void)willActivate { 26 | // This method is called when watch view controller is about to be visible to user 27 | [super willActivate]; 28 | } 29 | 30 | - (void)didDeactivate { 31 | // This method is called when watch view controller is no longer visible 32 | [super didDeactivate]; 33 | } 34 | 35 | @end 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/Images.xcassets/README__ignoredByTemplate__: -------------------------------------------------------------------------------- 1 | Did you know that git does not support storing empty directories? 2 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | TestWatchApp WatchKit Extension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | com.appcelerator.TestWatchApp.watchkitextension 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | WKAppBundleIdentifier 30 | com.appcelerator.TestWatchApp.watchkitapp 31 | 32 | NSExtensionPointIdentifier 33 | com.apple.watchkit 34 | 35 | RemoteInterfacePrincipalClass 36 | InterfaceController 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/InterfaceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.h 3 | // TestWatchApp WatchKit Extension 4 | // 5 | // Created by Jonathan Alter on 4/16/15. 6 | // Copyright (c) 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface InterfaceController : WKInterfaceController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/InterfaceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.m 3 | // TestWatchApp WatchKit Extension 4 | // 5 | // Created by Jonathan Alter on 4/16/15. 6 | // Copyright (c) 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "InterfaceController.h" 10 | 11 | 12 | @interface InterfaceController() 13 | 14 | @end 15 | 16 | 17 | @implementation InterfaceController 18 | 19 | - (void)awakeWithContext:(id)context { 20 | [super awakeWithContext:context]; 21 | 22 | // Configure interface objects here. 23 | } 24 | 25 | - (void)willActivate { 26 | // This method is called when watch view controller is about to be visible to user 27 | [super willActivate]; 28 | } 29 | 30 | - (void)didDeactivate { 31 | // This method is called when watch view controller is no longer visible 32 | [super didDeactivate]; 33 | } 34 | 35 | @end 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/NotificationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationController.h 3 | // TestWatchApp WatchKit Extension 4 | // 5 | // Created by Jonathan Alter on 4/16/15. 6 | // Copyright (c) 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface NotificationController : WKUserNotificationInterfaceController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/NotificationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationController.m 3 | // TestWatchApp WatchKit Extension 4 | // 5 | // Created by Jonathan Alter on 4/16/15. 6 | // Copyright (c) 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "NotificationController.h" 10 | 11 | 12 | @interface NotificationController() 13 | 14 | @end 15 | 16 | 17 | @implementation NotificationController 18 | 19 | - (instancetype)init { 20 | self = [super init]; 21 | if (self){ 22 | // Initialize variables here. 23 | // Configure interface objects here. 24 | 25 | } 26 | return self; 27 | } 28 | 29 | - (void)willActivate { 30 | // This method is called when watch view controller is about to be visible to user 31 | [super willActivate]; 32 | } 33 | 34 | - (void)didDeactivate { 35 | // This method is called when watch view controller is no longer visible 36 | [super didDeactivate]; 37 | } 38 | 39 | /* 40 | - (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { 41 | // This method is called when a local notification needs to be presented. 42 | // Implement it if you use a dynamic notification interface. 43 | // Populate your dynamic notification interface as quickly as possible. 44 | // 45 | // After populating your dynamic notification interface call the completion block. 46 | completionHandler(WKUserNotificationInterfaceTypeCustom); 47 | } 48 | */ 49 | 50 | /* 51 | - (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { 52 | // This method is called when a remote notification needs to be presented. 53 | // Implement it if you use a dynamic notification interface. 54 | // Populate your dynamic notification interface as quickly as possible. 55 | // 56 | // After populating your dynamic notification interface call the completion block. 57 | completionHandler(WKUserNotificationInterfaceTypeCustom); 58 | } 59 | */ 60 | 61 | @end 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp WatchKit Extension/PushNotificationPayload.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "alert": { 4 | "body": "Test message", 5 | "title": "Optional title" 6 | }, 7 | "category": "myCategory" 8 | }, 9 | 10 | "WatchKit Simulator Actions": [ 11 | { 12 | "title": "First Button", 13 | "identifier": "firstButtonAction" 14 | } 15 | ], 16 | 17 | "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App." 18 | } 19 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp.xcodeproj/xcshareddata/xcschemes/Glance - TestWatchApp WatchKit App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 81 | 85 | 91 | 92 | 93 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 113 | 117 | 123 | 124 | 125 | 126 | 132 | 133 | 134 | 135 | 137 | 138 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp.xcodeproj/xcshareddata/xcschemes/Notification - TestWatchApp WatchKit App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 81 | 85 | 91 | 92 | 93 | 94 | 100 | 101 | 102 | 103 | 104 | 105 | 113 | 117 | 123 | 124 | 125 | 126 | 132 | 133 | 134 | 135 | 137 | 138 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp.xcodeproj/xcshareddata/xcschemes/TestWatchApp WatchKit App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 79 | 83 | 89 | 90 | 91 | 92 | 98 | 99 | 100 | 101 | 102 | 103 | 109 | 113 | 119 | 120 | 121 | 122 | 128 | 129 | 130 | 131 | 133 | 134 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp.xcodeproj/xcshareddata/xcschemes/TestWatchApp.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 51 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TestWatchApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TestWatchApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | #ifdef TEST_BASIC_LOGGING 16 | NSLog(@"[INFO] info test"); 17 | NSLog(@"[DEBUG] debug test"); 18 | NSLog(@"[DEBUG] line 1 test\n[DEBUG] line 2 test"); 19 | NSLog(@"[DEBUG] AUTO_EXIT"); 20 | #endif 21 | 22 | #ifdef TEST_TIMOCHA 23 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_START"); 24 | NSLog(@"[DEBUG] {\"foo\":\"bar\"}"); 25 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_STOP"); 26 | #endif 27 | 28 | #ifdef TEST_TIMOCHA_MULTIPLE_LINES 29 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_START"); 30 | NSLog(@"[DEBUG] {"); 31 | NSLog(@"[DEBUG] \"foo\":\"bar\""); 32 | NSLog(@"[DEBUG] }"); 33 | NSLog(@"[DEBUG] TI_MOCHA_RESULT_STOP"); 34 | #endif 35 | 36 | #ifdef TEST_TIMEOUT 37 | // do nothing, we want to time out explicitly here 38 | #endif 39 | 40 | #ifdef TEST_OBJC_CRASH 41 | // force a crash (unrecognized selector) 42 | SEL selector = NSSelectorFromString(@"pleaseCrash"); 43 | [NSObject performSelector:selector]; 44 | #endif 45 | 46 | #ifdef TEST_C_CRASH 47 | // force a crash (divide by zero) 48 | int *x = NULL; 49 | *x = 99; 50 | #endif 51 | 52 | // Override point for customization after application launch. 53 | return YES; 54 | } 55 | 56 | - (void)applicationWillResignActive:(UIApplication *)application 57 | { 58 | // 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. 59 | // 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. 60 | } 61 | 62 | - (void)applicationDidEnterBackground:(UIApplication *)application 63 | { 64 | // 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. 65 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 66 | } 67 | 68 | - (void)applicationWillEnterForeground:(UIApplication *)application 69 | { 70 | // 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. 71 | } 72 | 73 | - (void)applicationDidBecomeActive:(UIApplication *)application 74 | { 75 | // 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. 76 | } 77 | 78 | - (void)applicationWillTerminate:(UIApplication *)application 79 | { 80 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/Base.lproj/Main_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/Base.lproj/Main_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/Images.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" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "29x29", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "40x40", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "76x76", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/TestWatchApp-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.appcelerator.$(PRODUCT_NAME:rfc1034identifier) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main_iPhone 29 | UIMainStoryboardFile~ipad 30 | Main_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/TestWatchApp-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TestWatchApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TestWatchApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad 18 | { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view, typically from a nib. 21 | } 22 | 23 | - (void)didReceiveMemoryWarning 24 | { 25 | [super didReceiveMemoryWarning]; 26 | // Dispose of any resources that can be recreated. 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /test/TestWatchApp/TestWatchApp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TestWatchApp 4 | // 5 | // Created by Chris Barber on 8/16/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "24x24", 5 | "idiom" : "watch", 6 | "scale" : "2x", 7 | "role" : "notificationCenter", 8 | "subtype" : "38mm" 9 | }, 10 | { 11 | "size" : "27.5x27.5", 12 | "idiom" : "watch", 13 | "scale" : "2x", 14 | "role" : "notificationCenter", 15 | "subtype" : "42mm" 16 | }, 17 | { 18 | "size" : "29x29", 19 | "idiom" : "watch", 20 | "role" : "companionSettings", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "size" : "29x29", 25 | "idiom" : "watch", 26 | "role" : "companionSettings", 27 | "scale" : "3x" 28 | }, 29 | { 30 | "size" : "40x40", 31 | "idiom" : "watch", 32 | "scale" : "2x", 33 | "role" : "appLauncher", 34 | "subtype" : "38mm" 35 | }, 36 | { 37 | "size" : "44x44", 38 | "idiom" : "watch", 39 | "scale" : "2x", 40 | "role" : "longLook", 41 | "subtype" : "42mm" 42 | }, 43 | { 44 | "size" : "86x86", 45 | "idiom" : "watch", 46 | "scale" : "2x", 47 | "role" : "quickLook", 48 | "subtype" : "38mm" 49 | }, 50 | { 51 | "size" : "98x98", 52 | "idiom" : "watch", 53 | "scale" : "2x", 54 | "role" : "quickLook", 55 | "subtype" : "42mm" 56 | } 57 | ], 58 | "info" : { 59 | "version" : 1, 60 | "author" : "xcode" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit App/Base.lproj/Interface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | TestWatchApp2 WatchKit App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | UISupportedInterfaceOrientations 26 | 27 | UIInterfaceOrientationPortrait 28 | UIInterfaceOrientationPortraitUpsideDown 29 | 30 | WKCompanionAppBundleIdentifier 31 | com.appcelerator.TestWatchApp2 32 | WKWatchKitApp 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/Assets.xcassets/README__ignoredByTemplate__: -------------------------------------------------------------------------------- 1 | Did you know that git does not support storing empty directories? 2 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/ExtensionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionDelegate.h 3 | // TestWatchApp2 WatchKit Extension 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ExtensionDelegate : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/ExtensionDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionDelegate.m 3 | // TestWatchApp2 WatchKit Extension 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "ExtensionDelegate.h" 10 | 11 | @implementation ExtensionDelegate 12 | 13 | - (void)applicationDidFinishLaunching { 14 | // Perform any final initialization of your application. 15 | } 16 | 17 | - (void)applicationDidBecomeActive { 18 | // 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. 19 | } 20 | 21 | - (void)applicationWillResignActive { 22 | // 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. 23 | // Use this method to pause ongoing tasks, disable timers, etc. 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | TestWatchApp2 WatchKit Extension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSExtension 26 | 27 | NSExtensionAttributes 28 | 29 | WKAppBundleIdentifier 30 | com.appcelerator.TestWatchApp2.watchkitapp 31 | 32 | NSExtensionPointIdentifier 33 | com.apple.watchkit 34 | 35 | RemoteInterfacePrincipalClass 36 | InterfaceController 37 | WKExtensionDelegateClassName 38 | ExtensionDelegate 39 | 40 | 41 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/InterfaceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.h 3 | // TestWatchApp2 WatchKit Extension 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface InterfaceController : WKInterfaceController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/InterfaceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.m 3 | // TestWatchApp2 WatchKit Extension 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "InterfaceController.h" 10 | 11 | 12 | @interface InterfaceController() 13 | 14 | @end 15 | 16 | 17 | @implementation InterfaceController 18 | 19 | - (void)awakeWithContext:(id)context { 20 | [super awakeWithContext:context]; 21 | 22 | // Configure interface objects here. 23 | } 24 | 25 | - (void)willActivate { 26 | // This method is called when watch view controller is about to be visible to user 27 | [super willActivate]; 28 | } 29 | 30 | - (void)didDeactivate { 31 | // This method is called when watch view controller is no longer visible 32 | [super didDeactivate]; 33 | } 34 | 35 | @end 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/NotificationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationController.h 3 | // TestWatchApp2 WatchKit Extension 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface NotificationController : WKUserNotificationInterfaceController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/NotificationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationController.m 3 | // TestWatchApp2 WatchKit Extension 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "NotificationController.h" 10 | 11 | 12 | @interface NotificationController() 13 | 14 | @end 15 | 16 | 17 | @implementation NotificationController 18 | 19 | - (instancetype)init { 20 | self = [super init]; 21 | if (self){ 22 | // Initialize variables here. 23 | // Configure interface objects here. 24 | 25 | } 26 | return self; 27 | } 28 | 29 | - (void)willActivate { 30 | // This method is called when watch view controller is about to be visible to user 31 | [super willActivate]; 32 | } 33 | 34 | - (void)didDeactivate { 35 | // This method is called when watch view controller is no longer visible 36 | [super didDeactivate]; 37 | } 38 | 39 | /* 40 | - (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { 41 | // This method is called when a local notification needs to be presented. 42 | // Implement it if you use a dynamic notification interface. 43 | // Populate your dynamic notification interface as quickly as possible. 44 | // 45 | // After populating your dynamic notification interface call the completion block. 46 | completionHandler(WKUserNotificationInterfaceTypeCustom); 47 | } 48 | */ 49 | 50 | /* 51 | - (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler { 52 | // This method is called when a remote notification needs to be presented. 53 | // Implement it if you use a dynamic notification interface. 54 | // Populate your dynamic notification interface as quickly as possible. 55 | // 56 | // After populating your dynamic notification interface call the completion block. 57 | completionHandler(WKUserNotificationInterfaceTypeCustom); 58 | } 59 | */ 60 | 61 | @end 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2 WatchKit Extension/PushNotificationPayload.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "alert": { 4 | "body": "Test message", 5 | "title": "Optional title" 6 | }, 7 | "category": "myCategory" 8 | }, 9 | 10 | "WatchKit Simulator Actions": [ 11 | { 12 | "title": "First Button", 13 | "identifier": "firstButtonAction" 14 | } 15 | ], 16 | 17 | "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App." 18 | } 19 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2.xcodeproj/xcshareddata/xcschemes/Notification - TestWatchApp2 WatchKit App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 71 | 72 | 84 | 88 | 94 | 95 | 96 | 97 | 103 | 104 | 105 | 106 | 107 | 108 | 116 | 120 | 126 | 127 | 128 | 129 | 135 | 136 | 137 | 138 | 140 | 141 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2.xcodeproj/xcshareddata/xcschemes/TestWatchApp2 WatchKit App.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 71 | 72 | 82 | 86 | 92 | 93 | 94 | 95 | 101 | 102 | 103 | 104 | 105 | 106 | 112 | 116 | 122 | 123 | 124 | 125 | 131 | 132 | 133 | 134 | 136 | 137 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2.xcodeproj/xcshareddata/xcschemes/TestWatchApp2.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 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TestWatchApp2 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TestWatchApp2 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/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 | } -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/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 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TestWatchApp2 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TestWatchApp2 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view, typically from a nib. 20 | } 21 | 22 | - (void)didReceiveMemoryWarning { 23 | [super didReceiveMemoryWarning]; 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /test/TestWatchApp2/TestWatchApp2/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TestWatchApp2 4 | // 5 | // Created by Chris Barber on 7/22/15. 6 | // Copyright © 2015 Appcelerator. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/init.js: -------------------------------------------------------------------------------- 1 | global.should = null; 2 | global.should = require('should'); 3 | 4 | var util = require('util'); 5 | global.dump = function () { 6 | for (var i = 0; i < arguments.length; i++) { 7 | console.error(util.inspect(arguments[i], false, null, true)); 8 | } 9 | }; -------------------------------------------------------------------------------- /test/test-certs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib's certs module. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | const ioslib = require('..'); 13 | 14 | describe('certs', function () { 15 | it('namespace should be an object', function () { 16 | should(ioslib.certs).be.an.Object; 17 | }); 18 | 19 | it('detect certs', function (done) { 20 | this.timeout(5000); 21 | this.slow(2000); 22 | 23 | ioslib.certs.detect(function (err, results) { 24 | if (err) { 25 | return done(err); 26 | } 27 | 28 | should(results).be.an.Object; 29 | should(results).have.keys('certs', 'issues'); 30 | 31 | should(results.certs).have.keys('keychains', 'wwdr'); 32 | should(results.certs.keychains).be.an.Object; 33 | should(results.certs.wwdr).be.a.Boolean; 34 | 35 | Object.keys(results.certs.keychains).forEach(function (keychain) { 36 | should(results.certs.keychains[keychain]).be.an.Object; 37 | should(results.certs.keychains[keychain]).have.keys('developer', 'distribution'); 38 | should(results.certs.keychains[keychain].developer).be.an.Array; 39 | results.certs.keychains[keychain].developer.forEach(function (d) { 40 | should(d).be.an.Object; 41 | should(d).have.keys('name', 'fullname', 'pem', 'before', 'after', 'expired', 'invalid'); 42 | should(d.name).be.a.String; 43 | should(d.pem).be.a.String; 44 | should(d.before).be.a.Date; 45 | should(d.after).be.a.Date; 46 | should(d.expired).be.a.Boolean; 47 | should(d.invalid).be.a.Boolean; 48 | }); 49 | should(results.certs.keychains[keychain].distribution).be.an.Array; 50 | results.certs.keychains[keychain].distribution.forEach(function (d) { 51 | should(d).be.an.Object; 52 | should(d).have.keys('name', 'fullname', 'pem', 'before', 'after', 'expired', 'invalid'); 53 | should(d.name).be.a.String; 54 | should(d.pem).be.a.String; 55 | should(d.before).be.a.Date; 56 | should(d.after).be.a.Date; 57 | should(d.expired).be.a.Boolean; 58 | should(d.invalid).be.a.Boolean; 59 | }); 60 | }); 61 | 62 | should(results.issues).be.an.Array; 63 | results.issues.forEach(function (issue) { 64 | should(issue).be.an.Object; 65 | should(issue).have.keys('id', 'type', 'message'); 66 | should(issue.id).be.a.String; 67 | should(issue.type).be.a.String; 68 | should(issue.type).match(/^info|warning|error$/); 69 | should(issue.message).be.a.String; 70 | }); 71 | 72 | done(); 73 | }); 74 | }); 75 | 76 | it('return a emitter', function (done) { 77 | this.timeout(5000); 78 | this.slow(2000); 79 | 80 | ioslib.certs.detect({ bypassCache: true }).on('detected', function (results) { 81 | should(results).be.an.Object; 82 | done(); 83 | }); 84 | }); 85 | 86 | it('return results from cache', function (done) { 87 | this.timeout(5000); 88 | this.slow(2000); 89 | 90 | ioslib.certs.detect({ bypassCache: false }).on('detected', function (results) { 91 | should(results).be.an.Object; 92 | done(); 93 | }); 94 | }); 95 | 96 | it('watch for changes for 10 seconds', function (done) { 97 | this.timeout(50000); 98 | this.slow(50000); 99 | 100 | ioslib.certs.watch({ watchInterval: 1000 }, function (err, results) { 101 | should(results).be.an.Object; 102 | }); 103 | 104 | setTimeout(function () { 105 | ioslib.certs.unwatch(); 106 | done(); 107 | }, 10000); 108 | }); 109 | 110 | it('stop watching for updates', function (done) { 111 | this.timeout(50000); 112 | this.slow(50000); 113 | 114 | var counter = 0, 115 | unwatch = ioslib.certs.watch({ watchInterval: 4000 }, function (err, results) { 116 | should(results).be.an.Object; 117 | if (++counter > 1) { 118 | done(new Error('Watcher event was fired despite unwatching')); 119 | } 120 | }); 121 | 122 | setTimeout(function () { 123 | unwatch(); 124 | setTimeout(function () { 125 | done(); 126 | }, 6000); 127 | }, 2000); 128 | }); 129 | }); -------------------------------------------------------------------------------- /test/test-device.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib's device module. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | const 13 | appc = require('node-appc'), 14 | exec = require('child_process').exec, 15 | fs = require('fs'), 16 | ioslib = require('..'), 17 | path = require('path'); 18 | 19 | function build(app, provisioningProfileUUID, certName, defs, done){ 20 | if (typeof defs === 'function') { 21 | done = defs; 22 | defs = []; 23 | } 24 | 25 | ioslib.xcode.detect(function (err, env) { 26 | if (err) { 27 | return done(err); 28 | } 29 | 30 | if (env.selectedXcode === null) { 31 | return done(new Error(__('No selected Xcode'))); 32 | } 33 | 34 | var cmd = [ 35 | env.selectedXcode.executables.xcodebuild, 36 | 'clean', 'build', 37 | '-configuration', 'Debug', 38 | '-sdk', 'iphoneos' + appc.version.format(env.selectedXcode.sdks[0], 2, 2), 39 | 'PROVISIONING_PROFILE=' + provisioningProfileUUID, 40 | 'DEPLOYMENT_POSTPROCESSING=YES', 41 | // 'CODE_SIGN_IDENTITY="' + certName + '"', 42 | 'GCC_PREPROCESSOR_DEFINITIONS="' + defs.join(' ') + '"' 43 | ].join(' '); 44 | 45 | exec(cmd, { 46 | cwd: path.join(__dirname, app) 47 | }, function (code, out, err) { 48 | should(out).match(/BUILD SUCCEEDED/); 49 | var appPath = path.join(__dirname, app, 'build', 'Debug-iphoneos', app + '.app'); 50 | should(fs.existsSync(appPath)).be.true; 51 | done(null, appPath); 52 | }); 53 | }); 54 | } 55 | 56 | describe('device', function () { 57 | it('namespace should be an object', function () { 58 | should(ioslib.device).be.an.Object; 59 | }); 60 | 61 | it('detect iOS devices', function (done) { 62 | this.timeout(5000); 63 | this.slow(2000); 64 | 65 | ioslib.device.detect(function (err, results) { 66 | if (err) { 67 | return done(err); 68 | } 69 | 70 | should(results).be.an.Object; 71 | should(results).have.keys('devices', 'issues'); 72 | 73 | should(results.devices).be.an.Array; 74 | results.devices.forEach(function (dev) { 75 | should(dev).be.an.Object; 76 | should(dev).have.keys('udid', 'name', 'buildVersion', 'cpuArchitecture', 'deviceClass', 'deviceColor', 77 | 'hardwareModel', 'modelNumber', 'productType', 'productVersion', 'serialNumber'); 78 | 79 | should(dev.udid).be.a.String; 80 | should(dev.udid).not.equal(''); 81 | 82 | should(dev.name).be.a.String; 83 | should(dev.name).not.equal(''); 84 | 85 | should(dev.buildVersion).be.a.String; 86 | should(dev.buildVersion).not.equal(''); 87 | 88 | should(dev.cpuArchitecture).be.a.String; 89 | should(dev.cpuArchitecture).not.equal(''); 90 | 91 | should(dev.deviceClass).be.a.String; 92 | should(dev.deviceClass).not.equal(''); 93 | 94 | should(dev.deviceColor).be.a.String; 95 | should(dev.deviceColor).not.equal(''); 96 | 97 | should(dev.hardwareModel).be.a.String; 98 | should(dev.hardwareModel).not.equal(''); 99 | 100 | should(dev.modelNumber).be.a.String; 101 | should(dev.modelNumber).not.equal(''); 102 | 103 | should(dev.productType).be.a.String; 104 | should(dev.productType).not.equal(''); 105 | 106 | should(dev.productVersion).be.a.String; 107 | should(dev.productVersion).not.equal(''); 108 | 109 | should(dev.serialNumber).be.a.String; 110 | should(dev.serialNumber).not.equal(''); 111 | }); 112 | 113 | should(results.issues).be.an.Array; 114 | results.issues.forEach(function (issue) { 115 | should(issue).be.an.Object; 116 | should(issue).have.keys('id', 'type', 'message'); 117 | should(issue.id).be.a.String; 118 | should(issue.type).be.a.String; 119 | should(issue.type).match(/^info|warning|error$/); 120 | should(issue.message).be.a.String; 121 | }); 122 | 123 | done(); 124 | }); 125 | }); 126 | 127 | (process.env.CI ? it.skip : it)('should fail to install app bad app path', function (done) { 128 | this.timeout(30000); 129 | this.slow(30000); 130 | 131 | ioslib.device 132 | .install(null, '/path/to/something/that/does/not/exist', 'foo', function (err) { 133 | done(new Error('Callback was called unexpectedly')); 134 | }) 135 | .on('error', function (err) { 136 | should(err).be.an.instanceOf(Error); 137 | done(); 138 | }); 139 | }); 140 | 141 | (process.env.CI ? it.skip : it)('should be able to install app to device', function (done) { 142 | this.timeout(60000); 143 | this.slow(60000); 144 | 145 | var appId = 'com.appcelerator.testapp3'; 146 | 147 | // find us a device 148 | ioslib.findValidDeviceCertProfileCombos({ 149 | appId: appId, 150 | unmanagedProvisioningProfile: true 151 | }, function (err, results) { 152 | function noop() {} 153 | 154 | if (err) { 155 | return done(err); 156 | } 157 | 158 | if (!results.length) { 159 | return done(new Error('No valid device/cert/provisioning profile combos found')); 160 | } 161 | 162 | build('TestApp', results[0].ppUUID, results[0].certName, ['TEST_BASIC_LOGGING'], function (err, appPath) { 163 | should(err).not.be.ok; 164 | should(appPath).be.a.String; 165 | should(fs.existsSync(appPath)).be.ok; 166 | 167 | ioslib.device 168 | .install(results[0].deviceUDID, appPath, appId) 169 | .on('installed', function () { 170 | done(); 171 | }) 172 | .on('error', function (err) { 173 | done(err); 174 | }); 175 | }); 176 | }); 177 | }); 178 | }); 179 | -------------------------------------------------------------------------------- /test/test-env.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib's env module. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | var fs = require('fs'), 13 | ioslib = require('..'); 14 | 15 | describe('env', function () { 16 | it('namespace should be an object', function () { 17 | should(ioslib.env).be.an.Object; 18 | }); 19 | 20 | it('detect should find dev environment dependencies', function (done) { 21 | this.timeout(5000); 22 | this.slow(2000); 23 | 24 | ioslib.env.detect(function (err, results) { 25 | if (err) { 26 | return done(err); 27 | } 28 | 29 | should(results).be.an.Object; 30 | should(results).have.keys('executables', 'issues'); 31 | 32 | should(results.executables).be.an.Object; 33 | should(results.executables).have.keys('security', 'xcodeSelect'); 34 | 35 | if (results.executables.security !== null) { 36 | should(results.executables.security).be.a.String; 37 | should(fs.existsSync(results.executables.security)).be.ok; 38 | } 39 | 40 | if (results.executables.xcodeSelect !== null) { 41 | should(results.executables.xcodeSelect).be.a.String; 42 | should(fs.existsSync(results.executables.xcodeSelect)).be.ok; 43 | } 44 | 45 | should(results.issues).be.an.Array; 46 | results.issues.forEach(function (issue) { 47 | should(issue).be.an.Object; 48 | should(issue).have.keys('id', 'type', 'message'); 49 | should(issue.id).be.a.String; 50 | should(issue.type).be.a.String; 51 | should(issue.type).match(/^info|warning|error$/); 52 | should(issue.message).be.a.String; 53 | }); 54 | 55 | done(); 56 | }); 57 | }); 58 | }); -------------------------------------------------------------------------------- /test/test-ioslib.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib main detect function. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | var ioslib = require('..'), 13 | fs = require('fs'); 14 | 15 | describe('ioslib', function () { 16 | it('namespace should be an object', function () { 17 | should(ioslib).be.an.Object; 18 | should(ioslib.detect).be.a.Function; 19 | }); 20 | 21 | it('detect all iOS information', function (done) { 22 | this.timeout(60000); 23 | this.slow(30000); 24 | 25 | ioslib.detect(function (err, results) { 26 | if (err) { 27 | return done(err); 28 | } 29 | 30 | should(results).be.an.Object; 31 | should(results).have.keys('detectVersion', 'issues', 'devices', 'provisioning', 'executables', 'selectedXcode', 32 | 'xcode', 'certs', 'teams', 'simulators'); 33 | 34 | should(results.detectVersion).be.a.String; 35 | 36 | should(results.issues).be.an.Array; 37 | results.issues.forEach(function (issue) { 38 | should(issue).be.an.Object; 39 | should(issue).have.property('id'); 40 | should(issue).have.property('type'); 41 | should(issue).have.property('message'); 42 | should(issue.id).be.a.String; 43 | should(issue.type).be.a.String; 44 | should(issue.type).match(/^info|warning|error$/); 45 | should(issue.message).be.a.String; 46 | }); 47 | 48 | should(results.devices).be.an.Array; 49 | results.devices.forEach(function (dev) { 50 | should(dev).be.an.Object; 51 | should(dev).have.keys('udid', 'name', 'buildVersion', 'cpuArchitecture', 'deviceClass', 'deviceColor', 52 | 'hardwareModel', 'modelNumber', 'productType', 'productVersion', 'serialNumber'); 53 | 54 | should(dev.udid).be.a.String; 55 | should(dev.udid).not.equal(''); 56 | 57 | should(dev.name).be.a.String; 58 | should(dev.name).not.equal(''); 59 | 60 | should(dev.buildVersion).be.a.String; 61 | should(dev.buildVersion).not.equal(''); 62 | 63 | should(dev.cpuArchitecture).be.a.String; 64 | should(dev.cpuArchitecture).not.equal(''); 65 | 66 | should(dev.deviceClass).be.a.String; 67 | should(dev.deviceClass).not.equal(''); 68 | 69 | should(dev.deviceColor).be.a.String; 70 | should(dev.deviceColor).not.equal(''); 71 | 72 | should(dev.hardwareModel).be.a.String; 73 | should(dev.hardwareModel).not.equal(''); 74 | 75 | should(dev.modelNumber).be.a.String; 76 | should(dev.modelNumber).not.equal(''); 77 | 78 | should(dev.productType).be.a.String; 79 | should(dev.productType).not.equal(''); 80 | 81 | should(dev.productVersion).be.a.String; 82 | should(dev.productVersion).not.equal(''); 83 | 84 | should(dev.serialNumber).be.a.String; 85 | should(dev.serialNumber).not.equal(''); 86 | }); 87 | 88 | should(results.provisioning).be.an.Object; 89 | should(results.provisioning).have.keys('profileDir', 'development', 'distribution', 'adhoc'); 90 | 91 | should(results.provisioning.profileDir).be.a.String; 92 | should(results.provisioning.profileDir).not.equal(''); 93 | 94 | function checkProfiles(list) { 95 | list.forEach(function (pp) { 96 | should(pp).be.an.Object; 97 | should(pp).have.keys('file', 'uuid', 'name', 'appPrefix', 'creationDate', 'expirationDate', 'expired', 'certs', 'devices', 'team', 'appId', 'getTaskAllow', 'apsEnvironment'); 98 | 99 | should(pp.file).be.a.String; 100 | should(pp.file).not.equal(''); 101 | 102 | should(pp.uuid).be.a.String; 103 | should(pp.uuid).not.equal(''); 104 | 105 | should(pp.name).be.a.String; 106 | should(pp.name).not.equal(''); 107 | 108 | should(pp.appPrefix).be.a.String; 109 | should(pp.appPrefix).not.equal(''); 110 | 111 | should(pp.creationDate).be.a.Date; 112 | should(pp.expirationDate).be.a.Date; 113 | 114 | should(pp.expired).be.a.Boolean; 115 | 116 | should(pp.certs).be.an.Array; 117 | pp.certs.forEach(function (s) { 118 | should(s).be.a.String; 119 | should(s).not.equal(''); 120 | }); 121 | 122 | if (pp.devices !== null) { 123 | should(pp.devices).be.an.Array; 124 | pp.devices.forEach(function (s) { 125 | should(s).be.a.String; 126 | should(s).not.equal(''); 127 | }); 128 | } 129 | 130 | should(pp.team).be.an.Array; 131 | pp.team.forEach(function (s) { 132 | should(s).be.a.String; 133 | should(s).not.equal(''); 134 | }); 135 | 136 | should(pp.appId).be.a.String; 137 | should(pp.appId).not.equal(''); 138 | 139 | should(pp.getTaskAllow).be.a.Boolean; 140 | 141 | should(pp.apsEnvironment).be.a.String; 142 | }); 143 | } 144 | 145 | should(results.provisioning.development).be.an.Array; 146 | checkProfiles(results.provisioning.development); 147 | 148 | should(results.provisioning.distribution).be.an.Array; 149 | checkProfiles(results.provisioning.distribution); 150 | 151 | should(results.provisioning.adhoc).be.an.Array; 152 | checkProfiles(results.provisioning.adhoc); 153 | 154 | should(results.executables).be.an.Object; 155 | should(results.executables).have.keys('xcodeSelect', 'security'); 156 | 157 | should(results.executables.xcodeSelect).be.a.String; 158 | should(results.executables.xcodeSelect).not.equal(''); 159 | 160 | should(results.executables.security).be.a.String; 161 | should(results.executables.security).not.equal(''); 162 | 163 | function checkXcode(xcode) { 164 | should(xcode).be.an.Object; 165 | should(xcode).have.keys('xcodeapp', 'path', 'selected', 'version', 'build', 'supported', 'eulaAccepted', 'sdks', 'sims', 'simDeviceTypes', 'simRuntimes', 'watchos', 'tvos', 'teams', 'executables'); 166 | 167 | should(xcode.xcodeapp).be.a.String; 168 | should(xcode.xcodeapp).not.equal(''); 169 | should(fs.existsSync(xcode.xcodeapp)).be.true; 170 | should(fs.statSync(xcode.xcodeapp).isDirectory()).be.true; 171 | 172 | should(xcode.path).be.a.String; 173 | should(xcode.path).not.equal(''); 174 | should(fs.existsSync(xcode.path)).be.true; 175 | should(fs.statSync(xcode.path).isDirectory()).be.true; 176 | 177 | should(xcode.selected).be.a.Boolean; 178 | 179 | should(xcode.version).be.a.String; 180 | should(xcode.version).not.equal(''); 181 | 182 | should(xcode.build).be.a.String; 183 | should(xcode.build).not.equal(''); 184 | 185 | should([null, true, false, 'maybe']).containEql(xcode.supported); 186 | 187 | should(xcode.sdks).be.an.Array; 188 | xcode.sdks.forEach(function (s) { 189 | should(s).be.a.String; 190 | should(s).not.equal(''); 191 | }); 192 | 193 | should(xcode.sims).be.an.Array; 194 | xcode.sims.forEach(function (s) { 195 | should(s).be.a.String; 196 | should(s).not.equal(''); 197 | }); 198 | 199 | var keys = ['xcodebuild', 'clang', 'clang_xx', 'libtool', 'lipo', 'otool', 'pngcrush', 'simulator', 'watchsimulator', 'simctl']; 200 | should(xcode.executables).be.an.Object; 201 | keys.forEach(function (key) { 202 | should(xcode.executables).have.property(key); 203 | if (xcode.executables[key] !== null) { 204 | should(xcode.executables[key]).be.a.String; 205 | should(xcode.executables[key]).not.equal(''); 206 | should(fs.existsSync(xcode.executables[key])).be.true; 207 | should(fs.statSync(xcode.executables[key]).isDirectory()).be.false; 208 | } 209 | }); 210 | } 211 | 212 | should(results.selectedXcode).be.an.Object; 213 | checkXcode(results.selectedXcode); 214 | 215 | should(results.xcode).be.an.Object; 216 | Object.keys(results.xcode).forEach(function (ver) { 217 | checkXcode(results.xcode[ver]); 218 | }); 219 | 220 | should(results.certs).have.keys('keychains', 'wwdr'); 221 | should(results.certs.keychains).be.an.Object; 222 | should(results.certs.wwdr).be.a.Boolean; 223 | 224 | Object.keys(results.certs.keychains).forEach(function (keychain) { 225 | should(results.certs.keychains[keychain]).be.an.Object; 226 | should(results.certs.keychains[keychain]).have.keys('developer', 'distribution'); 227 | should(results.certs.keychains[keychain].developer).be.an.Array; 228 | results.certs.keychains[keychain].developer.forEach(function (d) { 229 | should(d).be.an.Object; 230 | should(d).have.keys('name', 'fullname', 'pem', 'before', 'after', 'expired', 'invalid'); 231 | should(d.name).be.a.String; 232 | should(d.pem).be.a.String; 233 | should(d.before).be.a.Date; 234 | should(d.after).be.a.Date; 235 | should(d.expired).be.a.Boolean; 236 | should(d.invalid).be.a.Boolean; 237 | }); 238 | should(results.certs.keychains[keychain].distribution).be.an.Array; 239 | results.certs.keychains[keychain].distribution.forEach(function (d) { 240 | should(d).be.an.Object; 241 | should(d).have.keys('name', 'fullname', 'pem', 'before', 'after', 'expired', 'invalid'); 242 | should(d.name).be.a.String; 243 | should(d.pem).be.a.String; 244 | should(d.before).be.a.Date; 245 | should(d.after).be.a.Date; 246 | should(d.expired).be.a.Boolean; 247 | should(d.invalid).be.a.Boolean; 248 | }); 249 | }); 250 | 251 | done(); 252 | }); 253 | }); 254 | 255 | (process.env.CI ? it.skip : it)('should find a device/cert/profile combination', function (done) { 256 | this.timeout(10000); 257 | this.slow(10000); 258 | 259 | ioslib.findValidDeviceCertProfileCombos({ 260 | appId: 'com.appcelerator.TestApp' 261 | }, function (err, results) { 262 | if (err) { 263 | return done(err); 264 | } 265 | 266 | should(results).be.an.Array; 267 | results.forEach(function (combo) { 268 | should(combo).be.an.Object; 269 | should(combo).have.keys('ppUUID', 'certName', 'deviceUDID'); 270 | 271 | should(combo.ppUUID).be.a.String; 272 | should(combo.ppUUID).not.equal(''); 273 | 274 | should(combo.certName).be.a.String; 275 | should(combo.certName).not.equal(''); 276 | 277 | should(combo.deviceUDID).be.a.String; 278 | should(combo.deviceUDID).not.equal(''); 279 | }); 280 | 281 | done(); 282 | }); 283 | }); 284 | }); 285 | -------------------------------------------------------------------------------- /test/test-provisioning.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib's provisioning module. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | const ioslib = require('..'); 13 | 14 | function checkProfiles(list) { 15 | list.forEach(function (pp) { 16 | should(pp).be.an.Object; 17 | should(pp).have.keys('file', 'uuid', 'name', 'appPrefix', 'creationDate', 'expirationDate', 'expired', 'certs', 'devices', 'team', 'appId', 'getTaskAllow', 'apsEnvironment'); 18 | 19 | should(pp.file).be.a.String; 20 | should(pp.file).not.equal(''); 21 | 22 | should(pp.uuid).be.a.String; 23 | should(pp.uuid).not.equal(''); 24 | 25 | should(pp.name).be.a.String; 26 | should(pp.name).not.equal(''); 27 | 28 | should(pp.appPrefix).be.a.String; 29 | should(pp.appPrefix).not.equal(''); 30 | 31 | should(pp.creationDate).be.a.Date; 32 | should(pp.expirationDate).be.a.Date; 33 | 34 | should(pp.expired).be.a.Boolean; 35 | 36 | should(pp.certs).be.an.Array; 37 | pp.certs.forEach(function (s) { 38 | should(s).be.a.String; 39 | should(s).not.equal(''); 40 | }); 41 | 42 | if (pp.devices !== null) { 43 | should(pp.devices).be.an.Array; 44 | pp.devices.forEach(function (s) { 45 | should(s).be.a.String; 46 | should(s).not.equal(''); 47 | }); 48 | } 49 | 50 | should(pp.team).be.an.Array; 51 | pp.team.forEach(function (s) { 52 | should(s).be.a.String; 53 | should(s).not.equal(''); 54 | }); 55 | 56 | should(pp.appId).be.a.String; 57 | should(pp.appId).not.equal(''); 58 | 59 | should(pp.getTaskAllow).be.a.Boolean; 60 | 61 | should(pp.apsEnvironment).be.a.String; 62 | }); 63 | } 64 | 65 | describe('provisioning', function () { 66 | it('namespace should be an object', function () { 67 | should(ioslib.provisioning).be.an.Object; 68 | }); 69 | 70 | it('detect provisioning profiles', function (done) { 71 | this.timeout(5000); 72 | this.slow(2000); 73 | 74 | ioslib.provisioning.detect(function (err, results) { 75 | if (err) { 76 | return done(err); 77 | } 78 | 79 | should(results).be.an.Object; 80 | should(results).have.keys('provisioning', 'issues'); 81 | 82 | should(results.provisioning).be.an.Object; 83 | should(results.provisioning).have.keys('profileDir', 'development', 'distribution', 'adhoc'); 84 | 85 | should(results.provisioning.profileDir).be.a.String; 86 | should(results.provisioning.profileDir).not.equal(''); 87 | 88 | should(results.provisioning.development).be.an.Array; 89 | checkProfiles(results.provisioning.development); 90 | 91 | should(results.provisioning.distribution).be.an.Array; 92 | checkProfiles(results.provisioning.distribution); 93 | 94 | should(results.provisioning.adhoc).be.an.Array; 95 | checkProfiles(results.provisioning.adhoc); 96 | 97 | should(results.issues).be.an.Array; 98 | results.issues.forEach(function (issue) { 99 | should(issue).be.an.Object; 100 | should(issue).have.keys('id', 'type', 'message'); 101 | should(issue.id).be.a.String; 102 | should(issue.type).be.a.String; 103 | should(issue.type).match(/^info|warning|error$/); 104 | should(issue.message).be.a.String; 105 | }); 106 | 107 | done(); 108 | }); 109 | }); 110 | 111 | it('return a emitter', function (done) { 112 | this.timeout(5000); 113 | this.slow(2000); 114 | 115 | ioslib.provisioning.detect({ bypassCache: true }).on('detected', function (results) { 116 | should(results).be.an.Object; 117 | done(); 118 | }); 119 | }); 120 | 121 | it('return results from cache', function (done) { 122 | this.timeout(5000); 123 | this.slow(2000); 124 | 125 | ioslib.provisioning.detect({ bypassCache: false }).on('detected', function (results) { 126 | should(results).be.an.Object; 127 | done(); 128 | }); 129 | }); 130 | 131 | it('find best provisioning profiles without a cert and without a device', function (done) { 132 | this.timeout(5000); 133 | this.slow(2000); 134 | 135 | ioslib.provisioning.detect({ bypassCache: true }, function (err, all) { 136 | ioslib.provisioning.find(function (err, found) { 137 | if (err) { 138 | done(err); 139 | } else { 140 | should(found).be.an.Array; 141 | should(found).length(all.provisioning.development.length + all.provisioning.distribution.length + all.provisioning.adhoc.length); 142 | checkProfiles(found); 143 | done(); 144 | } 145 | }); 146 | }); 147 | }); 148 | 149 | (process.env.CI ? it.skip : it)('find best provisioning profiles with a cert, but without a device', function (done) { 150 | this.timeout(5000); 151 | this.slow(2000); 152 | 153 | ioslib.provisioning.detect({ bypassCache: true }, function (err, all) { 154 | var pem = null, 155 | matches = 0; 156 | 157 | function fn(pp) { 158 | if (!pp.expired) { 159 | pem || (pem = pp.certs[0]); 160 | if (pp.certs.indexOf(pem) !== -1) { 161 | matches++; 162 | } 163 | } 164 | } 165 | 166 | all.provisioning.development.forEach(fn); 167 | all.provisioning.distribution.forEach(fn); 168 | all.provisioning.adhoc.forEach(fn); 169 | 170 | if (pem === null) { 171 | return done(new Error('No provisioning profiles found to run this test')); 172 | } 173 | 174 | ioslib.provisioning.find({ 175 | certs: { pem: pem } 176 | }, function (err, found) { 177 | if (err) { 178 | done(err); 179 | } else { 180 | should(found).be.an.Array; 181 | should(found).be.length(matches); 182 | checkProfiles(found); 183 | done(); 184 | } 185 | }); 186 | }); 187 | }); 188 | 189 | (process.env.CI ? it.skip : it)('find best provisioning profiles without a cert, but with a device', function (done) { 190 | this.timeout(5000); 191 | this.slow(2000); 192 | 193 | ioslib.provisioning.detect({ bypassCache: true }, function (err, all) { 194 | var device = null, 195 | matches = 0; 196 | 197 | function fn(pp) { 198 | if (!pp.expired && pp.devices !== null && pp.devices.length) { 199 | device || (device = pp.devices[0]); 200 | if (pp.devices.indexOf(device) !== -1) { 201 | matches++; 202 | } 203 | } 204 | } 205 | 206 | all.provisioning.development.forEach(fn); 207 | all.provisioning.distribution.forEach(fn); 208 | all.provisioning.adhoc.forEach(fn); 209 | 210 | if (device === null) { 211 | return done(new Error('No provisioning profiles found to run this test')); 212 | } 213 | 214 | ioslib.provisioning.find({ 215 | deviceUDIDs: device 216 | }, function (err, found) { 217 | if (err) { 218 | done(err); 219 | } else { 220 | should(found).be.an.Array; 221 | should(found).be.length(matches); 222 | checkProfiles(found); 223 | done(); 224 | } 225 | }); 226 | }); 227 | }); 228 | 229 | (process.env.CI ? it.skip : it)('find best provisioning profiles with a cert and a device', function (done) { 230 | this.timeout(5000); 231 | this.slow(2000); 232 | 233 | ioslib.provisioning.detect({ bypassCache: true }, function (err, all) { 234 | var pem = null, 235 | device = null, 236 | matches = 0; 237 | 238 | function fn(pp) { 239 | if (!pp.expired && pp.devices !== null && pp.devices.length) { 240 | pem || (pem = pp.certs[0]); 241 | device || (device = pp.devices[0]); 242 | if (pp.devices.indexOf(device) !== -1 && pp.certs.indexOf(pem) !== -1) { 243 | matches++; 244 | } 245 | } 246 | } 247 | 248 | all.provisioning.development.forEach(fn); 249 | all.provisioning.distribution.forEach(fn); 250 | all.provisioning.adhoc.forEach(fn); 251 | 252 | if (pem === null || device === null) { 253 | return done(new Error('No provisioning profiles found to run this test')); 254 | } 255 | 256 | ioslib.provisioning.find({ 257 | certs: { pem: pem }, 258 | deviceUDIDs: device 259 | }, function (err, found) { 260 | if (err) { 261 | done(err); 262 | } else { 263 | should(found).be.an.Array; 264 | should(found).be.length(matches); 265 | checkProfiles(found); 266 | done(); 267 | } 268 | }); 269 | }); 270 | }); 271 | 272 | (process.env.CI ? it.skip : it)('watch for changes for 10 seconds', function (done) { 273 | this.timeout(80000); 274 | this.slow(80000); 275 | 276 | ioslib.provisioning.watch(function (err, results) { 277 | should(results).be.an.Object; 278 | }); 279 | 280 | setTimeout(function () { 281 | ioslib.certs.unwatch(); 282 | done(); 283 | }, 10000); 284 | }); 285 | 286 | (process.env.CI ? it.skip : it)('stop watching for updates', function (done) { 287 | this.timeout(80000); 288 | this.slow(80000); 289 | 290 | var counter = 0; 291 | 292 | ioslib.provisioning.watch(function (err, results) { 293 | should(results).be.an.Object; 294 | if (++counter > 1) { 295 | done(new Error('Watcher event was fired despite unwatching')); 296 | } 297 | }); 298 | 299 | setTimeout(function () { 300 | ioslib.certs.unwatch(); 301 | setTimeout(function () { 302 | done(); 303 | }, 2000); 304 | }, 2000); 305 | }); 306 | 307 | // TODO: malformed provisioning profile? 308 | }); 309 | -------------------------------------------------------------------------------- /test/test-teams.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib's teams module. 3 | * 4 | * @copyright 5 | * Copyright (c) 2016 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | const ioslib = require('..'); 13 | 14 | describe('teams', function () { 15 | it('namespace should be an object', function () { 16 | should(ioslib.teams).be.an.Object; 17 | }); 18 | 19 | it('detect teams', function (done) { 20 | this.timeout(5000); 21 | this.slow(2000); 22 | 23 | ioslib.teams.detect(function (err, results) { 24 | if (err) { 25 | return done(err); 26 | } 27 | 28 | validateResults(results); 29 | done(); 30 | }); 31 | }); 32 | 33 | it('return a emitter', function (done) { 34 | this.timeout(30000); 35 | this.slow(10000); 36 | 37 | ioslib.teams.detect({ bypassCache: true }) 38 | .on('detected', function (results) { 39 | validateResults(results); 40 | done(); 41 | }) 42 | .on('error', done); 43 | }); 44 | }); 45 | 46 | function validateResults(results) { 47 | should(results).be.an.Object; 48 | should(results).have.keys('teams'); 49 | should(results.teams).be.an.Array; 50 | 51 | results.teams.forEach(function (team) { 52 | should(team).be.an.Object; 53 | should(team).have.keys('id', 'name'); 54 | should(team.id).be.a.String; 55 | should(team.id).not.equal(''); 56 | should(team.name).be.a.String; 57 | should(team.name).not.equal(''); 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /test/test-xcode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Tests ioslib's xcode module. 3 | * 4 | * @copyright 5 | * Copyright (c) 2014-2016 by Appcelerator, Inc. All Rights Reserved. 6 | * 7 | * @license 8 | * Licensed under the terms of the Apache Public License. 9 | * Please see the LICENSE included with this distribution for details. 10 | */ 11 | 12 | const 13 | fs = require('fs'), 14 | ioslib = require('..'); 15 | 16 | function checkXcode(xcode) { 17 | should(xcode).be.an.Object; 18 | should(xcode).have.keys('xcodeapp', 'path', 'selected', 'version', 'build', 19 | 'supported', 'eulaAccepted', 'sdks', 'sims', 'simDeviceTypes', 20 | 'simRuntimes', 'watchos', 'tvos', 'teams', 'executables'); 21 | 22 | should(xcode.xcodeapp).be.a.String; 23 | should(xcode.xcodeapp).not.equal(''); 24 | should(fs.existsSync(xcode.xcodeapp)).be.true; 25 | should(fs.statSync(xcode.xcodeapp).isDirectory()).be.true; 26 | 27 | should(xcode.path).be.a.String; 28 | should(xcode.path).not.equal(''); 29 | should(fs.existsSync(xcode.path)).be.true; 30 | should(fs.statSync(xcode.path).isDirectory()).be.true; 31 | 32 | should(xcode.selected).be.a.Boolean; 33 | should(xcode.eulaAccepted).be.a.Boolean; 34 | 35 | should(xcode.version).be.a.String; 36 | should(xcode.version).not.equal(''); 37 | 38 | should(xcode.build).be.a.String; 39 | should(xcode.build).not.equal(''); 40 | 41 | should([null, true, false, 'maybe']).containEql(xcode.supported); 42 | 43 | should(xcode.sdks).be.an.Array; 44 | xcode.sdks.forEach(function (s) { 45 | should(s).be.a.String; 46 | should(s).not.equal(''); 47 | }); 48 | 49 | should(xcode.sims).be.an.Array; 50 | xcode.sims.forEach(function (s) { 51 | should(s).be.a.String; 52 | should(s).not.equal(''); 53 | }); 54 | 55 | should(xcode.simDeviceTypes).be.an.Object; 56 | Object.keys(xcode.simDeviceTypes).forEach(function (name) { 57 | should(xcode.simDeviceTypes[name]).be.an.Object; 58 | should(xcode.simDeviceTypes[name]).have.keys('name', 'model', 'supportsWatch'); 59 | should(xcode.simDeviceTypes[name].name).be.a.String; 60 | should(xcode.simDeviceTypes[name].name).not.equal(''); 61 | should(xcode.simDeviceTypes[name].model).be.a.String; 62 | should(xcode.simDeviceTypes[name].model).not.equal(''); 63 | should(xcode.simDeviceTypes[name].supportsWatch).be.a.Boolean; 64 | }); 65 | 66 | should(xcode.simRuntimes).be.an.Object; 67 | Object.keys(xcode.simRuntimes).forEach(function (name) { 68 | should(xcode.simRuntimes[name]).be.an.Object; 69 | should(xcode.simRuntimes[name]).have.keys('name', 'version'); 70 | should(xcode.simRuntimes[name].name).be.a.String; 71 | should(xcode.simRuntimes[name].name).not.equal(''); 72 | should(xcode.simRuntimes[name].version).be.a.String; 73 | should(xcode.simRuntimes[name].version).not.equal(''); 74 | }); 75 | 76 | if (xcode.watchos !== null) { 77 | should(xcode.watchos.sdks).be.an.Array; 78 | xcode.watchos.sdks.forEach(function (s) { 79 | should(s).be.a.String; 80 | should(s).not.equal(''); 81 | }); 82 | 83 | should(xcode.watchos.sims).be.an.Array; 84 | xcode.watchos.sims.forEach(function (s) { 85 | should(s).be.a.String; 86 | should(s).not.equal(''); 87 | }); 88 | } 89 | 90 | should(xcode.teams).be.an.Object; 91 | Object.keys(xcode.teams).forEach(function (teamId) { 92 | should(xcode.teams[teamId]).be.an.Object; 93 | should(xcode.teams[teamId]).have.keys('name', 'status', 'type'); 94 | should(xcode.teams[teamId].name).be.a.String(); 95 | should(xcode.teams[teamId].name).not.equal(''); 96 | should(xcode.teams[teamId].status).be.a.String(); 97 | should(xcode.teams[teamId].status).not.equal(''); 98 | should(xcode.teams[teamId].type).be.a.String(); 99 | should(xcode.teams[teamId].type).not.equal(''); 100 | }); 101 | 102 | var keys = ['xcodebuild', 'clang', 'clang_xx', 'libtool', 'lipo', 'otool', 'pngcrush', 'simulator', 'watchsimulator', 'simctl']; 103 | should(xcode.executables).be.an.Object; 104 | keys.forEach(function (key) { 105 | should(xcode.executables).have.property(key); 106 | if (xcode.executables[key] !== null) { 107 | should(xcode.executables[key]).be.a.String; 108 | should(xcode.executables[key]).not.equal(''); 109 | should(fs.existsSync(xcode.executables[key])).be.true; 110 | should(fs.statSync(xcode.executables[key]).isDirectory()).be.false; 111 | } 112 | }); 113 | } 114 | 115 | describe('xcode', function () { 116 | it('namespace should be an object', function () { 117 | should(ioslib.xcode).be.an.Object; 118 | }); 119 | 120 | it('detect should find Xcode installations', function (done) { 121 | this.timeout(5000); 122 | this.slow(2000); 123 | 124 | ioslib.xcode.detect(function (err, results) { 125 | if (err) { 126 | return done(err); 127 | } 128 | 129 | should(results).be.an.Object; 130 | should(results).have.keys('selectedXcode', 'xcode', 'issues'); 131 | should(results.selectedXcode).be.an.Object; 132 | should(results.xcode).be.an.Object; 133 | should(results.issues).be.an.Array; 134 | 135 | if (results.selectedXcode !== null) { 136 | checkXcode(results.selectedXcode); 137 | } 138 | 139 | Object.keys(results.xcode).forEach(function (ver) { 140 | checkXcode(results.xcode[ver]); 141 | }); 142 | 143 | results.issues.forEach(function (issue) { 144 | should(issue).be.an.Object; 145 | should(issue).have.property('id'); 146 | should(issue).have.property('type'); 147 | should(issue).have.property('message'); 148 | should(issue.id).be.a.String; 149 | should(issue.type).be.a.String; 150 | should(issue.type).match(/^info|warning|error$/); 151 | should(issue.message).be.a.String; 152 | }); 153 | 154 | done(); 155 | }); 156 | }); 157 | }); 158 | --------------------------------------------------------------------------------