@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,658 @@
|
|
|
1
|
+
# Android Platform Deep Dives
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Android Platform Deep Dives](#android-platform-deep-dives)
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [1. Android Intent Filters (Advanced)](#1-android-intent-filters-advanced)
|
|
8
|
+
- [Critical Step: Copy Root Activity](#critical-step-copy-root-activity)
|
|
9
|
+
- [Retrieving Intent Data](#retrieving-intent-data)
|
|
10
|
+
- [2. Broadcast Intents with Permissions](#2-broadcast-intents-with-permissions)
|
|
11
|
+
- [Sending with Permission](#sending-with-permission)
|
|
12
|
+
- [Declaring Permission in tiapp.xml](#declaring-permission-in-tiappxml)
|
|
13
|
+
- [3. FusedLocationProvider (TiSDK 7.1.0+)](#3-fusedlocationprovider-tisdk-710)
|
|
14
|
+
- [4. Android Intents](#4-android-intents)
|
|
15
|
+
- [Overview](#overview)
|
|
16
|
+
- [Intent Structure](#intent-structure)
|
|
17
|
+
- [Creating Intents](#creating-intents)
|
|
18
|
+
- [Simple Intent (Action only)](#simple-intent-action-only)
|
|
19
|
+
- [Intent with Action and Data](#intent-with-action-and-data)
|
|
20
|
+
- [Intent with Extras](#intent-with-extras)
|
|
21
|
+
- [Common Use Cases](#common-use-cases)
|
|
22
|
+
- [Open URL in Browser](#open-url-in-browser)
|
|
23
|
+
- [Dial Phone Number](#dial-phone-number)
|
|
24
|
+
- [Send Email](#send-email)
|
|
25
|
+
- [Share Content](#share-content)
|
|
26
|
+
- [Open PDF File](#open-pdf-file)
|
|
27
|
+
- [Starting Other Apps](#starting-other-apps)
|
|
28
|
+
- [2. Intent Filters](#2-intent-filters)
|
|
29
|
+
- [Overview](#overview-1)
|
|
30
|
+
- [Configuring in tiapp.xml](#configuring-in-tiappxml)
|
|
31
|
+
- [Handling Incoming Intents](#handling-incoming-intents)
|
|
32
|
+
- [Get Intent Data on Startup](#get-intent-data-on-startup)
|
|
33
|
+
- [Listen for New Intents (Activity Restart)](#listen-for-new-intents-activity-restart)
|
|
34
|
+
- [Deep Linking Example](#deep-linking-example)
|
|
35
|
+
- [3. Broadcast Intents and Receivers](#3-broadcast-intents-and-receivers)
|
|
36
|
+
- [Overview](#overview-2)
|
|
37
|
+
- [System Broadcasts](#system-broadcasts)
|
|
38
|
+
- [Registering Broadcast Receivers](#registering-broadcast-receivers)
|
|
39
|
+
- [Dynamic Registration (in code)](#dynamic-registration-in-code)
|
|
40
|
+
- [Network Change Listener](#network-change-listener)
|
|
41
|
+
- [Sending Custom Broadcasts](#sending-custom-broadcasts)
|
|
42
|
+
- [Receiver for Custom Broadcast](#receiver-for-custom-broadcast)
|
|
43
|
+
- [Boot Receiver](#boot-receiver)
|
|
44
|
+
- [4. Android Services](#4-android-services)
|
|
45
|
+
- [Overview](#overview-3)
|
|
46
|
+
- [Service Types](#service-types)
|
|
47
|
+
- [Creating a Service](#creating-a-service)
|
|
48
|
+
- [IntentService](#intentservice)
|
|
49
|
+
- [Foreground Service](#foreground-service)
|
|
50
|
+
- [Service Lifecycle Management](#service-lifecycle-management)
|
|
51
|
+
- [Inter-Service Communication](#inter-service-communication)
|
|
52
|
+
- [5. Android Permissions](#5-android-permissions)
|
|
53
|
+
- [Runtime Permissions (Android 6.0+)](#runtime-permissions-android-60)
|
|
54
|
+
- [Common Dangerous Permissions](#common-dangerous-permissions)
|
|
55
|
+
- [Best Practices](#best-practices)
|
|
56
|
+
- [Common Dangerous Permissions](#common-dangerous-permissions-1)
|
|
57
|
+
- [Best Practices](#best-practices-1)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 1. Android Intent Filters (Advanced)
|
|
62
|
+
|
|
63
|
+
To allow your app to receive implicit intents (e.g., opening a PDF file or a web link), you must register the filter in the manifest.
|
|
64
|
+
|
|
65
|
+
### Critical Step: Copy Root Activity
|
|
66
|
+
Before declaring an `intent-filter`, you must copy the `<activity>` node of your main activity from `build/android/AndroidManifest.xml` to the `<android>` section of your `tiapp.xml`:
|
|
67
|
+
|
|
68
|
+
```xml
|
|
69
|
+
<android xmlns:android="http://schemas.android.com/apk/res/android">
|
|
70
|
+
<manifest>
|
|
71
|
+
<application>
|
|
72
|
+
<!-- Copy this from build/android/AndroidManifest.xml -->
|
|
73
|
+
<activity android:name=".YourAppActivity" android:label="My App" android:configChanges="keyboardHidden|orientation">
|
|
74
|
+
<intent-filter>
|
|
75
|
+
<action android:name="android.intent.action.MAIN" />
|
|
76
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
77
|
+
</intent-filter>
|
|
78
|
+
|
|
79
|
+
<!-- Your new filter here -->
|
|
80
|
+
<intent-filter android:label="Open with My App">
|
|
81
|
+
<action android:name="android.intent.action.VIEW" />
|
|
82
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
83
|
+
<data android:mimeType="application/pdf" />
|
|
84
|
+
</intent-filter>
|
|
85
|
+
</activity>
|
|
86
|
+
</application>
|
|
87
|
+
</manifest>
|
|
88
|
+
</android>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Retrieving Intent Data
|
|
92
|
+
```javascript
|
|
93
|
+
const intent = Ti.Android.currentActivity.getIntent();
|
|
94
|
+
if (intent.hasExtra(Ti.Android.EXTRA_TEXT)) {
|
|
95
|
+
const sharedText = intent.getStringExtra(Ti.Android.EXTRA_TEXT);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 2. Broadcast Intents with Permissions
|
|
100
|
+
|
|
101
|
+
You can restrict who receives your broadcast messages for enhanced security.
|
|
102
|
+
|
|
103
|
+
### Sending with Permission
|
|
104
|
+
```javascript
|
|
105
|
+
const intent = Ti.Android.createBroadcastIntent({
|
|
106
|
+
action: 'com.mycompany.SECURE_ACTION'
|
|
107
|
+
});
|
|
108
|
+
// Only apps with the permission 'com.mycompany.SPECIAL_PERMISSION' will receive it
|
|
109
|
+
Ti.Android.currentActivity.sendBroadcastWithPermission(intent, 'com.mycompany.SPECIAL_PERMISSION');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Declaring Permission in tiapp.xml
|
|
113
|
+
```xml
|
|
114
|
+
<android>
|
|
115
|
+
<manifest>
|
|
116
|
+
<permission android:name="com.mycompany.SPECIAL_PERMISSION" />
|
|
117
|
+
<uses-permission android:name="com.mycompany.SPECIAL_PERMISSION" />
|
|
118
|
+
</manifest>
|
|
119
|
+
</android>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 3. FusedLocationProvider (TiSDK 7.1.0+)
|
|
123
|
+
|
|
124
|
+
For battery-efficient location tracking on Android, use the "fused" provider.
|
|
125
|
+
|
|
126
|
+
**Requirement**: Include the `ti.playservices` module in your project.
|
|
127
|
+
```xml
|
|
128
|
+
<module platform="android">ti.playservices</module>
|
|
129
|
+
```
|
|
130
|
+
Titanium will automatically switch to Google Play Services for geolocation, optimizing power consumption.
|
|
131
|
+
|
|
132
|
+
## 4. Android Intents
|
|
133
|
+
|
|
134
|
+
### Overview
|
|
135
|
+
Intents are message objects that specify actions to perform. They can start activities, broadcasts, or services.
|
|
136
|
+
|
|
137
|
+
### Intent Structure
|
|
138
|
+
- **Action**: What to do (e.g., `ACTION_VIEW`, `ACTION_SEND`)
|
|
139
|
+
- **Data**: URI operating on (e.g., URL, file path)
|
|
140
|
+
- **Type**: MIME type of data
|
|
141
|
+
- **Category**: Additional categorization
|
|
142
|
+
- **Extras**: Key-value pairs for additional data
|
|
143
|
+
|
|
144
|
+
### Creating Intents
|
|
145
|
+
|
|
146
|
+
#### Simple Intent (Action only)
|
|
147
|
+
```javascript
|
|
148
|
+
const intent = Ti.Android.createIntent({
|
|
149
|
+
action: Ti.Android.ACTION_VIEW
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Intent with Action and Data
|
|
154
|
+
```javascript
|
|
155
|
+
const intent = Ti.Android.createIntent({
|
|
156
|
+
action: Ti.Android.ACTION_VIEW,
|
|
157
|
+
data: 'https://titaniumsdk.com'
|
|
158
|
+
});
|
|
159
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Intent with Extras
|
|
163
|
+
```javascript
|
|
164
|
+
const intent = Ti.Android.createIntent({
|
|
165
|
+
action: 'com.example.MY_ACTION',
|
|
166
|
+
type: 'text/plain'
|
|
167
|
+
});
|
|
168
|
+
intent.addExtra('message', 'Hello from Titanium');
|
|
169
|
+
intent.addExtra('count', 42);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Common Use Cases
|
|
173
|
+
|
|
174
|
+
#### Open URL in Browser
|
|
175
|
+
```javascript
|
|
176
|
+
const intent = Ti.Android.createIntent({
|
|
177
|
+
action: Ti.Android.ACTION_VIEW,
|
|
178
|
+
data: 'https://www.example.com'
|
|
179
|
+
});
|
|
180
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Dial Phone Number
|
|
184
|
+
```javascript
|
|
185
|
+
const intent = Ti.Android.createIntent({
|
|
186
|
+
action: Ti.Android.ACTION_DIAL,
|
|
187
|
+
data: 'tel:5551234'
|
|
188
|
+
});
|
|
189
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### Send Email
|
|
193
|
+
```javascript
|
|
194
|
+
const intent = Ti.Android.createIntent({
|
|
195
|
+
action: Ti.Android.ACTION_SENDTO,
|
|
196
|
+
data: 'mailto:user@example.com'
|
|
197
|
+
});
|
|
198
|
+
intent.addExtra(Ti.Android.EXTRA_SUBJECT, 'Hello');
|
|
199
|
+
intent.addExtra(Ti.Android.EXTRA_TEXT, 'Email body');
|
|
200
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### Share Content
|
|
204
|
+
```javascript
|
|
205
|
+
const intent = Ti.Android.createIntent({
|
|
206
|
+
action: Ti.Android.ACTION_SEND,
|
|
207
|
+
type: 'text/plain'
|
|
208
|
+
});
|
|
209
|
+
intent.addExtra(Ti.Android.EXTRA_TEXT, 'Check this out!');
|
|
210
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Open PDF File
|
|
214
|
+
```javascript
|
|
215
|
+
const intent = Ti.Android.createIntent({
|
|
216
|
+
action: Ti.Android.ACTION_VIEW,
|
|
217
|
+
type: 'application/pdf',
|
|
218
|
+
data: file.nativePath // Ti.Filesystem.File object
|
|
219
|
+
});
|
|
220
|
+
intent.addFlags(Ti.Android.FLAG_GRANT_READ_URI_PERMISSION);
|
|
221
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Starting Other Apps
|
|
225
|
+
```javascript
|
|
226
|
+
// Open specific app by package name
|
|
227
|
+
const intent = Ti.Android.createIntent({
|
|
228
|
+
action: Ti.Android.ACTION_MAIN,
|
|
229
|
+
packageName: 'com.example.anotherapp',
|
|
230
|
+
className: 'com.example.anotherapp.MainActivity'
|
|
231
|
+
});
|
|
232
|
+
try {
|
|
233
|
+
Ti.Android.currentActivity.startActivity(intent);
|
|
234
|
+
} catch (e) {
|
|
235
|
+
Ti.API.error(`App not installed: ${e.message}`);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## 2. Intent Filters
|
|
240
|
+
|
|
241
|
+
### Overview
|
|
242
|
+
Intent Filters advertise your app's capability to handle certain actions and data types. Enable deep linking, file handling, and inter-app communication.
|
|
243
|
+
|
|
244
|
+
### Configuring in tiapp.xml
|
|
245
|
+
|
|
246
|
+
```xml
|
|
247
|
+
<android>
|
|
248
|
+
<manifest>
|
|
249
|
+
<application>
|
|
250
|
+
<activity>
|
|
251
|
+
<intent-filter>
|
|
252
|
+
<action android:name="android.intent.action.VIEW"/>
|
|
253
|
+
<category android:name="android.intent.category.DEFAULT"/>
|
|
254
|
+
<category android:name="android.intent.category.BROWSABLE"/>
|
|
255
|
+
<data android:scheme="myapp"/>
|
|
256
|
+
</intent-filter>
|
|
257
|
+
|
|
258
|
+
<!-- Handle PDF files -->
|
|
259
|
+
<intent-filter>
|
|
260
|
+
<action android:name="android.intent.action.VIEW"/>
|
|
261
|
+
<category android:name="android.intent.category.DEFAULT"/>
|
|
262
|
+
<data android:mimeType="application/pdf"/>
|
|
263
|
+
</intent-filter>
|
|
264
|
+
|
|
265
|
+
<!-- Handle HTTP URLs -->
|
|
266
|
+
<intent-filter>
|
|
267
|
+
<action android:name="android.intent.action.VIEW"/>
|
|
268
|
+
<category android:name="android.intent.category.DEFAULT"/>
|
|
269
|
+
<category android:name="android.intent.category.BROWSABLE"/>
|
|
270
|
+
<data android:scheme="http" android:host="www.example.com"/>
|
|
271
|
+
</intent-filter>
|
|
272
|
+
</activity>
|
|
273
|
+
</application>
|
|
274
|
+
</manifest>
|
|
275
|
+
</android>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Handling Incoming Intents
|
|
279
|
+
|
|
280
|
+
#### Get Intent Data on Startup
|
|
281
|
+
```javascript
|
|
282
|
+
const activity = Ti.Android.currentActivity;
|
|
283
|
+
const intent = activity.getIntent();
|
|
284
|
+
|
|
285
|
+
if (intent) {
|
|
286
|
+
const action = intent.getAction();
|
|
287
|
+
const data = intent.getData();
|
|
288
|
+
|
|
289
|
+
if (data) {
|
|
290
|
+
Ti.API.info(`Received data: ${data}`);
|
|
291
|
+
// Handle URL or file path
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Get extras
|
|
295
|
+
const extra = intent.getStringExtra('key');
|
|
296
|
+
Ti.API.info(`Extra value: ${extra}`);
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
#### Listen for New Intents (Activity Restart)
|
|
301
|
+
```javascript
|
|
302
|
+
Ti.Android.currentActivity.addEventListener('newintent', (e) => {
|
|
303
|
+
const intent = e.intent;
|
|
304
|
+
const data = intent.getData();
|
|
305
|
+
Ti.API.info(`New intent received: ${data}`);
|
|
306
|
+
|
|
307
|
+
// Handle the new intent
|
|
308
|
+
handleDeepLink(data);
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Deep Linking Example
|
|
313
|
+
|
|
314
|
+
```xml
|
|
315
|
+
<!-- In tiapp.xml -->
|
|
316
|
+
<intent-filter>
|
|
317
|
+
<action android:name="android.intent.action.VIEW"/>
|
|
318
|
+
<category android:name="android.intent.category.DEFAULT"/>
|
|
319
|
+
<category android:name="android.intent.category.BROWSABLE"/>
|
|
320
|
+
<data android:scheme="myapp" android:host="product"/>
|
|
321
|
+
</intent-filter>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
```javascript
|
|
325
|
+
// In app.js
|
|
326
|
+
function handleDeepLink(url) {
|
|
327
|
+
// Parse URL like: myapp://product/123
|
|
328
|
+
const parts = url.split('/');
|
|
329
|
+
const productId = parts[parts.length - 1];
|
|
330
|
+
openProductScreen(productId);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Check on startup
|
|
334
|
+
const activity = Ti.Android.currentActivity;
|
|
335
|
+
const intent = activity.getIntent();
|
|
336
|
+
if (intent && intent.getData()) {
|
|
337
|
+
handleDeepLink(intent.getData());
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## 3. Broadcast Intents and Receivers
|
|
342
|
+
|
|
343
|
+
### Overview
|
|
344
|
+
Broadcast Intents allow system-wide or app-wide messaging. Apps can send broadcasts and register receivers to listen for them.
|
|
345
|
+
|
|
346
|
+
### System Broadcasts
|
|
347
|
+
|
|
348
|
+
Common system broadcasts:
|
|
349
|
+
- `android.intent.action.BATTERY_LOW` - Battery low warning
|
|
350
|
+
- `android.intent.action.BATTERY_CHANGED` - Battery status changed
|
|
351
|
+
- `android.intent.action.ACTION_POWER_CONNECTED` - Power connected
|
|
352
|
+
- `android.intent.action.ACTION_POWER_DISCONNECTED` - Power disconnected
|
|
353
|
+
- `android.intent.action.BOOT_COMPLETED` - System boot completed
|
|
354
|
+
- `android.net.conn.CONNECTIVITY_CHANGE` - Network connection changed
|
|
355
|
+
- `android.intent.action.USER_PRESENT` - User unlocked device
|
|
356
|
+
- `android.intent.action.PACKAGE_INSTALL` / `PACKAGE_REMOVED` - Package changes
|
|
357
|
+
|
|
358
|
+
### Registering Broadcast Receivers
|
|
359
|
+
|
|
360
|
+
#### Dynamic Registration (in code)
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
// Create receiver
|
|
364
|
+
const batteryReceiver = Ti.Android.createBroadcastReceiver({
|
|
365
|
+
onReceived: (e) => {
|
|
366
|
+
const level = e.intent.getIntExtra(Ti.Android.EXTRA_BATTERY_LEVEL, -1);
|
|
367
|
+
Ti.API.info(`Battery level: ${level}%`);
|
|
368
|
+
|
|
369
|
+
if (level < 20) {
|
|
370
|
+
showLowBatteryWarning();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// Register for battery low
|
|
376
|
+
Ti.Android.registerBroadcastReceiver(batteryReceiver, [
|
|
377
|
+
Ti.Android.ACTION_BATTERY_LOW
|
|
378
|
+
]);
|
|
379
|
+
|
|
380
|
+
// Later: Unregister when no longer needed
|
|
381
|
+
Ti.Android.unregisterBroadcastReceiver(batteryReceiver);
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### Network Change Listener
|
|
385
|
+
|
|
386
|
+
```javascript
|
|
387
|
+
const networkReceiver = Ti.Android.createBroadcastReceiver({
|
|
388
|
+
onReceived: (e) => {
|
|
389
|
+
const connectivityManager = Ti.Android.getSystemService(
|
|
390
|
+
Ti.Android.CONNECTIVITY_SERVICE
|
|
391
|
+
);
|
|
392
|
+
const networkInfo = connectivityManager.getActiveNetworkInfo();
|
|
393
|
+
|
|
394
|
+
if (networkInfo && networkInfo.isConnected()) {
|
|
395
|
+
Ti.API.info(`Network connected: ${networkInfo.getTypeName()}`);
|
|
396
|
+
// Retry pending operations
|
|
397
|
+
} else {
|
|
398
|
+
Ti.API.info('Network disconnected');
|
|
399
|
+
// Show offline mode
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
Ti.Android.registerBroadcastReceiver(networkReceiver, [
|
|
405
|
+
'android.net.conn.CONNECTIVITY_CHANGE'
|
|
406
|
+
]);
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Sending Custom Broadcasts
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
// Send broadcast within your app
|
|
413
|
+
const intent = Ti.Android.createIntent({
|
|
414
|
+
action: 'com.myapp.CUSTOM_EVENT'
|
|
415
|
+
});
|
|
416
|
+
intent.addExtra('data', 'Custom data here');
|
|
417
|
+
Ti.Android.currentActivity.sendBroadcast(intent);
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### Receiver for Custom Broadcast
|
|
421
|
+
|
|
422
|
+
```javascript
|
|
423
|
+
const customReceiver = Ti.Android.createBroadcastReceiver({
|
|
424
|
+
onReceived: (e) => {
|
|
425
|
+
const data = e.intent.getStringExtra('data');
|
|
426
|
+
Ti.API.info(`Received custom event: ${data}`);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
Ti.Android.registerBroadcastReceiver(customReceiver, [
|
|
431
|
+
'com.myapp.CUSTOM_EVENT'
|
|
432
|
+
]);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Boot Receiver
|
|
436
|
+
|
|
437
|
+
**In tiapp.xml**:
|
|
438
|
+
```xml
|
|
439
|
+
<android>
|
|
440
|
+
<manifest>
|
|
441
|
+
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
|
442
|
+
<application>
|
|
443
|
+
<receiver
|
|
444
|
+
android:name="com.myapp.BootReceiver"
|
|
445
|
+
android:enabled="true">
|
|
446
|
+
<intent-filter>
|
|
447
|
+
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
|
448
|
+
</intent-filter>
|
|
449
|
+
</receiver>
|
|
450
|
+
</application>
|
|
451
|
+
</manifest>
|
|
452
|
+
</android>
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## 4. Android Services
|
|
456
|
+
|
|
457
|
+
### Overview
|
|
458
|
+
Services are background components that run independently of the UI. Useful for long-running operations like music playback, location tracking, or network polling.
|
|
459
|
+
|
|
460
|
+
### Service Types
|
|
461
|
+
|
|
462
|
+
1. **Regular Service**: Runs in background until stopped
|
|
463
|
+
2. **IntentService**: Queues work requests and processes sequentially
|
|
464
|
+
3. **Foreground Service**: Shows persistent notification, higher priority
|
|
465
|
+
|
|
466
|
+
### Creating a Service
|
|
467
|
+
|
|
468
|
+
```javascript
|
|
469
|
+
// Create service
|
|
470
|
+
const service = Ti.Android.createService({
|
|
471
|
+
url: 'myservice.js',
|
|
472
|
+
interval: 60000 // Check every 60 seconds
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Start service
|
|
476
|
+
service.start();
|
|
477
|
+
|
|
478
|
+
// Stop service when done
|
|
479
|
+
service.stop();
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**myservice.js**:
|
|
483
|
+
```javascript
|
|
484
|
+
Ti.API.info('Service running');
|
|
485
|
+
|
|
486
|
+
// Perform work
|
|
487
|
+
const xhr = Ti.Network.createHTTPClient({
|
|
488
|
+
onload: () => {
|
|
489
|
+
Ti.API.info('Data updated');
|
|
490
|
+
// Send notification if needed
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
xhr.open('GET', 'https://api.example.com/update');
|
|
494
|
+
xhr.send();
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### IntentService
|
|
498
|
+
|
|
499
|
+
For one-off or queued work:
|
|
500
|
+
|
|
501
|
+
```javascript
|
|
502
|
+
const intent = Ti.Android.createServiceIntent({
|
|
503
|
+
url: 'backgroundtask.js'
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
// Start service (runs once and stops)
|
|
507
|
+
Ti.Android.startService(intent);
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
**backgroundtask.js**:
|
|
511
|
+
```javascript
|
|
512
|
+
// Do work
|
|
513
|
+
const result = processHeavyTask();
|
|
514
|
+
|
|
515
|
+
// Optionally send result back to activity
|
|
516
|
+
const broadcast = Ti.Android.createBroadcastReceiver({
|
|
517
|
+
onReceived: () => { /* ... */ }
|
|
518
|
+
});
|
|
519
|
+
// ...
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Foreground Service
|
|
523
|
+
|
|
524
|
+
For critical, long-running operations (must show notification):
|
|
525
|
+
|
|
526
|
+
```javascript
|
|
527
|
+
const notification = Ti.Android.createNotification({
|
|
528
|
+
contentTitle: 'Service Running',
|
|
529
|
+
contentText: 'Tracking location...',
|
|
530
|
+
tickerText: 'Service started',
|
|
531
|
+
icon: Ti.App.Android.R.drawable.app_icon
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
const intent = Ti.Android.createServiceIntent({
|
|
535
|
+
url: 'trackingservice.js'
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
intent.addFlags(Ti.Android.FLAG_ACTIVITY_CLEAR_TOP);
|
|
539
|
+
intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
|
|
540
|
+
|
|
541
|
+
// Start as foreground service
|
|
542
|
+
Ti.Android.startForegroundService(intent, 101, notification);
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
To stop:
|
|
546
|
+
```javascript
|
|
547
|
+
Ti.Android.stopForegroundService(intent);
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Service Lifecycle Management
|
|
551
|
+
|
|
552
|
+
**Important**: Always stop services when no longer needed to conserve resources.
|
|
553
|
+
|
|
554
|
+
```javascript
|
|
555
|
+
// In activity
|
|
556
|
+
Ti.Android.currentActivity.addEventListener('pause', () => {
|
|
557
|
+
// Optionally pause service
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
Ti.Android.currentActivity.addEventListener('destroy', () => {
|
|
561
|
+
// Always stop service
|
|
562
|
+
if (service) {
|
|
563
|
+
service.stop();
|
|
564
|
+
service = null;
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Inter-Service Communication
|
|
570
|
+
|
|
571
|
+
```javascript
|
|
572
|
+
// From activity to service
|
|
573
|
+
const intent = Ti.Android.createServiceIntent({
|
|
574
|
+
url: 'myservice.js'
|
|
575
|
+
});
|
|
576
|
+
intent.addExtra('command', 'pause');
|
|
577
|
+
Ti.Android.startService(intent);
|
|
578
|
+
|
|
579
|
+
// In service
|
|
580
|
+
const command = intent.getStringExtra('command');
|
|
581
|
+
if (command === 'pause') {
|
|
582
|
+
// Handle pause command
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
## 5. Android Permissions
|
|
587
|
+
|
|
588
|
+
### Runtime Permissions (Android 6.0+)
|
|
589
|
+
|
|
590
|
+
Dangerous permissions require runtime request:
|
|
591
|
+
|
|
592
|
+
```javascript
|
|
593
|
+
function checkPermission() {
|
|
594
|
+
const result = Ti.Android.checkSelfPermission(
|
|
595
|
+
Ti.Android.PERMISSION_ACCESS_FINE_LOCATION
|
|
596
|
+
);
|
|
597
|
+
|
|
598
|
+
if (result === Ti.Android.RESULTS.GRANTED) {
|
|
599
|
+
startLocationTracking();
|
|
600
|
+
} else {
|
|
601
|
+
Ti.Android.requestPermissions(
|
|
602
|
+
[Ti.Android.PERMISSION_ACCESS_FINE_LOCATION],
|
|
603
|
+
999, // Request code
|
|
604
|
+
(e) => {
|
|
605
|
+
if (e.granted[0] === true) {
|
|
606
|
+
startLocationTracking();
|
|
607
|
+
} else {
|
|
608
|
+
alert('Location permission denied');
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
checkPermission();
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### Common Dangerous Permissions
|
|
619
|
+
- `ACCESS_FINE_LOCATION` - GPS location
|
|
620
|
+
- `ACCESS_COARSE_LOCATION` - Network location
|
|
621
|
+
- `CAMERA` - Camera access
|
|
622
|
+
- `READ_EXTERNAL_STORAGE` - Read files
|
|
623
|
+
- `WRITE_EXTERNAL_STORAGE` - Write files
|
|
624
|
+
- `RECORD_AUDIO` - Microphone
|
|
625
|
+
- `CALL_PHONE` - Make phone calls
|
|
626
|
+
- `SEND_SMS` / `READ_SMS` - SMS access
|
|
627
|
+
|
|
628
|
+
## Best Practices
|
|
629
|
+
|
|
630
|
+
1. **Always unregister** broadcast receivers when no longer needed
|
|
631
|
+
2. **Stop services** explicitly to conserve battery
|
|
632
|
+
3. **Use IntentService** for one-off background tasks
|
|
633
|
+
4. **Use foreground services** for user-visible long operations
|
|
634
|
+
5. **Handle runtime permissions** gracefully on Android 6.0+
|
|
635
|
+
6. **Validate intent data** before processing
|
|
636
|
+
7. **Use proper Intent Flags** for navigation behavior
|
|
637
|
+
8. **Test intent filters** with ADB: `adb shell am start -W -a android.intent.action.VIEW -d "myapp://path"`
|
|
638
|
+
|
|
639
|
+
### Common Dangerous Permissions
|
|
640
|
+
- `ACCESS_FINE_LOCATION` - GPS location
|
|
641
|
+
- `ACCESS_COARSE_LOCATION` - Network location
|
|
642
|
+
- `CAMERA` - Camera access
|
|
643
|
+
- `READ_EXTERNAL_STORAGE` - Read files
|
|
644
|
+
- `WRITE_EXTERNAL_STORAGE` - Write files
|
|
645
|
+
- `RECORD_AUDIO` - Microphone
|
|
646
|
+
- `CALL_PHONE` - Make phone calls
|
|
647
|
+
- `SEND_SMS` / `READ_SMS` - SMS access
|
|
648
|
+
|
|
649
|
+
## Best Practices
|
|
650
|
+
|
|
651
|
+
1. **Always unregister** broadcast receivers when no longer needed
|
|
652
|
+
2. **Stop services** explicitly to conserve battery
|
|
653
|
+
3. **Use IntentService** for one-off background tasks
|
|
654
|
+
4. **Use foreground services** for user-visible long operations
|
|
655
|
+
5. **Handle runtime permissions** gracefully on Android 6.0+
|
|
656
|
+
6. **Validate intent data** before processing
|
|
657
|
+
7. **Use proper Intent Flags** for navigation behavior
|
|
658
|
+
8. **Test intent filters** with ADB: `adb shell am start -W -a android.intent.action.VIEW -d "myapp://path"`
|