@maccesar/titools 5.2.5 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +58 -97
  3. package/agents/ti-pro.md +4 -2
  4. package/commands/ti-audit.md +7 -5
  5. package/docs/examples.md +24 -13
  6. package/docs/knowledge-index.md +2 -1
  7. package/lib/config.js +1 -0
  8. package/package.json +1 -1
  9. package/skills/alloy-guides/SKILL.md +18 -179
  10. package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
  11. package/skills/alloy-guides/references/CONCEPTS.md +27 -162
  12. package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
  13. package/skills/alloy-guides/references/MODELS.md +47 -723
  14. package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
  15. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
  16. package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
  17. package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
  18. package/skills/alloy-guides/references/WIDGETS.md +49 -127
  19. package/skills/alloy-howtos/SKILL.md +14 -169
  20. package/skills/alloy-howtos/references/best_practices.md +9 -113
  21. package/skills/alloy-howtos/references/cli_reference.md +18 -223
  22. package/skills/alloy-howtos/references/config_files.md +50 -133
  23. package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
  24. package/skills/alloy-howtos/references/samples.md +21 -138
  25. package/skills/ti-api/SKILL.md +10 -2
  26. package/skills/ti-api/references/api-android.md +36 -2
  27. package/skills/ti-api/references/api-app-platform.md +39 -3
  28. package/skills/ti-api/references/api-core.md +50 -18
  29. package/skills/ti-api/references/api-data-network.md +49 -35
  30. package/skills/ti-api/references/api-media.md +45 -27
  31. package/skills/ti-api/references/api-services.md +39 -9
  32. package/skills/ti-api/references/api-ui-android.md +33 -13
  33. package/skills/ti-api/references/api-ui-extras.md +41 -15
  34. package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
  35. package/skills/ti-api/references/api-ui-ios.md +74 -2
  36. package/skills/ti-api/references/api-ui-lists.md +32 -16
  37. package/skills/ti-api/references/api-ui-text-input.md +34 -17
  38. package/skills/ti-api/references/api-ui-views.md +27 -1
  39. package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
  40. package/skills/ti-api/references/api-xml-global.md +66 -16
  41. package/skills/ti-create-release/SKILL.md +98 -0
  42. package/skills/ti-create-release/references/module-discovery.md +69 -0
  43. package/skills/ti-expert/references/adaptive-layouts.md +1 -1
  44. package/skills/ti-guides/SKILL.md +37 -76
  45. package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
  46. package/skills/ti-guides/references/android-manifest.md +24 -83
  47. package/skills/ti-guides/references/app-distribution.md +31 -377
  48. package/skills/ti-guides/references/application-frameworks.md +127 -335
  49. package/skills/ti-guides/references/cli-reference.md +184 -633
  50. package/skills/ti-guides/references/commonjs-advanced.md +81 -231
  51. package/skills/ti-guides/references/compatibility-matrix.md +36 -75
  52. package/skills/ti-guides/references/hello-world.md +95 -70
  53. package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
  54. package/skills/ti-guides/references/resources.md +174 -142
  55. package/skills/ti-guides/references/sdk-release-notes.md +28 -71
  56. package/skills/ti-guides/references/tiapp-config.md +222 -598
  57. package/skills/ti-howtos/SKILL.md +23 -123
  58. package/skills/ti-howtos/references/cross-platform-development.md +119 -324
  59. package/skills/ti-howtos/references/debugging-profiling.md +77 -445
  60. package/skills/ti-howtos/references/extending-titanium.md +199 -673
  61. package/skills/ti-howtos/references/local-data-sources.md +87 -300
  62. package/skills/ti-howtos/references/location-and-maps.md +86 -213
  63. package/skills/ti-howtos/references/media-apis.md +103 -223
  64. package/skills/ti-howtos/references/notification-services.md +86 -506
  65. package/skills/ti-howtos/references/remote-data-sources.md +97 -316
  66. package/skills/ti-howtos/references/using-modules.md +77 -133
  67. package/skills/ti-synthengine/SKILL.md +62 -111
  68. package/skills/ti-synthengine/assets/example/README.md +50 -59
  69. package/skills/ti-synthengine/assets/example/app.js +67 -65
  70. package/skills/ti-synthengine/assets/example/lib/sequenceOwner.js +39 -40
  71. package/skills/ti-synthengine/assets/example/lib/soundPreset.js +34 -0
  72. package/skills/ti-synthengine/assets/index.d.ts +122 -2
  73. package/skills/ti-synthengine/references/advanced-examples.md +4 -4
  74. package/skills/ti-synthengine/references/api.md +40 -18
  75. package/skills/ti-synthengine/references/audio-engine.md +15 -57
  76. package/skills/ti-synthengine/references/examples.md +63 -6
  77. package/skills/ti-synthengine/references/guide.md +61 -57
  78. package/skills/ti-synthengine/references/instruments-and-effects.md +15 -15
  79. package/skills/ti-synthengine/references/native-variation.md +53 -14
  80. package/skills/ti-synthengine/references/recipes-interaction.md +25 -20
  81. package/skills/ti-synthengine/references/recipes.md +19 -16
  82. package/skills/ti-synthengine/references/recommendations.md +12 -12
  83. package/skills/ti-synthengine/references/sound-api.md +197 -0
  84. package/skills/ti-synthengine/references/sound-design.md +7 -7
  85. package/skills/ti-synthengine/references/source-notes.md +62 -172
  86. package/skills/ti-synthengine/references/troubleshooting.md +17 -19
  87. package/skills/ti-synthengine/references/upgrade-2.0.0.md +40 -0
  88. package/skills/ti-ui/SKILL.md +28 -143
  89. package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
  90. package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
  91. package/skills/ti-ui/references/listviews-and-performance.md +100 -703
  92. package/skills/ti-ui/references/platform-conventions.md +180 -0
  93. package/skills/ti-ui/references/user-interface.md +43 -0
  94. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
  95. package/skills/alloy-howtos/references/custom_tags.md +0 -148
  96. package/skills/ti-guides/references/coding-best-practices.md +0 -149
  97. package/skills/ti-guides/references/javascript-primer.md +0 -414
  98. package/skills/ti-guides/references/reserved-words.md +0 -36
  99. package/skills/ti-guides/references/style-and-conventions.md +0 -103
  100. package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
  101. package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
  102. package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
  103. package/skills/ti-howtos/references/google-maps-v2.md +0 -172
  104. package/skills/ti-howtos/references/ios-map-kit.md +0 -149
  105. package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
  106. package/skills/ti-howtos/references/tutorials.md +0 -565
  107. package/skills/ti-howtos/references/web-content-integration.md +0 -287
  108. package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
  109. package/skills/ti-synthengine/references/android-sim80-correction-evidence.zip +0 -0
  110. package/skills/ti-synthengine/references/android-sim80-correction.json +0 -162
  111. package/skills/ti-synthengine/references/audio-pipeline-validation.md +0 -19
  112. package/skills/ti-synthengine/references/bypass-physical-recheck-evidence.zip +0 -0
  113. package/skills/ti-synthengine/references/frontier-android-evidence.zip +0 -0
  114. package/skills/ti-synthengine/references/frontier-ipad-evidence.zip +0 -0
  115. package/skills/ti-synthengine/references/frontier-physical-validation.json +0 -1918
  116. package/skills/ti-synthengine/references/native-tone-repetition-validation.md +0 -59
  117. package/skills/ti-synthengine/references/native-variation-proposal.md +0 -182
  118. package/skills/ti-synthengine/references/native-variation-validation.md +0 -63
  119. package/skills/ti-synthengine/references/performance-review-evidence.zip +0 -0
  120. package/skills/ti-synthengine/references/performance-review.json +0 -1146
  121. package/skills/ti-synthengine/references/physical-validation.json +0 -1457
  122. package/skills/ti-synthengine/references/source-snapshot.json +0 -542
  123. package/skills/ti-synthengine/references/stats-performance.json +0 -2992
  124. package/skills/ti-synthengine/references/stats-performance.md +0 -82
  125. package/skills/ti-synthengine/references/studio-validation.json +0 -6202
  126. package/skills/ti-synthengine/references/unified-bypass-performance.json +0 -22425
  127. package/skills/ti-synthengine/references/unified-validation.json +0 -314
  128. package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
  129. package/skills/ti-ui/references/animation-and-matrices.md +0 -569
  130. package/skills/ti-ui/references/application-structures.md +0 -626
  131. package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
  132. package/skills/ti-ui/references/event-handling.md +0 -401
  133. package/skills/ti-ui/references/gestures.md +0 -448
  134. package/skills/ti-ui/references/orientation.md +0 -374
  135. package/skills/ti-ui/references/platform-ui-android.md +0 -727
  136. package/skills/ti-ui/references/platform-ui-ios.md +0 -576
  137. package/skills/ti-ui/references/scrolling-views.md +0 -288
  138. package/skills/ti-ui/references/tableviews.md +0 -542
@@ -1,551 +1,131 @@
1
- # Push and local notifications
1
+ # Notifications
2
2
 
3
- Guide to local and push notifications on iOS and Android.
3
+ Based on the [current official guide](https://titaniumsdk.com/docs/build/notifications.md). Examples target released SDK 13.4.1; verify the selected SDK before adopting version-specific behavior.
4
4
 
5
- <!-- TOC-START -->
6
- ## Contents
5
+ Two kinds, and they share almost nothing in Titanium. A **local** notification
6
+ is scheduled by the app on the device. A **push** notification arrives from a
7
+ server through APNs or FCM.
7
8
 
8
- - [Local notifications: Android](#local-notifications-android)
9
- - [Local notifications: iOS](#local-notifications-ios)
10
- - [Interactive notifications: iOS (iOS 8+)](#interactive-notifications-ios-ios-8)
11
- - [Push notifications](#push-notifications)
12
- - [Common patterns](#common-patterns)
13
- - [Platform-specific notes](#platform-specific-notes)
9
+ Both need the user's permission on both platforms. Android has required it
10
+ since Android 13.
14
11
 
15
- <!-- TOC-END -->
12
+ ## Local notifications
16
13
 
17
- ## Local notifications: Android
14
+ The APIs are platform-specific, so this is one of the places you write both
15
+ halves.
18
16
 
19
- ### Notification display locations
17
+ **iOS**
20
18
 
21
- - Notification drawer: swipe down from status bar
22
- - Lock screen: Android 5.0+ (API 21+)
23
- - Status bar: icon and ticker text
24
-
25
- ### Create a notification
26
-
27
- Basic layout:
28
- ```javascript
29
- const notification = Ti.Android.createNotification({
30
- contentTitle: 'Notification Title',
31
- contentText: 'Notification message',
32
- contentIntent: Ti.Android.createPendingIntent({
33
- intent: Ti.Android.createIntent({})
34
- }),
35
- icon: Ti.App.Android.R.drawable.warn, // or '/images/warn.png'
36
- number: 5, // Badge number
37
- when: new Date(), // Timestamp (does not schedule)
38
- tickerText: 'Text in status bar when notification first appears'
39
- });
40
-
41
- // Send immediately
42
- Ti.Android.NotificationManager.notify(1, notification);
43
- ```
44
-
45
- Icon paths:
46
- - Density-specific: `/app/assets/android/images/` (Alloy) or `/Resources/android/images/` (Classic), reference as `/images/filename.png`
47
- - Drawable folder: `/platform/android/res/drawable/filename.png`, reference as `Ti.App.Android.R.drawable.filename`
48
-
49
- ### Sound
50
-
51
- ```javascript
52
- const notification = Ti.Android.createNotification({
53
- // ... other properties
54
- sound: `${Ti.Filesystem.getResRawDirectory()}sound.wav`
55
- });
56
- ```
57
-
58
- Play only once (add flag):
59
- ```javascript
60
- notification.flags |= Ti.Android.FLAG_ONLY_ALERT_ONCE;
61
- ```
62
-
63
- ### Custom layout with RemoteViews
64
-
65
- 1. Create XML layout (`/platform/android/res/layout/customview.xml`):
66
- ```xml
67
- <?xml version="1.0" encoding="utf-8"?>
68
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
69
- android:layout_width="match_parent"
70
- android:layout_height="match_parent"
71
- android:orientation="horizontal">
72
- <TextView android:id="@+id/message"
73
- android:layout_width="wrap_content"
74
- android:layout_height="wrap_content"
75
- android:text="Default text" />
76
- <Button android:id="@+id/okbutton"
77
- android:layout_width="wrap_content"
78
- android:layout_height="wrap_content"
79
- android:text="OK" />
80
- </LinearLayout>
81
- ```
82
-
83
- 2. Create RemoteViews and bind intents:
84
- ```javascript
85
- const customView = Ti.Android.createRemoteViews({
86
- layoutId: Ti.App.Android.R.layout.customview
87
- });
88
-
89
- // Modify text
90
- customView.setTextViewText(Ti.App.Android.R.id.message, 'Update available!');
91
-
92
- // Bind intents to buttons
93
- const downloadIntent = Ti.Android.createPendingIntent({ intent: Ti.Android.createIntent() });
94
- customView.setOnClickPendingIntent(Ti.App.Android.R.id.okbutton, downloadIntent);
95
-
96
- const notification = Ti.Android.createNotification({
97
- contentView: customView // Avoid setting contentTitle/contentText or they override this
98
- });
99
- ```
100
-
101
- ### Additional properties
102
-
103
- Defaults (device settings):
104
- ```javascript
105
- notification.defaults = Ti.Android.DEFAULT_ALL; // or DEFAULT_SOUND, DEFAULT_VIBRATE, DEFAULT_LIGHTS
106
- ```
107
-
108
- Flags (behavior):
109
- ```javascript
110
- notification.flags |= Ti.Android.FLAG_AUTO_CANCEL; // Clear on tap
111
- notification.flags |= Ti.Android.FLAG_INSISTENT; // Repeat sound until canceled
112
- notification.flags |= Ti.Android.FLAG_NO_CLEAR; // Do not clear with "clear all"
113
- notification.flags |= Ti.Android.FLAG_ONGOING_EVENT; // Ongoing event (for example, music player)
114
- notification.flags |= Ti.Android.FLAG_ONLY_ALERT_ONCE; // Do not replay sound/vibrate
115
- notification.flags |= Ti.Android.FLAG_SHOW_LIGHTS; // Use LED (if device allows)
116
- ```
117
-
118
- Priority (Android 4.1+):
119
- ```javascript
120
- notification.priority = Ti.Android.PRIORITY_HIGH; // or PRIORITY_MAX, PRIORITY_DEFAULT, PRIORITY_LOW, PRIORITY_MIN
121
- ```
122
-
123
- Category (Android 5.0+):
124
- ```javascript
125
- notification.category = Ti.Android.CATEGORY_MESSAGE; // or CATEGORY_ALARM, CALL, EMAIL, ERROR, EVENT, etc.
126
- ```
127
-
128
- Visibility (Android 5.0+ - lock screen):
129
- ```javascript
130
- notification.visibility = Ti.Android.VISIBILITY_PUBLIC; // Show all
131
- // or VISIBILITY_PRIVATE (hide content), VISIBILITY_SECRET (do not show)
132
- ```
133
-
134
- ### Update notification
135
-
136
- ```javascript
137
- notification.setLatestEventInfo('New Title', 'New Message', notification.contentIntent);
138
- ```
139
-
140
- ### Remove notifications
141
-
142
- ```javascript
143
- // Remove specific notification
144
- Ti.Android.NotificationManager.cancel(1);
145
-
146
- // Remove all notifications
147
- Ti.Android.NotificationManager.cancelAll();
148
- ```
149
-
150
- ### Respond to notification tap
151
-
152
- Launch app when tapped:
153
- ```javascript
154
- const intent = Ti.Android.createIntent({
155
- action: Ti.Android.ACTION_MAIN,
156
- className: 'com.titaniumsdk.testapp.MyappActivity', // ProjectName + Activity
157
- packageName: 'com.titaniumsdk.testapp'
158
- });
159
- intent.flags |= Ti.Android.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Ti.Android.FLAG_ACTIVITY_SINGLE_TOP;
160
- intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
161
-
162
- notification.contentIntent = Ti.Android.createPendingIntent({ intent: intent });
163
- ```
164
-
165
- ### Delete intent (notification cleared)
166
-
167
- ```javascript
168
- // Execute intent when user clears notification
169
- notification.deleteIntent = Ti.Android.createPendingIntent({
170
- intent: Ti.Android.createIntent({
171
- action: 'com.myapp.NOTIFICATION_CLEARED'
172
- })
173
- });
174
- ```
175
-
176
- ### Schedule future notification (background service)
177
-
178
- `tiapp.xml`:
179
- ```xml
180
- <android xmlns:android="http://schemas.android.com/apk/res/android">
181
- <services>
182
- <service url="ExampleService.js" type="interval" />
183
- </services>
184
- </android>
185
- ```
186
-
187
- `ExampleService.js`:
188
- ```javascript
189
- const service = Ti.Android.currentService;
190
- const serviceIntent = service.getIntent();
191
- const timestamp = new Date(serviceIntent.getStringExtra('timestamp'));
192
-
193
- if (new Date() > timestamp) {
194
- const title = serviceIntent.getStringExtra('title');
195
- const message = serviceIntent.getStringExtra('message');
196
-
197
- const notification = Ti.Android.createNotification({
198
- contentTitle: title,
199
- contentText: message,
200
- contentIntent: Ti.Android.createPendingIntent({ intent: Ti.Android.createIntent() })
201
- });
202
-
203
- Ti.Android.NotificationManager.notify(1, notification);
204
- Ti.Android.stopService(serviceIntent);
205
- }
206
- ```
207
-
208
- Main app:
209
- ```javascript
210
- const intent = Ti.Android.createServiceIntent({ url: 'ExampleService.js' });
211
- intent.putExtra('interval', 5000); // Check every 5 seconds
212
- intent.putExtra('timestamp', new Date(new Date().getTime() + (30 * 1000))); // Fire in 30 seconds
213
- intent.putExtra('title', 'Scheduled Notification');
214
- intent.putExtra('message', 'This was scheduled!');
215
- Ti.Android.startService(intent);
216
- ```
217
-
218
- ## Local notifications: iOS
219
-
220
- ### Notification display locations
221
-
222
- - Alert dialog: Open or Close buttons (background, unlocked)
223
- - Banner message: swipe down for actions, tap to launch (background, unlocked)
224
- - Lock screen: swipe right to launch
225
- - Notification Center: queued notifications
226
- - Badge: number on app icon
227
- - Sound: audio alert
228
-
229
- ### Register for notifications (iOS 8+)
230
-
231
- ```javascript
232
- if (Ti.Platform.name === 'iPhone OS' && parseInt(Ti.Platform.version.split('.')[0]) >= 8) {
233
- Ti.App.iOS.registerUserNotificationSettings({
234
- types: [
235
- Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
236
- Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
237
- Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
238
- ]
239
- // Add 'categories' for interactive notifications
240
- });
241
- }
242
- ```
243
-
244
- Note: iOS shows a system prompt the first time. Check current settings with:
245
- ```javascript
246
- Ti.App.iOS.addEventListener('usernotificationsettings', (e) => {
247
- Ti.API.info(`Notification types allowed: ${e.types}`);
248
- });
249
- ```
250
-
251
- ### Schedule local notification
252
-
253
- ```javascript
254
- const notification = Ti.App.iOS.scheduleLocalNotification({
255
- date: new Date(new Date().getTime() + 3000), // 3 seconds from now
256
- alertBody: 'New content available!',
257
- alertAction: 'update', // Changes "slide to view" to "slide to update" or "Open" to "Update"
258
- alertLaunchImage: 'splash.png', // Custom splash image
259
- badge: 1, // Set badge number (negative to clear)
260
- sound: '/alert.wav', // Sound file in Resources or app/assets
261
- category: 'CATEGORY_ID', // For interactive notifications
262
- repeat: 'daily', // or 'weekly', 'monthly', 'yearly'
263
- timezone: 'America/Los_Angeles', // Optional (default: system timezone)
264
- userInfo: { url: 'http://example.com/data.json', id: '123' } // Custom data
265
- });
266
- ```
267
-
268
- ### Monitor notifications
269
-
270
- While app is in foreground or returns to foreground:
271
- ```javascript
272
- Ti.App.iOS.addEventListener('notification', (e) => {
273
- // Process custom data
274
- if (e.userInfo && e.userInfo.url) {
275
- // Handle URL
19
+ ```js
20
+ // Install the result listener before requesting permission.
21
+ Ti.App.iOS.addEventListener('usernotificationsettings', onSettings);
22
+ function onSettings(event) {
23
+ Ti.App.iOS.removeEventListener('usernotificationsettings', onSettings);
24
+ if (!event.types || event.types.length === 0) {
25
+ Ti.API.warn('Notification presentation permission denied');
26
+ return;
276
27
  }
277
-
278
- // Reset badge
279
- if (e.badge > 0) {
280
- Ti.App.iOS.scheduleLocalNotification({
281
- date: new Date(),
282
- badge: -1
283
- });
284
- }
285
- });
286
- ```
287
-
288
- ### Cancel notifications
289
-
290
- ```javascript
291
- // Cancel all
292
- Ti.App.iOS.cancelAllLocalNotifications();
293
-
294
- // Cancel specific notification
295
- const notification = Ti.App.iOS.scheduleLocalNotification({ ... });
296
- notification.cancel();
297
-
298
- // Or by ID
299
- Ti.App.iOS.scheduleLocalNotification({
300
- userInfo: { id: 'foo' },
301
- alertBody: 'Test'
302
- });
303
- Ti.App.iOS.cancelLocalNotification('foo');
304
- ```
305
-
306
- ## Interactive notifications: iOS (iOS 8+)
307
-
308
- ### Create notification actions
309
-
310
- ```javascript
311
- const acceptAction = Ti.App.iOS.createUserNotificationAction({
312
- identifier: 'ACCEPT_IDENTIFIER',
313
- title: 'Accept',
314
- activationMode: Ti.App.iOS.USER_NOTIFICATION_ACTIVATION_MODE_FOREGROUND, // or BACKGROUND
315
- destructive: false,
316
- authenticationRequired: true // Require device unlock
317
- });
318
-
319
- const rejectAction = Ti.App.iOS.createUserNotificationAction({
320
- identifier: 'REJECT_IDENTIFIER',
321
- title: 'Reject',
322
- activationMode: Ti.App.iOS.USER_NOTIFICATION_ACTIVATION_MODE_BACKGROUND,
323
- destructive: true, // Red background in lock screen/notification center
324
- authenticationRequired: false
325
- });
326
- ```
327
-
328
- ### Create notification category
329
-
330
- ```javascript
331
- const category = Ti.App.iOS.createUserNotificationCategory({
332
- identifier: 'INVITE_CATEGORY',
333
- actionsForDefaultContext: [acceptAction, rescheduleAction, delayAction, rejectAction], // Alert dialog (4 max)
334
- actionsForMinimalContext: [acceptAction, rejectAction] // Other styles (2 max)
335
- });
336
- ```
337
-
338
- ### Register categories
339
-
340
- ```javascript
28
+ scheduleReminder();
29
+ }
341
30
  Ti.App.iOS.registerUserNotificationSettings({
342
31
  types: [
343
32
  Ti.App.iOS.USER_NOTIFICATION_TYPE_ALERT,
344
- Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE,
345
- Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND
346
- ],
347
- categories: [category]
33
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_SOUND,
34
+ Ti.App.iOS.USER_NOTIFICATION_TYPE_BADGE
35
+ ]
348
36
  });
37
+
38
+ function scheduleReminder() {
39
+ Ti.App.iOS.scheduleLocalNotification({
40
+ alertTitle: 'Standup',
41
+ alertBody: 'Daily standup in five minutes',
42
+ date: new Date(Date.now() + 5 * 60 * 1000)
43
+ });
44
+ }
349
45
  ```
350
46
 
351
- ### Monitor interactive notifications
47
+ Use `Ti.App.iOS.UserNotificationCenter.getPendingNotifications()` and `removePendingNotifications()` to cancel pending alerts; `removeDeliveredNotifications()` clears delivered entries. The older `cancelLocalNotification`, `cancelAllLocalNotifications` and returned object's `cancel()` are deprecated since SDK 7.3.0. Canceling a delivered entry is different from canceling its future schedule.
352
48
 
353
- Local notifications:
354
- ```javascript
355
- Ti.App.iOS.addEventListener('localnotificationaction', (e) => {
356
- // e.category: category identifier
357
- // e.identifier: action identifier
358
- // e.userInfo: custom data
49
+ **Android**
359
50
 
360
- if (e.category === 'INVITE_CATEGORY' && e.identifier === 'ACCEPT_IDENTIFIER') {
361
- // Handle accept
362
- if (e.userInfo && e.userInfo.url) {
363
- // Process URL
364
- }
365
- }
51
+ Declare `android.permission.POST_NOTIFICATIONS` in `<android><manifest>` and request Android 13+ permission from an opened window before posting. `Ti.Network.registerForPushNotifications({ success, error })` requests that permission on Android; its success callback does not supply an FCM token. Handle denial and settings restrictions.
366
52
 
367
- // Reset badge
368
- if (e.badge > 0) {
369
- Ti.App.iOS.scheduleLocalNotification({ date: new Date(), badge: -1 });
370
- }
53
+ ```js
54
+ const channel = Ti.Android.NotificationManager.createNotificationChannel({
55
+ id: 'reminders',
56
+ name: 'Reminders',
57
+ importance: Ti.Android.IMPORTANCE_DEFAULT
371
58
  });
372
- ```
373
59
 
374
- Push notifications:
375
- ```javascript
376
- Ti.App.iOS.addEventListener('remotenotificationaction', (e) => {
377
- // e.category: category identifier
378
- // e.identifier: action identifier
379
- // e.data: push notification payload (JSON)
380
-
381
- if (e.category === 'DOWNLOAD_CATEGORY' && e.identifier === 'ACCEPT_IDENTIFIER') {
382
- if (e.data && e.data.url) {
383
- // Process URL
384
- }
385
- }
60
+ const notification = Ti.Android.createNotification({
61
+ contentTitle: 'Standup',
62
+ contentText: 'Daily standup in five minutes',
63
+ channelId: 'reminders'
386
64
  });
387
- ```
388
65
 
389
- ### Schedule interactive local notification
390
-
391
- ```javascript
392
- Ti.App.iOS.scheduleLocalNotification({
393
- date: new Date(new Date().getTime() + 3000),
394
- alertBody: 'New content available! Download now?',
395
- badge: 1,
396
- userInfo: { url: 'http://example.com/data.json' },
397
- category: 'INVITE_CATEGORY' // Must match registered category identifier
398
- });
66
+ Ti.Android.NotificationManager.notify(1, notification);
399
67
  ```
400
68
 
401
- ### Send interactive push notification
69
+ The integer passed to `notify` is the notification's id: notify again with the
70
+ same one and it replaces rather than stacks.
402
71
 
403
- Payload format:
404
- ```json
405
- {
406
- "alert": "New content available! Download now?",
407
- "badge": 1,
408
- "url": "http://example.com/data.json",
409
- "category": "INVITE_CATEGORY"
410
- }
411
- ```
72
+ > [!IMPORTANT]
73
+ > **Android needs a channel.** Since Android 8 a notification without a valid
74
+ > `channelId` is dropped by the system, with nothing in the log to say so. Create
75
+ > the channel once at startup - creating it again with the same id is a no-op.
76
+ >
77
+ > Channel importance is not freely reconfigured after creation. The user owns it
78
+ > from then on, and a release that wants a channel to behave differently needs a
79
+ > new id.
412
80
 
413
81
  ## Push notifications
414
82
 
415
- ### Overview
416
-
417
- Push notifications allow server-to-device communication. Infrastructure differs by platform:
418
-
419
- - Android: Firebase Cloud Messaging (FCM)
420
- - iOS: Apple Push Notification service (APNs)
421
-
422
- Note: the legacy Appcelerator Cloud Services (ACS/ArrowDB) push backend is no longer available. Use FCM for Android and APNs for iOS, either directly or via a third-party service.
423
-
424
- Google has deprecated Google Cloud Messaging (GCM) in favor of FCM. All new implementations should use FCM.
425
-
426
- For FCM on Titanium, use the community module `titanium-firebase-cloud-messaging` (by Hans Knöchel).
83
+ APNs and FCM registration are platform-specific. Send the resulting platform token to your backend, which sends the notifications. The following core API example is for **iOS APNs**, after the `usernotificationsettings` callback; it is not an Android FCM registration recipe.
427
84
 
428
- ### Register for push notifications
429
-
430
- ```javascript
85
+ ```js
431
86
  Ti.Network.registerForPushNotifications({
432
- success: (e) => {
433
- // e.deviceToken: token to send to your push server
434
- Ti.API.info(`Device Token: ${e.deviceToken}`);
435
- // Send this token to your server
87
+ success(e) {
88
+ Ti.API.info(`device token ${e.deviceToken}`);
89
+ // POST it to your own server here.
436
90
  },
437
- error: (e) => {
438
- Ti.API.error(`Push registration error: ${e.error}`);
91
+ error(e) {
92
+ Ti.API.error(`push registration failed: ${e.error}`);
439
93
  },
440
- callback: (e) => {
441
- // Incoming push notification
442
- // e.data: push payload (iOS)
443
- // e.data: JSON object (Android)
444
- Ti.API.info(`Push received: ${JSON.stringify(e.data)}`);
94
+ callback(e) {
95
+ // A notification arrived. `e.data` is the payload.
96
+ Ti.API.info(e.data);
445
97
  }
446
98
  });
447
99
  ```
448
100
 
449
- ### APNs configuration (iOS)
450
-
451
- 1. Register an explicit App ID (not wildcard) with Push Notifications enabled in Apple Developer Portal.
452
- 2. Generate an APNs certificate (Development for sandbox, Production for App Store).
453
- 3. Export the certificate as PKCS#12 (.p12) from Keychain Access.
454
- 4. Upload the .p12 to your push service provider.
455
- 5. In your app, call `Ti.Network.registerForPushNotifications()` to get the device token.
456
-
457
- ### FCM configuration (Android)
458
-
459
- 1. Create a project in Firebase Console.
460
- 2. Add your Android app (use your app's package name).
461
- 3. Download `google-services.json` and place it in the project root.
462
- 4. Add `titanium-firebase-cloud-messaging` to `tiapp.xml`.
463
- 5. Register for push and obtain the FCM token.
464
-
465
- ### Push notification payload format
466
-
467
- iOS:
468
- ```json
469
- {
470
- "aps": {
471
- "alert": "Message text",
472
- "badge": 1,
473
- "sound": "default"
474
- },
475
- "custom_field": "custom_value"
476
- }
477
- ```
478
-
479
- Android:
480
- ```json
481
- {
482
- "message": "Message text",
483
- "title": "Notification Title",
484
- "custom_field": "custom_value"
485
- }
486
- ```
487
-
488
- ### Send push notifications
489
-
490
- Send push notifications from your server using the FCM HTTP API or APNs. Collect device tokens from client registration and target them with your push payload.
491
-
492
- ### Best practices
493
-
494
- 1. Permissions: iOS requires user permission (prompted on first call to `registerForPushNotifications`).
495
- 2. Device tokens: cache and send to your server; they can change on app updates.
496
- 3. Background handling: use proper activation modes for interactive notifications.
497
- 4. Badge management: reset the badge after processing a notification.
498
- 5. Error handling: handle registration failures gracefully.
499
- 6. Testing: use development certificates/sandbox for iOS testing.
500
-
501
- ## Common patterns
502
-
503
- ### Check notification permissions
504
-
505
- ```javascript
506
- // Android 4.1+ can disable notifications per app
507
- // Check via Settings or handle gracefully (notification may not be shown)
508
- ```
509
-
510
- ### PendingIntent for notification actions
511
-
512
- ```javascript
513
- const intent = Ti.Android.createIntent({
514
- action: 'com.example.MY_ACTION'
515
- // Add data/flags
516
- });
517
- const pendingIntent = Ti.Android.createPendingIntent({
518
- intent: intent,
519
- flags: Ti.Android.FLAG_UPDATE_CURRENT
520
- });
521
- ```
522
-
523
- ### Notification groups (Android 7.0+)
101
+ `callback` fires when a notification is received **and** when one is tapped, so
102
+ if opening a screen is the response, check whether the app was in the
103
+ foreground first - otherwise a notification arriving while someone is using the
104
+ app navigates them away from what they were doing.
524
105
 
525
- ```javascript
526
- // Requires API 24+; check documentation for latest implementation
527
- ```
106
+ On iOS, ask for notification permission with
107
+ `registerUserNotificationSettings` before registering for push. On Android, use a native FCM integration and its own token/message APIs. The guide mentions `google-services.json` and `ti.playservices`, but those alone do not implement FCM registration. Follow the selected integration's current installation instructions, including dependencies and configuration-file placement. Core `callback` / `success.deviceToken` are Apple-only.
528
108
 
529
- ### Rich notifications (iOS 10+)
109
+ The token changes. It changes on reinstall, on restore to a new device, and at
110
+ the platform's discretion. Send it on every launch rather than once.
530
111
 
531
- Use `UNMutableNotificationContent` with attachments (images, video, audio).
112
+ ## Testing
532
113
 
533
- ### Silent push
114
+ Use a signed device build to validate APNs end to end; simulator capabilities depend on the selected OS/Xcode environment. An Android emulator needs the required Play Services/FCM integration. Local notification testing does not prove remote delivery.
534
115
 
535
- ```javascript
536
- // iOS: include "content-available": 1 in payload
537
- // Android: use data messages (FCM)
538
- ```
116
+ The most common "push is broken" causes, in the order worth checking:
539
117
 
540
- ## Platform-specific notes
118
+ 1. **The wrong environment.** A development APNs token is not valid against the
119
+ production gateway, and the failure is silent.
120
+ 2. **No permission.** Handle permission denial and explain the relevant system settings; do not assume another request will always show a dialog.
121
+ 3. **Missing channel on Android.** See above.
122
+ 4. **The token is stale.** See above.
541
123
 
542
- ### Android
124
+ ![An expanded notification in the Android shade, posted by an app called Hello. Its icon sits at the left, the title reads Standup and the body reads Daily standup in five minutes.](https://titaniumsdk.com/docs/guides/notification-shade-android.png)
543
125
 
544
- - Service lifecycle: services may be killed if app is swiped away. For critical notifications, use FCM instead of local services.
545
- - Notification channels: Android 8.0+ requires notification channels.
126
+ ## Next
546
127
 
547
- ### iOS
128
+ [Using modules](https://titaniumsdk.com/docs/build/modules.md) covers adding capabilities the core SDK
129
+ does not have, which is what `ti.playservices` above is.
548
130
 
549
- - Sandbox vs production: use correct certificates and endpoints.
550
- - Background app refresh: may be needed for certain push scenarios.
551
- - LiveView: callbacks only work properly when LiveView is enabled.
131
+ Contract corrections: [released Network API](https://github.com/tidev/titanium-sdk/blob/13_4_1_GA/apidoc/Titanium/Network/Network.yml), [UserNotificationCenter](https://github.com/tidev/titanium-sdk/blob/13_4_1_GA/apidoc/Titanium/App/iOS/UserNotificationCenter.yml), [NotificationManager](https://github.com/tidev/titanium-sdk/blob/13_4_1_GA/apidoc/Titanium/Android/NotificationManager/NotificationManager.yml).