@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,609 +0,0 @@
1
- # Android platform deep dives
2
-
3
- ## 1. Android intent filters (advanced)
4
-
5
- To receive implicit intents (for example, opening a PDF file or a web link), register a filter in the manifest.
6
-
7
- ### Critical step: copy root activity
8
- Before declaring an `intent-filter`, copy the `<activity>` node of your main activity from `build/android/AndroidManifest.xml` into the `<android>` section of your `tiapp.xml`:
9
-
10
- ```xml
11
- <android xmlns:android="http://schemas.android.com/apk/res/android">
12
- <manifest>
13
- <application>
14
- <!-- Copy this from build/android/AndroidManifest.xml -->
15
- <activity android:name=".YourAppActivity" android:label="My App" android:configChanges="keyboardHidden|orientation">
16
- <intent-filter>
17
- <action android:name="android.intent.action.MAIN" />
18
- <category android:name="android.intent.category.LAUNCHER" />
19
- </intent-filter>
20
-
21
- <!-- Your new filter here -->
22
- <intent-filter android:label="Open with My App">
23
- <action android:name="android.intent.action.VIEW" />
24
- <category android:name="android.intent.category.DEFAULT" />
25
- <data android:mimeType="application/pdf" />
26
- </intent-filter>
27
- </activity>
28
- </application>
29
- </manifest>
30
- </android>
31
- ```
32
-
33
- ### Retrieving intent data
34
- ```javascript
35
- const intent = Ti.Android.currentActivity.getIntent();
36
- if (intent.hasExtra(Ti.Android.EXTRA_TEXT)) {
37
- const sharedText = intent.getStringExtra(Ti.Android.EXTRA_TEXT);
38
- }
39
- ```
40
-
41
- ## 2. Broadcast intents with permissions
42
-
43
- You can restrict which apps receive your broadcast messages.
44
-
45
- ### Sending with permission
46
- ```javascript
47
- const intent = Ti.Android.createBroadcastIntent({
48
- action: 'com.mycompany.SECURE_ACTION'
49
- });
50
- // Only apps with the permission 'com.mycompany.SPECIAL_PERMISSION' will receive it
51
- Ti.Android.currentActivity.sendBroadcastWithPermission(intent, 'com.mycompany.SPECIAL_PERMISSION');
52
- ```
53
-
54
- ### Declaring permission in tiapp.xml
55
- ```xml
56
- <android>
57
- <manifest>
58
- <permission android:name="com.mycompany.SPECIAL_PERMISSION" />
59
- <uses-permission android:name="com.mycompany.SPECIAL_PERMISSION" />
60
- </manifest>
61
- </android>
62
- ```
63
-
64
- ## 3. FusedLocationProvider (TiSDK 7.1.0+)
65
-
66
- For battery-efficient location tracking on Android, use the fused provider.
67
-
68
- Requirement: include the `ti.playservices` module in your project.
69
- ```xml
70
- <module platform="android">ti.playservices</module>
71
- ```
72
- Titanium will switch to Google Play Services for geolocation, which reduces power consumption.
73
-
74
- ## 4. Android intents
75
-
76
- ### Overview
77
- Intents are message objects that specify actions to perform. They can start activities, broadcasts, or services.
78
-
79
- ### Intent structure
80
- - Action: what to do (for example, `ACTION_VIEW`, `ACTION_SEND`)
81
- - Data: URI the intent operates on (URL, file path)
82
- - Type: MIME type of data
83
- - Category: additional categorization
84
- - Extras: key-value pairs for additional data
85
-
86
- ### Creating intents
87
-
88
- #### Simple intent (action only)
89
- ```javascript
90
- const intent = Ti.Android.createIntent({
91
- action: Ti.Android.ACTION_VIEW
92
- });
93
- ```
94
-
95
- #### Intent with action and data
96
- ```javascript
97
- const intent = Ti.Android.createIntent({
98
- action: Ti.Android.ACTION_VIEW,
99
- data: 'https://titaniumsdk.com'
100
- });
101
- Ti.Android.currentActivity.startActivity(intent);
102
- ```
103
-
104
- #### Intent with extras
105
- ```javascript
106
- const intent = Ti.Android.createIntent({
107
- action: 'com.example.MY_ACTION',
108
- type: 'text/plain'
109
- });
110
- intent.putExtra('message', 'Hello from Titanium');
111
- intent.putExtra('count', 42);
112
- ```
113
-
114
- ### Common use cases
115
-
116
- #### Open URL in browser
117
- ```javascript
118
- const intent = Ti.Android.createIntent({
119
- action: Ti.Android.ACTION_VIEW,
120
- data: 'https://www.example.com'
121
- });
122
- Ti.Android.currentActivity.startActivity(intent);
123
- ```
124
-
125
- #### Dial phone number
126
- ```javascript
127
- const intent = Ti.Android.createIntent({
128
- action: Ti.Android.ACTION_DIAL,
129
- data: 'tel:5551234'
130
- });
131
- Ti.Android.currentActivity.startActivity(intent);
132
- ```
133
-
134
- #### Send email
135
- ```javascript
136
- const intent = Ti.Android.createIntent({
137
- action: Ti.Android.ACTION_SENDTO,
138
- data: 'mailto:user@example.com'
139
- });
140
- intent.putExtra(Ti.Android.EXTRA_SUBJECT, 'Hello');
141
- intent.putExtra(Ti.Android.EXTRA_TEXT, 'Email body');
142
- Ti.Android.currentActivity.startActivity(intent);
143
- ```
144
-
145
- #### Share content
146
- ```javascript
147
- const intent = Ti.Android.createIntent({
148
- action: Ti.Android.ACTION_SEND,
149
- type: 'text/plain'
150
- });
151
- intent.putExtra(Ti.Android.EXTRA_TEXT, 'Check this out!');
152
- Ti.Android.currentActivity.startActivity(intent);
153
- ```
154
-
155
- #### Open PDF file
156
- ```javascript
157
- const intent = Ti.Android.createIntent({
158
- action: Ti.Android.ACTION_VIEW,
159
- type: 'application/pdf',
160
- data: file.nativePath // Ti.Filesystem.File object
161
- });
162
- intent.addFlags(Ti.Android.FLAG_GRANT_READ_URI_PERMISSION);
163
- Ti.Android.currentActivity.startActivity(intent);
164
- ```
165
-
166
- ### Starting other apps
167
- ```javascript
168
- // Open specific app by package name
169
- const intent = Ti.Android.createIntent({
170
- action: Ti.Android.ACTION_MAIN,
171
- packageName: 'com.example.anotherapp',
172
- className: 'com.example.anotherapp.MainActivity'
173
- });
174
- try {
175
- Ti.Android.currentActivity.startActivity(intent);
176
- } catch (e) {
177
- Ti.API.error(`App not installed: ${e.message}`);
178
- }
179
- ```
180
-
181
- ### Intent chooser
182
- Force the system to show an app chooser dialog (even if a default is set):
183
- ```javascript
184
- const intent = Ti.Android.createIntent({
185
- action: Ti.Android.ACTION_SEND,
186
- type: 'text/plain'
187
- });
188
- intent.putExtra(Ti.Android.EXTRA_TEXT, 'Share this text');
189
-
190
- Ti.Android.currentActivity.startActivity(
191
- Ti.Android.createIntentChooser(intent, 'Share via...')
192
- );
193
- ```
194
-
195
- ### Getting results from activities
196
- ```javascript
197
- const intent = Ti.Android.createIntent({
198
- action: 'android.media.action.IMAGE_CAPTURE'
199
- });
200
-
201
- Ti.Android.currentActivity.startActivityForResult(intent, (e) => {
202
- if (e.resultCode === Ti.Android.RESULT_OK) {
203
- const imageUri = e.intent.data;
204
- Ti.API.info(`Captured image: ${imageUri}`);
205
- } else if (e.resultCode === Ti.Android.RESULT_CANCELED) {
206
- Ti.API.info('User canceled');
207
- }
208
- });
209
- ```
210
-
211
- ## 5. Intent filters
212
-
213
- ### Overview
214
- Intent filters advertise your app's capability to handle certain actions and data types. They enable deep linking, file handling, and inter-app communication.
215
-
216
- ### Configuring in tiapp.xml
217
-
218
- ```xml
219
- <android>
220
- <manifest>
221
- <application>
222
- <activity>
223
- <intent-filter>
224
- <action android:name="android.intent.action.VIEW"/>
225
- <category android:name="android.intent.category.DEFAULT"/>
226
- <category android:name="android.intent.category.BROWSABLE"/>
227
- <data android:scheme="myapp"/>
228
- </intent-filter>
229
-
230
- <!-- Handle PDF files -->
231
- <intent-filter>
232
- <action android:name="android.intent.action.VIEW"/>
233
- <category android:name="android.intent.category.DEFAULT"/>
234
- <data android:mimeType="application/pdf"/>
235
- </intent-filter>
236
-
237
- <!-- Handle HTTP URLs -->
238
- <intent-filter>
239
- <action android:name="android.intent.action.VIEW"/>
240
- <category android:name="android.intent.category.DEFAULT"/>
241
- <category android:name="android.intent.category.BROWSABLE"/>
242
- <data android:scheme="http" android:host="www.example.com"/>
243
- </intent-filter>
244
- </activity>
245
- </application>
246
- </manifest>
247
- </android>
248
- ```
249
-
250
- ### Handling incoming intents
251
-
252
- #### Get intent data on startup
253
- ```javascript
254
- const activity = Ti.Android.currentActivity;
255
- const intent = activity.getIntent();
256
-
257
- if (intent) {
258
- const action = intent.getAction();
259
- const data = intent.getData();
260
-
261
- if (data) {
262
- Ti.API.info(`Received data: ${data}`);
263
- // Handle URL or file path
264
- }
265
-
266
- // Get extras
267
- const extra = intent.getStringExtra('key');
268
- Ti.API.info(`Extra value: ${extra}`);
269
- }
270
- ```
271
-
272
- #### Listen for new intents (activity restart)
273
- ```javascript
274
- Ti.Android.currentActivity.addEventListener('newintent', (e) => {
275
- const intent = e.intent;
276
- const data = intent.getData();
277
- Ti.API.info(`New intent received: ${data}`);
278
-
279
- // Handle the new intent
280
- handleDeepLink(data);
281
- });
282
- ```
283
-
284
- ### Deep linking example
285
-
286
- ```xml
287
- <!-- In tiapp.xml -->
288
- <intent-filter>
289
- <action android:name="android.intent.action.VIEW"/>
290
- <category android:name="android.intent.category.DEFAULT"/>
291
- <category android:name="android.intent.category.BROWSABLE"/>
292
- <data android:scheme="myapp" android:host="product"/>
293
- </intent-filter>
294
- ```
295
-
296
- ```javascript
297
- // In app.js
298
- function handleDeepLink(url) {
299
- // Parse URL like: myapp://product/123
300
- const parts = url.split('/');
301
- const productId = parts[parts.length - 1];
302
- openProductScreen(productId);
303
- }
304
-
305
- // Check on startup
306
- const activity = Ti.Android.currentActivity;
307
- const intent = activity.getIntent();
308
- if (intent && intent.getData()) {
309
- handleDeepLink(intent.getData());
310
- }
311
- ```
312
-
313
- ## 6. Broadcast intents and receivers
314
-
315
- ### Overview
316
- Broadcast intents allow system-wide or app-wide messaging. Apps can send broadcasts and register receivers to listen for them.
317
-
318
- ### System broadcasts
319
-
320
- Common system broadcasts:
321
- - `android.intent.action.BATTERY_LOW` - battery low warning
322
- - `android.intent.action.BATTERY_CHANGED` - battery status changed
323
- - `android.intent.action.ACTION_POWER_CONNECTED` - power connected
324
- - `android.intent.action.ACTION_POWER_DISCONNECTED` - power disconnected
325
- - `android.intent.action.BOOT_COMPLETED` - system boot completed
326
- - `android.net.conn.CONNECTIVITY_CHANGE` - network connection changed
327
- - `android.intent.action.USER_PRESENT` - user unlocked device
328
- - `android.intent.action.PACKAGE_INSTALL` / `PACKAGE_REMOVED` - package changes
329
-
330
- ### Registering broadcast receivers
331
-
332
- #### Dynamic registration (in code)
333
-
334
- ```javascript
335
- // Create receiver
336
- const batteryReceiver = Ti.Android.createBroadcastReceiver({
337
- onReceived: (e) => {
338
- const level = e.intent.getIntExtra(Ti.Android.EXTRA_BATTERY_LEVEL, -1);
339
- Ti.API.info(`Battery level: ${level}%`);
340
-
341
- if (level < 20) {
342
- showLowBatteryWarning();
343
- }
344
- }
345
- });
346
-
347
- // Register for battery low
348
- Ti.Android.registerBroadcastReceiver(batteryReceiver, [
349
- Ti.Android.ACTION_BATTERY_LOW
350
- ]);
351
-
352
- // Later: unregister when no longer needed
353
- Ti.Android.unregisterBroadcastReceiver(batteryReceiver);
354
- ```
355
-
356
- #### Network change listener
357
-
358
- ```javascript
359
- const networkReceiver = Ti.Android.createBroadcastReceiver({
360
- onReceived: (e) => {
361
- const connectivityManager = Ti.Android.getSystemService(
362
- Ti.Android.CONNECTIVITY_SERVICE
363
- );
364
- const networkInfo = connectivityManager.getActiveNetworkInfo();
365
-
366
- if (networkInfo && networkInfo.isConnected()) {
367
- Ti.API.info(`Network connected: ${networkInfo.getTypeName()}`);
368
- // Retry pending operations
369
- } else {
370
- Ti.API.info('Network disconnected');
371
- // Show offline mode
372
- }
373
- }
374
- });
375
-
376
- Ti.Android.registerBroadcastReceiver(networkReceiver, [
377
- 'android.net.conn.CONNECTIVITY_CHANGE'
378
- ]);
379
- ```
380
-
381
- ### Sending custom broadcasts
382
-
383
- ```javascript
384
- // Send broadcast within your app
385
- const intent = Ti.Android.createIntent({
386
- action: 'com.myapp.CUSTOM_EVENT'
387
- });
388
- intent.putExtra('data', 'Custom data here');
389
- Ti.Android.currentActivity.sendBroadcast(intent);
390
- ```
391
-
392
- #### Receiver for custom broadcast
393
-
394
- ```javascript
395
- const customReceiver = Ti.Android.createBroadcastReceiver({
396
- onReceived: (e) => {
397
- const data = e.intent.getStringExtra('data');
398
- Ti.API.info(`Received custom event: ${data}`);
399
- }
400
- });
401
-
402
- Ti.Android.registerBroadcastReceiver(customReceiver, [
403
- 'com.myapp.CUSTOM_EVENT'
404
- ]);
405
- ```
406
-
407
- ### Boot receiver
408
-
409
- In `tiapp.xml`:
410
- ```xml
411
- <android>
412
- <manifest>
413
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
414
- <application>
415
- <receiver
416
- android:name="com.myapp.BootReceiver"
417
- android:enabled="true">
418
- <intent-filter>
419
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
420
- </intent-filter>
421
- </receiver>
422
- </application>
423
- </manifest>
424
- </android>
425
- ```
426
-
427
- ## 7. Android services
428
-
429
- ### Overview
430
- Services are background components that run independently of the UI. Useful for long-running operations like music playback, location tracking, or network polling.
431
-
432
- ### Service types
433
-
434
- 1. Regular service: runs in background until stopped
435
- 2. IntentService: queues work requests and processes sequentially
436
- 3. Foreground service: shows persistent notification, higher priority
437
-
438
- ### Creating a service
439
-
440
- ```javascript
441
- // Create service
442
- const service = Ti.Android.createService({
443
- url: 'myservice.js',
444
- interval: 60000 // Check every 60 seconds
445
- });
446
-
447
- // Start service
448
- service.start();
449
-
450
- // Stop service when done
451
- service.stop();
452
- ```
453
-
454
- `myservice.js`:
455
- ```javascript
456
- Ti.API.info('Service running');
457
-
458
- // Perform work
459
- const xhr = Ti.Network.createHTTPClient({
460
- onload: () => {
461
- Ti.API.info('Data updated');
462
- // Send notification if needed
463
- }
464
- });
465
- xhr.open('GET', 'https://api.example.com/update');
466
- xhr.send();
467
- ```
468
-
469
- ### IntentService
470
-
471
- For one-off or queued work:
472
-
473
- ```javascript
474
- const intent = Ti.Android.createServiceIntent({
475
- url: 'backgroundtask.js'
476
- });
477
-
478
- // Start service (runs once and stops)
479
- Ti.Android.startService(intent);
480
- ```
481
-
482
- `backgroundtask.js`:
483
- ```javascript
484
- // Do work
485
- const result = processHeavyTask();
486
-
487
- // Optionally send result back to activity
488
- const broadcast = Ti.Android.createBroadcastReceiver({
489
- onReceived: () => { /* ... */ }
490
- });
491
- // ...
492
- ```
493
-
494
- ### Foreground service
495
-
496
- For critical, long-running operations (must show notification):
497
-
498
- ```javascript
499
- const notification = Ti.Android.createNotification({
500
- contentTitle: 'Service Running',
501
- contentText: 'Tracking location...',
502
- tickerText: 'Service started',
503
- icon: Ti.App.Android.R.drawable.app_icon
504
- });
505
-
506
- const intent = Ti.Android.createServiceIntent({
507
- url: 'trackingservice.js'
508
- });
509
-
510
- intent.addFlags(Ti.Android.FLAG_ACTIVITY_CLEAR_TOP);
511
- intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
512
-
513
- // Start as foreground service
514
- Ti.Android.startForegroundService(intent, 101, notification);
515
- ```
516
-
517
- To stop:
518
- ```javascript
519
- Ti.Android.stopForegroundService(intent);
520
- ```
521
-
522
- ### Service lifecycle management
523
-
524
- Important: always stop services when no longer needed to conserve resources.
525
-
526
- ```javascript
527
- // In activity
528
- Ti.Android.currentActivity.addEventListener('pause', () => {
529
- // Optionally pause service
530
- });
531
-
532
- Ti.Android.currentActivity.addEventListener('destroy', () => {
533
- // Always stop service
534
- if (service) {
535
- service.stop();
536
- service = null;
537
- }
538
- });
539
- ```
540
-
541
- ### Inter-service communication
542
-
543
- ```javascript
544
- // From activity to service
545
- const intent = Ti.Android.createServiceIntent({
546
- url: 'myservice.js'
547
- });
548
- intent.putExtra('command', 'pause');
549
- Ti.Android.startService(intent);
550
-
551
- // In service
552
- const command = intent.getStringExtra('command');
553
- if (command === 'pause') {
554
- // Handle pause command
555
- }
556
- ```
557
-
558
- ## 8. Android permissions
559
-
560
- ### Runtime permissions (Android 6.0+)
561
-
562
- Dangerous permissions require a runtime request:
563
-
564
- ```javascript
565
- function checkPermission() {
566
- const result = Ti.Android.checkSelfPermission(
567
- Ti.Android.PERMISSION_ACCESS_FINE_LOCATION
568
- );
569
-
570
- if (result === Ti.Android.RESULTS.GRANTED) {
571
- startLocationTracking();
572
- } else {
573
- Ti.Android.requestPermissions(
574
- [Ti.Android.PERMISSION_ACCESS_FINE_LOCATION],
575
- 999, // Request code
576
- (e) => {
577
- if (e.granted[0] === true) {
578
- startLocationTracking();
579
- } else {
580
- alert('Location permission denied');
581
- }
582
- }
583
- );
584
- }
585
- }
586
-
587
- checkPermission();
588
- ```
589
-
590
- ### Common dangerous permissions
591
- - `ACCESS_FINE_LOCATION` - GPS location
592
- - `ACCESS_COARSE_LOCATION` - network location
593
- - `CAMERA` - camera access
594
- - `READ_EXTERNAL_STORAGE` - read files
595
- - `WRITE_EXTERNAL_STORAGE` - write files
596
- - `RECORD_AUDIO` - microphone
597
- - `CALL_PHONE` - make phone calls
598
- - `SEND_SMS` / `READ_SMS` - SMS access
599
-
600
- ## Best practices
601
-
602
- 1. Always unregister broadcast receivers when no longer needed.
603
- 2. Stop services explicitly to conserve battery.
604
- 3. Use IntentService for one-off background tasks.
605
- 4. Use foreground services for user-visible long operations.
606
- 5. Handle runtime permissions gracefully on Android 6.0+.
607
- 6. Validate intent data before processing.
608
- 7. Use proper intent flags for navigation behavior.
609
- 8. Test intent filters with ADB: `adb shell am start -W -a android.intent.action.VIEW -d "myapp://path"`.
@@ -1,96 +0,0 @@
1
- # Automation with Fastlane and Appium
2
-
3
- Guide to setting up CI pipelines, automated testing, and deployment for Titanium.
4
-
5
- ## 1. UI testing with Appium
6
-
7
- Appium supports automated functional testing on real devices and simulators.
8
-
9
- ### Prerequisites
10
- - Appium Desktop or CLI
11
- - Mocha (test runner)
12
- - WebdriverIO (recommended client)
13
-
14
- ### Test example (Mocha + WebdriverIO)
15
- ```javascript
16
- const opts = {
17
- port: 4723,
18
- capabilities: {
19
- platformName: 'iOS',
20
- deviceName: 'iPhone 15',
21
- app: '/path/to/your/app.app',
22
- automationName: 'XCUITest'
23
- }
24
- };
25
-
26
- describe('Login Test', () => {
27
- it('Should login with valid credentials', async () => {
28
- const client = await wdio.remote(opts);
29
- const userField = await client.$('~Enter Username'); // Use Accessibility ID
30
- await userField.setValue('my_user');
31
- await client.deleteSession();
32
- });
33
- });
34
- ```
35
-
36
- ## 2. Automation with Fastlane
37
-
38
- Fastlane automates building, signing, and uploading to the stores.
39
-
40
- ### Titanium plugins
41
- Install project plugins:
42
- ```bash
43
- fastlane add_plugin ti_build_app
44
- fastlane add_plugin mocha_run_tests
45
- ```
46
-
47
- ### Fastfile configuration
48
- Create `fastlane/Fastfile` in the root:
49
-
50
- ```ruby
51
- platform :ios do
52
- desc "Build for Simulator Tests"
53
- lane :build_test do
54
- ti_build_app(
55
- appc_cli: "ti build -p ios -T simulator --build-only"
56
- )
57
- end
58
-
59
- desc "Run UI Tests"
60
- lane :test do
61
- build_test
62
- mocha_run_tests(
63
- mocha_js_file_name: 'tests/login_test.js'
64
- )
65
- end
66
-
67
- desc "Deploy to TestFlight"
68
- lane :release do
69
- ti_build_app(
70
- appc_cli: "ti build -p ios -T dist-appstore --distribution-name 'Your Company' --pp-uuid 'UUID-HERE' --output-dir /dist"
71
- )
72
- # Add fastlane pilot command here to upload the .ipa
73
- end
74
- end
75
- ```
76
-
77
- ## 3. CI/CD best practices
78
- 1. Accessibility IDs: assign `accessibilityLabel` in XML/TSS so Appium can find elements reliably.
79
- 2. Environment lanes: define separate lanes for `beta`, `production`, and `test`.
80
- 3. Profile management: use Fastlane Match to sync certs and provisioning profiles across the team.
81
- 4. Snapshots: use Fastlane `snapshot` to automate App Store screenshot generation.
82
-
83
- ## 4. Unit testing with TiUnit
84
-
85
- For non-UI tests, consider TiUnit (Jasmine-based):
86
- - Runs tests inside the app context
87
- - Supports standard Jasmine `describe`/`it`/`expect` syntax
88
- - Integrates cleanly into CI pipelines
89
-
90
- ## 5. Broader CI/CD options
91
-
92
- Beyond Fastlane and Appium, Titanium apps can integrate with:
93
- - Jenkins for build orchestration and pipeline management
94
- - SonarQube for code quality analysis
95
- - AWS Device Farm for testing on real devices in the cloud
96
- - Nexus/Artifactory for build artifact archiving and versioning