@maccesar/titools 5.3.0 → 5.4.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/CONTRIBUTING.md +1 -1
- package/README.md +31 -60
- package/agents/ti-pro.md +3 -1
- package/commands/ti-audit.md +6 -4
- package/docs/examples.md +9 -0
- package/docs/knowledge-index.md +2 -1
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/skills/alloy-guides/SKILL.md +18 -179
- package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
- package/skills/alloy-guides/references/CONCEPTS.md +27 -162
- package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
- package/skills/alloy-guides/references/MODELS.md +47 -723
- package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
- package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
- package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
- package/skills/alloy-guides/references/WIDGETS.md +49 -127
- package/skills/alloy-howtos/SKILL.md +14 -169
- package/skills/alloy-howtos/references/best_practices.md +9 -113
- package/skills/alloy-howtos/references/cli_reference.md +18 -223
- package/skills/alloy-howtos/references/config_files.md +50 -133
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
- package/skills/alloy-howtos/references/samples.md +21 -138
- package/skills/ti-api/SKILL.md +10 -2
- package/skills/ti-api/references/api-android.md +36 -2
- package/skills/ti-api/references/api-app-platform.md +39 -3
- package/skills/ti-api/references/api-core.md +50 -18
- package/skills/ti-api/references/api-data-network.md +49 -35
- package/skills/ti-api/references/api-media.md +45 -27
- package/skills/ti-api/references/api-services.md +39 -9
- package/skills/ti-api/references/api-ui-android.md +33 -13
- package/skills/ti-api/references/api-ui-extras.md +41 -15
- package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
- package/skills/ti-api/references/api-ui-ios.md +74 -2
- package/skills/ti-api/references/api-ui-lists.md +32 -16
- package/skills/ti-api/references/api-ui-text-input.md +34 -17
- package/skills/ti-api/references/api-ui-views.md +27 -1
- package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
- package/skills/ti-api/references/api-xml-global.md +66 -16
- package/skills/ti-create-release/SKILL.md +98 -0
- package/skills/ti-create-release/references/module-discovery.md +69 -0
- package/skills/ti-expert/references/adaptive-layouts.md +1 -1
- package/skills/ti-guides/SKILL.md +37 -76
- package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
- package/skills/ti-guides/references/android-manifest.md +24 -83
- package/skills/ti-guides/references/app-distribution.md +31 -377
- package/skills/ti-guides/references/application-frameworks.md +127 -335
- package/skills/ti-guides/references/cli-reference.md +184 -633
- package/skills/ti-guides/references/commonjs-advanced.md +81 -231
- package/skills/ti-guides/references/compatibility-matrix.md +36 -75
- package/skills/ti-guides/references/hello-world.md +95 -70
- package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
- package/skills/ti-guides/references/resources.md +174 -142
- package/skills/ti-guides/references/sdk-release-notes.md +28 -71
- package/skills/ti-guides/references/tiapp-config.md +222 -598
- package/skills/ti-howtos/SKILL.md +23 -123
- package/skills/ti-howtos/references/cross-platform-development.md +119 -324
- package/skills/ti-howtos/references/debugging-profiling.md +77 -445
- package/skills/ti-howtos/references/extending-titanium.md +199 -673
- package/skills/ti-howtos/references/local-data-sources.md +87 -300
- package/skills/ti-howtos/references/location-and-maps.md +86 -213
- package/skills/ti-howtos/references/media-apis.md +103 -223
- package/skills/ti-howtos/references/notification-services.md +86 -506
- package/skills/ti-howtos/references/remote-data-sources.md +97 -316
- package/skills/ti-howtos/references/using-modules.md +77 -133
- package/skills/ti-ui/SKILL.md +28 -143
- package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
- package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
- package/skills/ti-ui/references/listviews-and-performance.md +100 -703
- package/skills/ti-ui/references/platform-conventions.md +180 -0
- package/skills/ti-ui/references/user-interface.md +43 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
- package/skills/alloy-howtos/references/custom_tags.md +0 -148
- package/skills/ti-guides/references/coding-best-practices.md +0 -149
- package/skills/ti-guides/references/javascript-primer.md +0 -414
- package/skills/ti-guides/references/reserved-words.md +0 -36
- package/skills/ti-guides/references/style-and-conventions.md +0 -103
- package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
- package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
- package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
- package/skills/ti-howtos/references/google-maps-v2.md +0 -172
- package/skills/ti-howtos/references/ios-map-kit.md +0 -149
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
- package/skills/ti-howtos/references/tutorials.md +0 -565
- package/skills/ti-howtos/references/web-content-integration.md +0 -287
- package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
- package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
- package/skills/ti-ui/references/animation-and-matrices.md +0 -569
- package/skills/ti-ui/references/application-structures.md +0 -626
- package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
- package/skills/ti-ui/references/event-handling.md +0 -401
- package/skills/ti-ui/references/gestures.md +0 -448
- package/skills/ti-ui/references/orientation.md +0 -374
- package/skills/ti-ui/references/platform-ui-android.md +0 -727
- package/skills/ti-ui/references/platform-ui-ios.md +0 -576
- package/skills/ti-ui/references/scrolling-views.md +0 -288
- package/skills/ti-ui/references/tableviews.md +0 -542
|
@@ -1,565 +0,0 @@
|
|
|
1
|
-
# Titanium SDK tutorials
|
|
2
|
-
|
|
3
|
-
Practical tutorials and guides for building real Titanium applications.
|
|
4
|
-
|
|
5
|
-
<!-- TOC-START -->
|
|
6
|
-
## Contents
|
|
7
|
-
|
|
8
|
-
- [RESTe - API integration](#reste---api-integration)
|
|
9
|
-
- [Camera app tutorial](#camera-app-tutorial)
|
|
10
|
-
- [Geolocation tutorial](#geolocation-tutorial)
|
|
11
|
-
- [Alloy controller chaining](#alloy-controller-chaining)
|
|
12
|
-
- [Build automation with Fastlane](#build-automation-with-fastlane)
|
|
13
|
-
- [Additional tutorials](#additional-tutorials)
|
|
14
|
-
- [Resources](#resources-1)
|
|
15
|
-
|
|
16
|
-
<!-- TOC-END -->
|
|
17
|
-
|
|
18
|
-
## RESTe - API integration
|
|
19
|
-
|
|
20
|
-
### Overview
|
|
21
|
-
RESTe by Jason Kneen is a module for consuming web APIs in Titanium.
|
|
22
|
-
|
|
23
|
-
Benefits:
|
|
24
|
-
- Eliminates boilerplate HTTP code
|
|
25
|
-
- Auto-generates JavaScript API from config
|
|
26
|
-
- Supports Backbone.js models and collections in Alloy
|
|
27
|
-
- Works with any API (not just REST)
|
|
28
|
-
|
|
29
|
-
### Installation
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npm install reste
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Basic configuration
|
|
36
|
-
|
|
37
|
-
`alloy.js`:
|
|
38
|
-
|
|
39
|
-
```javascript
|
|
40
|
-
const reste = require('reste');
|
|
41
|
-
const api = new reste();
|
|
42
|
-
|
|
43
|
-
api.config({
|
|
44
|
-
debug: true, // Console logging
|
|
45
|
-
errorsAsObjects: true, // Return errors as objects (1.4.5+) - breaks apps written for 1.4.4 that handle errors differently
|
|
46
|
-
autoValidateParams: false, // Throw error if params missing
|
|
47
|
-
validatesSecureCertificate: false,
|
|
48
|
-
timeout: 4000,
|
|
49
|
-
url: 'https://api.example.com/', // Base URL
|
|
50
|
-
requestHeaders: {
|
|
51
|
-
'X-API-Key': 'your-key-here',
|
|
52
|
-
'Content-Type': 'application/json'
|
|
53
|
-
},
|
|
54
|
-
methods: [
|
|
55
|
-
{
|
|
56
|
-
name: 'getVideos',
|
|
57
|
-
get: 'videos'
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'getVideoById',
|
|
61
|
-
get: 'videos/'
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: 'createVideo',
|
|
65
|
-
post: 'videos'
|
|
66
|
-
}
|
|
67
|
-
],
|
|
68
|
-
onError: (e, retry) => {
|
|
69
|
-
const dialog = Ti.UI.createAlertDialog({
|
|
70
|
-
title: 'Connection error',
|
|
71
|
-
message: 'Check your network and retry.',
|
|
72
|
-
buttonNames: ['Retry']
|
|
73
|
-
});
|
|
74
|
-
dialog.addEventListener('click', () => {
|
|
75
|
-
retry();
|
|
76
|
-
});
|
|
77
|
-
dialog.show();
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Usage
|
|
83
|
-
|
|
84
|
-
Auto-generated methods:
|
|
85
|
-
|
|
86
|
-
```javascript
|
|
87
|
-
// Fetch single video
|
|
88
|
-
api.getVideoById({
|
|
89
|
-
videoId: 'abc123'
|
|
90
|
-
}, (video) => {
|
|
91
|
-
Ti.API.info(`Got video: ${video.title}`);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Create video
|
|
95
|
-
api.createVideo({
|
|
96
|
-
body: {
|
|
97
|
-
title: 'My Video',
|
|
98
|
-
categoryId: 2
|
|
99
|
-
}
|
|
100
|
-
}, (response) => {
|
|
101
|
-
Ti.API.info(`Created: ${response.id}`);
|
|
102
|
-
});
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Backbone.js models and collections
|
|
106
|
-
|
|
107
|
-
Configuration:
|
|
108
|
-
|
|
109
|
-
```javascript
|
|
110
|
-
api.config({
|
|
111
|
-
// ... other config
|
|
112
|
-
models: [{
|
|
113
|
-
name: 'video',
|
|
114
|
-
id: 'objectId', // Primary key field
|
|
115
|
-
read: 'getVideo',
|
|
116
|
-
create: 'createVideo',
|
|
117
|
-
update: 'updateVideo',
|
|
118
|
-
delete: 'deleteVideo',
|
|
119
|
-
collections: [{
|
|
120
|
-
name: 'videos',
|
|
121
|
-
content: 'results', // Array wrapper in response
|
|
122
|
-
read: 'getVideos'
|
|
123
|
-
}]
|
|
124
|
-
}]
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
In an Alloy controller:
|
|
129
|
-
|
|
130
|
-
```javascript
|
|
131
|
-
// Fetch collection
|
|
132
|
-
Alloy.Collections.videos.fetch();
|
|
133
|
-
|
|
134
|
-
// Or fetch with parameters
|
|
135
|
-
Alloy.Collections.videos.fetch({
|
|
136
|
-
data: { category: 'sports' }
|
|
137
|
-
});
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
In an Alloy view:
|
|
141
|
-
|
|
142
|
-
```xml
|
|
143
|
-
<TableView dataCollection="videos" onClick="selectVideo">
|
|
144
|
-
<TableViewRow model="{objectId}">
|
|
145
|
-
<Label class="title" text="{title}"/>
|
|
146
|
-
<Label class="subtitle" text="{description}"/>
|
|
147
|
-
</TableViewRow>
|
|
148
|
-
</TableView>
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### RESTe advanced features
|
|
152
|
-
|
|
153
|
-
- Caching: built-in response caching
|
|
154
|
-
- Promises: use with `q.js` for Promise-based API calls
|
|
155
|
-
- Mock data: create models and collections on the fly for testing
|
|
156
|
-
|
|
157
|
-
```javascript
|
|
158
|
-
const mockUser = api.createModel('users', {
|
|
159
|
-
id: 1,
|
|
160
|
-
name: 'Test User'
|
|
161
|
-
});
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
- Backbone.js binding: use RESTe models directly with Alloy data binding without `<Model>` tags
|
|
165
|
-
|
|
166
|
-
### Important notes
|
|
167
|
-
|
|
168
|
-
- Do not use `<Model>` or `<Collection>` tags with RESTe
|
|
169
|
-
- RESTe creates models and collections automatically
|
|
170
|
-
- Use data binding like normal Alloy collections
|
|
171
|
-
- Useful for mocking data during UI development
|
|
172
|
-
|
|
173
|
-
### Mock data (on the fly)
|
|
174
|
-
|
|
175
|
-
```javascript
|
|
176
|
-
// Create model without API
|
|
177
|
-
const videoModel = api.createModel('video', {
|
|
178
|
-
title: 'Test Video',
|
|
179
|
-
description: 'Mock data'
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
// Create collection
|
|
183
|
-
const videoCollection = api.createCollection('videos', [
|
|
184
|
-
{ title: 'Video 1' },
|
|
185
|
-
{ title: 'Video 2' }
|
|
186
|
-
]);
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Resources
|
|
190
|
-
|
|
191
|
-
- npm: https://www.npmjs.com/package/reste
|
|
192
|
-
- GitHub: https://github.com/jasonkneen/reste
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## Camera app tutorial
|
|
197
|
-
|
|
198
|
-
### Camera permissions setup
|
|
199
|
-
|
|
200
|
-
iOS - add to `tiapp.xml` plist:
|
|
201
|
-
|
|
202
|
-
```xml
|
|
203
|
-
<key>NSCameraUsageDescription</key>
|
|
204
|
-
<string>This app needs camera access to take photos</string>
|
|
205
|
-
<key>NSMicrophoneUsageDescription</key>
|
|
206
|
-
<string>This app needs microphone access for video recording</string>
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Android: camera permissions are automatically added by the build system when you use `Ti.Media.showCamera()`.
|
|
210
|
-
|
|
211
|
-
Always check permissions at runtime:
|
|
212
|
-
|
|
213
|
-
```javascript
|
|
214
|
-
if (!Ti.Media.hasCameraPermissions()) {
|
|
215
|
-
Ti.Media.requestCameraPermissions((e) => {
|
|
216
|
-
if (e.success) openCamera();
|
|
217
|
-
});
|
|
218
|
-
} else {
|
|
219
|
-
openCamera();
|
|
220
|
-
}
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### Basic camera access
|
|
224
|
-
|
|
225
|
-
```javascript
|
|
226
|
-
// Show camera
|
|
227
|
-
Ti.Media.showCamera({
|
|
228
|
-
success: (event) => {
|
|
229
|
-
const image = event.media;
|
|
230
|
-
if (event.mediaType === Ti.Media.MEDIA_TYPE_PHOTO) {
|
|
231
|
-
// Use the photo
|
|
232
|
-
const imageView = Ti.UI.createImageView({
|
|
233
|
-
image: image,
|
|
234
|
-
width: 300,
|
|
235
|
-
height: 300
|
|
236
|
-
});
|
|
237
|
-
win.add(imageView);
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
cancel: () => {
|
|
241
|
-
Ti.API.info('Camera canceled');
|
|
242
|
-
},
|
|
243
|
-
error: (error) => {
|
|
244
|
-
const a = Ti.UI.createAlertDialog({ title: 'Camera Error' });
|
|
245
|
-
if (error.code === Ti.Media.NO_CAMERA) {
|
|
246
|
-
a.setMessage('Device does not have camera');
|
|
247
|
-
} else {
|
|
248
|
-
a.setMessage(`Unexpected error: ${error.code}`);
|
|
249
|
-
}
|
|
250
|
-
a.show();
|
|
251
|
-
},
|
|
252
|
-
saveToPhotoGallery: true,
|
|
253
|
-
allowEditing: true,
|
|
254
|
-
mediaTypes: [Ti.Media.MEDIA_TYPE_PHOTO],
|
|
255
|
-
videoQuality: Ti.Media.QUALITY_HIGH
|
|
256
|
-
});
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### Photo gallery
|
|
260
|
-
|
|
261
|
-
```javascript
|
|
262
|
-
// Open photo gallery
|
|
263
|
-
Ti.Media.openPhotoGallery({
|
|
264
|
-
success: (event) => {
|
|
265
|
-
const image = event.media;
|
|
266
|
-
// Process selected image
|
|
267
|
-
},
|
|
268
|
-
cancel: () => {
|
|
269
|
-
// User canceled
|
|
270
|
-
},
|
|
271
|
-
error: (error) => {
|
|
272
|
-
// Handle error
|
|
273
|
-
},
|
|
274
|
-
mediaTypes: [Ti.Media.MEDIA_TYPE_PHOTO]
|
|
275
|
-
});
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Saving images
|
|
279
|
-
|
|
280
|
-
```javascript
|
|
281
|
-
// Save to gallery
|
|
282
|
-
Ti.Media.saveToPhotoGallery({
|
|
283
|
-
media: myImageBlob,
|
|
284
|
-
success: () => {
|
|
285
|
-
alert('Saved!');
|
|
286
|
-
},
|
|
287
|
-
error: (e) => {
|
|
288
|
-
alert(`Error: ${e.error}`);
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
---
|
|
294
|
-
|
|
295
|
-
## Geolocation tutorial
|
|
296
|
-
|
|
297
|
-
### Geolocation permissions setup
|
|
298
|
-
|
|
299
|
-
iOS - add to `tiapp.xml` plist:
|
|
300
|
-
|
|
301
|
-
```xml
|
|
302
|
-
<key>NSLocationWhenInUseUsageDescription</key>
|
|
303
|
-
<string>We need your location to show nearby places</string>
|
|
304
|
-
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
305
|
-
<string>We need your location for background tracking</string>
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
Android - add to `tiapp.xml` manifest:
|
|
309
|
-
|
|
310
|
-
```xml
|
|
311
|
-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
312
|
-
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
Runtime permission check:
|
|
316
|
-
```javascript
|
|
317
|
-
if (!Ti.Geolocation.hasLocationPermissions(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE)) {
|
|
318
|
-
Ti.Geolocation.requestLocationPermissions(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE, (e) => {
|
|
319
|
-
if (e.success) startTracking();
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Basic location
|
|
325
|
-
|
|
326
|
-
```javascript
|
|
327
|
-
// One-time location
|
|
328
|
-
if (Ti.Geolocation.locationServicesEnabled) {
|
|
329
|
-
Ti.Geolocation.getCurrentPosition((e) => {
|
|
330
|
-
if (!e.error) {
|
|
331
|
-
Ti.API.info(`Lat: ${e.coords.latitude}`);
|
|
332
|
-
Ti.API.info(`Lon: ${e.coords.longitude}`);
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
### Continuous tracking
|
|
339
|
-
|
|
340
|
-
```javascript
|
|
341
|
-
// Configure accuracy
|
|
342
|
-
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_BEST;
|
|
343
|
-
Ti.Geolocation.distanceFilter = 10; // Meters
|
|
344
|
-
|
|
345
|
-
// Track location changes
|
|
346
|
-
Ti.Geolocation.addEventListener('location', (e) => {
|
|
347
|
-
if (!e.error) {
|
|
348
|
-
const lat = e.coords.latitude;
|
|
349
|
-
const lon = e.coords.longitude;
|
|
350
|
-
updateMap(lat, lon);
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
### Reverse geocoding
|
|
356
|
-
|
|
357
|
-
```javascript
|
|
358
|
-
// Coordinates to address
|
|
359
|
-
Ti.Geolocation.reverseGeocoder(37.389569, -122.050212, (e) => {
|
|
360
|
-
if (e.success) {
|
|
361
|
-
e.places.forEach((place) => {
|
|
362
|
-
Ti.API.info(place.address);
|
|
363
|
-
Ti.API.info(place.city);
|
|
364
|
-
Ti.API.info(place.country);
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
});
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
### Accuracy tuning
|
|
371
|
-
|
|
372
|
-
```javascript
|
|
373
|
-
// iOS: minimum distance before firing event
|
|
374
|
-
Ti.Geolocation.distanceFilter = 10; // meters
|
|
375
|
-
|
|
376
|
-
// Android: use FusedLocationProvider for better battery (requires ti.playservices module)
|
|
377
|
-
// Automatically enabled with SDK 7.1.0+ when ti.playservices is present
|
|
378
|
-
|
|
379
|
-
// Android: custom location rules
|
|
380
|
-
Ti.Geolocation.Android.addLocationRule(Ti.Geolocation.Android.createLocationRule({
|
|
381
|
-
provider: Ti.Geolocation.Android.PROVIDER_GPS,
|
|
382
|
-
accuracy: 100, // meters
|
|
383
|
-
minAge: 1000 // milliseconds
|
|
384
|
-
}));
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
---
|
|
388
|
-
|
|
389
|
-
## Alloy controller chaining
|
|
390
|
-
|
|
391
|
-
### Pattern overview
|
|
392
|
-
|
|
393
|
-
Chain controller methods to pass data between Alloy controllers in a clean, maintainable way.
|
|
394
|
-
|
|
395
|
-
### Basic pattern
|
|
396
|
-
|
|
397
|
-
Parent controller:
|
|
398
|
-
```javascript
|
|
399
|
-
const childController = Alloy.createController('child', {
|
|
400
|
-
data: someData,
|
|
401
|
-
onAction: (result) => {
|
|
402
|
-
// Handle result from child
|
|
403
|
-
Ti.API.info(`Child returned: ${result}`);
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
childController.on('customEvent', (data) => {
|
|
408
|
-
// Handle child events
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
childController.open();
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
Child controller:
|
|
415
|
-
```javascript
|
|
416
|
-
const args = arguments[0] || {};
|
|
417
|
-
|
|
418
|
-
// Access parent data
|
|
419
|
-
const parentData = args.data;
|
|
420
|
-
|
|
421
|
-
// Call parent callback
|
|
422
|
-
function notifyParent(result) {
|
|
423
|
-
if (args.onAction) {
|
|
424
|
-
args.onAction(result);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Trigger parent events
|
|
429
|
-
function triggerEvent(data) {
|
|
430
|
-
$.trigger('customEvent', data);
|
|
431
|
-
}
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### Benefits
|
|
435
|
-
|
|
436
|
-
- Clean separation. Controllers remain independent.
|
|
437
|
-
- Reusable. Child works in different contexts.
|
|
438
|
-
- Testable. You can mock parent callbacks.
|
|
439
|
-
- Maintainable. Clear data flow.
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## Build automation with Fastlane
|
|
444
|
-
|
|
445
|
-
### Overview
|
|
446
|
-
|
|
447
|
-
Automate building and deploying Titanium apps with Fastlane.
|
|
448
|
-
|
|
449
|
-
### Installing Fastlane
|
|
450
|
-
|
|
451
|
-
```bash
|
|
452
|
-
# Using Homebrew (macOS)
|
|
453
|
-
brew install fastlane
|
|
454
|
-
|
|
455
|
-
# Or using Ruby gems
|
|
456
|
-
sudo gem install fastlane -NV
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
### Basic Fastfile
|
|
460
|
-
|
|
461
|
-
`fastlane/Fastfile`:
|
|
462
|
-
```ruby
|
|
463
|
-
platform :ios do
|
|
464
|
-
desc "Build and deploy to TestFlight"
|
|
465
|
-
lane :beta do
|
|
466
|
-
# Build the app
|
|
467
|
-
sh "ti build -p ios -F"
|
|
468
|
-
|
|
469
|
-
# Upload to TestFlight
|
|
470
|
-
upload_to_testflight(
|
|
471
|
-
skip_waiting_for_build_processing: true
|
|
472
|
-
)
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
desc "Build for development"
|
|
476
|
-
lane :dev do
|
|
477
|
-
sh "ti build -p ios -T developer"
|
|
478
|
-
end
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
platform :android do
|
|
482
|
-
desc "Build Android APK"
|
|
483
|
-
lane :build do
|
|
484
|
-
sh "ti build -p android -A"
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
desc "Deploy to Play Store (Beta)"
|
|
488
|
-
lane :beta do
|
|
489
|
-
# Build
|
|
490
|
-
sh "ti build -p android -F"
|
|
491
|
-
|
|
492
|
-
# Upload to Play Store
|
|
493
|
-
upload_to_play_store(
|
|
494
|
-
track: 'beta',
|
|
495
|
-
apk: 'app/build/android/bin/app.apk'
|
|
496
|
-
)
|
|
497
|
-
end
|
|
498
|
-
end
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
### Usage
|
|
502
|
-
|
|
503
|
-
```bash
|
|
504
|
-
# iOS Beta
|
|
505
|
-
fastlane ios beta
|
|
506
|
-
|
|
507
|
-
# Android Build
|
|
508
|
-
fastlane android build
|
|
509
|
-
|
|
510
|
-
# Android Beta
|
|
511
|
-
fastlane android beta
|
|
512
|
-
```
|
|
513
|
-
|
|
514
|
-
### Advanced options
|
|
515
|
-
|
|
516
|
-
Multiple environments:
|
|
517
|
-
```ruby
|
|
518
|
-
lane :staging do
|
|
519
|
-
sh "ti build -p ios -T dist --config ../staging.js"
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
lane :production do
|
|
523
|
-
sh "ti build -p ios -T dist --config ../production.js"
|
|
524
|
-
end
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
Environment-specific configs:
|
|
528
|
-
```javascript
|
|
529
|
-
// staging.js
|
|
530
|
-
module.exports = {
|
|
531
|
-
apiURL: 'https://staging-api.example.com',
|
|
532
|
-
analyticsEnabled: true
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
// production.js
|
|
536
|
-
module.exports = {
|
|
537
|
-
apiURL: 'https://api.example.com',
|
|
538
|
-
analyticsEnabled: true
|
|
539
|
-
};
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
---
|
|
543
|
-
|
|
544
|
-
## Additional tutorials
|
|
545
|
-
|
|
546
|
-
### Alloy boilerplates
|
|
547
|
-
|
|
548
|
-
See `Titanium_Boilerplates` folder for:
|
|
549
|
-
- TypeScript boilerplates
|
|
550
|
-
- App templates
|
|
551
|
-
- Project scaffolding
|
|
552
|
-
|
|
553
|
-
### Complete sample apps
|
|
554
|
-
|
|
555
|
-
- ToDoList - CommonJS module pattern example
|
|
556
|
-
- Tweetanium - Namespaced pattern example
|
|
557
|
-
- KitchenSink - Complete API reference (built with Alloy)
|
|
558
|
-
|
|
559
|
-
---
|
|
560
|
-
|
|
561
|
-
## Resources
|
|
562
|
-
|
|
563
|
-
- RESTe: https://github.com/jasonkneen/reste
|
|
564
|
-
- Fastlane: https://fastlane.tools
|
|
565
|
-
- Alloy Framework: see alloy-guides skill
|