@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.
- package/AGENTS-TEMPLATE.md +173 -0
- package/README.md +867 -0
- package/agents/ti-researcher.md +108 -0
- package/bin/titools.js +53 -0
- package/lib/commands/agents.js +126 -0
- package/lib/commands/install.js +188 -0
- package/lib/commands/uninstall.js +215 -0
- package/lib/commands/update.js +159 -0
- package/lib/config.js +119 -0
- package/lib/downloader.js +153 -0
- package/lib/installer.js +253 -0
- package/lib/platform.js +108 -0
- package/lib/symlink.js +142 -0
- package/lib/utils.js +270 -0
- package/package.json +67 -0
- package/skills/alloy-expert/SKILL.md +247 -0
- package/skills/alloy-expert/assets/ControllerAutoCleanup.js +182 -0
- package/skills/alloy-expert/references/alloy-structure.md +381 -0
- package/skills/alloy-expert/references/anti-patterns.md +133 -0
- package/skills/alloy-expert/references/code-conventions.md +469 -0
- package/skills/alloy-expert/references/contracts.md +280 -0
- package/skills/alloy-expert/references/controller-patterns.md +520 -0
- package/skills/alloy-expert/references/error-handling.md +484 -0
- package/skills/alloy-expert/references/examples.md +735 -0
- package/skills/alloy-expert/references/migration-patterns.md +298 -0
- package/skills/alloy-expert/references/patterns.md +448 -0
- package/skills/alloy-expert/references/performance-patterns.md +855 -0
- package/skills/alloy-expert/references/security-patterns.md +847 -0
- package/skills/alloy-expert/references/state-management.md +779 -0
- package/skills/alloy-expert/references/testing.md +872 -0
- package/skills/alloy-guides/SKILL.md +214 -0
- package/skills/alloy-guides/references/CLI_TASKS.md +243 -0
- package/skills/alloy-guides/references/CONCEPTS.md +191 -0
- package/skills/alloy-guides/references/CONTROLLERS.md +298 -0
- package/skills/alloy-guides/references/MODELS.md +1028 -0
- package/skills/alloy-guides/references/PURGETSS.md +56 -0
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +242 -0
- package/skills/alloy-guides/references/VIEWS_STYLES.md +388 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +109 -0
- package/skills/alloy-guides/references/VIEWS_XML.md +558 -0
- package/skills/alloy-guides/references/WIDGETS.md +176 -0
- package/skills/alloy-howtos/SKILL.md +203 -0
- package/skills/alloy-howtos/references/best_practices.md +138 -0
- package/skills/alloy-howtos/references/cli_reference.md +253 -0
- package/skills/alloy-howtos/references/config_files.md +87 -0
- package/skills/alloy-howtos/references/custom_tags.md +147 -0
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +101 -0
- package/skills/alloy-howtos/references/samples.md +167 -0
- package/skills/purgetss/SKILL.md +442 -0
- package/skills/purgetss/assets/purgetss.config.cjs +17 -0
- package/skills/purgetss/references/EXAMPLES.md +247 -0
- package/skills/purgetss/references/animation-system.md +1294 -0
- package/skills/purgetss/references/apply-directive.md +375 -0
- package/skills/purgetss/references/arbitrary-values.md +612 -0
- package/skills/purgetss/references/class-index.md +1350 -0
- package/skills/purgetss/references/cli-commands.md +948 -0
- package/skills/purgetss/references/configurable-properties.md +654 -0
- package/skills/purgetss/references/custom-rules.md +161 -0
- package/skills/purgetss/references/customization-deep-dive.md +722 -0
- package/skills/purgetss/references/dynamic-component-creation.md +489 -0
- package/skills/purgetss/references/grid-layout.md +455 -0
- package/skills/purgetss/references/icon-fonts.md +609 -0
- package/skills/purgetss/references/installation-setup.md +366 -0
- package/skills/purgetss/references/opacity-modifier.md +291 -0
- package/skills/purgetss/references/platform-modifiers.md +479 -0
- package/skills/purgetss/references/smart-mappings.md +42 -0
- package/skills/purgetss/references/titanium-resets.md +359 -0
- package/skills/purgetss/references/ui-ux-design.md +1526 -0
- package/skills/ti-guides/SKILL.md +94 -0
- package/skills/ti-guides/references/advanced-data-and-images.md +19 -0
- package/skills/ti-guides/references/alloy-cli-advanced.md +84 -0
- package/skills/ti-guides/references/alloy-data-mastery.md +29 -0
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +19 -0
- package/skills/ti-guides/references/android-manifest.md +97 -0
- package/skills/ti-guides/references/app-distribution.md +258 -0
- package/skills/ti-guides/references/application-frameworks.md +377 -0
- package/skills/ti-guides/references/cli-reference.md +402 -0
- package/skills/ti-guides/references/coding-best-practices.md +102 -0
- package/skills/ti-guides/references/commonjs-advanced.md +134 -0
- package/skills/ti-guides/references/hello-world.md +100 -0
- package/skills/ti-guides/references/hyperloop-native-access.md +62 -0
- package/skills/ti-guides/references/javascript-primer.md +411 -0
- package/skills/ti-guides/references/reserved-words.md +36 -0
- package/skills/ti-guides/references/resources.md +183 -0
- package/skills/ti-guides/references/style-and-conventions.md +48 -0
- package/skills/ti-guides/references/tiapp-config.md +609 -0
- package/skills/ti-howtos/SKILL.md +174 -0
- package/skills/ti-howtos/references/android-platform-deep-dives.md +658 -0
- package/skills/ti-howtos/references/automation-fastlane-appium.md +95 -0
- package/skills/ti-howtos/references/buffer-codec-streams.md +140 -0
- package/skills/ti-howtos/references/cross-platform-development.md +348 -0
- package/skills/ti-howtos/references/debugging-profiling.md +543 -0
- package/skills/ti-howtos/references/extending-titanium.md +723 -0
- package/skills/ti-howtos/references/google-maps-v2.md +169 -0
- package/skills/ti-howtos/references/ios-map-kit.md +143 -0
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +783 -0
- package/skills/ti-howtos/references/local-data-sources.md +301 -0
- package/skills/ti-howtos/references/location-and-maps.md +252 -0
- package/skills/ti-howtos/references/media-apis.md +210 -0
- package/skills/ti-howtos/references/notification-services.md +599 -0
- package/skills/ti-howtos/references/remote-data-sources.md +349 -0
- package/skills/ti-howtos/references/tutorials.md +502 -0
- package/skills/ti-howtos/references/using-modules.md +237 -0
- package/skills/ti-howtos/references/web-content-integration.md +307 -0
- package/skills/ti-howtos/references/webpack-build-pipeline.md +78 -0
- package/skills/ti-ui/SKILL.md +179 -0
- package/skills/ti-ui/references/accessibility-deep-dive.md +242 -0
- package/skills/ti-ui/references/animation-and-matrices.md +599 -0
- package/skills/ti-ui/references/application-structures.md +655 -0
- package/skills/ti-ui/references/custom-fonts-styling.md +579 -0
- package/skills/ti-ui/references/event-handling.md +393 -0
- package/skills/ti-ui/references/gestures.md +473 -0
- package/skills/ti-ui/references/icons-and-splash-screens.md +409 -0
- package/skills/ti-ui/references/layouts-and-positioning.md +462 -0
- package/skills/ti-ui/references/listviews-and-performance.md +619 -0
- package/skills/ti-ui/references/orientation.md +362 -0
- package/skills/ti-ui/references/platform-ui-android.md +635 -0
- package/skills/ti-ui/references/platform-ui-ios.md +469 -0
- package/skills/ti-ui/references/scrolling-views.md +252 -0
- package/skills/ti-ui/references/tableviews.md +568 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Local Data Sources
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Local Data Sources](#local-data-sources)
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [1. Filesystem Access and Storage](#1-filesystem-access-and-storage)
|
|
8
|
+
- [Modules Overview](#modules-overview)
|
|
9
|
+
- [Storage Locations](#storage-locations)
|
|
10
|
+
- [File Operations](#file-operations)
|
|
11
|
+
- [Getting a File Handle](#getting-a-file-handle)
|
|
12
|
+
- [Writing Files](#writing-files)
|
|
13
|
+
- [Reading Files](#reading-files)
|
|
14
|
+
- [Appending](#appending)
|
|
15
|
+
- [Creating/Copying](#creatingcopying)
|
|
16
|
+
- [Renaming](#renaming)
|
|
17
|
+
- [Deleting](#deleting)
|
|
18
|
+
- [Directory Operations](#directory-operations)
|
|
19
|
+
- [Case Sensitivity Warning](#case-sensitivity-warning)
|
|
20
|
+
- [2. SQLite Database](#2-sqlite-database)
|
|
21
|
+
- [Opening Databases](#opening-databases)
|
|
22
|
+
- [Querying Data](#querying-data)
|
|
23
|
+
- [Parameterized Queries](#parameterized-queries)
|
|
24
|
+
- [Data Modification](#data-modification)
|
|
25
|
+
- [**CRITICAL**: Always Close Connections](#critical-always-close-connections)
|
|
26
|
+
- [3. Properties API (Ti.App.Properties)](#3-properties-api-tiappproperties)
|
|
27
|
+
- [Overview](#overview)
|
|
28
|
+
- [Data Type Methods](#data-type-methods)
|
|
29
|
+
- [Usage Examples](#usage-examples)
|
|
30
|
+
- [Storing Complex Objects as JSON](#storing-complex-objects-as-json)
|
|
31
|
+
- [Platform Storage](#platform-storage)
|
|
32
|
+
- [4. Advanced Data Manipulation (Buffer, Codec, and Streams)](#4-advanced-data-manipulation-buffer-codec-and-streams)
|
|
33
|
+
- [5. Choosing a Persistence Strategy](#5-choosing-a-persistence-strategy)
|
|
34
|
+
- [Decision Guide](#decision-guide)
|
|
35
|
+
- [Best Practices](#best-practices)
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 1. Filesystem Access and Storage
|
|
40
|
+
|
|
41
|
+
### Modules Overview
|
|
42
|
+
- `Ti.Filesystem` - Top-level module for file/directory operations
|
|
43
|
+
- `Ti.Filesystem.File` - File object with read/write methods
|
|
44
|
+
- `Ti.Filesystem.FileStream` - Stream wrapper implementing Ti.IOStream interface
|
|
45
|
+
|
|
46
|
+
### Storage Locations
|
|
47
|
+
|
|
48
|
+
| Location | Read/Write | Persistence | Notes |
|
|
49
|
+
| --------------------------- | ---------- | ---------------- | -------------------------------------- |
|
|
50
|
+
| `applicationDataDirectory` | R/W | Until uninstall | Primary app data location |
|
|
51
|
+
| `resourcesDirectory` | R-only | Until uninstall | App resources (R/W in simulator only!) |
|
|
52
|
+
| `tempDirectory` | R/W | Until app closes | OS may delete anytime |
|
|
53
|
+
| `applicationCacheDirectory` | R/W | OS may clean | For cached data |
|
|
54
|
+
| `externalCacheDirectory` | R/W | OS may clean | Android SD card cache |
|
|
55
|
+
| `externalStorageDirectory` | R/W | Until uninstall | Android SD card storage |
|
|
56
|
+
|
|
57
|
+
**Always check** `Ti.Filesystem.isExternalStoragePresent()` before using external storage on Android.
|
|
58
|
+
|
|
59
|
+
### File Operations
|
|
60
|
+
|
|
61
|
+
#### Getting a File Handle
|
|
62
|
+
```javascript
|
|
63
|
+
const f = Ti.Filesystem.getFile(
|
|
64
|
+
Ti.Filesystem.applicationDataDirectory,
|
|
65
|
+
'myfile.txt'
|
|
66
|
+
);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Writing Files
|
|
70
|
+
```javascript
|
|
71
|
+
f.write('Content here'); // Overwrites or creates
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### Reading Files
|
|
75
|
+
```javascript
|
|
76
|
+
const contents = f.read(); // Returns Blob
|
|
77
|
+
Ti.API.info(contents.text); // Text content
|
|
78
|
+
Ti.API.info(contents.mimeType); // MIME type
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Appending
|
|
82
|
+
```javascript
|
|
83
|
+
f.append('More content\n'); // String, Blob, or File
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Creating/Copying
|
|
87
|
+
```javascript
|
|
88
|
+
// Auto-creates on write, but explicit option exists:
|
|
89
|
+
if (!f.exists()) {
|
|
90
|
+
f.createFile();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Android copy method:
|
|
94
|
+
const oldFile = Ti.Filesystem.getFile(applicationDataDirectory, 'old.txt');
|
|
95
|
+
oldFile.copy(`${applicationDataDirectory}new.txt`);
|
|
96
|
+
|
|
97
|
+
// iOS (no copy method):
|
|
98
|
+
const newFile = Ti.Filesystem.getFile(applicationDataDirectory, 'new.txt');
|
|
99
|
+
newFile.write(oldFile.read());
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Renaming
|
|
103
|
+
**Important**: File handle still points to old name after rename!
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
const f = Ti.Filesystem.getFile(applicationDataDirectory, 'old.txt');
|
|
107
|
+
f.rename('new.txt');
|
|
108
|
+
// f still references 'old.txt' (now non-existent)
|
|
109
|
+
const newf = Ti.Filesystem.getFile(applicationDataDirectory, 'new.txt');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Deleting
|
|
113
|
+
```javascript
|
|
114
|
+
if (f.exists() && f.writable) {
|
|
115
|
+
const success = f.deleteFile(); // Returns Boolean, no error thrown
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Directory Operations
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
// Create directory
|
|
123
|
+
const dir = Ti.Filesystem.getFile(applicationDataDirectory, 'mysubdir');
|
|
124
|
+
dir.createDirectory();
|
|
125
|
+
|
|
126
|
+
// List contents
|
|
127
|
+
const listing = dir.getDirectoryListing();
|
|
128
|
+
|
|
129
|
+
// Move file into directory
|
|
130
|
+
const file = Ti.Filesystem.getFile(applicationDataDirectory, 'file.txt');
|
|
131
|
+
file.move('mysubdir/file.txt');
|
|
132
|
+
|
|
133
|
+
// Delete directory (must be empty or force recursive)
|
|
134
|
+
dir.deleteDirectory(false); // Fails if not empty
|
|
135
|
+
dir.deleteDirectory(true); // Recursive delete
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Case Sensitivity Warning
|
|
139
|
+
Android and Mobile Web use case-sensitive filesystems. File names referenced in code must match actual file names exactly. Recommendation: **lowercase all file names**.
|
|
140
|
+
|
|
141
|
+
## 2. SQLite Database
|
|
142
|
+
|
|
143
|
+
### Opening Databases
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
// Install (copies from Resources if first time)
|
|
147
|
+
const db = Ti.Database.install('mydb.sqlite', 'myInstalledDB');
|
|
148
|
+
|
|
149
|
+
// Or open existing database in applicationDataDirectory
|
|
150
|
+
const db = Ti.Database.open('myDatabase');
|
|
151
|
+
|
|
152
|
+
// For app data directory location:
|
|
153
|
+
const dbFile = Ti.Filesystem.getFile(
|
|
154
|
+
Ti.Filesystem.applicationDataDirectory,
|
|
155
|
+
'mydb.sqlite'
|
|
156
|
+
);
|
|
157
|
+
const db = Ti.Database.open(dbFile.nativePath);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Querying Data
|
|
161
|
+
|
|
162
|
+
```javascript
|
|
163
|
+
const rows = db.execute('SELECT * FROM users WHERE age > ?', [18]);
|
|
164
|
+
|
|
165
|
+
while (rows.isValidRow()) {
|
|
166
|
+
Ti.API.info(rows.fieldByName('name'));
|
|
167
|
+
Ti.API.info(rows.field(0)); // First column by index
|
|
168
|
+
rows.next();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// **CRITICAL**: Always close result set
|
|
172
|
+
rows.close();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Parameterized Queries
|
|
176
|
+
Always use parameters to prevent SQL injection:
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
// SAFE - parameterized
|
|
180
|
+
db.execute('INSERT INTO users (name, age) VALUES (?, ?)', ['John', 25]);
|
|
181
|
+
|
|
182
|
+
// UNSAFE - never do this
|
|
183
|
+
db.execute(`INSERT INTO users (name, age) VALUES ('${name}', ${age})`);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Data Modification
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// INSERT
|
|
190
|
+
db.execute('INSERT INTO users (name, age) VALUES (?, ?)', ['Jane', 30]);
|
|
191
|
+
const lastId = db.lastInsertRowId; // Get inserted ID
|
|
192
|
+
|
|
193
|
+
// UPDATE
|
|
194
|
+
db.execute('UPDATE users SET age = ? WHERE name = ?', [31, 'Jane']);
|
|
195
|
+
const rowsAffected = db.rowsAffected;
|
|
196
|
+
|
|
197
|
+
// DELETE
|
|
198
|
+
db.execute('DELETE FROM users WHERE age < ?', [18]);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### **CRITICAL**: Always Close Connections
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
try {
|
|
205
|
+
// Database operations
|
|
206
|
+
} finally {
|
|
207
|
+
// Always close, even on error
|
|
208
|
+
if (rows) rows.close();
|
|
209
|
+
if (db) db.close();
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 3. Properties API (Ti.App.Properties)
|
|
214
|
+
|
|
215
|
+
### Overview
|
|
216
|
+
Lightweight key-value storage for simple data types. Loaded into memory at launch for fast access.
|
|
217
|
+
|
|
218
|
+
**Warning**: No hard limit, but all properties load into memory - avoid storing large data.
|
|
219
|
+
|
|
220
|
+
### Data Type Methods
|
|
221
|
+
|
|
222
|
+
| Type | Get Method | Set Method |
|
|
223
|
+
| ------ | -------------------------- | ------------------------ |
|
|
224
|
+
| String | `getString(name, default)` | `setString(name, value)` |
|
|
225
|
+
| Int | `getInt(name, default)` | `setInt(name, value)` |
|
|
226
|
+
| Double | `getDouble(name, default)` | `setDouble(name, value)` |
|
|
227
|
+
| Bool | `getBool(name, default)` | `setBool(name, value)` |
|
|
228
|
+
| List | `getList(name, default)` | `setList(name, value)` |
|
|
229
|
+
|
|
230
|
+
### Usage Examples
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
// Set values
|
|
234
|
+
Ti.App.Properties.setString('username', 'john');
|
|
235
|
+
Ti.App.Properties.setInt('loginCount', 5);
|
|
236
|
+
Ti.App.Properties.setBool('isLoggedIn', true);
|
|
237
|
+
Ti.App.Properties.setDouble('price', 19.99);
|
|
238
|
+
Ti.App.Properties.setList('favorites', ['item1', 'item2']);
|
|
239
|
+
|
|
240
|
+
// Get values (with defaults)
|
|
241
|
+
const username = Ti.App.Properties.getString('username', 'guest');
|
|
242
|
+
const count = Ti.App.Properties.getInt('loginCount', 0);
|
|
243
|
+
|
|
244
|
+
// Check if property exists
|
|
245
|
+
if (Ti.App.Properties.hasProperty('username')) {
|
|
246
|
+
// ...
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Remove property
|
|
250
|
+
Ti.App.Properties.removeProperty('username');
|
|
251
|
+
|
|
252
|
+
// List all properties
|
|
253
|
+
const allProps = Ti.App.Properties.listProperties();
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Storing Complex Objects as JSON
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
// Store object as JSON string
|
|
260
|
+
const data = { city: 'Mountain View', temp: 72 };
|
|
261
|
+
Ti.App.Properties.setString('weatherData', JSON.stringify(data));
|
|
262
|
+
|
|
263
|
+
// Retrieve and parse
|
|
264
|
+
const stored = Ti.App.Properties.getString('weatherData', '{}');
|
|
265
|
+
const weather = JSON.parse(stored);
|
|
266
|
+
Ti.API.info(weather.city); // 'Mountain View'
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Platform Storage
|
|
270
|
+
- **iOS**: `NSUserDefaults` in `.plist` file
|
|
271
|
+
- **Android**: XML file at `/data/data/com.domain.app/shared_prefs/titanium.xml`
|
|
272
|
+
|
|
273
|
+
## 4. Advanced Data Manipulation (Buffer, Codec, and Streams)
|
|
274
|
+
|
|
275
|
+
For binary data handling, character encoding, and large file streams, refer to the detailed guide:
|
|
276
|
+
|
|
277
|
+
- [Buffer, Codec, and Streams](./buffer-codec-streams.md): Using `Ti.Buffer`, `Ti.Codec` for numbers/strings, and efficient chunk-based reading.
|
|
278
|
+
|
|
279
|
+
## 5. Choosing a Persistence Strategy
|
|
280
|
+
|
|
281
|
+
### Decision Guide
|
|
282
|
+
|
|
283
|
+
| Scenario | Recommended Approach |
|
|
284
|
+
| ---------------------------------- | ---------------------------------------- |
|
|
285
|
+
| User settings/preferences | `Ti.App.Properties` |
|
|
286
|
+
| Small config data (< 100KB) | `Ti.App.Properties` with JSON |
|
|
287
|
+
| Structured relational data | SQLite |
|
|
288
|
+
| Large binary data (images, videos) | Filesystem |
|
|
289
|
+
| Downloaded content cache | Filesystem (`applicationCacheDirectory`) |
|
|
290
|
+
| Temporary processing data | Filesystem (`tempDirectory`) |
|
|
291
|
+
| User-generated files | Filesystem (`applicationDataDirectory`) |
|
|
292
|
+
| Offline-first app data | SQLite + Filesystem combo |
|
|
293
|
+
|
|
294
|
+
### Best Practices
|
|
295
|
+
|
|
296
|
+
1. **Properties API**: Use only for small, frequently-accessed config data
|
|
297
|
+
2. **SQLite**: Always close connections and result sets; use parameterized queries
|
|
298
|
+
3. **Filesystem**: Check external storage availability on Android; handle case sensitivity
|
|
299
|
+
4. **Streams**: Use for large file operations to avoid memory issues
|
|
300
|
+
5. **Hybrid Approach**: Store metadata in SQLite, file paths in records, actual files on filesystem
|
|
301
|
+
6. **Cleanup**: Implement cleanup for temp files and cache; don't let them accumulate
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Location Services and Maps
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Location Services and Maps](#location-services-and-maps)
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [1. GPS Position Tracking](#1-gps-position-tracking)
|
|
8
|
+
- [FusedLocationProvider (Android)](#fusedlocationprovider-android)
|
|
9
|
+
- [Accuracy Configuration](#accuracy-configuration)
|
|
10
|
+
- [Android Configuration Modes](#android-configuration-modes)
|
|
11
|
+
- [One-Time Position](#one-time-position)
|
|
12
|
+
- [Continuous Monitoring](#continuous-monitoring)
|
|
13
|
+
- [Lifecycle Management (Critical for Battery)](#lifecycle-management-critical-for-battery)
|
|
14
|
+
- [Compass/Heading](#compassheading)
|
|
15
|
+
- [Geocoding](#geocoding)
|
|
16
|
+
- [Forward Geocoding (Address → Coordinates)](#forward-geocoding-address--coordinates)
|
|
17
|
+
- [Reverse Geocoding (Coordinates → Places)](#reverse-geocoding-coordinates--places)
|
|
18
|
+
- [2. Native Maps (Platform-Specific Details)](#2-native-maps-platform-specific-details)
|
|
19
|
+
- [Common Map Patterns](#common-map-patterns)
|
|
20
|
+
- [Add Annotation After Map Creation](#add-annotation-after-map-creation)
|
|
21
|
+
- [Remove Annotation](#remove-annotation)
|
|
22
|
+
- [Remove All Annotations](#remove-all-annotations)
|
|
23
|
+
- [Select Annotation Programmatically](#select-annotation-programmatically)
|
|
24
|
+
- [Deselect Annotation](#deselect-annotation)
|
|
25
|
+
- [Set Region with Animation](#set-region-with-animation)
|
|
26
|
+
- [Zoom to Annotations](#zoom-to-annotations)
|
|
27
|
+
- [Best Practices](#best-practices)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 1. GPS Position Tracking
|
|
32
|
+
|
|
33
|
+
### FusedLocationProvider (Android)
|
|
34
|
+
Since TiSDK 7.1.0, Titanium supports `FusedLocationProvider` for significant battery savings.
|
|
35
|
+
**Requirement**: Include the `ti.playservices` module in your project.
|
|
36
|
+
|
|
37
|
+
### Accuracy Configuration
|
|
38
|
+
|
|
39
|
+
**iOS Accuracy Levels:**
|
|
40
|
+
- `ACCURACY_BEST` - Highest power (GPS)
|
|
41
|
+
- `ACCURACY_NEAREST_TEN_METERS` - Medium-high power
|
|
42
|
+
- `ACCURACY_HUNDRED_METERS` - Medium power
|
|
43
|
+
- `ACCURACY_KILOMETER` - Low power
|
|
44
|
+
- `ACCURACY_THREE_KILOMETERS` - Lowest power (cell/wifi)
|
|
45
|
+
|
|
46
|
+
**Key Properties:**
|
|
47
|
+
```javascript
|
|
48
|
+
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_BEST;
|
|
49
|
+
Ti.Geolocation.distanceFilter = 10; // meters - only fire if moved X meters
|
|
50
|
+
Ti.Geolocation.headingFilter = 5; // degrees - only fire if heading changed X degrees
|
|
51
|
+
Ti.Geolocation.preferredProvider = Ti.Geolocation.PROVIDER_GPS; // or PROVIDER_NETWORK
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Android Configuration Modes
|
|
55
|
+
|
|
56
|
+
**Simple Mode** (ACCURACY_HIGH/LOW):
|
|
57
|
+
```javascript
|
|
58
|
+
Ti.Geolocation.accuracy = Ti.Geolocation.ACCURACY_HIGH;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Manual Mode** (fine-grained control):
|
|
62
|
+
```javascript
|
|
63
|
+
const providerGps = Ti.Geolocation.Android.createLocationProvider({
|
|
64
|
+
name: Ti.Geolocation.PROVIDER_GPS,
|
|
65
|
+
minUpdateDistance: 0.0,
|
|
66
|
+
minUpdateTime: 0
|
|
67
|
+
});
|
|
68
|
+
Ti.Geolocation.Android.addLocationProvider(providerGps);
|
|
69
|
+
Ti.Geolocation.Android.manualMode = true;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### One-Time Position
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
if (Ti.Geolocation.locationServicesEnabled) {
|
|
76
|
+
Ti.Geolocation.getCurrentPosition((e) => {
|
|
77
|
+
if (e.error) {
|
|
78
|
+
Ti.API.error(`Error: ${e.error}`);
|
|
79
|
+
} else {
|
|
80
|
+
const coords = e.coords;
|
|
81
|
+
// { latitude, longitude, altitude, accuracy, heading, speed, timestamp }
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Continuous Monitoring
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
Ti.Geolocation.addEventListener('location', (e) => {
|
|
91
|
+
if (e.error) {
|
|
92
|
+
Ti.API.error(`Error: ${e.error}`);
|
|
93
|
+
} else {
|
|
94
|
+
Ti.API.info(`${e.coords.latitude}, ${e.coords.longitude}`);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Lifecycle Management (Critical for Battery)
|
|
100
|
+
|
|
101
|
+
**Android Activity Events:**
|
|
102
|
+
```javascript
|
|
103
|
+
let locationAdded = false;
|
|
104
|
+
const handleLocation = (e) => {
|
|
105
|
+
if (!e.error) {
|
|
106
|
+
Ti.API.info(e.coords);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
function addHandler() {
|
|
111
|
+
if (!locationAdded) {
|
|
112
|
+
Ti.Geolocation.addEventListener('location', handleLocation);
|
|
113
|
+
locationAdded = true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function removeHandler() {
|
|
118
|
+
if (locationAdded) {
|
|
119
|
+
Ti.Geolocation.removeEventListener('location', handleLocation);
|
|
120
|
+
locationAdded = false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Add listeners
|
|
125
|
+
addHandler();
|
|
126
|
+
|
|
127
|
+
const activity = Ti.Android.currentActivity;
|
|
128
|
+
activity.addEventListener('destroy', removeHandler);
|
|
129
|
+
activity.addEventListener('pause', removeHandler); // Stop when in background
|
|
130
|
+
activity.addEventListener('resume', addHandler); // Resume when foreground
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Compass/Heading
|
|
134
|
+
|
|
135
|
+
```javascript
|
|
136
|
+
// One-time heading
|
|
137
|
+
Ti.Geolocation.getCurrentHeading((e) => {
|
|
138
|
+
Ti.API.info(e.heading.magneticHeading); // degrees from magnetic north
|
|
139
|
+
Ti.API.info(e.heading.trueHeading); // degrees from true north
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Continuous heading monitoring
|
|
143
|
+
Ti.Geolocation.addEventListener('heading', (e) => {
|
|
144
|
+
if (!e.error) {
|
|
145
|
+
Ti.API.info(`Heading: ${e.heading.magneticHeading}`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Geocoding
|
|
153
|
+
|
|
154
|
+
### Forward Geocoding (Address → Coordinates)
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
Ti.Geolocation.forwardGeocoder('440 Bernardo Ave Mountain View CA', (e) => {
|
|
158
|
+
if (e.success) {
|
|
159
|
+
Ti.API.info(`Lat: ${e.latitude}, Lon: ${e.longitude}`);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Reverse Geocoding (Coordinates → Places)
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
Ti.Geolocation.reverseGeocoder(37.389569, -122.050212, (e) => {
|
|
168
|
+
if (e.success) {
|
|
169
|
+
e.places.forEach((place) => {
|
|
170
|
+
Ti.API.info(place.address); // Full address
|
|
171
|
+
Ti.API.info(place.city); // City name
|
|
172
|
+
Ti.API.info(place.country); // Country
|
|
173
|
+
Ti.API.info(place.zipcode); // Postal code
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## 2. Native Maps (Platform-Specific Details)
|
|
180
|
+
|
|
181
|
+
Due to the complexity of modern native maps, refer to the detailed guides:
|
|
182
|
+
|
|
183
|
+
- [Google Maps v2 for Android](./google-maps-v2.md): API Keys configuration, Google Play Services, and advanced controls.
|
|
184
|
+
- [iOS Map Kit](./ios-map-kit.md): 3D Camera, system buttons, and Info.plist configuration.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Common Map Patterns
|
|
189
|
+
|
|
190
|
+
### Add Annotation After Map Creation
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
mapview.addAnnotation(annotation);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Remove Annotation
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
mapview.removeAnnotation(annotation);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Remove All Annotations
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
mapview.removeAllAnnotations();
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Select Annotation Programmatically
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
mapview.selectAnnotation(annotation);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Deselect Annotation
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
mapview.deselectAnnotation(annotation);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Set Region with Animation
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
mapview.setLocation({
|
|
224
|
+
latitude: 37.389569,
|
|
225
|
+
longitude: -122.050212,
|
|
226
|
+
animate: true
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Or for region
|
|
230
|
+
mapview.setRegion({
|
|
231
|
+
latitude: 37.389569,
|
|
232
|
+
longitude: -122.050212,
|
|
233
|
+
latitudeDelta: 0.05,
|
|
234
|
+
longitudeDelta: 0.05,
|
|
235
|
+
animate: true
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Zoom to Annotations
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
mapview.showAnnotations([annotation1, annotation2], true); // true = animate
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Best Practices
|
|
246
|
+
|
|
247
|
+
1. **Battery Life**: Always remove location listeners when not needed. Use `distanceFilter` to reduce updates.
|
|
248
|
+
2. **Accuracy**: Use the lowest accuracy that meets your needs.
|
|
249
|
+
3. **Permissions**: Check permissions before requesting location. Handle denial gracefully.
|
|
250
|
+
4. **Maps on Android**: Only one map view per application (legacy). Use ti.map module for multiple views.
|
|
251
|
+
5. **API Keys**: Google Maps API key required for Android (both debug and production).
|
|
252
|
+
6. **User Location**: Requires location permissions (`NSLocationWhenInUseUsageDescription` for iOS).
|