{ "id": "170218", "key": "TIMOB-25478", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": { "id": "10100", "description": "This issue won't be actioned.", "name": "Won't Do" }, "resolutiondate": "2018-08-22T06:29:12.000+0000", "created": "2017-11-03T14:46:25.000+0000", "priority": { "name": "Critical", "id": "1" }, "labels": [ "alloy", "hyperloop", "ios" ], "versions": [], "issuelinks": [], "assignee": { "name": "jvennemann", "key": "jvennemann", "displayName": "Jan Vennemann", "active": true, "timeZone": "Europe/Berlin" }, "updated": "2018-08-27T09:23:46.000+0000", "status": { "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.", "name": "Resolved", "id": "5", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "13715", "name": "Hyperloop", "description": "Hyperloop project" }, { "id": "10206", "name": "iOS", "description": "iOS Platform" } ], "description": "While the Hyperloop requirements state \"Alloy 1.8.0+\" does this mean that you MUST use Alloy for your UI or just that you have Alloy 1.8.0+ installed.\r\n\r\nWe have tried to use Hyperloop with a Classic project for iOS and while the correct JS and Objective-C code was generated, the app was not able to resolve references to classes generated by the Hyperloop invocations.\r\n\r\nWe put the same code into the Hyperloop-examples app (which is Alloy) and it compiled and ran OK.\r\n\r\nWe can get more specific about the problems and submit example code but I wanted initially to see whether the intention was to allow Hyperloop to work with Classic (Non-Alloy UI) apps.", "attachment": [ { "id": "63527", "filename": "test_hyperloop_classic.zip", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-11-03T15:28:55.000+0000", "size": 4911706, "mimeType": "application/zip" } ], "flagged": false, "summary": "Hyperloop: iOS - Cannot use Hyperloop.defineClass with a Classic (Non-Alloy) project", "creator": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "environment": "iOS 10/11, SDK 6.3, Hyperloop 2.2, Studio 4.9.1", "closedSprints": [ { "id": 1065, "state": "closed", "name": "2016 Sprint 17 SDK", "startDate": "2018-08-13T17:39:36.846Z", "endDate": "2018-08-27T17:39:00.000Z", "completeDate": "2018-08-29T16:10:57.013Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "430069", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "The requirements of Alloy 1.8+ are actually only for using Hyperloop with common-js tags (e.g. exposing native api's as view tags like {{}} using own tag-classes). I am pretty sure it should work with classic Titanium but let me attach a project to verify.\r\n\r\n*EDIT*: It works, I attached an example project. I probably know you issue :-) You may created a classic project, included the module but not the plugin. Please check the tiapp.xml of the attached example and let me know, I'll keep the ticket open until then.", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2017-11-03T15:20:17.000+0000", "updated": "2017-11-03T15:29:36.000+0000" }, { "id": "430072", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "That wasn't the problem. We're trying to use the iOS Bluetooth Library and we can get the same code to work when we include it in the Hyperloop-examples app but not in our own Classic app. We'll attach our example app but for a preview...\r\n\r\nThis is the error we get at runtime from this line...\r\n\r\nvar CentralManagerDelegate = Hyperloop.defineClass('CentralManagerDelegate', 'NSObject', ['CBCentralManagerDelegate']);\r\n\r\n[ERROR] :  Cannot find class with name: CentralManagerDelegate ... /BLETest.app/centralmanagerdelegate.js", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T16:09:32.000+0000", "updated": "2017-11-03T16:12:49.000+0000" }, { "id": "430087", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "It is starting to look to me like its all about the file system hierarchy with Classic doing its own thing vs Alloy. I was able to get defineClass to work in a Classic project but I'm waiting for my colleague to compare what I've done to what he was trying to do. ", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T19:25:18.000+0000", "updated": "2017-11-03T19:25:18.000+0000" }, { "id": "430090", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "So I went back to my colleague's test program and it is also very simple but it generates these errors from this call (I will attach his ap):\r\n\r\nvar CentralManagerDelegate = Hyperloop.defineClass('CentralManagerDelegate', 'NSObject', ['CBCentralManagerDelegate']);\r\n\r\nCannot find class with name: CentralManagerDelegate\r\n[ERROR] : Script Error {\r\n[ERROR] : column = 181;\r\n[ERROR] : description = \"Cannot find class with name: CentralManagerDelegate\";\r\n[ERROR] : line = 1;\r\n[ERROR] : message = \"Cannot find class with name: CentralManagerDelegate\";\r\n[ERROR] : name = ClassNotFound;\r\n[ERROR] : nativeStack = \"1 libobjc.A.dylib 0x0000000111dc7f41 objc_exception_throw + 48\\n2 BLETest 0x000000010af508e2 -[HyperloopClass initWithClassName:alloc:init:args:] + 386\\n3 BLETest 0x000000010af43614 DefineClass + 452\\n4 BLETest 0x000000010ad07c21 _ZN2TI19APICallbackFunction4callINS_18JSCallbackFunctionEEExPNS_9ExecStateE + 593\\n5 BLETest 0x000000010adb6187 _ZN2TI5LLInt9setUpCallEPNS_9ExecStateEPNS_11InstructionENS_22CodeSpecializationKindENS_7TiValueEPNS_17LLIntCallLinkInfoE + 503\\n6 BLETest 0x000000010adbabbd llint_op_call + 148\";\r\n[ERROR] : sourceURL = \"file:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/centralmanagerdelegate.js\";\r\n[ERROR] : stack = \"defineClass@[native code]\\nfile:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/centralmanagerdelegate.js:1:181\\nglobal code@file:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/centralmanagerdelegate.js:63:70\\nrequire@[native code]\\nfile:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/centralble.js:13:37\\nglobal code@file:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/centralble.js:96:70\\nrequire@[native code]\\nfile:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/app.js:62:27\\nglobal code@file:///Users/jrf/Library/Developer/CoreSimulator/Devices/88EBE46A-7202-4E84-8CF2-D18FEA477C6A/data/Containers/Bundle/Application/CAD70CE8-BD5C-47D3-880E-FF5DAC2ADC7B/BLETest.app/app.js:65:3\";\r\n[ERROR] : }\r\n[ERROR] : Script Error Module \"centralmanagerdelegate.js\" failed to leave a valid exports object\r\n[ERROR] : ErrorController is up. ABORTING showing of modal controller\r\n[ERROR] : Script Error Module \"centralble.js\" failed to leave a valid exports object\r\n[ERROR] : ErrorController is up. ABORTING showing of modal controller\r\n", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T20:34:12.000+0000", "updated": "2017-11-03T20:34:12.000+0000" }, { "id": "430091", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "Maybe I'm missing something somewhere but I can't find where to add an attachment.\r\n\r\nIn any case, here is the class definition file - centralmanagerdelegate.js:\r\n\r\n\r\n{code:java}\r\n/**\r\n * @author Kon Lovett\r\n */\r\n\r\nvar CentralManagerDelegate = Hyperloop.defineClass('CentralManagerDelegate', 'NSObject', ['CBCentralManagerDelegate']);\r\n\r\nCentralManagerDelegate.addMethod({\r\n selector : 'centralManagerDidUpdateState:',\r\n instance : true,\r\n arguments : ['CBCentralManager'],\r\n callback : function(central) {\r\n if (this.didUpdateState) {\r\n return this.didUpdateState(central);\r\n }\r\n }\r\n});\r\n\r\nCentralManagerDelegate.addMethod({\r\n selector : 'centralManager:willRestoreState:',\r\n instance : true,\r\n arguments : ['CBCentralManager', 'NSDictionary'],\r\n callback : function(central, dict) {\r\n if (this.willRestoreState) {\r\n return this.willRestoreState(central, dict);\r\n }\r\n }\r\n});\r\n\r\nCentralManagerDelegate.addMethod({\r\n selector : 'centralManager:didDiscoverPeripheral:advertisementData:RSSI:',\r\n instance : true,\r\n arguments : ['CBCentralManager', 'CBPeripheral', 'NSDictionary', 'NSNumber'],\r\n callback : function(central, peripheral, advertisementData, RSSI) {\r\n if (this.didDiscoverPeripheral) {\r\n return this.didDiscoverPeripheral(central, peripheral, advertisementData, RSSI);\r\n }\r\n }\r\n});\r\n\r\nCentralManagerDelegate.addMethod({\r\n selector : 'centralManager:didConnectPeripheral:',\r\n instance : true,\r\n arguments : ['CBCentralManager', 'CBPeripheral'],\r\n callback : function(central, peripheral) {\r\n if (this.didConnectPeripheral) {\r\n return this.didConnectPeripheral(central, peripheral);\r\n }\r\n }\r\n});\r\n\r\nCentralManagerDelegate.addMethod({\r\n selector : 'centralManager:didFailToConnectPeripheral:error:',\r\n instance : true,\r\n arguments : ['CBCentralManager', 'CBPeripheral', 'NSError'],\r\n callback : function(central, peripheral, error) {\r\n if (this.didFailToConnectPeripheral) {\r\n return this.didFailToConnectPeripheral(central, peripheral, error);\r\n }\r\n }\r\n});\r\n\r\nCentralManagerDelegate.addMethod({\r\n selector : 'centralManager:didDisconnectPeripheral:error:',\r\n instance : true,\r\n arguments : ['CBCentralManager', 'CBPeripheral', 'NSError'],\r\n callback : function(central, peripheral, error) {\r\n if (this.didDisconnectPeripheral) {\r\n return this.didDisconnectPeripheral(central, peripheral, error);\r\n }\r\n }\r\n});\r\n\r\nmodule.exports = CentralManagerDelegate;\r\n{code}\r\n", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T20:39:36.000+0000", "updated": "2017-11-03T20:42:15.000+0000" }, { "id": "430092", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "And here is the file that uses the new class... centralble.js\r\n\r\n\r\n{code:java}\r\n/**\r\n * @author Kon Lovett\r\n */\r\n\r\n/* */\r\n\r\nvar CBCentralManager = require('CoreBluetooth/CBCentralManager');\r\nvar CBUUID = require('CoreBluetooth/CBUUID');\r\n\r\nvar _ = require('underscore');\r\n\r\n//relative load\r\nvar CentralManagerDelegate = require('centralmanagerdelegate');\r\n\r\n/*\r\n* Module Init\r\n*/\r\n\r\n// CM delegate define\r\nvar cenManDel = new CentralManagerDelegate();\r\ncenManDel.didUpdateState = didUpdateState;\r\ncenManDel.willRestoreState = willRestoreState;\r\ncenManDel.didDiscoverPeripheral = didDiscoverPeripheral;\r\ncenManDel.didConnectPeripheral = didConnectPeripheral;\r\ncenManDel.didFailToConnectPeripheral = didFailToConnectPeripheral;\r\ncenManDel.didDisconnectPeripheral = didDisconnectPeripheral;\r\n\r\nvar centralManager = CBCentralManager.alloc().initWithDelegateQueueOptions(cenManDel, null, null);\r\n\r\nvar kindsMatcher;\r\n\r\n/* */\r\n\r\n// kinds : [ string ]\r\nfunction scan(kinds) {\r\n\r\n Ti.API.info('Scanning Desired');\r\n\r\n // look for all or a subset of peripherals\r\n var nativeKinds = null;\r\n if (!(kinds || kindsMatcher) || !kindsMatcher(kinds)) {\r\n kindsMatcher = null;\r\n if (kinds) {\r\n kindsMatcher = _.matcher(kinds);\r\n nativeKinds = _.map(kinds, function(uuidStr) {\r\n return CBUUID.UUIDWithString(uuidStr);\r\n });\r\n }\r\n }\r\n\r\n centralManager.scanForPeripheralsWithServicesOptions(nativeKinds, null);\r\n\r\n Ti.API.info('Scanning Started');\r\n}\r\n\r\n/* Delegate Callbacks */\r\n\r\nfunction didUpdateState(central) {\r\n Ti.API.info('didUpdateState');\r\n};\r\n\r\nfunction willRestoreState(central, dict) {\r\n Ti.API.info('willRestoreState');\r\n Ti.API.info('dict: ' + JSON.strfingify(dict, null, 4));\r\n};\r\n\r\nfunction didDiscoverPeripheral(central, peripheral, advertisementData, RSSI) {\r\n Ti.API.info('didDiscoverPeripheral');\r\n Ti.API.info('peripheral: ' + JSON.stringify(peripheral, null, 4));\r\n Ti.API.info('advertisementData: ' + JSON.stringify(advertisementData, null, 4));\r\n Ti.API.info('RSSI: ' + JSON.stringify(RSSI, null, 4));\r\n};\r\n\r\nfunction didConnectPeripheral(central, peripheral) {\r\n Ti.API.info('didConnectPeripheral');\r\n Ti.API.info('peripheral: ' + JSON.stringify(peripheral, null, 4));\r\n};\r\n\r\nfunction didFailToConnectPeripheral(central, peripheral, error) {\r\n Ti.API.info('didFailToConnectPeripheral');\r\n Ti.API.info('peripheral: ' + JSON.stringify(peripheral, null, 4));\r\n Ti.API.info('error: ' + JSON.stringify(error, null, 4));\r\n};\r\n\r\nfunction didDisconnectPeripheral(central, peripheral, error) {\r\n Ti.API.info('didDisconnectPeripheral');\r\n Ti.API.info('peripheral: ' + JSON.stringify(peripheral, null, 4));\r\n Ti.API.info('error: ' + JSON.stringify(error, null, 4));\r\n};\r\n\r\n/* */\r\n\r\nexports.scan = scan;\r\n{code}\r\n", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T20:40:47.000+0000", "updated": "2017-11-03T20:41:53.000+0000" }, { "id": "430094", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "and here is app.js\r\n\r\n\r\n{code:java}\r\n/*\r\n * Single Window Application Template:\r\n * A basic starting point for your application. Mostly a blank canvas.\r\n *\r\n * In app.js, we generally take care of a few things:\r\n * - Bootstrap the application with any data we need\r\n * - Check for dependencies like device type, platform version or network connection\r\n * - Require and open our top-level UI component\r\n *\r\n */\r\n\r\n//bootstrap and check dependencies\r\nif (Ti.version < 1.8) {\r\n alert('Sorry - this application template requires Titanium Mobile SDK 1.8 or later');\r\n}\r\n\r\n// This is a single context application with multiple windows in a stack\r\n(function() {\r\n //render appropriate components based on the platform and form factor\r\n var osname = Ti.Platform.osname,\r\n version = Ti.Platform.version,\r\n height = Ti.Platform.displayCaps.platformHeight,\r\n width = Ti.Platform.displayCaps.platformWidth;\r\n\r\n //considering tablets to have width over 720px and height over 600px - you can define your own\r\n function checkTablet() {\r\n var platform = Ti.Platform.osname;\r\n\r\n switch (platform) {\r\n case 'ipad':\r\n return true;\r\n case 'android':\r\n var psc = Ti.Platform.Android.physicalSizeCategory;\r\n var tiAndroid = Ti.Platform.Android;\r\n return psc === tiAndroid.PHYSICAL_SIZE_CATEGORY_LARGE || psc === tiAndroid.PHYSICAL_SIZE_CATEGORY_XLARGE;\r\n default:\r\n return Math.min(\r\n Ti.Platform.displayCaps.platformHeight,\r\n Ti.Platform.displayCaps.platformWidth\r\n ) >= 400;\r\n }\r\n }\r\n\r\n var isTablet = checkTablet();\r\n console.log(isTablet);\r\n\r\n var Window;\r\n if (isTablet) {\r\n Window = require('ui/tablet/ApplicationWindow');\r\n } else {\r\n // Android uses platform-specific properties to create windows.\r\n // All other platforms follow a similar UI pattern.\r\n if (osname === 'android') {\r\n Window = require('ui/handheld/android/ApplicationWindow');\r\n } else {\r\n Window = require('ui/handheld/ApplicationWindow');\r\n }\r\n }\r\n new Window().open();\r\n \r\n // pulled from iphone/ or android/ into toplevel depending on OS\r\n var CentralBLE = require('centralble');\r\n CentralBLE.scan();\r\n \r\n})();\r\n\r\n{code}\r\n", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T20:41:23.000+0000", "updated": "2017-11-03T20:41:23.000+0000" }, { "id": "430095", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "I put all 3 of these files in the top level (Resources). That's it for the code files.", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T20:43:30.000+0000", "updated": "2017-11-03T20:43:30.000+0000" }, { "id": "430096", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "As I noted before, this code works when it is integrated into Hyperloop-examples which is an Alloy app. ", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2017-11-03T20:51:26.000+0000", "updated": "2017-11-03T20:51:26.000+0000" }, { "id": "440979", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "So we investigates this internally and I even ran into this myself while trying to setup a test app. The reason it does does not work is that you need to import a Hyperloop-related class in order to trigger the Hyperloop compiler. Since there is no case where you would define a class without assigning it to a native class (e.g. as a delegate in 90 %), this does not represent an issue that should block anyone. An example to resolve this:\r\n{code:js}\r\n/ ES6+\r\nimport { UIButton } from 'UIKit';\r\n\r\n// ES5\r\nconst UIButton = require('UIKit/UIButton');\r\n{code}", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-08-22T06:29:12.000+0000", "updated": "2018-08-22T06:29:12.000+0000" }, { "id": "441003", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "So importing any random class will do the trick and \"fix\" this problem. Thanks for pointing this out.", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-08-22T23:52:40.000+0000", "updated": "2018-08-22T23:52:40.000+0000" }, { "id": "441008", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "[~jfalcone] I am wondering what you do with the created native class if not passed to any other Hyperloop based API (class/method/property). I personally only used it for subclassing / delegate-handling so far, but if there is a case where you would use it without that, we can make that happen as well. A simple change would be to scan for the \"Hyperloop.defineClass\" call like we do for the specific require/import statements already. All in for better UX!", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-08-23T07:19:03.000+0000", "updated": "2018-08-23T07:19:03.000+0000" }, { "id": "441013", "author": { "name": "weevil", "key": "weevil", "displayName": "Kon Lovett", "active": true, "timeZone": "America/Los_Angeles" }, "body": "(define)\r\nvar CentralManagerDelegate = Hyperloop.defineClass('CentralManagerDelegate', 'NSObject', ['CBCentralManagerDelegate']);\r\n ...\r\nmodule.exports = CentralManagerDelegate;\r\n\r\n(use)\r\nvar CentralManagerDelegate = require('centralmanagerdelegate');\r\n\r\nat no point is the BLE code directly associated w/ any native UI. so BLE is not a \"Hyperloop based API\"?\r\n\r\n", "updateAuthor": { "name": "weevil", "key": "weevil", "displayName": "Kon Lovett", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-08-23T13:46:58.000+0000", "updated": "2018-08-23T13:46:58.000+0000" }, { "id": "441023", "author": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "body": "What my colleague is saying is that there are situations where you would be using classes that may not be associated with native UX classes such as artificial intelligence/neural networks, data mining, communications and the like. ", "updateAuthor": { "name": "jfalcone", "key": "jfalcone", "displayName": "Joe Falcone", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2018-08-23T18:26:47.000+0000", "updated": "2018-08-23T18:26:47.000+0000" }, { "id": "441075", "author": { "name": "jvennemann", "key": "jvennemann", "displayName": "Jan Vennemann", "active": true, "timeZone": "Europe/Berlin" }, "body": "[~weevil], [~jfalcone], i think there might be a misunderstanding here. At some point you will do\r\n\r\n{code:js}\r\nvar CBCentralManager = require('CoreBluetooth/CBCentralManager');\r\nvar CentralManagerDelegate = require('centralmanagerdelegate');\r\nvar cenManDel = new CentralManagerDelegate();\r\nvar centralManager = CBCentralManager.alloc().initWithDelegateQueueOptions(cenManDel, null, null);\r\n{code}\r\n\r\nThe first line is your native class usage that will trigger Hyperloop. It is not required to use any UI related classes, just any native class will do. Hans' code using the UIButton was only an example for a native class usage. I hope this clears things up :)", "updateAuthor": { "name": "jvennemann", "key": "jvennemann", "displayName": "Jan Vennemann", "active": true, "timeZone": "Europe/Berlin" }, "created": "2018-08-27T09:23:07.000+0000", "updated": "2018-08-27T09:23:46.000+0000" } ], "maxResults": 19, "total": 19, "startAt": 0 } } }