@maccesar/titools 2.0.6 → 2.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.
- package/{AGENTS-TEMPLATE.md → AGENTS-VERCEL-RESEARCH.md} +16 -18
- package/README.md +250 -168
- package/agents/{ti-researcher.md → ti-pro.md} +10 -10
- package/bin/titools.js +16 -12
- package/lib/cleanup.js +95 -0
- package/lib/commands/agents.js +146 -70
- package/lib/commands/skills.js +349 -0
- package/lib/commands/uninstall.js +189 -154
- package/lib/commands/update.js +104 -21
- package/lib/config.js +26 -20
- package/lib/downloader.js +1 -1
- package/lib/installer.js +37 -97
- package/lib/platform.js +9 -5
- package/lib/prompts/checkboxCancel.js +264 -0
- package/lib/prompts/selectCancel.js +204 -0
- package/lib/symlink.js +19 -7
- package/lib/utils.js +21 -31
- package/package.json +10 -10
- package/skills/alloy-guides/SKILL.md +8 -30
- package/skills/alloy-guides/references/CLI_TASKS.md +14 -24
- package/skills/alloy-guides/references/CONCEPTS.md +5 -25
- package/skills/alloy-guides/references/CONTROLLERS.md +2 -19
- package/skills/alloy-guides/references/MODELS.md +40 -10
- package/skills/alloy-guides/references/PURGETSS.md +1 -11
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +8 -14
- package/skills/alloy-guides/references/VIEWS_STYLES.md +14 -25
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +2 -8
- package/skills/alloy-guides/references/VIEWS_XML.md +29 -40
- package/skills/alloy-guides/references/WIDGETS.md +1 -17
- package/skills/alloy-howtos/SKILL.md +1 -22
- package/skills/alloy-howtos/references/best_practices.md +0 -17
- package/skills/alloy-howtos/references/cli_reference.md +1 -23
- package/skills/alloy-howtos/references/config_files.md +86 -15
- package/skills/alloy-howtos/references/custom_tags.md +14 -13
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +3 -22
- package/skills/alloy-howtos/references/samples.md +4 -14
- package/skills/purgetss/SKILL.md +11 -37
- package/skills/purgetss/references/EXAMPLES.md +106 -17
- package/skills/purgetss/references/animation-system.md +0 -67
- package/skills/purgetss/references/apply-directive.md +0 -18
- package/skills/purgetss/references/arbitrary-values.md +0 -25
- package/skills/purgetss/references/class-index.md +0 -46
- package/skills/purgetss/references/cli-commands.md +0 -41
- package/skills/purgetss/references/configurable-properties.md +0 -55
- package/skills/purgetss/references/custom-rules.md +0 -14
- package/skills/purgetss/references/customization-deep-dive.md +0 -49
- package/skills/purgetss/references/dynamic-component-creation.md +56 -37
- package/skills/purgetss/references/grid-layout.md +0 -32
- package/skills/purgetss/references/icon-fonts.md +0 -50
- package/skills/purgetss/references/installation-setup.md +61 -32
- package/skills/purgetss/references/migration-guide.md +127 -0
- package/skills/purgetss/references/opacity-modifier.md +0 -34
- package/skills/purgetss/references/performance-tips.md +261 -0
- package/skills/purgetss/references/platform-modifiers.md +0 -46
- package/skills/purgetss/references/smart-mappings.md +0 -12
- package/skills/purgetss/references/tikit-components.md +393 -0
- package/skills/purgetss/references/titanium-resets.md +1 -27
- package/skills/purgetss/references/ui-ux-design.md +467 -117
- package/skills/{alloy-expert → ti-expert}/SKILL.md +45 -54
- package/skills/ti-expert/references/alloy-builtins.md +387 -0
- package/skills/{alloy-expert → ti-expert}/references/alloy-structure.md +147 -40
- package/skills/ti-expert/references/anti-patterns.md +90 -0
- package/skills/ti-expert/references/cli-expert.md +109 -0
- package/skills/{alloy-expert → ti-expert}/references/code-conventions.md +182 -49
- package/skills/{alloy-expert → ti-expert}/references/controller-patterns.md +103 -93
- package/skills/{alloy-expert → ti-expert}/references/error-handling.md +12 -12
- package/skills/{alloy-expert → ti-expert}/references/examples.md +144 -85
- package/skills/{alloy-expert → ti-expert}/references/migration-patterns.md +38 -36
- package/skills/{alloy-expert → ti-expert}/references/patterns.md +8 -8
- package/skills/ti-expert/references/performance-listview.md +251 -0
- package/skills/{alloy-expert/references/performance-patterns.md → ti-expert/references/performance-optimization.md} +67 -283
- package/skills/{alloy-expert/references/security-patterns.md → ti-expert/references/security-device.md} +12 -295
- package/skills/ti-expert/references/security-fundamentals.md +284 -0
- package/skills/{alloy-expert → ti-expert}/references/state-management.md +10 -10
- package/skills/ti-expert/references/testing-e2e-ci.md +432 -0
- package/skills/ti-expert/references/testing-unit.md +433 -0
- package/skills/ti-expert/references/theming.md +394 -0
- package/skills/ti-guides/SKILL.md +1 -14
- package/skills/ti-guides/references/advanced-data-and-images.md +126 -10
- package/skills/ti-guides/references/app-distribution.md +48 -10
- package/skills/ti-guides/references/application-frameworks.md +9 -2
- package/skills/ti-guides/references/cli-reference.md +338 -82
- package/skills/ti-guides/references/coding-best-practices.md +14 -4
- package/skills/ti-guides/references/commonjs-advanced.md +103 -6
- package/skills/ti-guides/references/hello-world.md +5 -2
- package/skills/ti-guides/references/hyperloop-native-access.md +439 -46
- package/skills/ti-guides/references/javascript-primer.md +4 -3
- package/skills/ti-guides/references/resources.md +0 -1
- package/skills/ti-guides/references/style-and-conventions.md +57 -9
- package/skills/ti-guides/references/tiapp-config.md +48 -6
- package/skills/ti-howtos/SKILL.md +2 -27
- package/skills/ti-howtos/references/android-platform-deep-dives.md +41 -90
- package/skills/ti-howtos/references/automation-fastlane-appium.md +15 -14
- package/skills/ti-howtos/references/buffer-codec-streams.md +22 -22
- package/skills/ti-howtos/references/cross-platform-development.md +68 -37
- package/skills/ti-howtos/references/debugging-profiling.md +8 -53
- package/skills/ti-howtos/references/extending-titanium.md +12 -51
- package/skills/ti-howtos/references/google-maps-v2.md +30 -29
- package/skills/ti-howtos/references/ios-map-kit.md +19 -25
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +95 -283
- package/skills/ti-howtos/references/local-data-sources.md +45 -37
- package/skills/ti-howtos/references/location-and-maps.md +47 -28
- package/skills/ti-howtos/references/media-apis.md +84 -27
- package/skills/ti-howtos/references/notification-services.md +40 -89
- package/skills/ti-howtos/references/remote-data-sources.md +21 -36
- package/skills/ti-howtos/references/tutorials.md +79 -39
- package/skills/ti-howtos/references/using-modules.md +4 -30
- package/skills/ti-howtos/references/web-content-integration.md +28 -45
- package/skills/ti-howtos/references/webpack-build-pipeline.md +54 -18
- package/skills/ti-ui/SKILL.md +1 -21
- package/skills/ti-ui/references/accessibility-deep-dive.md +71 -25
- package/skills/ti-ui/references/animation-and-matrices.md +0 -47
- package/skills/ti-ui/references/application-structures.md +0 -46
- package/skills/ti-ui/references/custom-fonts-styling.md +9 -57
- package/skills/ti-ui/references/event-handling.md +32 -40
- package/skills/ti-ui/references/gestures.md +0 -40
- package/skills/ti-ui/references/icons-and-splash-screens.md +21 -44
- package/skills/ti-ui/references/layouts-and-positioning.md +47 -39
- package/skills/ti-ui/references/listviews-and-performance.md +187 -73
- package/skills/ti-ui/references/orientation.md +57 -71
- package/skills/ti-ui/references/platform-ui-android.md +114 -48
- package/skills/ti-ui/references/platform-ui-ios.md +63 -38
- package/skills/ti-ui/references/scrolling-views.md +14 -23
- package/skills/ti-ui/references/tableviews.md +6 -56
- package/lib/commands/install.js +0 -188
- package/skills/alloy-expert/references/anti-patterns.md +0 -133
- package/skills/alloy-expert/references/testing.md +0 -872
- package/skills/ti-guides/references/alloy-cli-advanced.md +0 -84
- package/skills/ti-guides/references/alloy-data-mastery.md +0 -29
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +0 -19
- /package/skills/{alloy-expert → ti-expert}/assets/ControllerAutoCleanup.js +0 -0
- /package/skills/{alloy-expert → ti-expert}/references/contracts.md +0 -0
|
@@ -1,32 +1,5 @@
|
|
|
1
1
|
# Media APIs
|
|
2
2
|
|
|
3
|
-
## Table of Contents
|
|
4
|
-
|
|
5
|
-
- [Media APIs](#media-apis)
|
|
6
|
-
- [Table of Contents](#table-of-contents)
|
|
7
|
-
- [1. Audio APIs](#1-audio-apis)
|
|
8
|
-
- [Playing Basic Sounds (Ti.Media.Sound)](#playing-basic-sounds-timediasound)
|
|
9
|
-
- [Streaming Audio (Ti.Media.AudioPlayer)](#streaming-audio-timediaaudioplayer)
|
|
10
|
-
- [Recording Audio (Ti.Media.AudioRecorder)](#recording-audio-timediaaudiorecorder)
|
|
11
|
-
- [2. Video APIs (Ti.Media.VideoPlayer)](#2-video-apis-timediavideoplayer)
|
|
12
|
-
- [Cross-Platform Considerations](#cross-platform-considerations)
|
|
13
|
-
- [Basic Usage](#basic-usage)
|
|
14
|
-
- [Key Events](#key-events)
|
|
15
|
-
- [3. Camera and Photo Gallery APIs](#3-camera-and-photo-gallery-apis)
|
|
16
|
-
- [Camera (Ti.Media.showCamera)](#camera-timediashowcamera)
|
|
17
|
-
- [Gallery (Ti.Media.openPhotoGallery)](#gallery-timediaopenphotogallery)
|
|
18
|
-
- [Memory Management](#memory-management)
|
|
19
|
-
- [4. Images and ImageView APIs](#4-images-and-imageview-apis)
|
|
20
|
-
- [Background Images](#background-images)
|
|
21
|
-
- [ImageView Component](#imageview-component)
|
|
22
|
-
- [Density-Specific Images](#density-specific-images)
|
|
23
|
-
- [Flipbook Animations](#flipbook-animations)
|
|
24
|
-
- [Permissions Checklist](#permissions-checklist)
|
|
25
|
-
- [iOS (tiapp.xml)](#ios-tiappxml)
|
|
26
|
-
- [Android (tiapp.xml)](#android-tiappxml)
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
3
|
## 1. Audio APIs
|
|
31
4
|
|
|
32
5
|
### Playing Basic Sounds (Ti.Media.Sound)
|
|
@@ -77,6 +50,13 @@ Ti.App.addEventListener('resume', () => { streamer.setPaused(false); });
|
|
|
77
50
|
- `movieControlStyle`: `Ti.Media.VIDEO_CONTROL_EMBEDDED` for embedded controls
|
|
78
51
|
- `scalingMode`: Control fill/fit behavior
|
|
79
52
|
|
|
53
|
+
```javascript
|
|
54
|
+
const videoPlayer = Ti.Media.createVideoPlayer({
|
|
55
|
+
url: 'movie.mp4',
|
|
56
|
+
scalingMode: Ti.Media.VIDEO_SCALING_ASPECT_FIT // or ASPECT_FILL, MODE_FILL, NONE
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
80
60
|
```javascript
|
|
81
61
|
const player = Ti.Media.createVideoPlayer({
|
|
82
62
|
url: 'movie.mp4',
|
|
@@ -100,16 +80,87 @@ win.addEventListener('close', () => { player.stop(); });
|
|
|
100
80
|
|
|
101
81
|
## 3. Camera and Photo Gallery APIs
|
|
102
82
|
|
|
83
|
+
### Camera Availability and Permissions
|
|
84
|
+
|
|
85
|
+
Always check device support and permissions before opening the camera:
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
if (!Ti.Media.isCameraSupported) {
|
|
89
|
+
Ti.API.warn('No camera available on this device');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (Ti.Media.hasCameraPermissions()) {
|
|
94
|
+
openCamera();
|
|
95
|
+
} else {
|
|
96
|
+
Ti.Media.requestCameraPermissions((e) => {
|
|
97
|
+
if (e.success) {
|
|
98
|
+
openCamera();
|
|
99
|
+
} else {
|
|
100
|
+
Ti.API.error('Camera permission denied');
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Required tiapp.xml keys (iOS)**:
|
|
107
|
+
```xml
|
|
108
|
+
<key>NSCameraUsageDescription</key>
|
|
109
|
+
<string>We need camera access to take photos</string>
|
|
110
|
+
<key>NSPhotoLibraryUsageDescription</key>
|
|
111
|
+
<string>We need photo library access to save photos</string>
|
|
112
|
+
```
|
|
113
|
+
|
|
103
114
|
### Camera (Ti.Media.showCamera)
|
|
104
115
|
- Requires camera permission and usage descriptions
|
|
105
116
|
- Success callback provides `event.media` (blob)
|
|
106
117
|
- Use `saveToPhotoGallery: true` to automatically save
|
|
107
118
|
- Handle `cancel` and `error` callbacks
|
|
108
119
|
|
|
120
|
+
### Front and Rear Camera
|
|
121
|
+
```javascript
|
|
122
|
+
const cameras = Ti.Media.availableCameras;
|
|
123
|
+
|
|
124
|
+
// Check if front camera exists
|
|
125
|
+
if (cameras.indexOf(Ti.Media.CAMERA_FRONT) !== -1) {
|
|
126
|
+
Ti.Media.showCamera({
|
|
127
|
+
whichCamera: Ti.Media.CAMERA_FRONT,
|
|
128
|
+
// ... other options
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Switch camera programmatically
|
|
133
|
+
Ti.Media.switchCamera(Ti.Media.CAMERA_REAR);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Advanced Camera Options (iOS)
|
|
137
|
+
| Property | Description |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `autohide` | Auto-hide camera after capture (default: true) |
|
|
140
|
+
| `animated` | Animate camera appearance |
|
|
141
|
+
| `allowEditing` | Allow user to crop/edit after capture |
|
|
142
|
+
| `mediaTypes` | Array: `MEDIA_TYPE_PHOTO`, `MEDIA_TYPE_VIDEO` |
|
|
143
|
+
| `videoMaximumDuration` | Max video duration in milliseconds |
|
|
144
|
+
| `videoQuality` | `QUALITY_HIGH`, `QUALITY_MEDIUM`, `QUALITY_LOW` |
|
|
145
|
+
| `overlay` | Custom Ti.UI.View overlay on camera |
|
|
146
|
+
| `showControls` | Show/hide default camera controls |
|
|
147
|
+
|
|
148
|
+
When using a custom overlay, call `Ti.Media.takePicture()` to capture and `Ti.Media.hideCamera()` to dismiss.
|
|
149
|
+
|
|
109
150
|
### Gallery (Ti.Media.openPhotoGallery)
|
|
110
151
|
- Success callback provides `event.media` (blob)
|
|
111
152
|
- Note: `event.media` may contain only file info, use `Ti.Filesystem.getFile(event.media.nativePath)` to access actual file
|
|
112
153
|
|
|
154
|
+
### iPad-Specific Gallery Options
|
|
155
|
+
On iPad, the photo gallery opens as a popover. Configure its position:
|
|
156
|
+
```javascript
|
|
157
|
+
Ti.Media.openPhotoGallery({
|
|
158
|
+
popoverView: myButton, // Anchor popover to this view
|
|
159
|
+
arrowDirection: Ti.UI.iPad.POPOVER_ARROW_DIRECTION_UP,
|
|
160
|
+
success: (e) => { /* ... */ }
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
113
164
|
### Memory Management
|
|
114
165
|
- **Critical**: Use `imageAsResized()` on blobs to avoid memory exhaustion
|
|
115
166
|
- For display: Resize to target dimensions before assigning to ImageView
|
|
@@ -132,6 +183,12 @@ Ti.Media.showCamera({
|
|
|
132
183
|
- **iOS**: Use `backgroundLeftCap` and `backgroundTopCap` to control stretch regions
|
|
133
184
|
- **Android**: Supports remote URLs as background images; iOS does not
|
|
134
185
|
|
|
186
|
+
### Image Stretching (Background Images)
|
|
187
|
+
When using small images as backgrounds, iOS and Android stretch differently:
|
|
188
|
+
- **`backgroundLeftCap`** (iOS): Number of pixels from the left that are NOT stretched. The middle section stretches.
|
|
189
|
+
- **`backgroundTopCap`** (iOS): Number of pixels from the top that are NOT stretched.
|
|
190
|
+
- **Android**: Supports remote URLs for background images; iOS does NOT.
|
|
191
|
+
|
|
135
192
|
### ImageView Component
|
|
136
193
|
- `image` property accepts: URL, local path, or Ti.Filesystem.File object
|
|
137
194
|
- Scaling behavior:
|
|
@@ -2,53 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Comprehensive guide for local and push notifications on iOS and Android.
|
|
4
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
5
|
## Local Notifications Android
|
|
53
6
|
|
|
54
7
|
### Notification Display Locations
|
|
@@ -197,6 +150,17 @@ intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
|
|
|
197
150
|
notification.contentIntent = Ti.Android.createPendingIntent({intent: intent});
|
|
198
151
|
```
|
|
199
152
|
|
|
153
|
+
### Delete Intent (Notification Cleared)
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
// Execute intent when user clears notification
|
|
157
|
+
notification.deleteIntent = Ti.Android.createPendingIntent({
|
|
158
|
+
intent: Ti.Android.createIntent({
|
|
159
|
+
action: 'com.myapp.NOTIFICATION_CLEARED'
|
|
160
|
+
})
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
200
164
|
### Schedule Future Notification (Background Service)
|
|
201
165
|
|
|
202
166
|
**tiapp.xml:**
|
|
@@ -267,6 +231,13 @@ if (Ti.Platform.name === 'iPhone OS' && parseInt(Ti.Platform.version.split('.')[
|
|
|
267
231
|
}
|
|
268
232
|
```
|
|
269
233
|
|
|
234
|
+
**Note**: iOS will show a system prompt asking the user to allow notifications on the first call. Check current settings with:
|
|
235
|
+
```javascript
|
|
236
|
+
Ti.App.iOS.addEventListener('usernotificationsettings', (e) => {
|
|
237
|
+
Ti.API.info(`Notification types allowed: ${e.types}`);
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
270
241
|
### Schedule Local Notification
|
|
271
242
|
|
|
272
243
|
```javascript
|
|
@@ -439,9 +410,15 @@ Ti.App.iOS.scheduleLocalNotification({
|
|
|
439
410
|
|
|
440
411
|
Push notifications allow server-to-device communication. Infrastructure differs by platform:
|
|
441
412
|
|
|
442
|
-
- **Android**: Firebase Cloud Messaging (FCM)
|
|
413
|
+
- **Android**: Firebase Cloud Messaging (FCM)
|
|
443
414
|
- **iOS**: Apple Push Notification service (APNs)
|
|
444
415
|
|
|
416
|
+
> **Note**: The legacy Appcelerator Cloud Services (ACS/ArrowDB) push backend is no longer available. Use Firebase Cloud Messaging (FCM) for Android and Apple Push Notification service (APNs) for iOS, either directly or through a third-party service.
|
|
417
|
+
|
|
418
|
+
> Google has deprecated Google Cloud Messaging (GCM) in favor of Firebase Cloud Messaging (FCM). All new implementations should use FCM.
|
|
419
|
+
|
|
420
|
+
For FCM on Titanium, use the community Firebase Cloud Messaging module: `titanium-firebase-cloud-messaging` (by Hans Knöchel).
|
|
421
|
+
|
|
445
422
|
### Register for Push Notifications
|
|
446
423
|
|
|
447
424
|
```javascript
|
|
@@ -463,18 +440,21 @@ Ti.Network.registerForPushNotifications({
|
|
|
463
440
|
});
|
|
464
441
|
```
|
|
465
442
|
|
|
466
|
-
###
|
|
443
|
+
### APNs Configuration (iOS)
|
|
444
|
+
|
|
445
|
+
1. Register an **Explicit App ID** (not Wildcard) with Push Notifications enabled in Apple Developer Portal
|
|
446
|
+
2. Generate an APNs certificate (Development for sandbox, Production for App Store)
|
|
447
|
+
3. Export the certificate as PKCS#12 (.p12) from Keychain Access
|
|
448
|
+
4. Upload the .p12 to your push service provider
|
|
449
|
+
5. In your app, call `Ti.Network.registerForPushNotifications()` to get the device token
|
|
467
450
|
|
|
468
|
-
|
|
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)
|
|
451
|
+
### FCM Configuration (Android)
|
|
472
452
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
453
|
+
1. Create a project in Firebase Console
|
|
454
|
+
2. Add your Android app (use your app's package name)
|
|
455
|
+
3. Download `google-services.json` and place in project root
|
|
456
|
+
4. Add the `titanium-firebase-cloud-messaging` module to tiapp.xml
|
|
457
|
+
5. Register for push and obtain the FCM token
|
|
478
458
|
|
|
479
459
|
### Push Notification Payload Format
|
|
480
460
|
|
|
@@ -499,38 +479,9 @@ Ti.Network.registerForPushNotifications({
|
|
|
499
479
|
}
|
|
500
480
|
```
|
|
501
481
|
|
|
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
482
|
### Send Push Notifications
|
|
518
483
|
|
|
519
|
-
|
|
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.
|
|
484
|
+
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.
|
|
534
485
|
|
|
535
486
|
### Best Practices
|
|
536
487
|
|
|
@@ -588,7 +539,7 @@ Use `UNMutableNotificationContent` with attachments (images, video, audio).
|
|
|
588
539
|
|
|
589
540
|
### Android
|
|
590
541
|
|
|
591
|
-
- **Service lifecycle**: Services may be killed if app is swiped away
|
|
542
|
+
- **Service lifecycle**: Services may be killed if app is swiped away. **Warning**: Android services may stop if the app is killed (user backs out or removes from recent apps). For critical notifications, use FCM push notifications instead of local services
|
|
592
543
|
- **Notification channels**: Android 8.0+ requires notification channels
|
|
593
544
|
- **Limitations**: Legacy MapView only supports single map view
|
|
594
545
|
|
|
@@ -1,40 +1,5 @@
|
|
|
1
1
|
# Remote Data Sources
|
|
2
2
|
|
|
3
|
-
## Table of Contents
|
|
4
|
-
|
|
5
|
-
- [Remote Data Sources](#remote-data-sources)
|
|
6
|
-
- [Table of Contents](#table-of-contents)
|
|
7
|
-
- [1. HTTPClient and Request Lifecycle](#1-httpclient-and-request-lifecycle)
|
|
8
|
-
- [Basic Pattern](#basic-pattern)
|
|
9
|
-
- [HTTP Methods](#http-methods)
|
|
10
|
-
- [Setting Headers](#setting-headers)
|
|
11
|
-
- [XHR Lifecycle States](#xhr-lifecycle-states)
|
|
12
|
-
- [Progress Monitoring](#progress-monitoring)
|
|
13
|
-
- [2. Working with JSON Data](#2-working-with-json-data)
|
|
14
|
-
- [Receiving JSON](#receiving-json)
|
|
15
|
-
- [Sending JSON](#sending-json)
|
|
16
|
-
- [Important Limitation](#important-limitation)
|
|
17
|
-
- [3. Working with XML Data](#3-working-with-xml-data)
|
|
18
|
-
- [Parsing XML](#parsing-xml)
|
|
19
|
-
- [Common DOM Methods](#common-dom-methods)
|
|
20
|
-
- [Important: Know Your DTD](#important-know-your-dtd)
|
|
21
|
-
- [4. File Uploads and Downloads](#4-file-uploads-and-downloads)
|
|
22
|
-
- [File Upload](#file-upload)
|
|
23
|
-
- [File Download (Cross-Platform)](#file-download-cross-platform)
|
|
24
|
-
- [File Storage Locations](#file-storage-locations)
|
|
25
|
-
- [5. Sockets](#5-sockets)
|
|
26
|
-
- [Creating a TCP Socket](#creating-a-tcp-socket)
|
|
27
|
-
- [Socket Listening (Android/iOS)](#socket-listening-androidios)
|
|
28
|
-
- [6. Dealing with SOAP Web Services](#6-dealing-with-soap-web-services)
|
|
29
|
-
- [Manual Approach (SOAP Envelope)](#manual-approach-soap-envelope)
|
|
30
|
-
- [7. SSL Certificate \& Security Manager](#7-ssl-certificate--security-manager)
|
|
31
|
-
- [SSL Pinning (TiSDK 3.3.0+)](#ssl-pinning-tisdk-330)
|
|
32
|
-
- [Android: addTrustManager](#android-addtrustmanager)
|
|
33
|
-
- [CORS Considerations for Mobile Web](#cors-considerations-for-mobile-web)
|
|
34
|
-
- [Best Practices](#best-practices)
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
3
|
## 1. HTTPClient and Request Lifecycle
|
|
39
4
|
|
|
40
5
|
### Basic Pattern
|
|
@@ -195,6 +160,8 @@ if (file.exists()) {
|
|
|
195
160
|
}
|
|
196
161
|
```
|
|
197
162
|
|
|
163
|
+
> **Note**: When uploading from the photo gallery, `event.media` returns a Blob. For file uploads from the filesystem, use `Ti.Filesystem.getFile(path).read()` to get the Blob.
|
|
164
|
+
|
|
198
165
|
### File Download (Cross-Platform)
|
|
199
166
|
|
|
200
167
|
**Option 1**: Write manually to filesystem
|
|
@@ -217,6 +184,11 @@ xhr.send();
|
|
|
217
184
|
|
|
218
185
|
**Option 2**: iOS-only automatic saving with `file` property
|
|
219
186
|
|
|
187
|
+
**iOS-only**: Use `xhr.file` to save downloads directly to a file without buffering in memory:
|
|
188
|
+
```javascript
|
|
189
|
+
xhr.file = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, 'download.zip');
|
|
190
|
+
```
|
|
191
|
+
|
|
220
192
|
```javascript
|
|
221
193
|
const xhr = Ti.Network.createHTTPClient({
|
|
222
194
|
onload: () => {
|
|
@@ -278,6 +250,8 @@ listenSocket.listen();
|
|
|
278
250
|
listenSocket.accept(); // Asynchronous, waits for next connection
|
|
279
251
|
```
|
|
280
252
|
|
|
253
|
+
> **Platform Note**: On iOS, `Ti.Platform.address` returns the WiFi interface address. On Android, only the loopback address (`127.0.0.1`) is available for listening sockets.
|
|
254
|
+
|
|
281
255
|
## 6. Dealing with SOAP Web Services
|
|
282
256
|
|
|
283
257
|
Although JSON is recommended, you can consume legacy SOAP services using a "low-tech" approach by sending the XML envelope manually.
|
|
@@ -315,7 +289,18 @@ Unlike standard certificate validation, Pinning ensures the app only communicate
|
|
|
315
289
|
const xhr = Ti.Network.createHTTPClient({
|
|
316
290
|
validatesSecureCertificate: true,
|
|
317
291
|
// securityManager allows implementing custom validation logic
|
|
318
|
-
securityManager: mySecurityModule
|
|
292
|
+
securityManager: mySecurityModule
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### SSL Certificate Store (Android)
|
|
297
|
+
```javascript
|
|
298
|
+
const certificateStore = require('ti.certificatestore');
|
|
299
|
+
const httpClient = Ti.Network.createHTTPClient({
|
|
300
|
+
securityManager: certificateStore.createX509CertificatePinningSecurityManager([{
|
|
301
|
+
url: 'https://api.example.com',
|
|
302
|
+
serverCertificate: 'api_cert.der'
|
|
303
|
+
}])
|
|
319
304
|
});
|
|
320
305
|
```
|
|
321
306
|
|
|
@@ -2,44 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Practical tutorials and guides for building real-world Titanium applications.
|
|
4
4
|
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Titanium SDK Tutorials](#titanium-sdk-tutorials)
|
|
8
|
-
- [Table of Contents](#table-of-contents)
|
|
9
|
-
- [RESTe - API Integration](#reste---api-integration)
|
|
10
|
-
- [Overview](#overview)
|
|
11
|
-
- [Installation](#installation)
|
|
12
|
-
- [Basic Configuration](#basic-configuration)
|
|
13
|
-
- [Usage](#usage)
|
|
14
|
-
- [Backbone.js Models/Collections](#backbonejs-modelscollections)
|
|
15
|
-
- [Important Notes](#important-notes)
|
|
16
|
-
- [Mock Data (On-The-Fly)](#mock-data-on-the-fly)
|
|
17
|
-
- [Resources](#resources)
|
|
18
|
-
- [Camera App Tutorial](#camera-app-tutorial)
|
|
19
|
-
- [Basic Camera Access](#basic-camera-access)
|
|
20
|
-
- [Photo Gallery](#photo-gallery)
|
|
21
|
-
- [Saving Images](#saving-images)
|
|
22
|
-
- [Geolocation Tutorial](#geolocation-tutorial)
|
|
23
|
-
- [Basic Location](#basic-location)
|
|
24
|
-
- [Continuous Tracking](#continuous-tracking)
|
|
25
|
-
- [Reverse Geocoding](#reverse-geocoding)
|
|
26
|
-
- [Alloy Controller Chaining](#alloy-controller-chaining)
|
|
27
|
-
- [Pattern Overview](#pattern-overview)
|
|
28
|
-
- [Basic Pattern](#basic-pattern)
|
|
29
|
-
- [Benefits](#benefits)
|
|
30
|
-
- [Build Automation with Fastlane](#build-automation-with-fastlane)
|
|
31
|
-
- [Overview](#overview-1)
|
|
32
|
-
- [Installing Fastlane](#installing-fastlane)
|
|
33
|
-
- [Basic Fastfile](#basic-fastfile)
|
|
34
|
-
- [Usage](#usage-1)
|
|
35
|
-
- [Advanced Options](#advanced-options)
|
|
36
|
-
- [Additional Tutorials](#additional-tutorials)
|
|
37
|
-
- [Alloy Boilerplates](#alloy-boilerplates)
|
|
38
|
-
- [Complete Sample Apps](#complete-sample-apps)
|
|
39
|
-
- [Resources](#resources-1)
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
5
|
## RESTe - API Integration
|
|
44
6
|
|
|
45
7
|
### Overview
|
|
@@ -67,7 +29,7 @@ const api = new reste();
|
|
|
67
29
|
|
|
68
30
|
api.config({
|
|
69
31
|
debug: true, // Console logging
|
|
70
|
-
errorsAsObjects: true, // Return errors as objects (1.4.5+)
|
|
32
|
+
errorsAsObjects: true, // Return errors as objects (1.4.5+) — WARNING: breaks apps written for 1.4.4 that handle errors differently
|
|
71
33
|
autoValidateParams: false, // Throw error if params missing
|
|
72
34
|
validatesSecureCertificate: false,
|
|
73
35
|
timeout: 4000,
|
|
@@ -169,6 +131,19 @@ Alloy.Collections.videos.fetch({
|
|
|
169
131
|
</TableView>
|
|
170
132
|
```
|
|
171
133
|
|
|
134
|
+
### RESTe Advanced Features
|
|
135
|
+
|
|
136
|
+
- **Caching**: Built-in response caching support
|
|
137
|
+
- **Promises**: Use with `q.js` for Promise-based API calls
|
|
138
|
+
- **Mock data**: Create models/collections on-the-fly for testing:
|
|
139
|
+
```javascript
|
|
140
|
+
const mockUser = api.createModel('users', {
|
|
141
|
+
id: 1,
|
|
142
|
+
name: 'Test User'
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
- **Backbone.js binding**: Use RESTe models directly with Alloy data binding without `<Model>` tags
|
|
146
|
+
|
|
172
147
|
### Important Notes
|
|
173
148
|
|
|
174
149
|
- **Don't use `<Model>` or `<Collection>` tags** with RESTe
|
|
@@ -201,6 +176,29 @@ const videoCollection = api.createCollection('videos', [
|
|
|
201
176
|
|
|
202
177
|
## Camera App Tutorial
|
|
203
178
|
|
|
179
|
+
### Camera Permissions Setup
|
|
180
|
+
|
|
181
|
+
**iOS** — add to tiapp.xml plist:
|
|
182
|
+
```xml
|
|
183
|
+
<key>NSCameraUsageDescription</key>
|
|
184
|
+
<string>This app needs camera access to take photos</string>
|
|
185
|
+
<key>NSMicrophoneUsageDescription</key>
|
|
186
|
+
<string>This app needs microphone access for video recording</string>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Android**: Camera permissions are automatically added by the build system when using `Ti.Media.showCamera()`.
|
|
190
|
+
|
|
191
|
+
Always check permissions at runtime:
|
|
192
|
+
```javascript
|
|
193
|
+
if (!Ti.Media.hasCameraPermissions()) {
|
|
194
|
+
Ti.Media.requestCameraPermissions((e) => {
|
|
195
|
+
if (e.success) openCamera();
|
|
196
|
+
});
|
|
197
|
+
} else {
|
|
198
|
+
openCamera();
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
204
202
|
### Basic Camera Access
|
|
205
203
|
|
|
206
204
|
```javascript
|
|
@@ -275,6 +273,31 @@ Ti.Media.saveToPhotoGallery({
|
|
|
275
273
|
|
|
276
274
|
## Geolocation Tutorial
|
|
277
275
|
|
|
276
|
+
### Geolocation Permissions Setup
|
|
277
|
+
|
|
278
|
+
**iOS** — add to tiapp.xml plist:
|
|
279
|
+
```xml
|
|
280
|
+
<key>NSLocationWhenInUseUsageDescription</key>
|
|
281
|
+
<string>We need your location to show nearby places</string>
|
|
282
|
+
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
283
|
+
<string>We need your location for background tracking</string>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Android** — add to tiapp.xml manifest:
|
|
287
|
+
```xml
|
|
288
|
+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
|
289
|
+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Runtime permission check:
|
|
293
|
+
```javascript
|
|
294
|
+
if (!Ti.Geolocation.hasLocationPermissions(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE)) {
|
|
295
|
+
Ti.Geolocation.requestLocationPermissions(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE, (e) => {
|
|
296
|
+
if (e.success) startTracking();
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
278
301
|
### Basic Location
|
|
279
302
|
|
|
280
303
|
```javascript
|
|
@@ -321,6 +344,23 @@ Ti.Geolocation.reverseGeocoder(37.389569, -122.050212, (e) => {
|
|
|
321
344
|
});
|
|
322
345
|
```
|
|
323
346
|
|
|
347
|
+
### Accuracy Tuning
|
|
348
|
+
|
|
349
|
+
```javascript
|
|
350
|
+
// iOS: minimum distance before firing event
|
|
351
|
+
Ti.Geolocation.distanceFilter = 10; // meters
|
|
352
|
+
|
|
353
|
+
// Android: use FusedLocationProvider for better battery (requires ti.playservices module)
|
|
354
|
+
// Automatically enabled with SDK 7.1.0+ when ti.playservices is present
|
|
355
|
+
|
|
356
|
+
// Android: custom location rules
|
|
357
|
+
Ti.Geolocation.Android.addLocationRule(Ti.Geolocation.Android.createLocationRule({
|
|
358
|
+
provider: Ti.Geolocation.Android.PROVIDER_GPS,
|
|
359
|
+
accuracy: 100, // meters
|
|
360
|
+
minAge: 1000 // milliseconds
|
|
361
|
+
}));
|
|
362
|
+
```
|
|
363
|
+
|
|
324
364
|
---
|
|
325
365
|
|
|
326
366
|
## Alloy Controller Chaining
|
|
@@ -2,34 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Guide for obtaining, installing, and using Titanium modules to extend app functionality.
|
|
4
4
|
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Using Modules](#using-modules)
|
|
8
|
-
- [Table of Contents](#table-of-contents)
|
|
9
|
-
- [Obtaining Modules](#obtaining-modules)
|
|
10
|
-
- [Sources of Modules](#sources-of-modules)
|
|
11
|
-
- [Installing Modules](#installing-modules)
|
|
12
|
-
- [Single Project Installation](#single-project-installation)
|
|
13
|
-
- [Global Installation (All Projects)](#global-installation-all-projects)
|
|
14
|
-
- [Configuring Your App](#configuring-your-app)
|
|
15
|
-
- [Updating tiapp.xml](#updating-tiappxml)
|
|
16
|
-
- [Selecting Module Versions](#selecting-module-versions)
|
|
17
|
-
- [Enable Debugger (for native modules)](#enable-debugger-for-native-modules)
|
|
18
|
-
- [Using a Module](#using-a-module)
|
|
19
|
-
- [Loading the Module (ES5)](#loading-the-module-es5)
|
|
20
|
-
- [Loading the Module (ES6+)](#loading-the-module-es6)
|
|
21
|
-
- [Using Module Functionality](#using-module-functionality)
|
|
22
|
-
- [Module Patterns](#module-patterns)
|
|
23
|
-
- [Troubleshooting](#troubleshooting)
|
|
24
|
-
- ["Requested module not found"](#requested-module-not-found)
|
|
25
|
-
- [Version Conflicts](#version-conflicts)
|
|
26
|
-
- [Platform-Specific Issues](#platform-specific-issues)
|
|
27
|
-
- [Clean Build](#clean-build)
|
|
28
|
-
- [Best Practices](#best-practices)
|
|
29
|
-
- [Module Development](#module-development)
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
5
|
## Obtaining Modules
|
|
34
6
|
|
|
35
7
|
### Sources of Modules
|
|
@@ -55,8 +27,10 @@ Guide for obtaining, installing, and using Titanium modules to extend app functi
|
|
|
55
27
|
- Curated list of modules maintained by Michael Gangolf
|
|
56
28
|
|
|
57
29
|
**Marketplace:**
|
|
58
|
-
|
|
59
|
-
|
|
30
|
+
> **Note**: The original Appcelerator Marketplace is no longer available. Find community modules on GitHub and npm. A curated list is at [From Zero to App](https://fromzerotoapp.com/modules/).
|
|
31
|
+
|
|
32
|
+
### Pre-installed Modules
|
|
33
|
+
Some modules ship with the SDK and don't need separate installation: `ti.map`, `ti.identity`, `ti.webdialog`, `ti.applesignin`
|
|
60
34
|
|
|
61
35
|
---
|
|
62
36
|
|