@maccesar/titools 2.0.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 (120) hide show
  1. package/AGENTS-TEMPLATE.md +173 -0
  2. package/README.md +867 -0
  3. package/agents/ti-researcher.md +108 -0
  4. package/bin/titools.js +53 -0
  5. package/lib/commands/agents.js +126 -0
  6. package/lib/commands/install.js +188 -0
  7. package/lib/commands/uninstall.js +215 -0
  8. package/lib/commands/update.js +159 -0
  9. package/lib/config.js +119 -0
  10. package/lib/downloader.js +153 -0
  11. package/lib/installer.js +253 -0
  12. package/lib/platform.js +108 -0
  13. package/lib/symlink.js +142 -0
  14. package/lib/utils.js +270 -0
  15. package/package.json +67 -0
  16. package/skills/alloy-expert/SKILL.md +247 -0
  17. package/skills/alloy-expert/assets/ControllerAutoCleanup.js +182 -0
  18. package/skills/alloy-expert/references/alloy-structure.md +381 -0
  19. package/skills/alloy-expert/references/anti-patterns.md +133 -0
  20. package/skills/alloy-expert/references/code-conventions.md +469 -0
  21. package/skills/alloy-expert/references/contracts.md +280 -0
  22. package/skills/alloy-expert/references/controller-patterns.md +520 -0
  23. package/skills/alloy-expert/references/error-handling.md +484 -0
  24. package/skills/alloy-expert/references/examples.md +735 -0
  25. package/skills/alloy-expert/references/migration-patterns.md +298 -0
  26. package/skills/alloy-expert/references/patterns.md +448 -0
  27. package/skills/alloy-expert/references/performance-patterns.md +855 -0
  28. package/skills/alloy-expert/references/security-patterns.md +847 -0
  29. package/skills/alloy-expert/references/state-management.md +779 -0
  30. package/skills/alloy-expert/references/testing.md +872 -0
  31. package/skills/alloy-guides/SKILL.md +214 -0
  32. package/skills/alloy-guides/references/CLI_TASKS.md +243 -0
  33. package/skills/alloy-guides/references/CONCEPTS.md +191 -0
  34. package/skills/alloy-guides/references/CONTROLLERS.md +298 -0
  35. package/skills/alloy-guides/references/MODELS.md +1028 -0
  36. package/skills/alloy-guides/references/PURGETSS.md +56 -0
  37. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +242 -0
  38. package/skills/alloy-guides/references/VIEWS_STYLES.md +388 -0
  39. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +109 -0
  40. package/skills/alloy-guides/references/VIEWS_XML.md +558 -0
  41. package/skills/alloy-guides/references/WIDGETS.md +176 -0
  42. package/skills/alloy-howtos/SKILL.md +203 -0
  43. package/skills/alloy-howtos/references/best_practices.md +138 -0
  44. package/skills/alloy-howtos/references/cli_reference.md +253 -0
  45. package/skills/alloy-howtos/references/config_files.md +87 -0
  46. package/skills/alloy-howtos/references/custom_tags.md +147 -0
  47. package/skills/alloy-howtos/references/debugging_troubleshooting.md +101 -0
  48. package/skills/alloy-howtos/references/samples.md +167 -0
  49. package/skills/purgetss/SKILL.md +442 -0
  50. package/skills/purgetss/assets/purgetss.config.cjs +17 -0
  51. package/skills/purgetss/references/EXAMPLES.md +247 -0
  52. package/skills/purgetss/references/animation-system.md +1294 -0
  53. package/skills/purgetss/references/apply-directive.md +375 -0
  54. package/skills/purgetss/references/arbitrary-values.md +612 -0
  55. package/skills/purgetss/references/class-index.md +1350 -0
  56. package/skills/purgetss/references/cli-commands.md +948 -0
  57. package/skills/purgetss/references/configurable-properties.md +654 -0
  58. package/skills/purgetss/references/custom-rules.md +161 -0
  59. package/skills/purgetss/references/customization-deep-dive.md +722 -0
  60. package/skills/purgetss/references/dynamic-component-creation.md +489 -0
  61. package/skills/purgetss/references/grid-layout.md +455 -0
  62. package/skills/purgetss/references/icon-fonts.md +609 -0
  63. package/skills/purgetss/references/installation-setup.md +366 -0
  64. package/skills/purgetss/references/opacity-modifier.md +291 -0
  65. package/skills/purgetss/references/platform-modifiers.md +479 -0
  66. package/skills/purgetss/references/smart-mappings.md +42 -0
  67. package/skills/purgetss/references/titanium-resets.md +359 -0
  68. package/skills/purgetss/references/ui-ux-design.md +1526 -0
  69. package/skills/ti-guides/SKILL.md +94 -0
  70. package/skills/ti-guides/references/advanced-data-and-images.md +19 -0
  71. package/skills/ti-guides/references/alloy-cli-advanced.md +84 -0
  72. package/skills/ti-guides/references/alloy-data-mastery.md +29 -0
  73. package/skills/ti-guides/references/alloy-widgets-and-themes.md +19 -0
  74. package/skills/ti-guides/references/android-manifest.md +97 -0
  75. package/skills/ti-guides/references/app-distribution.md +258 -0
  76. package/skills/ti-guides/references/application-frameworks.md +377 -0
  77. package/skills/ti-guides/references/cli-reference.md +402 -0
  78. package/skills/ti-guides/references/coding-best-practices.md +102 -0
  79. package/skills/ti-guides/references/commonjs-advanced.md +134 -0
  80. package/skills/ti-guides/references/hello-world.md +100 -0
  81. package/skills/ti-guides/references/hyperloop-native-access.md +62 -0
  82. package/skills/ti-guides/references/javascript-primer.md +411 -0
  83. package/skills/ti-guides/references/reserved-words.md +36 -0
  84. package/skills/ti-guides/references/resources.md +183 -0
  85. package/skills/ti-guides/references/style-and-conventions.md +48 -0
  86. package/skills/ti-guides/references/tiapp-config.md +609 -0
  87. package/skills/ti-howtos/SKILL.md +174 -0
  88. package/skills/ti-howtos/references/android-platform-deep-dives.md +658 -0
  89. package/skills/ti-howtos/references/automation-fastlane-appium.md +95 -0
  90. package/skills/ti-howtos/references/buffer-codec-streams.md +140 -0
  91. package/skills/ti-howtos/references/cross-platform-development.md +348 -0
  92. package/skills/ti-howtos/references/debugging-profiling.md +543 -0
  93. package/skills/ti-howtos/references/extending-titanium.md +723 -0
  94. package/skills/ti-howtos/references/google-maps-v2.md +169 -0
  95. package/skills/ti-howtos/references/ios-map-kit.md +143 -0
  96. package/skills/ti-howtos/references/ios-platform-deep-dives.md +783 -0
  97. package/skills/ti-howtos/references/local-data-sources.md +301 -0
  98. package/skills/ti-howtos/references/location-and-maps.md +252 -0
  99. package/skills/ti-howtos/references/media-apis.md +210 -0
  100. package/skills/ti-howtos/references/notification-services.md +599 -0
  101. package/skills/ti-howtos/references/remote-data-sources.md +349 -0
  102. package/skills/ti-howtos/references/tutorials.md +502 -0
  103. package/skills/ti-howtos/references/using-modules.md +237 -0
  104. package/skills/ti-howtos/references/web-content-integration.md +307 -0
  105. package/skills/ti-howtos/references/webpack-build-pipeline.md +78 -0
  106. package/skills/ti-ui/SKILL.md +179 -0
  107. package/skills/ti-ui/references/accessibility-deep-dive.md +242 -0
  108. package/skills/ti-ui/references/animation-and-matrices.md +599 -0
  109. package/skills/ti-ui/references/application-structures.md +655 -0
  110. package/skills/ti-ui/references/custom-fonts-styling.md +579 -0
  111. package/skills/ti-ui/references/event-handling.md +393 -0
  112. package/skills/ti-ui/references/gestures.md +473 -0
  113. package/skills/ti-ui/references/icons-and-splash-screens.md +409 -0
  114. package/skills/ti-ui/references/layouts-and-positioning.md +462 -0
  115. package/skills/ti-ui/references/listviews-and-performance.md +619 -0
  116. package/skills/ti-ui/references/orientation.md +362 -0
  117. package/skills/ti-ui/references/platform-ui-android.md +635 -0
  118. package/skills/ti-ui/references/platform-ui-ios.md +469 -0
  119. package/skills/ti-ui/references/scrolling-views.md +252 -0
  120. package/skills/ti-ui/references/tableviews.md +568 -0
@@ -0,0 +1,599 @@
1
+ # Push and Local Notifications
2
+
3
+ Comprehensive guide for local and push notifications on iOS and Android.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Push and Local Notifications](#push-and-local-notifications)
8
+ - [Table of Contents](#table-of-contents)
9
+ - [Local Notifications Android](#local-notifications-android)
10
+ - [Notification Display Locations](#notification-display-locations)
11
+ - [Create a Notification](#create-a-notification)
12
+ - [Sound](#sound)
13
+ - [Custom Layout with RemoteViews](#custom-layout-with-remoteviews)
14
+ - [Additional Properties](#additional-properties)
15
+ - [Update Notification](#update-notification)
16
+ - [Remove Notifications](#remove-notifications)
17
+ - [Respond to Notification Tap](#respond-to-notification-tap)
18
+ - [Schedule Future Notification (Background Service)](#schedule-future-notification-background-service)
19
+ - [Local Notifications iOS](#local-notifications-ios)
20
+ - [Notification Display Locations](#notification-display-locations-1)
21
+ - [Register for Notifications (iOS 8+)](#register-for-notifications-ios-8)
22
+ - [Schedule Local Notification](#schedule-local-notification)
23
+ - [Monitor Notifications](#monitor-notifications)
24
+ - [Cancel Notifications](#cancel-notifications)
25
+ - [Interactive Notifications iOS (iOS 8+)](#interactive-notifications-ios-ios-8)
26
+ - [Create Notification Actions](#create-notification-actions)
27
+ - [Create Notification Category](#create-notification-category)
28
+ - [Register Categories](#register-categories)
29
+ - [Monitor Interactive Notifications](#monitor-interactive-notifications)
30
+ - [Schedule Interactive Local Notification](#schedule-interactive-local-notification)
31
+ - [Send Interactive Push Notification](#send-interactive-push-notification)
32
+ - [Push Notifications](#push-notifications)
33
+ - [Overview](#overview)
34
+ - [Register for Push Notifications](#register-for-push-notifications)
35
+ - [Configure Push Services](#configure-push-services)
36
+ - [Push Notification Payload Format](#push-notification-payload-format)
37
+ - [Subscribe to Channels](#subscribe-to-channels)
38
+ - [Send Push Notifications](#send-push-notifications)
39
+ - [Best Practices](#best-practices)
40
+ - [Common Patterns](#common-patterns)
41
+ - [Check Notification Permissions](#check-notification-permissions)
42
+ - [PendingIntent for Notification Actions](#pendingintent-for-notification-actions)
43
+ - [Notification Groups (Android 7.0+)](#notification-groups-android-70)
44
+ - [Rich Notifications (iOS 10+)](#rich-notifications-ios-10)
45
+ - [Silent Push](#silent-push)
46
+ - [Platform-Specific Notes](#platform-specific-notes)
47
+ - [Android](#android)
48
+ - [iOS](#ios)
49
+
50
+ ---
51
+
52
+ ## Local Notifications Android
53
+
54
+ ### Notification Display Locations
55
+
56
+ - **Notification Drawer**: Swipe down from status bar
57
+ - **Lock Screen**: Android 5.0+ (API 21+)
58
+ - **Status Bar**: Icon and ticker text
59
+
60
+ ### Create a Notification
61
+
62
+ **Basic Layout:**
63
+ ```javascript
64
+ const notification = Ti.Android.createNotification({
65
+ contentTitle: 'Notification Title',
66
+ contentText: 'Notification message',
67
+ contentIntent: Ti.Android.createPendingIntent({
68
+ intent: Ti.Android.createIntent({})
69
+ }),
70
+ icon: Ti.App.Android.R.drawable.warn, // or '/images/warn.png'
71
+ number: 5, // Badge number
72
+ when: new Date(), // Timestamp (does NOT schedule)
73
+ tickerText: 'Text in status bar when notification first appears'
74
+ });
75
+
76
+ // Send immediately
77
+ Ti.Android.NotificationManager.notify(1, notification);
78
+ ```
79
+
80
+ **Icon paths:**
81
+ - Density-specific: `/app/assets/android/images/` (Alloy) or `/Resources/android/images/` (Classic), reference as `/images/filename.png`
82
+ - Drawable folder: `/platform/android/res/drawable/filename.png`, reference as `Ti.App.Android.R.drawable.filename`
83
+
84
+ ### Sound
85
+
86
+ ```javascript
87
+ const notification = Ti.Android.createNotification({
88
+ // ... other properties
89
+ sound: `${Ti.Filesystem.getResRawDirectory()}sound.wav`
90
+ });
91
+ ```
92
+
93
+ Play only once (add flag):
94
+ ```javascript
95
+ notification.flags |= Ti.Android.FLAG_ONLY_ALERT_ONCE;
96
+ ```
97
+
98
+ ### Custom Layout with RemoteViews
99
+
100
+ **1. Create XML Layout** (`/platform/android/res/layout/customview.xml`):
101
+ ```xml
102
+ <?xml version="1.0" encoding="utf-8"?>
103
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
104
+ android:layout_width="match_parent"
105
+ android:layout_height="match_parent"
106
+ android:orientation="horizontal">
107
+ <TextView android:id="@+id/message"
108
+ android:layout_width="wrap_content"
109
+ android:layout_height="wrap_content"
110
+ android:text="Default text" />
111
+ <Button android:id="@+id/okbutton"
112
+ android:layout_width="wrap_content"
113
+ android:layout_height="wrap_content"
114
+ android:text="OK" />
115
+ </LinearLayout>
116
+ ```
117
+
118
+ **2. Create RemoteViews and bind intents:**
119
+ ```javascript
120
+ const customView = Ti.Android.createRemoteViews({
121
+ layoutId: Ti.App.Android.R.layout.customview
122
+ });
123
+
124
+ // Modify text
125
+ customView.setTextViewText(Ti.App.Android.R.id.message, "Update available!");
126
+
127
+ // Bind intents to buttons
128
+ const downloadIntent = Ti.Android.createPendingIntent({intent: Ti.Android.createIntent()});
129
+ customView.setOnClickPendingIntent(Ti.App.Android.R.id.okbutton, downloadIntent);
130
+
131
+ const notification = Ti.Android.createNotification({
132
+ contentView: customView // Avoid setting contentTitle/contentText or they override this
133
+ });
134
+ ```
135
+
136
+ ### Additional Properties
137
+
138
+ **Defaults (device settings):**
139
+ ```javascript
140
+ notification.defaults = Ti.Android.DEFAULT_ALL; // or DEFAULT_SOUND, DEFAULT_VIBRATE, DEFAULT_LIGHTS
141
+ ```
142
+
143
+ **Flags (behavior):**
144
+ ```javascript
145
+ notification.flags |= Ti.Android.FLAG_AUTO_CANCEL; // Clear on tap
146
+ notification.flags |= Ti.Android.FLAG_INSISTENT; // Repeat sound until canceled
147
+ notification.flags |= Ti.Android.FLAG_NO_CLEAR; // Don't clear with "clear all"
148
+ notification.flags |= Ti.Android.FLAG_ONGOING_EVENT; // Ongoing event (e.g., music player)
149
+ notification.flags |= Ti.Android.FLAG_ONLY_ALERT_ONCE; // Don't replay sound/vibrate
150
+ notification.flags |= Ti.Android.FLAG_SHOW_LIGHTS; // Use LED (if device allows)
151
+ ```
152
+
153
+ **Priority** (Android 4.1+):
154
+ ```javascript
155
+ notification.priority = Ti.Android.PRIORITY_HIGH; // or PRIORITY_MAX, PRIORITY_DEFAULT, PRIORITY_LOW, PRIORITY_MIN
156
+ ```
157
+
158
+ **Category** (Android 5.0+):
159
+ ```javascript
160
+ notification.category = Ti.Android.CATEGORY_MESSAGE; // or CATEGORY_ALARM, CALL, EMAIL, ERROR, EVENT, etc.
161
+ ```
162
+
163
+ **Visibility** (Android 5.0+ - lock screen):
164
+ ```javascript
165
+ notification.visibility = Ti.Android.VISIBILITY_PUBLIC; // Show all
166
+ // or VISIBILITY_PRIVATE (hide content), VISIBILITY_SECRET (don't show)
167
+ ```
168
+
169
+ ### Update Notification
170
+
171
+ ```javascript
172
+ notification.setLatestEventInfo('New Title', 'New Message', notification.contentIntent);
173
+ ```
174
+
175
+ ### Remove Notifications
176
+
177
+ ```javascript
178
+ // Remove specific notification
179
+ Ti.Android.NotificationManager.cancel(1);
180
+
181
+ // Remove all notifications
182
+ Ti.Android.NotificationManager.cancelAll();
183
+ ```
184
+
185
+ ### Respond to Notification Tap
186
+
187
+ **Launch app when tapped:**
188
+ ```javascript
189
+ const intent = Ti.Android.createIntent({
190
+ action: Ti.Android.ACTION_MAIN,
191
+ className: 'com.titaniumsdk.testapp.MyappActivity', // ProjectName + Activity
192
+ packageName: 'com.titaniumsdk.testapp'
193
+ });
194
+ intent.flags |= Ti.Android.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Ti.Android.FLAG_ACTIVITY_SINGLE_TOP;
195
+ intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
196
+
197
+ notification.contentIntent = Ti.Android.createPendingIntent({intent: intent});
198
+ ```
199
+
200
+ ### Schedule Future Notification (Background Service)
201
+
202
+ **tiapp.xml:**
203
+ ```xml
204
+ <android xmlns:android="http://schemas.android.com/apk/res/android">
205
+ <services>
206
+ <service url="ExampleService.js" type="interval" />
207
+ </services>
208
+ </android>
209
+ ```
210
+
211
+ **ExampleService.js:**
212
+ ```javascript
213
+ const service = Ti.Android.currentService;
214
+ const serviceIntent = service.getIntent();
215
+ const timestamp = new Date(serviceIntent.getStringExtra('timestamp'));
216
+
217
+ if (new Date() > timestamp) {
218
+ const title = serviceIntent.getStringExtra('title');
219
+ const message = serviceIntent.getStringExtra('message');
220
+
221
+ const notification = Ti.Android.createNotification({
222
+ contentTitle: title,
223
+ contentText: message,
224
+ contentIntent: Ti.Android.createPendingIntent({intent: Ti.Android.createIntent()})
225
+ });
226
+
227
+ Ti.Android.NotificationManager.notify(1, notification);
228
+ Ti.Android.stopService(serviceIntent);
229
+ }
230
+ ```
231
+
232
+ **Main app:**
233
+ ```javascript
234
+ const intent = Ti.Android.createServiceIntent({url: 'ExampleService.js'});
235
+ intent.putExtra('interval', 5000); // Check every 5 seconds
236
+ intent.putExtra('timestamp', new Date(new Date().getTime() + (30 * 1000))); // Fire in 30 seconds
237
+ intent.putExtra('title', 'Scheduled Notification');
238
+ intent.putExtra('message', 'This was scheduled!');
239
+ Ti.Android.startService(intent);
240
+ ```
241
+
242
+ ---
243
+
244
+ ## Local Notifications iOS
245
+
246
+ ### Notification Display Locations
247
+
248
+ - **Alert Dialog**: "Open" or "Close" buttons (background, unlocked)
249
+ - **Banner Message**: Swipe down for actions, tap to launch (background, unlocked)
250
+ - **Lock Screen**: Swipe right to launch
251
+ - **Notification Center**: Queued notifications
252
+ - **Badge**: Number on app icon
253
+ - **Sound**: Audio alert
254
+
255
+ ### Register for Notifications (iOS 8+)
256
+
257
+ ```javascript
258
+ if (Ti.Platform.name === 'iPhone OS' && parseInt(Ti.Platform.version.split('.')[0]) >= 8) {
259
+ Ti.App.iOS.registerUserNotificationSettings({
260
+ types: [
261
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
262
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
263
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
264
+ ]
265
+ // Add 'categories' for interactive notifications
266
+ });
267
+ }
268
+ ```
269
+
270
+ ### Schedule Local Notification
271
+
272
+ ```javascript
273
+ const notification = Ti.App.iOS.scheduleLocalNotification({
274
+ date: new Date(new Date().getTime() + 3000), // 3 seconds from now
275
+ alertBody: 'New content available!',
276
+ alertAction: 'update', // Changes "slide to view" to "slide to update" or "Open" to "Update"
277
+ alertLaunchImage: 'splash.png', // Custom splash image
278
+ badge: 1, // Set badge number (negative to clear)
279
+ sound: '/alert.wav', // Sound file in Resources or app/assets
280
+ category: 'CATEGORY_ID', // For interactive notifications
281
+ repeat: 'daily', // or 'weekly', 'monthly', 'yearly'
282
+ timezone: 'America/Los_Angeles', // Optional (default: system timezone)
283
+ userInfo: { url: 'http://example.com/data.json', id: '123' } // Custom data
284
+ });
285
+ ```
286
+
287
+ ### Monitor Notifications
288
+
289
+ **While app is in foreground or returns to foreground:**
290
+ ```javascript
291
+ Ti.App.iOS.addEventListener('notification', (e) => {
292
+ // Process custom data
293
+ if (e.userInfo && e.userInfo.url) {
294
+ // Handle URL
295
+ }
296
+
297
+ // Reset badge
298
+ if (e.badge > 0) {
299
+ Ti.App.iOS.scheduleLocalNotification({
300
+ date: new Date(),
301
+ badge: -1
302
+ });
303
+ }
304
+ });
305
+ ```
306
+
307
+ ### Cancel Notifications
308
+
309
+ ```javascript
310
+ // Cancel all
311
+ Ti.App.iOS.cancelAllLocalNotifications();
312
+
313
+ // Cancel specific notification
314
+ const notification = Ti.App.iOS.scheduleLocalNotification({...});
315
+ notification.cancel();
316
+
317
+ // Or by ID
318
+ Ti.App.iOS.scheduleLocalNotification({
319
+ userInfo: {id: 'foo'},
320
+ alertBody: 'Test'
321
+ });
322
+ Ti.App.iOS.cancelLocalNotification('foo');
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Interactive Notifications iOS (iOS 8+)
328
+
329
+ ### Create Notification Actions
330
+
331
+ ```javascript
332
+ const acceptAction = Ti.App.iOS.createUserNotificationAction({
333
+ identifier: 'ACCEPT_IDENTIFIER',
334
+ title: 'Accept',
335
+ activationMode: Ti.App.iOS.USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND, // or BACKGROUND
336
+ destructive: false,
337
+ authenticationRequired: true // Require device unlock
338
+ });
339
+
340
+ const rejectAction = Ti.App.iOS.createUserNotificationAction({
341
+ identifier: 'REJECT_IDENTIFIER',
342
+ title: 'Reject',
343
+ activationMode: Ti.App.iOS.USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND,
344
+ destructive: true, // Red background in lock screen/notification center
345
+ authenticationRequired: false
346
+ });
347
+ ```
348
+
349
+ ### Create Notification Category
350
+
351
+ ```javascript
352
+ const category = Ti.App.iOS.createUserNotificationCategory({
353
+ identifier: 'INVITE_CATEGORY',
354
+ actionsForDefaultContext: [acceptAction, rescheduleAction, delayAction, rejectAction], // Alert dialog (4 max)
355
+ actionsForMinimalContext: [acceptAction, rejectAction] // Other styles (2 max)
356
+ });
357
+ ```
358
+
359
+ ### Register Categories
360
+
361
+ ```javascript
362
+ Ti.App.iOS.registerUserNotificationSettings({
363
+ types: [
364
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
365
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE,
366
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND
367
+ ],
368
+ categories: [category]
369
+ });
370
+ ```
371
+
372
+ ### Monitor Interactive Notifications
373
+
374
+ **Local notifications:**
375
+ ```javascript
376
+ Ti.App.iOS.addEventListener('localnotificationaction', (e) => {
377
+ // e.category: category identifier
378
+ // e.identifier: action identifier
379
+ // e.userInfo: custom data
380
+
381
+ if (e.category === 'INVITE_CATEGORY' && e.identifier === 'ACCEPT_IDENTIFIER') {
382
+ // Handle accept
383
+ if (e.userInfo && e.userInfo.url) {
384
+ // Process URL
385
+ }
386
+ }
387
+
388
+ // Reset badge
389
+ if (e.badge > 0) {
390
+ Ti.App.iOS.scheduleLocalNotification({ date: new Date(), badge: -1 });
391
+ }
392
+ });
393
+ ```
394
+
395
+ **Push notifications:**
396
+ ```javascript
397
+ Ti.App.iOS.addEventListener('remotenotificationaction', (e) => {
398
+ // e.category: category identifier
399
+ // e.identifier: action identifier
400
+ // e.data: push notification payload (JSON)
401
+
402
+ if (e.category === 'DOWNLOAD_CATEGORY' && e.identifier === 'ACCEPT_IDENTIFIER') {
403
+ if (e.data && e.data.url) {
404
+ // Process URL
405
+ }
406
+ }
407
+ });
408
+ ```
409
+
410
+ ### Schedule Interactive Local Notification
411
+
412
+ ```javascript
413
+ Ti.App.iOS.scheduleLocalNotification({
414
+ date: new Date(new Date().getTime() + 3000),
415
+ alertBody: 'New content available! Download now?',
416
+ badge: 1,
417
+ userInfo: {url: 'http://example.com/data.json'},
418
+ category: 'INVITE_CATEGORY' // Must match registered category identifier
419
+ });
420
+ ```
421
+
422
+ ### Send Interactive Push Notification
423
+
424
+ **Payload format:**
425
+ ```json
426
+ {
427
+ "alert": "New content available! Download now?",
428
+ "badge": 1,
429
+ "url": "http://example.com/data.json",
430
+ "category": "INVITE_CATEGORY"
431
+ }
432
+ ```
433
+
434
+ ---
435
+
436
+ ## Push Notifications
437
+
438
+ ### Overview
439
+
440
+ Push notifications allow server-to-device communication. Infrastructure differs by platform:
441
+
442
+ - **Android**: Firebase Cloud Messaging (FCM) or Google Cloud Messaging (GCM)
443
+ - **iOS**: Apple Push Notification service (APNs)
444
+
445
+ ### Register for Push Notifications
446
+
447
+ ```javascript
448
+ Ti.Network.registerForPushNotifications({
449
+ success: (e) => {
450
+ // e.deviceToken: token to send to your push server
451
+ Ti.API.info(`Device Token: ${e.deviceToken}`);
452
+ // Send this token to your server
453
+ },
454
+ error: (e) => {
455
+ Ti.API.error(`Push registration error: ${e.error}`);
456
+ },
457
+ callback: (e) => {
458
+ // Incoming push notification
459
+ // e.data: push payload (iOS)
460
+ // e.data: JSON object (Android)
461
+ Ti.API.info(`Push received: ${JSON.stringify(e.data)}`);
462
+ }
463
+ });
464
+ ```
465
+
466
+ ### Configure Push Services
467
+
468
+ **Android (FCM/GCM):**
469
+ 1. Create project in Firebase Console or Google API Console
470
+ 2. Get API key/Sender ID
471
+ 3. Configure with your push provider (e.g., ArrowDB, ACS, or custom server)
472
+
473
+ **iOS (APNs):**
474
+ 1. Create App ID in Apple Developer Portal
475
+ 2. Enable Push Notifications
476
+ 3. Create SSL certificate (development/production)
477
+ 4. Configure with your push provider
478
+
479
+ ### Push Notification Payload Format
480
+
481
+ **iOS:**
482
+ ```json
483
+ {
484
+ "aps": {
485
+ "alert": "Message text",
486
+ "badge": 1,
487
+ "sound": "default"
488
+ },
489
+ "custom_field": "custom_value"
490
+ }
491
+ ```
492
+
493
+ **Android:**
494
+ ```json
495
+ {
496
+ "message": "Message text",
497
+ "title": "Notification Title",
498
+ "custom_field": "custom_value"
499
+ }
500
+ ```
501
+
502
+ ### Subscribe to Channels
503
+
504
+ **Using Arrow/ACS:**
505
+ ```javascript
506
+ Cloud.PushNotifications.subscribeToken({
507
+ device_token: deviceToken,
508
+ channel: 'news',
509
+ type: Ti.Platform.name === 'iPhone OS' ? 'ios' : 'android'
510
+ }, (e) => {
511
+ if (e.success) {
512
+ Ti.API.info('Subscribed to news channel');
513
+ }
514
+ });
515
+ ```
516
+
517
+ ### Send Push Notifications
518
+
519
+ **Using Arrow/ACS:**
520
+ ```javascript
521
+ Cloud.PushNotifications.notify({
522
+ channel: 'news',
523
+ payload: 'Hello subscribers!',
524
+ title: 'News Update'
525
+ }, (e) => {
526
+ if (e.success) {
527
+ Ti.API.info('Push sent successfully');
528
+ }
529
+ });
530
+ ```
531
+
532
+ **Direct API call:**
533
+ Send to your push server with device tokens and payload.
534
+
535
+ ### Best Practices
536
+
537
+ 1. **Permissions**: iOS requires user permission (prompted on first call to `registerForPushNotifications`)
538
+ 2. **Device Tokens**: Cache and send to your server; can change on app updates
539
+ 3. **Background Handling**: Use proper activation modes for interactive notifications
540
+ 4. **Badge Management**: Always reset badge after processing notification
541
+ 5. **Error Handling**: Handle registration failures gracefully
542
+ 6. **Testing**: Use development certificates/sandbox for testing iOS
543
+
544
+ ---
545
+
546
+ ## Common Patterns
547
+
548
+ ### Check Notification Permissions
549
+
550
+ ```javascript
551
+ // Android 4.1+ can disable notifications per app
552
+ // Check via Settings or handle gracefully (notification may not be shown)
553
+ ```
554
+
555
+ ### PendingIntent for Notification Actions
556
+
557
+ ```javascript
558
+ const intent = Ti.Android.createIntent({
559
+ action: 'com.example.MY_ACTION',
560
+ // Add data/flags
561
+ });
562
+ const pendingIntent = Ti.Android.createPendingIntent({
563
+ intent: intent,
564
+ flags: Ti.Android.FLAG_UPDATE_CURRENT
565
+ });
566
+ ```
567
+
568
+ ### Notification Groups (Android 7.0+)
569
+
570
+ ```javascript
571
+ // Requires API 24+; check documentation for latest implementation
572
+ ```
573
+
574
+ ### Rich Notifications (iOS 10+)
575
+
576
+ Use `UNMutableNotificationContent` with attachments (images, video, audio).
577
+
578
+ ### Silent Push
579
+
580
+ ```javascript
581
+ // iOS: include "content-available": 1 in payload
582
+ // Android: use data messages (FCM)
583
+ ```
584
+
585
+ ---
586
+
587
+ ## Platform-Specific Notes
588
+
589
+ ### Android
590
+
591
+ - **Service lifecycle**: Services may be killed if app is swiped away
592
+ - **Notification channels**: Android 8.0+ requires notification channels
593
+ - **Limitations**: Legacy MapView only supports single map view
594
+
595
+ ### iOS
596
+
597
+ - **Sandbox vs Production**: Use correct certificates and endpoints
598
+ - **Background app refresh**: May be needed for certain push scenarios
599
+ - **LiveView**: Callbacks only work properly when LiveView is enabled