@maccesar/titools 2.0.7 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
- package/README.md +250 -168
- package/agents/{ti-researcher.md → ti-pro.md} +10 -10
- package/bin/titools.js +16 -12
- package/lib/cleanup.js +95 -0
- package/lib/commands/agents.js +146 -70
- package/lib/commands/skills.js +349 -0
- package/lib/commands/uninstall.js +189 -154
- package/lib/commands/update.js +104 -21
- package/lib/config.js +26 -20
- package/lib/downloader.js +1 -1
- package/lib/installer.js +37 -97
- package/lib/platform.js +9 -5
- package/lib/prompts/checkboxCancel.js +264 -0
- package/lib/prompts/selectCancel.js +204 -0
- package/lib/symlink.js +19 -7
- package/lib/utils.js +17 -17
- package/package.json +10 -10
- package/skills/alloy-guides/SKILL.md +8 -30
- package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
- package/skills/alloy-guides/references/CONCEPTS.md +5 -25
- package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
- package/skills/alloy-guides/references/MODELS.md +40 -10
- package/skills/alloy-guides/references/PURGETSS.md +1 -11
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
- package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
- package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
- package/skills/alloy-guides/references/WIDGETS.md +1 -17
- package/skills/alloy-howtos/SKILL.md +1 -22
- package/skills/alloy-howtos/references/best_practices.md +0 -17
- package/skills/alloy-howtos/references/cli_reference.md +1 -23
- package/skills/alloy-howtos/references/config_files.md +86 -15
- package/skills/alloy-howtos/references/custom_tags.md +14 -13
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
- package/skills/alloy-howtos/references/samples.md +4 -14
- package/skills/purgetss/SKILL.md +11 -37
- package/skills/purgetss/references/EXAMPLES.md +106 -17
- package/skills/purgetss/references/animation-system.md +0 -67
- package/skills/purgetss/references/apply-directive.md +0 -18
- package/skills/purgetss/references/arbitrary-values.md +0 -25
- package/skills/purgetss/references/class-index.md +0 -46
- package/skills/purgetss/references/cli-commands.md +0 -41
- package/skills/purgetss/references/configurable-properties.md +0 -55
- package/skills/purgetss/references/custom-rules.md +0 -14
- package/skills/purgetss/references/customization-deep-dive.md +0 -49
- package/skills/purgetss/references/dynamic-component-creation.md +56 -37
- package/skills/purgetss/references/grid-layout.md +0 -32
- package/skills/purgetss/references/icon-fonts.md +0 -50
- package/skills/purgetss/references/installation-setup.md +61 -32
- package/skills/purgetss/references/migration-guide.md +127 -0
- package/skills/purgetss/references/opacity-modifier.md +0 -34
- package/skills/purgetss/references/performance-tips.md +261 -0
- package/skills/purgetss/references/platform-modifiers.md +0 -46
- package/skills/purgetss/references/smart-mappings.md +0 -12
- package/skills/purgetss/references/tikit-components.md +393 -0
- package/skills/purgetss/references/titanium-resets.md +1 -27
- package/skills/purgetss/references/ui-ux-design.md +467 -117
- package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
- package/skills/ti-expert/references/alloy-builtins.md +387 -0
- package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
- package/skills/ti-expert/references/anti-patterns.md +90 -0
- package/skills/ti-expert/references/cli-expert.md +109 -0
- package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
- package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
- package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
- package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
- package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
- package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
- package/skills/ti-expert/references/performance-listview.md +251 -0
- package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
- package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
- package/skills/ti-expert/references/security-fundamentals.md +284 -0
- package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
- package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
- package/skills/ti-expert/references/testing-unit.md +433 -0
- package/skills/ti-expert/references/theming.md +394 -0
- package/skills/ti-guides/SKILL.md +1 -14
- package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
- package/skills/ti-guides/references/app-distribution.md +48 -10
- package/skills/ti-guides/references/application-frameworks.md +9 -2
- package/skills/ti-guides/references/cli-reference.md +338 -82
- package/skills/ti-guides/references/coding-best-practices.md +14 -4
- package/skills/ti-guides/references/commonjs-advanced.md +103 -6
- package/skills/ti-guides/references/hello-world.md +5 -2
- package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
- package/skills/ti-guides/references/javascript-primer.md +4 -3
- package/skills/ti-guides/references/resources.md +0 -1
- package/skills/ti-guides/references/style-and-conventions.md +57 -9
- package/skills/ti-guides/references/tiapp-config.md +48 -6
- package/skills/ti-howtos/SKILL.md +2 -27
- package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
- package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
- package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
- package/skills/ti-howtos/references/cross-platform-development.md +68 -37
- package/skills/ti-howtos/references/debugging-profiling.md +8 -53
- package/skills/ti-howtos/references/extending-titanium.md +12 -51
- package/skills/ti-howtos/references/google-maps-v2.md +30 -29
- package/skills/ti-howtos/references/ios-map-kit.md +19 -25
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
- package/skills/ti-howtos/references/local-data-sources.md +45 -37
- package/skills/ti-howtos/references/location-and-maps.md +47 -28
- package/skills/ti-howtos/references/media-apis.md +84 -27
- package/skills/ti-howtos/references/notification-services.md +40 -89
- package/skills/ti-howtos/references/remote-data-sources.md +21 -36
- package/skills/ti-howtos/references/tutorials.md +79 -39
- package/skills/ti-howtos/references/using-modules.md +4 -30
- package/skills/ti-howtos/references/web-content-integration.md +28 -45
- package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
- package/skills/ti-ui/SKILL.md +1 -21
- package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
- package/skills/ti-ui/references/animation-and-matrices.md +0 -47
- package/skills/ti-ui/references/application-structures.md +0 -46
- package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
- package/skills/ti-ui/references/event-handling.md +32 -40
- package/skills/ti-ui/references/gestures.md +0 -40
- package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
- package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
- package/skills/ti-ui/references/listviews-and-performance.md +187 -73
- package/skills/ti-ui/references/orientation.md +57 -71
- package/skills/ti-ui/references/platform-ui-android.md +114 -48
- package/skills/ti-ui/references/platform-ui-ios.md +63 -38
- package/skills/ti-ui/references/scrolling-views.md +14 -23
- package/skills/ti-ui/references/tableviews.md +6 -56
- package/lib/commands/install.js +0 -188
- package/skills/alloy-expert/references/anti-patterns.md +0 -133
- package/skills/alloy-expert/references/testing.md +0 -872
- package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
- package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
- /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
- /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# CommonJS Advanced Patterns
|
|
2
2
|
|
|
3
|
+
> For more on CommonJS in Titanium, see the official CommonJS Modules guide in the Titanium SDK documentation.
|
|
4
|
+
|
|
5
|
+
## Definitions
|
|
6
|
+
|
|
7
|
+
- **Module** - Any CommonJS-compliant module consumed in a Titanium SDK application. This can be a JavaScript file included with the app, or a native extension to Titanium which exposes a JavaScript API.
|
|
8
|
+
- **Resources** - The Resources directory of a Titanium application, where user source code lives before processing by the build system. **Note**: For Alloy, CommonJS modules are placed in `app/lib`.
|
|
9
|
+
- **`exports`** - A free variable within a module, to which multiple properties may be added to create a public interface.
|
|
10
|
+
- **`module.exports`** - An object within a module, which may be REPLACED by an object representing the public interface to the module.
|
|
11
|
+
|
|
3
12
|
## 1. Stateful Modules (Singleton Pattern)
|
|
4
13
|
|
|
5
14
|
Modules in Titanium are created once per JavaScript context and then passed by reference on subsequent `require()` calls. This makes them ideal for maintaining application state.
|
|
@@ -27,7 +36,49 @@ exports.reset = () => {
|
|
|
27
36
|
### Critical Note
|
|
28
37
|
A module is created once **per Titanium JavaScript context**. Additional contexts create new module instances.
|
|
29
38
|
|
|
30
|
-
## 2.
|
|
39
|
+
## 2. Native/Compiled Modules
|
|
40
|
+
|
|
41
|
+
When `require()` is called, Titanium first checks for a native/compiled module before looking for a JavaScript module. Native modules take priority.
|
|
42
|
+
|
|
43
|
+
Native modules are identified by a single string and configured in `tiapp.xml`:
|
|
44
|
+
|
|
45
|
+
```xml
|
|
46
|
+
<modules>
|
|
47
|
+
<module version="1.0">ti.paypal</module>
|
|
48
|
+
</modules>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const paypal = require('ti.paypal')
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Titanium loads `ti.paypal` as a native module and will NOT look for a JavaScript file in Resources. Only if no native module matches does Titanium fall back to JavaScript module resolution.
|
|
56
|
+
|
|
57
|
+
## 3. Module Path Resolution
|
|
58
|
+
|
|
59
|
+
The string passed to `require()` is treated as a path to a JavaScript file, minus the `.js` extension.
|
|
60
|
+
|
|
61
|
+
**Resolution rules:**
|
|
62
|
+
- **No prefix** (`require('app/lib/myModule')`) - resolved relative to the `Resources` directory (or `app/lib` in Alloy)
|
|
63
|
+
- **`/` prefix** (`require('/app/lib/myModule')`) - also resolved relative to the `Resources` directory
|
|
64
|
+
- **`./` or `../` prefix** (`require('./widgets/SomeView')`) - resolved relative to the current module file
|
|
65
|
+
|
|
66
|
+
**Example with relative paths:**
|
|
67
|
+
|
|
68
|
+
Given these files:
|
|
69
|
+
- `Resources/app/ui/SomeCustomView.js`
|
|
70
|
+
- `Resources/app/ui/widgets/SomeOtherCustomView.js`
|
|
71
|
+
- `Resources/app/lib/myModule.js`
|
|
72
|
+
|
|
73
|
+
Inside `SomeCustomView.js`:
|
|
74
|
+
```javascript
|
|
75
|
+
const myModule = require('../lib/myModule')
|
|
76
|
+
const SomeOtherCustomView = require('./widgets/SomeOtherCustomView')
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The `.js` extension is always omitted in `require()` calls.
|
|
80
|
+
|
|
81
|
+
## 4. Caching Behavior
|
|
31
82
|
|
|
32
83
|
Titanium caches the object returned by `require()` and provides the same reference without re-evaluating the code.
|
|
33
84
|
|
|
@@ -42,7 +93,7 @@ exports.createView = (args) => {
|
|
|
42
93
|
// Bad - expecting re-evaluation
|
|
43
94
|
```
|
|
44
95
|
|
|
45
|
-
##
|
|
96
|
+
## 5. ES6+ Support (SDK 7.1.0+)
|
|
46
97
|
|
|
47
98
|
Since Titanium SDK 7.1.0, you can use ES6+ module syntax. Code is transpiled to ES5 for all platforms.
|
|
48
99
|
|
|
@@ -63,7 +114,7 @@ import MyClass from 'MyClass'
|
|
|
63
114
|
const instance = new MyClass('World')
|
|
64
115
|
```
|
|
65
116
|
|
|
66
|
-
##
|
|
117
|
+
## 6. Module Composition Patterns
|
|
67
118
|
|
|
68
119
|
### Exports Object Pattern
|
|
69
120
|
```javascript
|
|
@@ -90,7 +141,53 @@ class Person {
|
|
|
90
141
|
module.exports = Person
|
|
91
142
|
```
|
|
92
143
|
|
|
93
|
-
|
|
144
|
+
### Utility Library Pattern
|
|
145
|
+
```javascript
|
|
146
|
+
// app/lib/logger.js
|
|
147
|
+
exports.info = (str) => {
|
|
148
|
+
Ti.API.info(`${new Date()}: ${str}`)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
exports.debug = (str) => {
|
|
152
|
+
Ti.API.debug(`${new Date()}: ${str}`)
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Usage:**
|
|
157
|
+
```javascript
|
|
158
|
+
const logger = require('logger')
|
|
159
|
+
logger.info('some log statement with a timestamp')
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 7. Inter-Module State Sharing
|
|
163
|
+
|
|
164
|
+
When a module assigns a primitive value to `exports`, the consumer gets a **copy**, not a live reference. Subsequent changes to the internal variable are NOT reflected in the exported property.
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
// app/lib/statefulModule.js
|
|
168
|
+
let _stepVal = 5
|
|
169
|
+
|
|
170
|
+
exports.setPointStep = (value) => {
|
|
171
|
+
_stepVal = value
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
exports.getPointStep = () => {
|
|
175
|
+
return _stepVal
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
exports.stepVal = _stepVal // This is a COPY of _stepVal (value: 5)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
const stateful = require('statefulModule')
|
|
183
|
+
stateful.setPointStep(10)
|
|
184
|
+
Ti.API.info(stateful.getPointStep()) // 10 - correct, uses getter
|
|
185
|
+
Ti.API.info(stateful.stepVal) // 5 - still the original copy!
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Rule**: Always use getter/setter functions for stateful values. Direct property exports of primitives are snapshots at module load time.
|
|
189
|
+
|
|
190
|
+
## 8. Antipatterns to Avoid
|
|
94
191
|
|
|
95
192
|
### Don't Assign Directly to exports
|
|
96
193
|
```javascript
|
|
@@ -114,7 +211,7 @@ exports.foo = 'bar'
|
|
|
114
211
|
### No Global Variables Across Modules
|
|
115
212
|
Any data a module needs must be passed during construction or initialization. Never rely on globals shared across modules.
|
|
116
213
|
|
|
117
|
-
##
|
|
214
|
+
## 9. Security and Scope
|
|
118
215
|
|
|
119
216
|
All modules have private scope. Variables declared within the module are private unless added to `exports`.
|
|
120
217
|
|
|
@@ -127,7 +224,7 @@ exports.publicMethod = () => {
|
|
|
127
224
|
}
|
|
128
225
|
```
|
|
129
226
|
|
|
130
|
-
##
|
|
227
|
+
## 10. Node.js Compatibility
|
|
131
228
|
|
|
132
229
|
Titanium supports Node.js module patterns and `require()` resolution. Node.js modules can often be used directly.
|
|
133
230
|
|
|
@@ -40,6 +40,7 @@ Choose template:
|
|
|
40
40
|
- All lowercase (Android issues with uppercase)
|
|
41
41
|
- No Java keywords (`case`, `package`, etc.)
|
|
42
42
|
- Cannot change after publishing
|
|
43
|
+
- **Platform Relationship**: On iOS, the App ID must match the Bundle Identifier; on Android, it serves as the Application Package Name
|
|
43
44
|
|
|
44
45
|
## Project Structure
|
|
45
46
|
|
|
@@ -54,11 +55,13 @@ MyApp/
|
|
|
54
55
|
├── platform/ # Platform-specific files
|
|
55
56
|
│ ├── android/
|
|
56
57
|
│ └── ios/
|
|
57
|
-
├── Resources/ #
|
|
58
|
+
├── Resources/ # Code files and graphics with platform-specific subdirectories
|
|
59
|
+
│ ├── android/ # Android-specific assets
|
|
60
|
+
│ └── iphone/ # iOS-specific assets
|
|
58
61
|
├── i18n/ # Internationalization
|
|
59
62
|
├── tiapp.xml # App configuration
|
|
60
63
|
├── config.json # Alloy config
|
|
61
|
-
└── app.js #
|
|
64
|
+
└── app.js # Bootstrap file loaded first when app launches
|
|
62
65
|
```
|
|
63
66
|
|
|
64
67
|
## Running Your App
|
|
@@ -1,62 +1,455 @@
|
|
|
1
1
|
# Hyperloop: Native API Access
|
|
2
2
|
|
|
3
|
-
Hyperloop allows you to access 100% of native APIs (iOS Objective-C/Swift and Android Java/Kotlin) directly from JavaScript.
|
|
4
|
-
|
|
5
|
-
## 1.
|
|
6
|
-
|
|
7
|
-
- **
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
3
|
+
Hyperloop allows you to access 100% of native APIs (iOS Objective-C/Swift and Android Java/Kotlin) directly from JavaScript. It is pre-packaged with the Titanium SDK and works as a native module.
|
|
4
|
+
|
|
5
|
+
## 1. Requirements
|
|
6
|
+
|
|
7
|
+
- **Titanium SDK**: 9.0.0+
|
|
8
|
+
- **Titanium CLI**: 7.0.0+
|
|
9
|
+
- **Alloy** (optional): 1.8.0+
|
|
10
|
+
- **CocoaPods** (optional, iOS only): 1.0.0+
|
|
11
|
+
- **Xcode location**: Must be at `/Applications/Xcode.app` -- Hyperloop uses a bundled library from Xcode to inspect available native APIs. Having Xcode in a non-default location (via `xcode-select` or Xcode preferences) while another installation exists in the default folder can cause metadata errors.
|
|
12
|
+
|
|
13
|
+
## 2. Enabling Hyperloop
|
|
14
|
+
|
|
15
|
+
Add the Hyperloop module to your `tiapp.xml`:
|
|
16
|
+
|
|
17
|
+
```xml
|
|
18
|
+
<modules>
|
|
19
|
+
<module>hyperloop</module>
|
|
20
|
+
</modules>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The `run-on-main-thread` property should already be in `tiapp.xml` by default:
|
|
24
|
+
```xml
|
|
25
|
+
<property name="run-on-main-thread" type="bool">true</property>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> Do NOT name your app "Hyperloop" in tiapp.xml -- it is a reserved word and will cause build failures.
|
|
29
|
+
|
|
30
|
+
## 3. Framework Namespace Conventions
|
|
31
|
+
|
|
32
|
+
Each platform uses different `require()` conventions:
|
|
33
|
+
|
|
34
|
+
**iOS** -- use `Framework/Class` with a forward slash:
|
|
35
|
+
```javascript
|
|
36
|
+
const UIView = require('UIKit/UIView');
|
|
37
|
+
const NSBundle = require('Foundation/NSBundle');
|
|
38
|
+
const UIColor = require('UIKit/UIColor');
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Android** -- use the full Java package with dots:
|
|
42
|
+
```javascript
|
|
43
|
+
const View = require('android.view.View');
|
|
44
|
+
const Activity = require('android.app.Activity');
|
|
45
|
+
const Context = require('android.content.Context');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 4. iOS (Objective-C)
|
|
49
|
+
|
|
50
|
+
### Instantiation: `new` vs `alloc().init()`
|
|
51
|
+
|
|
52
|
+
- **`new Class()`**: Equivalent to `alloc().init()`. Only calls the **default** initializer (`init`).
|
|
53
|
+
- **`Class.alloc().initWith*()`**: Use when you need a **special initializer** with arguments.
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
const UIView = require('UIKit/UIView');
|
|
57
|
+
|
|
58
|
+
// Default initializer (both are equivalent)
|
|
59
|
+
const view1 = new UIView();
|
|
60
|
+
const view2 = UIView.alloc().init();
|
|
61
|
+
|
|
62
|
+
// Special initializer with arguments -- must use alloc().init*()
|
|
63
|
+
const CGRectMake = require('CoreGraphics').CGRectMake;
|
|
64
|
+
const view3 = UIView.alloc().initWithFrame(CGRectMake(0, 0, 100, 100));
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Named Methods (Selector Concatenation)
|
|
68
|
+
|
|
69
|
+
Selectors with multiple parameters are camel-cased and colons are removed. Arguments are passed in the same order as in Objective-C.
|
|
70
|
+
|
|
71
|
+
Selector `addAttribute:value:range:` becomes `addAttributeValueRange(attr, val, range)`.
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
// Objective-C: [myView insertSubview:anotherView atIndex:0]
|
|
75
|
+
myView.insertSubviewAtIndex(anotherView, 0);
|
|
76
|
+
|
|
77
|
+
// Objective-C: [UIView animateWithDuration:1.0 animations:^{} completion:^(BOOL){}]
|
|
78
|
+
UIView.animateWithDurationAnimationsCompletion(1.0, () => {
|
|
79
|
+
view.layer.opacity = 0.0;
|
|
80
|
+
}, (finished) => {
|
|
81
|
+
// Animation completed
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Properties
|
|
86
|
+
|
|
87
|
+
Objective-C properties map directly to JavaScript property accessors. Auto-generated setters are also available:
|
|
88
|
+
```javascript
|
|
89
|
+
view.backgroundColor = UIColor.redColor;
|
|
90
|
+
// or
|
|
91
|
+
view.setBackgroundColor(UIColor.redColor);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Casting
|
|
95
|
+
|
|
96
|
+
Use `Class.cast(object)` to convert a generic return type (`NSObject` / `id`) or a Titanium proxy to a native view:
|
|
97
|
+
```javascript
|
|
98
|
+
const UIView = require('UIKit/UIView');
|
|
99
|
+
|
|
100
|
+
// Cast a generic object
|
|
101
|
+
const view = UIView.cast(someObject);
|
|
102
|
+
|
|
103
|
+
// Cast a Titanium view to its native equivalent
|
|
104
|
+
const tiView = Ti.UI.createView({ backgroundColor: 'red' });
|
|
105
|
+
const nativeView = UIView.cast(tiView);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
> Be careful with casting: casting to the wrong type will cause a crash.
|
|
109
|
+
|
|
110
|
+
### Blocks
|
|
111
|
+
|
|
112
|
+
Blocks are translated to JavaScript callback functions:
|
|
113
|
+
```javascript
|
|
114
|
+
const UIView = require('UIKit/UIView');
|
|
115
|
+
|
|
116
|
+
UIView.animateWithDurationAnimationsCompletion(1.0, () => {
|
|
117
|
+
view.layer.opacity = 0.0;
|
|
118
|
+
}, (done) => {
|
|
119
|
+
// Animation completed
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Constants, Enumerations, and Functions
|
|
124
|
+
|
|
125
|
+
Framework-level constants and enums are accessed by requiring the framework itself:
|
|
126
|
+
```javascript
|
|
127
|
+
const UIKit = require('UIKit');
|
|
128
|
+
const unspecified = UIKit.UISemanticContentAttributeUnspecified;
|
|
129
|
+
view.semanticContentAttribute = unspecified;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### TiApp Utility Class
|
|
133
|
+
|
|
134
|
+
Access Titanium's app instance for the app delegate, key window, and app-level properties:
|
|
135
|
+
```javascript
|
|
136
|
+
const TiApp = require('TiApp/TiApp');
|
|
137
|
+
const app = TiApp.app();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## 5. iOS: Creating Custom Classes
|
|
141
|
+
|
|
142
|
+
Use `Hyperloop.defineClass()` to create Objective-C classes at runtime:
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// defineClass(className, superClass, protocolsArray)
|
|
146
|
+
const MyView = Hyperloop.defineClass('MyView', 'UIView', ['UIAppearance']);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Add methods with `addMethod()`:
|
|
150
|
+
```javascript
|
|
151
|
+
MyView.addMethod({
|
|
152
|
+
selector: 'drawRect:',
|
|
153
|
+
instance: true,
|
|
154
|
+
arguments: ['CGRect'],
|
|
155
|
+
callback: function(rect) {
|
|
156
|
+
// Called when drawRect: is invoked
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Methods with multiple arguments and return types:
|
|
162
|
+
```javascript
|
|
163
|
+
MyView.addMethod({
|
|
164
|
+
selector: 'foo:bar:hello:',
|
|
165
|
+
instance: true,
|
|
166
|
+
returnType: 'void',
|
|
167
|
+
arguments: ['int', 'float', 'id'],
|
|
168
|
+
callback: function(a, b, c) {
|
|
169
|
+
// Invoked when the method is called
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`addMethod` properties:
|
|
175
|
+
- **`selector`**: The Objective-C selector string
|
|
176
|
+
- **`instance`**: `true` for instance methods, `false` for class methods
|
|
177
|
+
- **`arguments`**: Array or String of argument types (Objective-C encoding types or general types like `float`, `int`, `id`)
|
|
178
|
+
- **`returnType`**: String return type. Omit for `void`.
|
|
179
|
+
- **`callback`**: The JavaScript function implementation
|
|
180
|
+
|
|
181
|
+
Instantiate the custom class normally:
|
|
182
|
+
```javascript
|
|
183
|
+
const myView = new MyView();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 6. iOS: CocoaPods Support
|
|
187
|
+
|
|
188
|
+
### Installation
|
|
189
|
+
|
|
190
|
+
Install CocoaPods if not already installed:
|
|
191
|
+
```bash
|
|
192
|
+
sudo gem install cocoapods
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Podfile Configuration
|
|
196
|
+
|
|
197
|
+
Create a `Podfile` in your Titanium project root:
|
|
198
|
+
```ruby
|
|
199
|
+
# Required for CocoaPods 1.x
|
|
200
|
+
install! 'cocoapods',
|
|
201
|
+
:integrate_targets => false
|
|
202
|
+
|
|
203
|
+
platform :ios, '12.0'
|
|
204
|
+
target 'YourProjectName' do
|
|
205
|
+
pod 'SomeLibrary'
|
|
206
|
+
end
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Replace `YourProjectName` with your actual Titanium project name.
|
|
210
|
+
|
|
211
|
+
### Using the Pod
|
|
212
|
+
|
|
213
|
+
```javascript
|
|
214
|
+
const JBBarChartView = require('JBChartView/JBBarChartView');
|
|
215
|
+
const chart = new JBBarChartView();
|
|
216
|
+
chart.minimumValue = 1;
|
|
217
|
+
chart.maximumValue = 100;
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Bitcode Handling for Ad-Hoc Builds
|
|
221
|
+
|
|
222
|
+
If your build fails due to mixed Bitcode frameworks, disable Bitcode in your Podfile:
|
|
223
|
+
```ruby
|
|
224
|
+
post_install do |installer|
|
|
225
|
+
installer.pods_project.targets.each do |target|
|
|
226
|
+
target.build_configurations.each do |config|
|
|
227
|
+
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Custom Frameworks (without CocoaPods)
|
|
234
|
+
|
|
235
|
+
Drop native iOS frameworks (static or dynamic) into `app/platform/ios` (Alloy) or `platform/ios` (Classic). They will be automatically detected and linked.
|
|
236
|
+
|
|
237
|
+
## 7. iOS: Swift Support
|
|
238
|
+
|
|
239
|
+
Hyperloop supports Swift classes alongside Objective-C:
|
|
26
240
|
- Swift and Objective-C classes can be mixed in the same app
|
|
27
241
|
- Use the same `require()` syntax for Swift classes
|
|
242
|
+
- For Swift frameworks via CocoaPods, use the `use_frameworks!` flag in your Podfile
|
|
243
|
+
|
|
244
|
+
## 8. iOS: XIB and Storyboards
|
|
245
|
+
|
|
246
|
+
XIB files and Storyboards must be programmatically loaded. Place them in `app/assets/iphone` (Alloy) or `Resources/iphone` (Classic) and they will be compiled automatically.
|
|
28
247
|
|
|
29
|
-
## 5. XIB and Storyboards (iOS)
|
|
30
|
-
XIB files and Storyboards are supported but must be programmatically loaded:
|
|
31
248
|
```javascript
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const UINib = require('UIKit.UINib');
|
|
249
|
+
const NSBundle = require('Foundation/NSBundle');
|
|
250
|
+
const UINib = require('UIKit/UINib');
|
|
35
251
|
|
|
36
|
-
const nib = UINib.
|
|
37
|
-
const objects = nib.
|
|
252
|
+
const nib = UINib.nibWithNibNameBundle('MyView', NSBundle.mainBundle);
|
|
253
|
+
const objects = nib.instantiateWithOwnerOptions(null, null);
|
|
38
254
|
```
|
|
39
255
|
|
|
40
|
-
|
|
256
|
+
The following resources are compiled automatically: `*.storyboard`, `*.xcdatamodel`, `*.xcdatamodeld`, `*.xcmappingmodel`, `*.xib`.
|
|
257
|
+
|
|
258
|
+
## 9. iOS: Customizing the Xcode Build
|
|
259
|
+
|
|
260
|
+
Use `appc.js` in the project root to pass custom flags to `xcodebuild`:
|
|
261
|
+
```javascript
|
|
262
|
+
module.exports = {
|
|
263
|
+
hyperloop: {
|
|
264
|
+
ios: {
|
|
265
|
+
xcodebuild: {
|
|
266
|
+
flags: {
|
|
267
|
+
GCC_PREPROCESSOR_DEFINITIONS: 'foo=bar'
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
```
|
|
41
274
|
|
|
42
|
-
|
|
43
|
-
- Studio debugging capabilities are limited for Hyperloop code
|
|
44
|
-
- Hyperloop modifies source files during build, which throws debuggers off track
|
|
45
|
-
- Breakpoints may not hit correctly in main listview click events
|
|
275
|
+
## 10. Android (Java)
|
|
46
276
|
|
|
47
|
-
###
|
|
48
|
-
- **iOS**: Use Safari Web Inspector for debugging up to the native transition point
|
|
49
|
-
- **Android**: Use Chrome DevTools (SDK 7.0.0+)
|
|
50
|
-
- Note: No source maps available for processed Alloy controllers
|
|
277
|
+
### Activity Context
|
|
51
278
|
|
|
52
|
-
|
|
53
|
-
The `TiApp` utility class provides access to Titanium's app instance:
|
|
279
|
+
Most Android view constructors require an Activity context:
|
|
54
280
|
```javascript
|
|
55
|
-
const
|
|
56
|
-
const
|
|
281
|
+
const Activity = require('android.app.Activity');
|
|
282
|
+
const activity = new Activity(Ti.Android.currentActivity);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Methods and Fields
|
|
286
|
+
|
|
287
|
+
Java methods map to JavaScript functions. Java fields map to JavaScript property accessors. Static methods and constants are attached to the class type:
|
|
288
|
+
```javascript
|
|
289
|
+
const View = require('android.view.View');
|
|
290
|
+
const generatedId = View.generateViewId(); // static method
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Method Overloading
|
|
294
|
+
|
|
295
|
+
Hyperloop automatically selects the matching overload based on parameter types. It is slightly more liberal with numeric primitives due to JavaScript Number conversion.
|
|
296
|
+
|
|
297
|
+
### Casting
|
|
298
|
+
|
|
299
|
+
Pass the object to the constructor of the target type:
|
|
300
|
+
```javascript
|
|
301
|
+
const View = require('android.view.View');
|
|
302
|
+
|
|
303
|
+
// Cast a generic Object to a View
|
|
304
|
+
const view = new View(someObject);
|
|
305
|
+
|
|
306
|
+
// Cast a Titanium view to native
|
|
307
|
+
const tiView = Ti.UI.createView({ backgroundColor: 'red' });
|
|
308
|
+
const nativeView = new View(tiView);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Interfaces
|
|
312
|
+
|
|
313
|
+
Implement Java interfaces by passing a JavaScript object with matching method names:
|
|
314
|
+
```javascript
|
|
315
|
+
const OnTouchListener = require('android.view.View.OnTouchListener');
|
|
316
|
+
const listener = new OnTouchListener({
|
|
317
|
+
onTouch: (v, event) => {
|
|
318
|
+
// Handle touch
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Creating Custom Classes (Android)
|
|
325
|
+
|
|
326
|
+
Use `.extend()` on the class to subclass, passing an object with method overrides:
|
|
327
|
+
```javascript
|
|
328
|
+
const Activity = require('android.app.Activity');
|
|
329
|
+
const View = require('android.view.View');
|
|
330
|
+
const activity = new Activity(Ti.Android.currentActivity);
|
|
331
|
+
|
|
332
|
+
const MyView = View.extend({
|
|
333
|
+
onDraw: function(canvas) {
|
|
334
|
+
this.super.onDraw(canvas);
|
|
335
|
+
// Custom drawing implementation
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
const customView = new MyView(activity);
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## 11. Android: Native XML Layouts
|
|
342
|
+
|
|
343
|
+
### Creating the Layout
|
|
344
|
+
|
|
345
|
+
Place XML layout files in `app/platform/android/res/layout/` (Alloy) or `platform/android/res/layout/` (Classic).
|
|
346
|
+
|
|
347
|
+
Example `main_content.xml`:
|
|
348
|
+
```xml
|
|
349
|
+
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
350
|
+
android:id="@+id/main_content"
|
|
351
|
+
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
352
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
353
|
+
android:layout_width="match_parent"
|
|
354
|
+
android:layout_height="match_parent">
|
|
355
|
+
|
|
356
|
+
<ListView
|
|
357
|
+
android:id="@+id/lvToDoList"
|
|
358
|
+
android:layout_width="match_parent"
|
|
359
|
+
android:layout_height="match_parent" />
|
|
360
|
+
|
|
361
|
+
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
362
|
+
android:layout_width="wrap_content"
|
|
363
|
+
android:layout_height="wrap_content"
|
|
364
|
+
android:layout_gravity="bottom|right"
|
|
365
|
+
android:layout_margin="16dp" />
|
|
366
|
+
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
57
367
|
```
|
|
58
368
|
|
|
59
|
-
|
|
369
|
+
### Inflating the Layout
|
|
370
|
+
|
|
371
|
+
```javascript
|
|
372
|
+
const Activity = require('android.app.Activity');
|
|
373
|
+
const Context = require('android.content.Context');
|
|
374
|
+
const Inflater = require('android.view.LayoutInflater');
|
|
375
|
+
|
|
376
|
+
const activity = new Activity(Ti.Android.currentActivity);
|
|
377
|
+
const inflater = Inflater.cast(
|
|
378
|
+
activity.getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
// getIdentifier(name, defType, defPackage) retrieves the R.layout.* ID
|
|
382
|
+
const resId = activity.getResources().getIdentifier('main_content', 'layout', activity.getPackageName());
|
|
383
|
+
const view = inflater.inflate(resId, null);
|
|
384
|
+
|
|
385
|
+
// Add to a Titanium view
|
|
386
|
+
$.myView.add(view);
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`getIdentifier()` also works for other resource types: `R.color.*`, `R.string.*`, `R.drawable.*`, etc.
|
|
390
|
+
|
|
391
|
+
## 12. Android: Third-Party Libraries
|
|
392
|
+
|
|
393
|
+
### AndroidX Requirement
|
|
394
|
+
|
|
395
|
+
As of Titanium SDK 9.0.0, you must use **AndroidX** libraries. Google's deprecated Support libraries (`android.support.*`) are no longer supported.
|
|
396
|
+
|
|
397
|
+
### Gradle Dependencies (Preferred)
|
|
398
|
+
|
|
399
|
+
Add a `build.gradle` file to `app/platform/android/` (Alloy) or `platform/android/` (Classic):
|
|
400
|
+
|
|
401
|
+
```groovy
|
|
402
|
+
dependencies {
|
|
403
|
+
implementation 'com.google.android.material:material:1.1.0'
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Local JAR/AAR Dependencies
|
|
408
|
+
|
|
409
|
+
Place JAR and AAR files directly in `app/platform/android/` (Alloy) or `platform/android/` (Classic). Hyperloop will automatically:
|
|
410
|
+
- Load Java classes and generate bindings
|
|
411
|
+
- For AARs: extract resources, assets, `*.so` libraries, and merge `AndroidManifest.xml`
|
|
412
|
+
|
|
413
|
+
### Third-Party Library Example
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
// After adding the AAR to app/platform/android/
|
|
417
|
+
const Activity = require('android.app.Activity');
|
|
418
|
+
const ParkedTextView = require('com.goka.parkedtextview.ParkedTextView');
|
|
419
|
+
|
|
420
|
+
const activity = new Activity(Ti.Android.currentActivity);
|
|
421
|
+
const parkedView = new ParkedTextView(activity);
|
|
422
|
+
parkedView.setParkedText('.slack.com');
|
|
423
|
+
parkedView.setHintText('your-team');
|
|
424
|
+
|
|
425
|
+
// Listen to events via interfaces
|
|
426
|
+
const TextWatcher = require('android.text.TextWatcher');
|
|
427
|
+
const watcher = new TextWatcher({
|
|
428
|
+
onTextChanged: () => { console.log('Changed'); },
|
|
429
|
+
afterTextChanged: (s) => { console.log('After:', s); },
|
|
430
|
+
beforeTextChanged: () => { console.log('Before'); }
|
|
431
|
+
});
|
|
432
|
+
parkedView.addTextChangedListener(watcher);
|
|
433
|
+
|
|
434
|
+
$.myView.add(parkedView);
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## 13. Debugging Hyperloop
|
|
438
|
+
|
|
439
|
+
- **iOS**: Use **Safari Web Inspector** to debug Hyperloop code up to the native transition point
|
|
440
|
+
- **Android**: Use **Chrome DevTools** for JavaScript debugging
|
|
441
|
+
- Breakpoints may not hit correctly in all cases because Hyperloop modifies source files during the build process
|
|
442
|
+
- No source maps are available for processed Alloy controllers
|
|
443
|
+
|
|
444
|
+
## 14. Performance Tips
|
|
445
|
+
|
|
446
|
+
- Do NOT use Hyperloop for things Titanium already does well
|
|
447
|
+
- Use it for specialized APIs: custom UI components, hardware access not covered by modules, or native third-party library integration
|
|
448
|
+
- Existing Titanium modules (Java for Android, Objective-C for iOS) continue to be fully supported alongside Hyperloop
|
|
449
|
+
|
|
450
|
+
## 15. Sample Projects
|
|
451
|
+
|
|
452
|
+
The official cross-platform example app demonstrates native APIs for iOS and Android, including CocoaPods, Android AAR packages, UICollectionView, Beacons, BottomNavigationView, native XML layouts, Storyboards, XIBs, and more:
|
|
60
453
|
|
|
61
|
-
|
|
62
|
-
|
|
454
|
+
- **Repository**: `https://github.com/tidev/hyperloop-examples`
|
|
455
|
+
- **Community modules**: `https://github.com/hyperloop-modules` -- JavaScript wrappers around native APIs (Speech, Mapbox, Snackbar, etc.)
|