@maccesar/titools 2.10.1 → 3.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.
Files changed (95) 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/config.js +9 -11
  7. package/lib/platform.js +1 -1
  8. package/package.json +2 -3
  9. package/skills/purgetss/SKILL.md +44 -57
  10. package/skills/purgetss/references/EXAMPLES.md +8 -1
  11. package/skills/purgetss/references/app-branding.md +96 -16
  12. package/skills/purgetss/references/apply-directive.md +26 -1
  13. package/skills/purgetss/references/arbitrary-values.md +72 -2
  14. package/skills/purgetss/references/class-categories.md +1 -1
  15. package/skills/purgetss/references/cli-commands.md +37 -13
  16. package/skills/purgetss/references/customization-deep-dive.md +18 -11
  17. package/skills/purgetss/references/dynamic-component-creation.md +0 -1
  18. package/skills/purgetss/references/migration-guide.md +162 -1
  19. package/skills/purgetss/references/multi-density-images.md +69 -0
  20. package/skills/purgetss/references/version-history.md +82 -0
  21. package/skills/ti-expert/SKILL.md +1 -1
  22. package/skills/ti-ui/SKILL.md +1 -1
  23. package/skills/alloy-guides/SKILL.md +0 -190
  24. package/skills/alloy-guides/references/CLI_TASKS.md +0 -233
  25. package/skills/alloy-guides/references/CONCEPTS.md +0 -171
  26. package/skills/alloy-guides/references/CONTROLLERS.md +0 -279
  27. package/skills/alloy-guides/references/MODELS.md +0 -1214
  28. package/skills/alloy-guides/references/PURGETSS.md +0 -46
  29. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +0 -235
  30. package/skills/alloy-guides/references/VIEWS_STYLES.md +0 -375
  31. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
  32. package/skills/alloy-guides/references/VIEWS_XML.md +0 -581
  33. package/skills/alloy-guides/references/WIDGETS.md +0 -160
  34. package/skills/alloy-howtos/SKILL.md +0 -181
  35. package/skills/alloy-howtos/references/best_practices.md +0 -121
  36. package/skills/alloy-howtos/references/cli_reference.md +0 -230
  37. package/skills/alloy-howtos/references/config_files.md +0 -158
  38. package/skills/alloy-howtos/references/custom_tags.md +0 -148
  39. package/skills/alloy-howtos/references/debugging_troubleshooting.md +0 -78
  40. package/skills/alloy-howtos/references/samples.md +0 -156
  41. package/skills/ti-api/SKILL.md +0 -109
  42. package/skills/ti-api/references/api-android.md +0 -675
  43. package/skills/ti-api/references/api-app-platform.md +0 -636
  44. package/skills/ti-api/references/api-core.md +0 -764
  45. package/skills/ti-api/references/api-data-network.md +0 -641
  46. package/skills/ti-api/references/api-media.md +0 -655
  47. package/skills/ti-api/references/api-modules-ble-bluetooth.md +0 -657
  48. package/skills/ti-api/references/api-modules-coremotion-urlsession.md +0 -411
  49. package/skills/ti-api/references/api-modules-map.md +0 -632
  50. package/skills/ti-api/references/api-modules-nfc.md +0 -725
  51. package/skills/ti-api/references/api-modules-social-misc.md +0 -526
  52. package/skills/ti-api/references/api-services.md +0 -700
  53. package/skills/ti-api/references/api-ui-android.md +0 -499
  54. package/skills/ti-api/references/api-ui-extras.md +0 -702
  55. package/skills/ti-api/references/api-ui-ios-animator.md +0 -378
  56. package/skills/ti-api/references/api-ui-ios.md +0 -756
  57. package/skills/ti-api/references/api-ui-lists.md +0 -581
  58. package/skills/ti-api/references/api-ui-text-input.md +0 -607
  59. package/skills/ti-api/references/api-ui-views.md +0 -572
  60. package/skills/ti-api/references/api-ui-windows-navigation.md +0 -676
  61. package/skills/ti-api/references/api-xml-global.md +0 -743
  62. package/skills/ti-guides/SKILL.md +0 -75
  63. package/skills/ti-guides/references/advanced-data-and-images.md +0 -155
  64. package/skills/ti-guides/references/android-manifest.md +0 -97
  65. package/skills/ti-guides/references/app-distribution.md +0 -373
  66. package/skills/ti-guides/references/application-frameworks.md +0 -366
  67. package/skills/ti-guides/references/cli-reference.md +0 -700
  68. package/skills/ti-guides/references/coding-best-practices.md +0 -150
  69. package/skills/ti-guides/references/commonjs-advanced.md +0 -279
  70. package/skills/ti-guides/references/hello-world.md +0 -99
  71. package/skills/ti-guides/references/hyperloop-native-access.md +0 -458
  72. package/skills/ti-guides/references/javascript-primer.md +0 -402
  73. package/skills/ti-guides/references/reserved-words.md +0 -36
  74. package/skills/ti-guides/references/resources.md +0 -172
  75. package/skills/ti-guides/references/style-and-conventions.md +0 -104
  76. package/skills/ti-guides/references/tiapp-config.md +0 -655
  77. package/skills/ti-howtos/SKILL.md +0 -143
  78. package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -609
  79. package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
  80. package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
  81. package/skills/ti-howtos/references/cross-platform-development.md +0 -358
  82. package/skills/ti-howtos/references/debugging-profiling.md +0 -473
  83. package/skills/ti-howtos/references/extending-titanium.md +0 -684
  84. package/skills/ti-howtos/references/google-maps-v2.md +0 -172
  85. package/skills/ti-howtos/references/ios-map-kit.md +0 -149
  86. package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -595
  87. package/skills/ti-howtos/references/local-data-sources.md +0 -310
  88. package/skills/ti-howtos/references/location-and-maps.md +0 -267
  89. package/skills/ti-howtos/references/media-apis.md +0 -268
  90. package/skills/ti-howtos/references/notification-services.md +0 -539
  91. package/skills/ti-howtos/references/remote-data-sources.md +0 -339
  92. package/skills/ti-howtos/references/tutorials.md +0 -552
  93. package/skills/ti-howtos/references/using-modules.md +0 -182
  94. package/skills/ti-howtos/references/web-content-integration.md +0 -288
  95. 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.