@maccesar/titools 2.10.0 → 3.1.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.
Files changed (99) hide show
  1. package/AGENTS-VERCEL-RESEARCH.md +23 -12
  2. package/README.md +81 -182
  3. package/agents/ti-pro.md +8 -14
  4. package/lib/cleanup.js +13 -0
  5. package/lib/commands/skills.js +2 -1
  6. package/lib/commands/update.js +4 -1
  7. package/lib/config.js +9 -11
  8. package/lib/platform.js +1 -1
  9. package/package.json +2 -3
  10. package/skills/purgetss/SKILL.md +12 -0
  11. package/skills/purgetss/references/animation-advanced.md +0 -9
  12. package/skills/purgetss/references/app-branding.md +20 -0
  13. package/skills/purgetss/references/appearance-module.md +85 -27
  14. package/skills/purgetss/references/apply-directive.md +60 -0
  15. package/skills/purgetss/references/arbitrary-values.md +41 -0
  16. package/skills/purgetss/references/cli-commands.md +52 -17
  17. package/skills/purgetss/references/custom-rules.md +36 -19
  18. package/skills/purgetss/references/customization-deep-dive.md +37 -15
  19. package/skills/purgetss/references/grid-layout.md +45 -26
  20. package/skills/purgetss/references/icon-fonts.md +27 -25
  21. package/skills/purgetss/references/installation-setup.md +28 -2
  22. package/skills/purgetss/references/ios-large-titles.md +31 -15
  23. package/skills/purgetss/references/multi-density-images.md +57 -0
  24. package/skills/purgetss/references/opacity-modifier.md +11 -2
  25. package/skills/purgetss/references/semantic-colors.md +44 -1
  26. package/skills/purgetss/references/tikit-components.md +1 -3
  27. package/skills/alloy-guides/SKILL.md +0 -190
  28. package/skills/alloy-guides/references/CLI_TASKS.md +0 -233
  29. package/skills/alloy-guides/references/CONCEPTS.md +0 -171
  30. package/skills/alloy-guides/references/CONTROLLERS.md +0 -279
  31. package/skills/alloy-guides/references/MODELS.md +0 -1214
  32. package/skills/alloy-guides/references/PURGETSS.md +0 -46
  33. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +0 -235
  34. package/skills/alloy-guides/references/VIEWS_STYLES.md +0 -375
  35. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
  36. package/skills/alloy-guides/references/VIEWS_XML.md +0 -581
  37. package/skills/alloy-guides/references/WIDGETS.md +0 -160
  38. package/skills/alloy-howtos/SKILL.md +0 -181
  39. package/skills/alloy-howtos/references/best_practices.md +0 -121
  40. package/skills/alloy-howtos/references/cli_reference.md +0 -230
  41. package/skills/alloy-howtos/references/config_files.md +0 -158
  42. package/skills/alloy-howtos/references/custom_tags.md +0 -148
  43. package/skills/alloy-howtos/references/debugging_troubleshooting.md +0 -78
  44. package/skills/alloy-howtos/references/samples.md +0 -156
  45. package/skills/ti-api/SKILL.md +0 -109
  46. package/skills/ti-api/references/api-android.md +0 -675
  47. package/skills/ti-api/references/api-app-platform.md +0 -636
  48. package/skills/ti-api/references/api-core.md +0 -764
  49. package/skills/ti-api/references/api-data-network.md +0 -641
  50. package/skills/ti-api/references/api-media.md +0 -655
  51. package/skills/ti-api/references/api-modules-ble-bluetooth.md +0 -657
  52. package/skills/ti-api/references/api-modules-coremotion-urlsession.md +0 -411
  53. package/skills/ti-api/references/api-modules-map.md +0 -632
  54. package/skills/ti-api/references/api-modules-nfc.md +0 -725
  55. package/skills/ti-api/references/api-modules-social-misc.md +0 -526
  56. package/skills/ti-api/references/api-services.md +0 -700
  57. package/skills/ti-api/references/api-ui-android.md +0 -499
  58. package/skills/ti-api/references/api-ui-extras.md +0 -702
  59. package/skills/ti-api/references/api-ui-ios-animator.md +0 -378
  60. package/skills/ti-api/references/api-ui-ios.md +0 -756
  61. package/skills/ti-api/references/api-ui-lists.md +0 -581
  62. package/skills/ti-api/references/api-ui-text-input.md +0 -607
  63. package/skills/ti-api/references/api-ui-views.md +0 -572
  64. package/skills/ti-api/references/api-ui-windows-navigation.md +0 -676
  65. package/skills/ti-api/references/api-xml-global.md +0 -743
  66. package/skills/ti-guides/SKILL.md +0 -75
  67. package/skills/ti-guides/references/advanced-data-and-images.md +0 -155
  68. package/skills/ti-guides/references/android-manifest.md +0 -97
  69. package/skills/ti-guides/references/app-distribution.md +0 -373
  70. package/skills/ti-guides/references/application-frameworks.md +0 -366
  71. package/skills/ti-guides/references/cli-reference.md +0 -700
  72. package/skills/ti-guides/references/coding-best-practices.md +0 -150
  73. package/skills/ti-guides/references/commonjs-advanced.md +0 -279
  74. package/skills/ti-guides/references/hello-world.md +0 -99
  75. package/skills/ti-guides/references/hyperloop-native-access.md +0 -458
  76. package/skills/ti-guides/references/javascript-primer.md +0 -402
  77. package/skills/ti-guides/references/reserved-words.md +0 -36
  78. package/skills/ti-guides/references/resources.md +0 -172
  79. package/skills/ti-guides/references/style-and-conventions.md +0 -104
  80. package/skills/ti-guides/references/tiapp-config.md +0 -655
  81. package/skills/ti-howtos/SKILL.md +0 -143
  82. package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -609
  83. package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
  84. package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
  85. package/skills/ti-howtos/references/cross-platform-development.md +0 -358
  86. package/skills/ti-howtos/references/debugging-profiling.md +0 -473
  87. package/skills/ti-howtos/references/extending-titanium.md +0 -684
  88. package/skills/ti-howtos/references/google-maps-v2.md +0 -172
  89. package/skills/ti-howtos/references/ios-map-kit.md +0 -149
  90. package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -595
  91. package/skills/ti-howtos/references/local-data-sources.md +0 -310
  92. package/skills/ti-howtos/references/location-and-maps.md +0 -267
  93. package/skills/ti-howtos/references/media-apis.md +0 -268
  94. package/skills/ti-howtos/references/notification-services.md +0 -539
  95. package/skills/ti-howtos/references/remote-data-sources.md +0 -339
  96. package/skills/ti-howtos/references/tutorials.md +0 -552
  97. package/skills/ti-howtos/references/using-modules.md +0 -182
  98. package/skills/ti-howtos/references/web-content-integration.md +0 -288
  99. package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -125
@@ -1,595 +0,0 @@
1
- # iOS platform deep dives
2
-
3
- ## 1. iOS 17+ privacy requirements (critical)
4
- Apple requires declaring the use of certain APIs to prevent fingerprinting.
5
-
6
- ### PrivacyInfo.xcprivacy file
7
- Create this file in `app/assets/iphone/` (Alloy) or `Resources/iphone/` (Classic):
8
- ```xml
9
- <?xml version="1.0" encoding="UTF-8"?>
10
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
11
- <plist version="1.0">
12
- <dict>
13
- <key>NSPrivacyAccessedAPITypes</key>
14
- <array>
15
- <dict>
16
- <key>NSPrivacyAccessedAPIType</key>
17
- <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
18
- <key>NSPrivacyAccessedAPITypeReasons</key>
19
- <array><string>AC6B.1</string></array>
20
- </dict>
21
- </array>
22
- </dict>
23
- </plist>
24
- ```
25
- Common categories: `UserDefaults` (Ti.App.Properties), `FileTimestamp` (file.createdAt), `SystemBootTime`.
26
-
27
- ## 2. Background services and silent push
28
-
29
- ### Overview
30
- iOS allows limited background execution. For large downloads, use the `com.titaniumsdk.urlSession` module.
31
-
32
- ### Silent push (background update)
33
- Wakes up the app to download content without showing a notification.
34
-
35
- `tiapp.xml`:
36
- ```xml
37
- <key>UIBackgroundModes</key>
38
- <array>
39
- <string>remote-notification</string>
40
- </array>
41
- ```
42
-
43
- `app.js`:
44
- ```javascript
45
- Ti.App.iOS.addEventListener('silentpush', (e) => {
46
- // Start download or update
47
- Ti.API.info(`Data received: ${JSON.stringify(e)}`);
48
-
49
- // Mandatory to call upon completion (max 30 seconds)
50
- Ti.App.iOS.endBackgroundHandler(e.handlerId);
51
- });
52
- ```
53
-
54
- ### Background fetch
55
- ```javascript
56
- // Enable in tiapp.xml:
57
- // <key>UIBackgroundModes</key>
58
- // <array><string>fetch</string></array>
59
-
60
- // Set minimum fetch interval
61
- Ti.App.iOS.setMinimumBackgroundFetchInterval(Ti.App.iOS.BACKGROUNDFETCHINTERVAL_MIN);
62
-
63
- Ti.App.iOS.addEventListener('backgroundfetch', (e) => {
64
- // Fetch new data
65
- Ti.API.info('Background fetch triggered');
66
-
67
- // Must call endBackgroundHandler when done (max 30 seconds)
68
- Ti.App.iOS.endBackgroundHandler(e.handlerId);
69
- });
70
-
71
- // To disable background fetch:
72
- // Ti.App.iOS.setMinimumBackgroundFetchInterval(Ti.App.iOS.BACKGROUNDFETCHINTERVAL_NEVER);
73
- ```
74
-
75
- ### URL Session module
76
- For large downloads that continue even if the app is suspended, use `com.titaniumsdk.urlSession`:
77
-
78
- ```javascript
79
- const urlSession = require('com.titaniumsdk.urlSession');
80
-
81
- const config = urlSession.createSessionConfiguration({
82
- identifier: 'com.myapp.downloads'
83
- });
84
-
85
- const session = urlSession.createSession({
86
- configuration: config
87
- });
88
-
89
- // Start a download task
90
- session.downloadTask({
91
- url: 'https://example.com/largefile.zip'
92
- });
93
-
94
- // Monitor progress
95
- session.addEventListener('downloadprogress', (e) => {
96
- Ti.API.info(`Progress: ${e.totalBytesWritten}/${e.totalBytesExpectedToWrite}`);
97
- });
98
-
99
- session.addEventListener('downloadcompleted', (e) => {
100
- Ti.API.info(`Download saved to: ${e.data}`);
101
- });
102
-
103
- session.addEventListener('sessioncompleted', (e) => {
104
- if (!e.success) {
105
- Ti.API.error(`Session error: ${e.errorDescription}`);
106
- }
107
- });
108
-
109
- // Invalidate session when no longer needed
110
- session.invalidateAndCancel();
111
- ```
112
-
113
- ## 3. iCloud services and backup control
114
-
115
- ### Disable individual backup (best practice)
116
- Apple rejects apps that upload unnecessary data to iCloud. Disable backup for temporary or recreatable files.
117
-
118
- ```javascript
119
- const file = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'cache.dat');
120
- file.remoteBackup = false; // Prevents upload to iCloud/iTunes
121
- ```
122
-
123
- ### Recursive folder backup disable
124
- ```javascript
125
- function disableiCloudBackup(folder) {
126
- const dir = Ti.Filesystem.getFile(folder);
127
- const files = dir.getDirectoryListing();
128
- files.forEach((name) => {
129
- const f = Ti.Filesystem.getFile(folder, name);
130
- f.remoteBackup = false;
131
- if (f.isDirectory()) disableiCloudBackup(f.nativePath);
132
- });
133
- }
134
- ```
135
-
136
- ## 4. WatchKit and Ti.WatchSession
137
-
138
- For watchOS 2+, use `Ti.WatchSession` for bidirectional communication.
139
-
140
- ### Activate session
141
- ```javascript
142
- if (Ti.WatchSession.isSupported) {
143
- Ti.WatchSession.activateSession();
144
- }
145
- ```
146
-
147
- ### Send message (immediate)
148
- ```javascript
149
- if (Ti.WatchSession.isReachable) {
150
- Ti.WatchSession.sendMessage({
151
- orderId: '123',
152
- status: 'shipped'
153
- });
154
- }
155
- ```
156
-
157
- ### Receive data from Watch
158
- ```javascript
159
- Ti.WatchSession.addEventListener('receivemessage', (e) => {
160
- Ti.API.info(`Message from Watch: ${e.message}`);
161
- });
162
- ```
163
-
164
- ### Provisioning profiles for Watch
165
- Both the iOS app and WatchKit extension need separate provisioning profiles. Configure in `tiapp.xml`:
166
- ```xml
167
- <ios>
168
- <extensions>
169
- <extension projectPath="extensions/WatchApp/WatchApp.xcodeproj">
170
- <target name="WatchApp Extension">
171
- <provisioning-profiles>
172
- <device>WATCH_DEV_PROFILE_UUID</device>
173
- <dist-appstore>WATCH_DIST_PROFILE_UUID</dist-appstore>
174
- </provisioning-profiles>
175
- </target>
176
- </extension>
177
- </extensions>
178
- </ios>
179
- ```
180
-
181
- Note: for Xcode 8+, ensure your Team ID matches across all targets.
182
-
183
- ## 5. SiriKit and Siri intents
184
-
185
- Allows your app to respond to Siri voice commands (Messaging, Payments, Workouts).
186
-
187
- ### Configuration in tiapp.xml
188
- ```xml
189
- <key>NSSiriUsageDescription</key>
190
- <string>Siri will use your voice to send messages in this app.</string>
191
- ```
192
-
193
- ### Siri extensions
194
- Create an Intents Extension in Xcode and add it to the `extensions/` folder. Then register it in `tiapp.xml`:
195
- ```xml
196
- <ios>
197
- <extensions>
198
- <extension projectPath="extensions/SiriIntent/SiriIntent.xcodeproj">
199
- <target name="SiriIntent">
200
- <provisioning-profiles>
201
- <device>PROVISIONING_PROFILE_UUID</device>
202
- </provisioning-profiles>
203
- </target>
204
- </extension>
205
- </extensions>
206
- </ios>
207
- ```
208
-
209
- ### Implementation steps
210
- 1. Register App ID with SiriKit capability in Apple Developer Portal.
211
- 2. Create Intents Extension in Xcode (File > New > Target > Intents Extension).
212
- 3. Configure entitlements (add `com.apple.developer.siri`).
213
- 4. Add extension to project (place in `extensions/` folder).
214
- 5. Register in `tiapp.xml` with provisioning profiles for the extension target.
215
- 6. Handle intents in the native extension code (Swift/Objective-C).
216
-
217
- Note: SiriKit requires native code in the Intent Extension. The Titanium app receives results via `continueactivity` events.
218
-
219
- ## 6. Spotlight search (Core Spotlight)
220
-
221
- Indexes your app content to appear in global iOS search results.
222
-
223
- ```javascript
224
- const itemAttr = Ti.App.iOS.createSearchableItemAttributeSet({
225
- itemContentType: Ti.App.iOS.UTTYPE_TEXT,
226
- title: 'My Article',
227
- contentDescription: 'Content description...',
228
- keywords: ['titanium', 'help']
229
- });
230
-
231
- const item = Ti.App.iOS.createSearchableItem({
232
- uniqueIdentifier: 'id-123',
233
- domainIdentifier: 'articles',
234
- attributeSet: itemAttr
235
- });
236
-
237
- const indexer = Ti.App.iOS.createSearchableIndex();
238
- indexer.addToDefaultSearchableIndex([item], (e) => {
239
- if (e.success) Ti.API.info('Indexed!');
240
- });
241
- ```
242
-
243
- ## 7. Core Motion module
244
-
245
- ### Overview
246
- Core Motion provides access to hardware sensors: accelerometer, gyroscope, magnetometer, and more.
247
-
248
- Requirements:
249
- - Add module to `tiapp.xml`:
250
- ```xml
251
- <modules>
252
- <module platform="iphone">ti.coremotion</module>
253
- </modules>
254
- ```
255
-
256
- - Can only test on device, not simulator
257
- - Motion Activity permission required for Activity API
258
-
259
- ### Basic workflow
260
-
261
- 1. Require the module:
262
- ```javascript
263
- var CoreMotion = require('ti.coremotion');
264
- ```
265
-
266
- 2. Check availability:
267
- ```javascript
268
- var Accelerometer = CoreMotion.createAccelerometer();
269
- if (Accelerometer.isAccelerometerAvailable()) {
270
- // Use accelerometer
271
- }
272
- ```
273
-
274
- 3. Start updates:
275
- ```javascript
276
- Accelerometer.setAccelerometerUpdateInterval(1000); // 1 second
277
- Accelerometer.startAccelerometerUpdates((e) => {
278
- if (e.success) {
279
- const data = e.acceleration;
280
- Ti.API.info(`X: ${data.x} Y: ${data.y} Z: ${data.z}`);
281
- }
282
- });
283
- ```
284
-
285
- 4. Stop when done:
286
- ```javascript
287
- Accelerometer.stopAccelerometerUpdates();
288
- ```
289
-
290
- ### Coordinate system
291
- Hold device in portrait mode, screen facing you:
292
- - X-axis: width (positive = right, negative = left)
293
- - Y-axis: height (positive = up, negative = down)
294
- - Z-axis: through screen (positive = toward screen, negative = behind)
295
-
296
- ### Accelerometer
297
-
298
- Measures g-force acceleration along three axes.
299
-
300
- ```javascript
301
- var CoreMotion = require('ti.coremotion');
302
- var Accelerometer = CoreMotion.createAccelerometer();
303
-
304
- if (Accelerometer.isAccelerometerAvailable()) {
305
- Accelerometer.setAccelerometerUpdateInterval(100);
306
- Accelerometer.startAccelerometerUpdates(function(e) {
307
- if (e.success) {
308
- var data = e.acceleration;
309
- updateDisplay(data.x, data.y, data.z);
310
- }
311
- });
312
- }
313
- ```
314
-
315
- Use for: shake detection, device orientation, movement detection.
316
-
317
- ### Gyroscope
318
-
319
- Measures rotational rate along three axes (radians).
320
-
321
- ```javascript
322
- var Gyroscope = CoreMotion.createGyroscope();
323
-
324
- if (Gyroscope.isGyroAvailable()) {
325
- Gyroscope.setGyroUpdateInterval(100);
326
- Gyroscope.startGyroUpdates(function(e) {
327
- if (e.success) {
328
- var data = e.rotationRate;
329
- Ti.API.info('Rotation: X=' + data.x + ' Y=' + data.y + ' Z=' + data.z);
330
- }
331
- });
332
- }
333
- ```
334
-
335
- Use for: rotation gestures, 3D motion tracking, enhanced UI.
336
-
337
- ### Magnetometer
338
-
339
- Measures magnetic field strength (microteslas). Acts as a digital compass.
340
-
341
- ```javascript
342
- var Magnetometer = CoreMotion.createMagnetometer();
343
-
344
- if (Magnetometer.isMagnetometerAvailable()) {
345
- Magnetometer.startMagnetometerUpdates();
346
- // Or poll manually:
347
- var data = Magnetometer.getMagnetometerData();
348
- Ti.API.info('Magnetic field: ' + JSON.stringify(data.magneticField));
349
- }
350
- ```
351
-
352
- Use for: compass direction, magnetic field detection.
353
-
354
- ### Device motion
355
-
356
- Combines accelerometer, gyroscope, and magnetometer for attitude and user acceleration.
357
-
358
- ```javascript
359
- var DeviceMotion = CoreMotion.createDeviceMotion();
360
-
361
- if (DeviceMotion.isDeviceMotionAvailable()) {
362
- DeviceMotion.setDeviceMotionUpdateInterval(500);
363
-
364
- // Check available reference frames
365
- var frames = DeviceMotion.availableAttitudeReferenceFrames();
366
-
367
- if (frames & CoreMotion.ATTITUDE_REFERENCE_FRAME_X_TRUE_NORTH_Z_VERTICAL) {
368
- // Use true north reference
369
- DeviceMotion.startDeviceMotionUpdatesUsingReferenceFrame(
370
- { referenceFrame: CoreMotion.ATTITUDE_REFERENCE_FRAME_X_TRUE_NORTH_Z_VERTICAL },
371
- (e) => {
372
- if (e.success) {
373
- // Attitude: orientation (pitch, roll, yaw)
374
- const attitude = e.attitude;
375
- Ti.API.info(`Pitch: ${attitude.pitch} Roll: ${attitude.roll} Yaw: ${attitude.yaw}`);
376
-
377
- // User acceleration: force applied by user (not gravity)
378
- const userAccel = e.userAcceleration;
379
- }
380
- }
381
- );
382
- }
383
- }
384
- ```
385
-
386
- Attitude formats:
387
- - Pitch/Roll/Yaw (Euler angles)
388
- - Quaternion (w, x, y, z)
389
- - Rotation Matrix (m11-m33)
390
-
391
- Reference frames:
392
- - `ATTITUDE_REFERENCE_FRAME_X_ARBITRARY_Z_VERTICAL` - default
393
- - `ATTITUDE_REFERENCE_FRAME_X_ARBITRARY_CORRECTED_Z_VERTICAL` - uses magnetometer for yaw
394
- - `ATTITUDE_REFERENCE_FRAME_X_MAGNETIC_NORTH_Z_VERTICAL` - magnetic north
395
- - `ATTITUDE_REFERENCE_FRAME_X_TRUE_NORTH_Z_VERTICAL` - true north (requires location)
396
-
397
- ### Activity API
398
-
399
- ```javascript
400
- const MotionActivity = CoreMotion.createMotionActivity();
401
-
402
- MotionActivity.startActivityUpdates((e) => {
403
- const activity = e.activity;
404
-
405
- // Check confidence
406
- if (activity.confidence !== CoreMotion.MOTION_ACTIVITY_CONFIDENCE_LOW) {
407
- if (activity.walking) {
408
- Ti.API.info('User is walking');
409
- } else if (activity.running) {
410
- Ti.API.info('User is running');
411
- } else if (activity.automotive) {
412
- Ti.API.info('User in vehicle');
413
- } else if (activity.stationary) {
414
- Ti.API.info('Device stationary');
415
- }
416
- }
417
- });
418
- ```
419
-
420
- Query historical activity:
421
- ```javascript
422
- var endDate = new Date();
423
- var startDate = new Date(endDate.getTime() - 60 * 60 * 1000); // 1 hour ago
424
-
425
- MotionActivity.queryActivity({
426
- start: startDate,
427
- end: endDate
428
- }, function(e) {
429
- var activities = e.activities;
430
- // Process historical data
431
- });
432
- ```
433
-
434
- Requires Motion Activity permission in `tiapp.xml`:
435
- ```xml
436
- <key>NSMotionUsageDescription</key>
437
- <string>Need motion data for fitness tracking</string>
438
- ```
439
-
440
- ### Pedometer
441
-
442
- ```javascript
443
- const Pedometer = CoreMotion.createPedometer();
444
-
445
- if (Pedometer.isStepCountingAvailable()) {
446
- // Start live updates
447
- Pedometer.startPedometerUpdates({
448
- start: new Date(new Date().getTime() - (60 * 60 * 1000)) // From 1 hour ago
449
- }, (e) => {
450
- Ti.API.info(`Steps: ${e.numberOfSteps}`);
451
- Ti.API.info(`Distance: ${e.distance} meters`);
452
- Ti.API.info(`Floors up: ${e.floorsAscended}`);
453
- Ti.API.info(`Floors down: ${e.floorsDescended}`);
454
- });
455
- }
456
-
457
- // Query historical data
458
- var endDate = new Date();
459
- var startDate = new Date(endDate.getTime() - 24 * 60 * 60 * 1000); // 24 hours ago
460
-
461
- Pedometer.queryPedometerData({
462
- start: startDate,
463
- end: endDate
464
- }, function(e) {
465
- Ti.API.info('Steps in last 24h: ' + e.numberOfSteps);
466
- });
467
- ```
468
-
469
- Use for: fitness apps, step challenges, activity tracking.
470
-
471
- ### Core Motion best practices
472
-
473
- 1. Always check availability; not all devices have all sensors.
474
- 2. Set appropriate update intervals; high frequency means more CPU/battery.
475
- 3. Stop updates when not needed to conserve battery.
476
- 4. Handle errors gracefully; sensors can fail or be unavailable.
477
- 5. Test on physical devices; sensors do not work in simulator.
478
-
479
- ## 8. Handoff user activities
480
-
481
- ```javascript
482
- const UserActivity = Ti.App.iOS.createUserActivity({
483
- activityType: 'com.myapp.reading-article',
484
- title: 'Reading: Titanium SDK Guide',
485
- userInfo: {
486
- articleId: '123',
487
- scrollPosition: 450
488
- },
489
- webpageURL: 'https://myapp.com/articles/123' // For web fallback
490
- });
491
-
492
- // Mark as current activity
493
- UserActivity.becomeCurrent();
494
- ```
495
-
496
- ### Handling incoming Handoff
497
-
498
- ```javascript
499
- Ti.App.iOS.addEventListener('continueactivity', function(e) {
500
- if (e.activityType === 'com.myapp.reading-article') {
501
- var userInfo = e.userInfo;
502
-
503
- // Restore activity state
504
- openArticle(userInfo.articleId, {
505
- scrollTo: userInfo.scrollPosition
506
- });
507
- }
508
- });
509
- ```
510
-
511
- ### Invalidating activities
512
-
513
- ```javascript
514
- // When user closes article
515
- UserActivity.invalidate();
516
- ```
517
-
518
- ### Declaring activity types in tiapp.xml
519
-
520
- ```xml
521
- <key>NSUserActivityTypes</key>
522
- <array>
523
- <string>com.myapp.reading-article</string>
524
- <string>com.myapp.editing-document</string>
525
- <string>com.myapp.viewing-product</string>
526
- </array>
527
- ```
528
-
529
- ### Requirements
530
- - Both devices must be signed into the same iCloud account
531
- - Bluetooth LE must be enabled on both devices
532
- - Both devices must be on the same Wi-Fi network
533
- - Test with Safari first to verify Handoff works between your devices
534
-
535
- ## 9. Additional iOS features
536
-
537
- ### 3D Touch (Force Touch)
538
-
539
- ```javascript
540
- // Check for 3D Touch support
541
- if (Ti.Platform.forceTouchSupported) {
542
- view.addEventListener('touchstart', (e) => {
543
- const force = e.force || 0;
544
- const maxForce = e.maximumForce || 1;
545
-
546
- if (force / maxForce > 0.75) {
547
- // Deep press
548
- showQuickActions();
549
- }
550
- });
551
- }
552
- ```
553
-
554
- ### Haptic feedback
555
-
556
- ```javascript
557
- // Generate haptic feedback
558
- const generator = Ti.UI.iOS.createHapticFeedbackGenerator();
559
-
560
- // Impact feedback (light, medium, heavy)
561
- generator.impactOccurred(Ti.UI.iOS.HAPTIC_FEEDBACK_STYLE_MEDIUM);
562
-
563
- // Selection feedback
564
- generator.selectionChanged();
565
-
566
- // Notification feedback (success, warning, error)
567
- generator.notificationOccurred(Ti.UI.iOS.HAPTIC_FEEDBACK_TYPE_SUCCESS);
568
- ```
569
-
570
- ### Document interaction
571
-
572
- Open documents in other apps:
573
-
574
- ```javascript
575
- var docController = Ti.UI.iOS.createDocumentViewer({
576
- url: file.nativePath
577
- });
578
-
579
- docController.addEventListener('complete', function(e) {
580
- Ti.API.info('Document interaction complete');
581
- });
582
-
583
- win.add(docController);
584
- ```
585
-
586
- ## Best practices summary
587
-
588
- 1. Background services: use sparingly; stop when done.
589
- 2. Core Motion: check availability and test on device.
590
- 3. Spotlight: index content as it changes.
591
- 4. Handoff: provide a web URL fallback.
592
- 5. iCloud: use for small synced data, not large files.
593
- 6. SiriKit: requires native extension; use only if beneficial.
594
- 7. Permissions: always include usage descriptions in `tiapp.xml`.
595
- 8. Testing: many features require physical device testing.