@maccesar/titools 2.10.1 → 3.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-VERCEL-RESEARCH.md +23 -12
- package/README.md +81 -182
- package/agents/ti-pro.md +8 -14
- package/lib/cleanup.js +13 -0
- package/lib/commands/skills.js +2 -1
- package/lib/config.js +9 -11
- package/lib/platform.js +1 -1
- package/package.json +2 -3
- package/skills/purgetss/SKILL.md +44 -57
- package/skills/purgetss/references/EXAMPLES.md +8 -1
- package/skills/purgetss/references/app-branding.md +96 -16
- package/skills/purgetss/references/apply-directive.md +26 -1
- package/skills/purgetss/references/arbitrary-values.md +72 -2
- package/skills/purgetss/references/class-categories.md +1 -1
- package/skills/purgetss/references/cli-commands.md +37 -13
- package/skills/purgetss/references/customization-deep-dive.md +18 -11
- package/skills/purgetss/references/dynamic-component-creation.md +0 -1
- package/skills/purgetss/references/migration-guide.md +162 -1
- package/skills/purgetss/references/multi-density-images.md +69 -0
- package/skills/purgetss/references/version-history.md +82 -0
- package/skills/ti-expert/SKILL.md +1 -1
- package/skills/ti-ui/SKILL.md +1 -1
- package/skills/alloy-guides/SKILL.md +0 -190
- package/skills/alloy-guides/references/CLI_TASKS.md +0 -233
- package/skills/alloy-guides/references/CONCEPTS.md +0 -171
- package/skills/alloy-guides/references/CONTROLLERS.md +0 -279
- package/skills/alloy-guides/references/MODELS.md +0 -1214
- package/skills/alloy-guides/references/PURGETSS.md +0 -46
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +0 -235
- package/skills/alloy-guides/references/VIEWS_STYLES.md +0 -375
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
- package/skills/alloy-guides/references/VIEWS_XML.md +0 -581
- package/skills/alloy-guides/references/WIDGETS.md +0 -160
- package/skills/alloy-howtos/SKILL.md +0 -181
- package/skills/alloy-howtos/references/best_practices.md +0 -121
- package/skills/alloy-howtos/references/cli_reference.md +0 -230
- package/skills/alloy-howtos/references/config_files.md +0 -158
- package/skills/alloy-howtos/references/custom_tags.md +0 -148
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +0 -78
- package/skills/alloy-howtos/references/samples.md +0 -156
- package/skills/ti-api/SKILL.md +0 -109
- package/skills/ti-api/references/api-android.md +0 -675
- package/skills/ti-api/references/api-app-platform.md +0 -636
- package/skills/ti-api/references/api-core.md +0 -764
- package/skills/ti-api/references/api-data-network.md +0 -641
- package/skills/ti-api/references/api-media.md +0 -655
- package/skills/ti-api/references/api-modules-ble-bluetooth.md +0 -657
- package/skills/ti-api/references/api-modules-coremotion-urlsession.md +0 -411
- package/skills/ti-api/references/api-modules-map.md +0 -632
- package/skills/ti-api/references/api-modules-nfc.md +0 -725
- package/skills/ti-api/references/api-modules-social-misc.md +0 -526
- package/skills/ti-api/references/api-services.md +0 -700
- package/skills/ti-api/references/api-ui-android.md +0 -499
- package/skills/ti-api/references/api-ui-extras.md +0 -702
- package/skills/ti-api/references/api-ui-ios-animator.md +0 -378
- package/skills/ti-api/references/api-ui-ios.md +0 -756
- package/skills/ti-api/references/api-ui-lists.md +0 -581
- package/skills/ti-api/references/api-ui-text-input.md +0 -607
- package/skills/ti-api/references/api-ui-views.md +0 -572
- package/skills/ti-api/references/api-ui-windows-navigation.md +0 -676
- package/skills/ti-api/references/api-xml-global.md +0 -743
- package/skills/ti-guides/SKILL.md +0 -75
- package/skills/ti-guides/references/advanced-data-and-images.md +0 -155
- package/skills/ti-guides/references/android-manifest.md +0 -97
- package/skills/ti-guides/references/app-distribution.md +0 -373
- package/skills/ti-guides/references/application-frameworks.md +0 -366
- package/skills/ti-guides/references/cli-reference.md +0 -700
- package/skills/ti-guides/references/coding-best-practices.md +0 -150
- package/skills/ti-guides/references/commonjs-advanced.md +0 -279
- package/skills/ti-guides/references/hello-world.md +0 -99
- package/skills/ti-guides/references/hyperloop-native-access.md +0 -458
- package/skills/ti-guides/references/javascript-primer.md +0 -402
- package/skills/ti-guides/references/reserved-words.md +0 -36
- package/skills/ti-guides/references/resources.md +0 -172
- package/skills/ti-guides/references/style-and-conventions.md +0 -104
- package/skills/ti-guides/references/tiapp-config.md +0 -655
- package/skills/ti-howtos/SKILL.md +0 -143
- package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -609
- package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
- package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
- package/skills/ti-howtos/references/cross-platform-development.md +0 -358
- package/skills/ti-howtos/references/debugging-profiling.md +0 -473
- package/skills/ti-howtos/references/extending-titanium.md +0 -684
- package/skills/ti-howtos/references/google-maps-v2.md +0 -172
- package/skills/ti-howtos/references/ios-map-kit.md +0 -149
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -595
- package/skills/ti-howtos/references/local-data-sources.md +0 -310
- package/skills/ti-howtos/references/location-and-maps.md +0 -267
- package/skills/ti-howtos/references/media-apis.md +0 -268
- package/skills/ti-howtos/references/notification-services.md +0 -539
- package/skills/ti-howtos/references/remote-data-sources.md +0 -339
- package/skills/ti-howtos/references/tutorials.md +0 -552
- package/skills/ti-howtos/references/using-modules.md +0 -182
- package/skills/ti-howtos/references/web-content-integration.md +0 -288
- package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -125
|
@@ -1,609 +0,0 @@
|
|
|
1
|
-
# Android platform deep dives
|
|
2
|
-
|
|
3
|
-
## 1. Android intent filters (advanced)
|
|
4
|
-
|
|
5
|
-
To receive implicit intents (for example, opening a PDF file or a web link), register a filter in the manifest.
|
|
6
|
-
|
|
7
|
-
### Critical step: copy root activity
|
|
8
|
-
Before declaring an `intent-filter`, copy the `<activity>` node of your main activity from `build/android/AndroidManifest.xml` into the `<android>` section of your `tiapp.xml`:
|
|
9
|
-
|
|
10
|
-
```xml
|
|
11
|
-
<android xmlns:android="http://schemas.android.com/apk/res/android">
|
|
12
|
-
<manifest>
|
|
13
|
-
<application>
|
|
14
|
-
<!-- Copy this from build/android/AndroidManifest.xml -->
|
|
15
|
-
<activity android:name=".YourAppActivity" android:label="My App" android:configChanges="keyboardHidden|orientation">
|
|
16
|
-
<intent-filter>
|
|
17
|
-
<action android:name="android.intent.action.MAIN" />
|
|
18
|
-
<category android:name="android.intent.category.LAUNCHER" />
|
|
19
|
-
</intent-filter>
|
|
20
|
-
|
|
21
|
-
<!-- Your new filter here -->
|
|
22
|
-
<intent-filter android:label="Open with My App">
|
|
23
|
-
<action android:name="android.intent.action.VIEW" />
|
|
24
|
-
<category android:name="android.intent.category.DEFAULT" />
|
|
25
|
-
<data android:mimeType="application/pdf" />
|
|
26
|
-
</intent-filter>
|
|
27
|
-
</activity>
|
|
28
|
-
</application>
|
|
29
|
-
</manifest>
|
|
30
|
-
</android>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Retrieving intent data
|
|
34
|
-
```javascript
|
|
35
|
-
const intent = Ti.Android.currentActivity.getIntent();
|
|
36
|
-
if (intent.hasExtra(Ti.Android.EXTRA_TEXT)) {
|
|
37
|
-
const sharedText = intent.getStringExtra(Ti.Android.EXTRA_TEXT);
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## 2. Broadcast intents with permissions
|
|
42
|
-
|
|
43
|
-
You can restrict which apps receive your broadcast messages.
|
|
44
|
-
|
|
45
|
-
### Sending with permission
|
|
46
|
-
```javascript
|
|
47
|
-
const intent = Ti.Android.createBroadcastIntent({
|
|
48
|
-
action: 'com.mycompany.SECURE_ACTION'
|
|
49
|
-
});
|
|
50
|
-
// Only apps with the permission 'com.mycompany.SPECIAL_PERMISSION' will receive it
|
|
51
|
-
Ti.Android.currentActivity.sendBroadcastWithPermission(intent, 'com.mycompany.SPECIAL_PERMISSION');
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Declaring permission in tiapp.xml
|
|
55
|
-
```xml
|
|
56
|
-
<android>
|
|
57
|
-
<manifest>
|
|
58
|
-
<permission android:name="com.mycompany.SPECIAL_PERMISSION" />
|
|
59
|
-
<uses-permission android:name="com.mycompany.SPECIAL_PERMISSION" />
|
|
60
|
-
</manifest>
|
|
61
|
-
</android>
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## 3. FusedLocationProvider (TiSDK 7.1.0+)
|
|
65
|
-
|
|
66
|
-
For battery-efficient location tracking on Android, use the fused provider.
|
|
67
|
-
|
|
68
|
-
Requirement: include the `ti.playservices` module in your project.
|
|
69
|
-
```xml
|
|
70
|
-
<module platform="android">ti.playservices</module>
|
|
71
|
-
```
|
|
72
|
-
Titanium will switch to Google Play Services for geolocation, which reduces power consumption.
|
|
73
|
-
|
|
74
|
-
## 4. Android intents
|
|
75
|
-
|
|
76
|
-
### Overview
|
|
77
|
-
Intents are message objects that specify actions to perform. They can start activities, broadcasts, or services.
|
|
78
|
-
|
|
79
|
-
### Intent structure
|
|
80
|
-
- Action: what to do (for example, `ACTION_VIEW`, `ACTION_SEND`)
|
|
81
|
-
- Data: URI the intent operates on (URL, file path)
|
|
82
|
-
- Type: MIME type of data
|
|
83
|
-
- Category: additional categorization
|
|
84
|
-
- Extras: key-value pairs for additional data
|
|
85
|
-
|
|
86
|
-
### Creating intents
|
|
87
|
-
|
|
88
|
-
#### Simple intent (action only)
|
|
89
|
-
```javascript
|
|
90
|
-
const intent = Ti.Android.createIntent({
|
|
91
|
-
action: Ti.Android.ACTION_VIEW
|
|
92
|
-
});
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
#### Intent with action and data
|
|
96
|
-
```javascript
|
|
97
|
-
const intent = Ti.Android.createIntent({
|
|
98
|
-
action: Ti.Android.ACTION_VIEW,
|
|
99
|
-
data: 'https://titaniumsdk.com'
|
|
100
|
-
});
|
|
101
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
#### Intent with extras
|
|
105
|
-
```javascript
|
|
106
|
-
const intent = Ti.Android.createIntent({
|
|
107
|
-
action: 'com.example.MY_ACTION',
|
|
108
|
-
type: 'text/plain'
|
|
109
|
-
});
|
|
110
|
-
intent.putExtra('message', 'Hello from Titanium');
|
|
111
|
-
intent.putExtra('count', 42);
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Common use cases
|
|
115
|
-
|
|
116
|
-
#### Open URL in browser
|
|
117
|
-
```javascript
|
|
118
|
-
const intent = Ti.Android.createIntent({
|
|
119
|
-
action: Ti.Android.ACTION_VIEW,
|
|
120
|
-
data: 'https://www.example.com'
|
|
121
|
-
});
|
|
122
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
#### Dial phone number
|
|
126
|
-
```javascript
|
|
127
|
-
const intent = Ti.Android.createIntent({
|
|
128
|
-
action: Ti.Android.ACTION_DIAL,
|
|
129
|
-
data: 'tel:5551234'
|
|
130
|
-
});
|
|
131
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
#### Send email
|
|
135
|
-
```javascript
|
|
136
|
-
const intent = Ti.Android.createIntent({
|
|
137
|
-
action: Ti.Android.ACTION_SENDTO,
|
|
138
|
-
data: 'mailto:user@example.com'
|
|
139
|
-
});
|
|
140
|
-
intent.putExtra(Ti.Android.EXTRA_SUBJECT, 'Hello');
|
|
141
|
-
intent.putExtra(Ti.Android.EXTRA_TEXT, 'Email body');
|
|
142
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
#### Share content
|
|
146
|
-
```javascript
|
|
147
|
-
const intent = Ti.Android.createIntent({
|
|
148
|
-
action: Ti.Android.ACTION_SEND,
|
|
149
|
-
type: 'text/plain'
|
|
150
|
-
});
|
|
151
|
-
intent.putExtra(Ti.Android.EXTRA_TEXT, 'Check this out!');
|
|
152
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
#### Open PDF file
|
|
156
|
-
```javascript
|
|
157
|
-
const intent = Ti.Android.createIntent({
|
|
158
|
-
action: Ti.Android.ACTION_VIEW,
|
|
159
|
-
type: 'application/pdf',
|
|
160
|
-
data: file.nativePath // Ti.Filesystem.File object
|
|
161
|
-
});
|
|
162
|
-
intent.addFlags(Ti.Android.FLAG_GRANT_READ_URI_PERMISSION);
|
|
163
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Starting other apps
|
|
167
|
-
```javascript
|
|
168
|
-
// Open specific app by package name
|
|
169
|
-
const intent = Ti.Android.createIntent({
|
|
170
|
-
action: Ti.Android.ACTION_MAIN,
|
|
171
|
-
packageName: 'com.example.anotherapp',
|
|
172
|
-
className: 'com.example.anotherapp.MainActivity'
|
|
173
|
-
});
|
|
174
|
-
try {
|
|
175
|
-
Ti.Android.currentActivity.startActivity(intent);
|
|
176
|
-
} catch (e) {
|
|
177
|
-
Ti.API.error(`App not installed: ${e.message}`);
|
|
178
|
-
}
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### Intent chooser
|
|
182
|
-
Force the system to show an app chooser dialog (even if a default is set):
|
|
183
|
-
```javascript
|
|
184
|
-
const intent = Ti.Android.createIntent({
|
|
185
|
-
action: Ti.Android.ACTION_SEND,
|
|
186
|
-
type: 'text/plain'
|
|
187
|
-
});
|
|
188
|
-
intent.putExtra(Ti.Android.EXTRA_TEXT, 'Share this text');
|
|
189
|
-
|
|
190
|
-
Ti.Android.currentActivity.startActivity(
|
|
191
|
-
Ti.Android.createIntentChooser(intent, 'Share via...')
|
|
192
|
-
);
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
### Getting results from activities
|
|
196
|
-
```javascript
|
|
197
|
-
const intent = Ti.Android.createIntent({
|
|
198
|
-
action: 'android.media.action.IMAGE_CAPTURE'
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
Ti.Android.currentActivity.startActivityForResult(intent, (e) => {
|
|
202
|
-
if (e.resultCode === Ti.Android.RESULT_OK) {
|
|
203
|
-
const imageUri = e.intent.data;
|
|
204
|
-
Ti.API.info(`Captured image: ${imageUri}`);
|
|
205
|
-
} else if (e.resultCode === Ti.Android.RESULT_CANCELED) {
|
|
206
|
-
Ti.API.info('User canceled');
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
## 5. Intent filters
|
|
212
|
-
|
|
213
|
-
### Overview
|
|
214
|
-
Intent filters advertise your app's capability to handle certain actions and data types. They enable deep linking, file handling, and inter-app communication.
|
|
215
|
-
|
|
216
|
-
### Configuring in tiapp.xml
|
|
217
|
-
|
|
218
|
-
```xml
|
|
219
|
-
<android>
|
|
220
|
-
<manifest>
|
|
221
|
-
<application>
|
|
222
|
-
<activity>
|
|
223
|
-
<intent-filter>
|
|
224
|
-
<action android:name="android.intent.action.VIEW"/>
|
|
225
|
-
<category android:name="android.intent.category.DEFAULT"/>
|
|
226
|
-
<category android:name="android.intent.category.BROWSABLE"/>
|
|
227
|
-
<data android:scheme="myapp"/>
|
|
228
|
-
</intent-filter>
|
|
229
|
-
|
|
230
|
-
<!-- Handle PDF files -->
|
|
231
|
-
<intent-filter>
|
|
232
|
-
<action android:name="android.intent.action.VIEW"/>
|
|
233
|
-
<category android:name="android.intent.category.DEFAULT"/>
|
|
234
|
-
<data android:mimeType="application/pdf"/>
|
|
235
|
-
</intent-filter>
|
|
236
|
-
|
|
237
|
-
<!-- Handle HTTP URLs -->
|
|
238
|
-
<intent-filter>
|
|
239
|
-
<action android:name="android.intent.action.VIEW"/>
|
|
240
|
-
<category android:name="android.intent.category.DEFAULT"/>
|
|
241
|
-
<category android:name="android.intent.category.BROWSABLE"/>
|
|
242
|
-
<data android:scheme="http" android:host="www.example.com"/>
|
|
243
|
-
</intent-filter>
|
|
244
|
-
</activity>
|
|
245
|
-
</application>
|
|
246
|
-
</manifest>
|
|
247
|
-
</android>
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Handling incoming intents
|
|
251
|
-
|
|
252
|
-
#### Get intent data on startup
|
|
253
|
-
```javascript
|
|
254
|
-
const activity = Ti.Android.currentActivity;
|
|
255
|
-
const intent = activity.getIntent();
|
|
256
|
-
|
|
257
|
-
if (intent) {
|
|
258
|
-
const action = intent.getAction();
|
|
259
|
-
const data = intent.getData();
|
|
260
|
-
|
|
261
|
-
if (data) {
|
|
262
|
-
Ti.API.info(`Received data: ${data}`);
|
|
263
|
-
// Handle URL or file path
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Get extras
|
|
267
|
-
const extra = intent.getStringExtra('key');
|
|
268
|
-
Ti.API.info(`Extra value: ${extra}`);
|
|
269
|
-
}
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
#### Listen for new intents (activity restart)
|
|
273
|
-
```javascript
|
|
274
|
-
Ti.Android.currentActivity.addEventListener('newintent', (e) => {
|
|
275
|
-
const intent = e.intent;
|
|
276
|
-
const data = intent.getData();
|
|
277
|
-
Ti.API.info(`New intent received: ${data}`);
|
|
278
|
-
|
|
279
|
-
// Handle the new intent
|
|
280
|
-
handleDeepLink(data);
|
|
281
|
-
});
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### Deep linking example
|
|
285
|
-
|
|
286
|
-
```xml
|
|
287
|
-
<!-- In tiapp.xml -->
|
|
288
|
-
<intent-filter>
|
|
289
|
-
<action android:name="android.intent.action.VIEW"/>
|
|
290
|
-
<category android:name="android.intent.category.DEFAULT"/>
|
|
291
|
-
<category android:name="android.intent.category.BROWSABLE"/>
|
|
292
|
-
<data android:scheme="myapp" android:host="product"/>
|
|
293
|
-
</intent-filter>
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
```javascript
|
|
297
|
-
// In app.js
|
|
298
|
-
function handleDeepLink(url) {
|
|
299
|
-
// Parse URL like: myapp://product/123
|
|
300
|
-
const parts = url.split('/');
|
|
301
|
-
const productId = parts[parts.length - 1];
|
|
302
|
-
openProductScreen(productId);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Check on startup
|
|
306
|
-
const activity = Ti.Android.currentActivity;
|
|
307
|
-
const intent = activity.getIntent();
|
|
308
|
-
if (intent && intent.getData()) {
|
|
309
|
-
handleDeepLink(intent.getData());
|
|
310
|
-
}
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
## 6. Broadcast intents and receivers
|
|
314
|
-
|
|
315
|
-
### Overview
|
|
316
|
-
Broadcast intents allow system-wide or app-wide messaging. Apps can send broadcasts and register receivers to listen for them.
|
|
317
|
-
|
|
318
|
-
### System broadcasts
|
|
319
|
-
|
|
320
|
-
Common system broadcasts:
|
|
321
|
-
- `android.intent.action.BATTERY_LOW` - battery low warning
|
|
322
|
-
- `android.intent.action.BATTERY_CHANGED` - battery status changed
|
|
323
|
-
- `android.intent.action.ACTION_POWER_CONNECTED` - power connected
|
|
324
|
-
- `android.intent.action.ACTION_POWER_DISCONNECTED` - power disconnected
|
|
325
|
-
- `android.intent.action.BOOT_COMPLETED` - system boot completed
|
|
326
|
-
- `android.net.conn.CONNECTIVITY_CHANGE` - network connection changed
|
|
327
|
-
- `android.intent.action.USER_PRESENT` - user unlocked device
|
|
328
|
-
- `android.intent.action.PACKAGE_INSTALL` / `PACKAGE_REMOVED` - package changes
|
|
329
|
-
|
|
330
|
-
### Registering broadcast receivers
|
|
331
|
-
|
|
332
|
-
#### Dynamic registration (in code)
|
|
333
|
-
|
|
334
|
-
```javascript
|
|
335
|
-
// Create receiver
|
|
336
|
-
const batteryReceiver = Ti.Android.createBroadcastReceiver({
|
|
337
|
-
onReceived: (e) => {
|
|
338
|
-
const level = e.intent.getIntExtra(Ti.Android.EXTRA_BATTERY_LEVEL, -1);
|
|
339
|
-
Ti.API.info(`Battery level: ${level}%`);
|
|
340
|
-
|
|
341
|
-
if (level < 20) {
|
|
342
|
-
showLowBatteryWarning();
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
// Register for battery low
|
|
348
|
-
Ti.Android.registerBroadcastReceiver(batteryReceiver, [
|
|
349
|
-
Ti.Android.ACTION_BATTERY_LOW
|
|
350
|
-
]);
|
|
351
|
-
|
|
352
|
-
// Later: unregister when no longer needed
|
|
353
|
-
Ti.Android.unregisterBroadcastReceiver(batteryReceiver);
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
#### Network change listener
|
|
357
|
-
|
|
358
|
-
```javascript
|
|
359
|
-
const networkReceiver = Ti.Android.createBroadcastReceiver({
|
|
360
|
-
onReceived: (e) => {
|
|
361
|
-
const connectivityManager = Ti.Android.getSystemService(
|
|
362
|
-
Ti.Android.CONNECTIVITY_SERVICE
|
|
363
|
-
);
|
|
364
|
-
const networkInfo = connectivityManager.getActiveNetworkInfo();
|
|
365
|
-
|
|
366
|
-
if (networkInfo && networkInfo.isConnected()) {
|
|
367
|
-
Ti.API.info(`Network connected: ${networkInfo.getTypeName()}`);
|
|
368
|
-
// Retry pending operations
|
|
369
|
-
} else {
|
|
370
|
-
Ti.API.info('Network disconnected');
|
|
371
|
-
// Show offline mode
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
Ti.Android.registerBroadcastReceiver(networkReceiver, [
|
|
377
|
-
'android.net.conn.CONNECTIVITY_CHANGE'
|
|
378
|
-
]);
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### Sending custom broadcasts
|
|
382
|
-
|
|
383
|
-
```javascript
|
|
384
|
-
// Send broadcast within your app
|
|
385
|
-
const intent = Ti.Android.createIntent({
|
|
386
|
-
action: 'com.myapp.CUSTOM_EVENT'
|
|
387
|
-
});
|
|
388
|
-
intent.putExtra('data', 'Custom data here');
|
|
389
|
-
Ti.Android.currentActivity.sendBroadcast(intent);
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
#### Receiver for custom broadcast
|
|
393
|
-
|
|
394
|
-
```javascript
|
|
395
|
-
const customReceiver = Ti.Android.createBroadcastReceiver({
|
|
396
|
-
onReceived: (e) => {
|
|
397
|
-
const data = e.intent.getStringExtra('data');
|
|
398
|
-
Ti.API.info(`Received custom event: ${data}`);
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
Ti.Android.registerBroadcastReceiver(customReceiver, [
|
|
403
|
-
'com.myapp.CUSTOM_EVENT'
|
|
404
|
-
]);
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### Boot receiver
|
|
408
|
-
|
|
409
|
-
In `tiapp.xml`:
|
|
410
|
-
```xml
|
|
411
|
-
<android>
|
|
412
|
-
<manifest>
|
|
413
|
-
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
|
414
|
-
<application>
|
|
415
|
-
<receiver
|
|
416
|
-
android:name="com.myapp.BootReceiver"
|
|
417
|
-
android:enabled="true">
|
|
418
|
-
<intent-filter>
|
|
419
|
-
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
|
420
|
-
</intent-filter>
|
|
421
|
-
</receiver>
|
|
422
|
-
</application>
|
|
423
|
-
</manifest>
|
|
424
|
-
</android>
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
## 7. Android services
|
|
428
|
-
|
|
429
|
-
### Overview
|
|
430
|
-
Services are background components that run independently of the UI. Useful for long-running operations like music playback, location tracking, or network polling.
|
|
431
|
-
|
|
432
|
-
### Service types
|
|
433
|
-
|
|
434
|
-
1. Regular service: runs in background until stopped
|
|
435
|
-
2. IntentService: queues work requests and processes sequentially
|
|
436
|
-
3. Foreground service: shows persistent notification, higher priority
|
|
437
|
-
|
|
438
|
-
### Creating a service
|
|
439
|
-
|
|
440
|
-
```javascript
|
|
441
|
-
// Create service
|
|
442
|
-
const service = Ti.Android.createService({
|
|
443
|
-
url: 'myservice.js',
|
|
444
|
-
interval: 60000 // Check every 60 seconds
|
|
445
|
-
});
|
|
446
|
-
|
|
447
|
-
// Start service
|
|
448
|
-
service.start();
|
|
449
|
-
|
|
450
|
-
// Stop service when done
|
|
451
|
-
service.stop();
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
`myservice.js`:
|
|
455
|
-
```javascript
|
|
456
|
-
Ti.API.info('Service running');
|
|
457
|
-
|
|
458
|
-
// Perform work
|
|
459
|
-
const xhr = Ti.Network.createHTTPClient({
|
|
460
|
-
onload: () => {
|
|
461
|
-
Ti.API.info('Data updated');
|
|
462
|
-
// Send notification if needed
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
xhr.open('GET', 'https://api.example.com/update');
|
|
466
|
-
xhr.send();
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### IntentService
|
|
470
|
-
|
|
471
|
-
For one-off or queued work:
|
|
472
|
-
|
|
473
|
-
```javascript
|
|
474
|
-
const intent = Ti.Android.createServiceIntent({
|
|
475
|
-
url: 'backgroundtask.js'
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
// Start service (runs once and stops)
|
|
479
|
-
Ti.Android.startService(intent);
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
`backgroundtask.js`:
|
|
483
|
-
```javascript
|
|
484
|
-
// Do work
|
|
485
|
-
const result = processHeavyTask();
|
|
486
|
-
|
|
487
|
-
// Optionally send result back to activity
|
|
488
|
-
const broadcast = Ti.Android.createBroadcastReceiver({
|
|
489
|
-
onReceived: () => { /* ... */ }
|
|
490
|
-
});
|
|
491
|
-
// ...
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
### Foreground service
|
|
495
|
-
|
|
496
|
-
For critical, long-running operations (must show notification):
|
|
497
|
-
|
|
498
|
-
```javascript
|
|
499
|
-
const notification = Ti.Android.createNotification({
|
|
500
|
-
contentTitle: 'Service Running',
|
|
501
|
-
contentText: 'Tracking location...',
|
|
502
|
-
tickerText: 'Service started',
|
|
503
|
-
icon: Ti.App.Android.R.drawable.app_icon
|
|
504
|
-
});
|
|
505
|
-
|
|
506
|
-
const intent = Ti.Android.createServiceIntent({
|
|
507
|
-
url: 'trackingservice.js'
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
intent.addFlags(Ti.Android.FLAG_ACTIVITY_CLEAR_TOP);
|
|
511
|
-
intent.addCategory(Ti.Android.CATEGORY_LAUNCHER);
|
|
512
|
-
|
|
513
|
-
// Start as foreground service
|
|
514
|
-
Ti.Android.startForegroundService(intent, 101, notification);
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
To stop:
|
|
518
|
-
```javascript
|
|
519
|
-
Ti.Android.stopForegroundService(intent);
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
### Service lifecycle management
|
|
523
|
-
|
|
524
|
-
Important: always stop services when no longer needed to conserve resources.
|
|
525
|
-
|
|
526
|
-
```javascript
|
|
527
|
-
// In activity
|
|
528
|
-
Ti.Android.currentActivity.addEventListener('pause', () => {
|
|
529
|
-
// Optionally pause service
|
|
530
|
-
});
|
|
531
|
-
|
|
532
|
-
Ti.Android.currentActivity.addEventListener('destroy', () => {
|
|
533
|
-
// Always stop service
|
|
534
|
-
if (service) {
|
|
535
|
-
service.stop();
|
|
536
|
-
service = null;
|
|
537
|
-
}
|
|
538
|
-
});
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
### Inter-service communication
|
|
542
|
-
|
|
543
|
-
```javascript
|
|
544
|
-
// From activity to service
|
|
545
|
-
const intent = Ti.Android.createServiceIntent({
|
|
546
|
-
url: 'myservice.js'
|
|
547
|
-
});
|
|
548
|
-
intent.putExtra('command', 'pause');
|
|
549
|
-
Ti.Android.startService(intent);
|
|
550
|
-
|
|
551
|
-
// In service
|
|
552
|
-
const command = intent.getStringExtra('command');
|
|
553
|
-
if (command === 'pause') {
|
|
554
|
-
// Handle pause command
|
|
555
|
-
}
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
## 8. Android permissions
|
|
559
|
-
|
|
560
|
-
### Runtime permissions (Android 6.0+)
|
|
561
|
-
|
|
562
|
-
Dangerous permissions require a runtime request:
|
|
563
|
-
|
|
564
|
-
```javascript
|
|
565
|
-
function checkPermission() {
|
|
566
|
-
const result = Ti.Android.checkSelfPermission(
|
|
567
|
-
Ti.Android.PERMISSION_ACCESS_FINE_LOCATION
|
|
568
|
-
);
|
|
569
|
-
|
|
570
|
-
if (result === Ti.Android.RESULTS.GRANTED) {
|
|
571
|
-
startLocationTracking();
|
|
572
|
-
} else {
|
|
573
|
-
Ti.Android.requestPermissions(
|
|
574
|
-
[Ti.Android.PERMISSION_ACCESS_FINE_LOCATION],
|
|
575
|
-
999, // Request code
|
|
576
|
-
(e) => {
|
|
577
|
-
if (e.granted[0] === true) {
|
|
578
|
-
startLocationTracking();
|
|
579
|
-
} else {
|
|
580
|
-
alert('Location permission denied');
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
checkPermission();
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
### Common dangerous permissions
|
|
591
|
-
- `ACCESS_FINE_LOCATION` - GPS location
|
|
592
|
-
- `ACCESS_COARSE_LOCATION` - network location
|
|
593
|
-
- `CAMERA` - camera access
|
|
594
|
-
- `READ_EXTERNAL_STORAGE` - read files
|
|
595
|
-
- `WRITE_EXTERNAL_STORAGE` - write files
|
|
596
|
-
- `RECORD_AUDIO` - microphone
|
|
597
|
-
- `CALL_PHONE` - make phone calls
|
|
598
|
-
- `SEND_SMS` / `READ_SMS` - SMS access
|
|
599
|
-
|
|
600
|
-
## Best practices
|
|
601
|
-
|
|
602
|
-
1. Always unregister broadcast receivers when no longer needed.
|
|
603
|
-
2. Stop services explicitly to conserve battery.
|
|
604
|
-
3. Use IntentService for one-off background tasks.
|
|
605
|
-
4. Use foreground services for user-visible long operations.
|
|
606
|
-
5. Handle runtime permissions gracefully on Android 6.0+.
|
|
607
|
-
6. Validate intent data before processing.
|
|
608
|
-
7. Use proper intent flags for navigation behavior.
|
|
609
|
-
8. Test intent filters with ADB: `adb shell am start -W -a android.intent.action.VIEW -d "myapp://path"`.
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# Automation with Fastlane and Appium
|
|
2
|
-
|
|
3
|
-
Guide to setting up CI pipelines, automated testing, and deployment for Titanium.
|
|
4
|
-
|
|
5
|
-
## 1. UI testing with Appium
|
|
6
|
-
|
|
7
|
-
Appium supports automated functional testing on real devices and simulators.
|
|
8
|
-
|
|
9
|
-
### Prerequisites
|
|
10
|
-
- Appium Desktop or CLI
|
|
11
|
-
- Mocha (test runner)
|
|
12
|
-
- WebdriverIO (recommended client)
|
|
13
|
-
|
|
14
|
-
### Test example (Mocha + WebdriverIO)
|
|
15
|
-
```javascript
|
|
16
|
-
const opts = {
|
|
17
|
-
port: 4723,
|
|
18
|
-
capabilities: {
|
|
19
|
-
platformName: 'iOS',
|
|
20
|
-
deviceName: 'iPhone 15',
|
|
21
|
-
app: '/path/to/your/app.app',
|
|
22
|
-
automationName: 'XCUITest'
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
describe('Login Test', () => {
|
|
27
|
-
it('Should login with valid credentials', async () => {
|
|
28
|
-
const client = await wdio.remote(opts);
|
|
29
|
-
const userField = await client.$('~Enter Username'); // Use Accessibility ID
|
|
30
|
-
await userField.setValue('my_user');
|
|
31
|
-
await client.deleteSession();
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## 2. Automation with Fastlane
|
|
37
|
-
|
|
38
|
-
Fastlane automates building, signing, and uploading to the stores.
|
|
39
|
-
|
|
40
|
-
### Titanium plugins
|
|
41
|
-
Install project plugins:
|
|
42
|
-
```bash
|
|
43
|
-
fastlane add_plugin ti_build_app
|
|
44
|
-
fastlane add_plugin mocha_run_tests
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Fastfile configuration
|
|
48
|
-
Create `fastlane/Fastfile` in the root:
|
|
49
|
-
|
|
50
|
-
```ruby
|
|
51
|
-
platform :ios do
|
|
52
|
-
desc "Build for Simulator Tests"
|
|
53
|
-
lane :build_test do
|
|
54
|
-
ti_build_app(
|
|
55
|
-
appc_cli: "ti build -p ios -T simulator --build-only"
|
|
56
|
-
)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
desc "Run UI Tests"
|
|
60
|
-
lane :test do
|
|
61
|
-
build_test
|
|
62
|
-
mocha_run_tests(
|
|
63
|
-
mocha_js_file_name: 'tests/login_test.js'
|
|
64
|
-
)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
desc "Deploy to TestFlight"
|
|
68
|
-
lane :release do
|
|
69
|
-
ti_build_app(
|
|
70
|
-
appc_cli: "ti build -p ios -T dist-appstore --distribution-name 'Your Company' --pp-uuid 'UUID-HERE' --output-dir /dist"
|
|
71
|
-
)
|
|
72
|
-
# Add fastlane pilot command here to upload the .ipa
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## 3. CI/CD best practices
|
|
78
|
-
1. Accessibility IDs: assign `accessibilityLabel` in XML/TSS so Appium can find elements reliably.
|
|
79
|
-
2. Environment lanes: define separate lanes for `beta`, `production`, and `test`.
|
|
80
|
-
3. Profile management: use Fastlane Match to sync certs and provisioning profiles across the team.
|
|
81
|
-
4. Snapshots: use Fastlane `snapshot` to automate App Store screenshot generation.
|
|
82
|
-
|
|
83
|
-
## 4. Unit testing with TiUnit
|
|
84
|
-
|
|
85
|
-
For non-UI tests, consider TiUnit (Jasmine-based):
|
|
86
|
-
- Runs tests inside the app context
|
|
87
|
-
- Supports standard Jasmine `describe`/`it`/`expect` syntax
|
|
88
|
-
- Integrates cleanly into CI pipelines
|
|
89
|
-
|
|
90
|
-
## 5. Broader CI/CD options
|
|
91
|
-
|
|
92
|
-
Beyond Fastlane and Appium, Titanium apps can integrate with:
|
|
93
|
-
- Jenkins for build orchestration and pipeline management
|
|
94
|
-
- SonarQube for code quality analysis
|
|
95
|
-
- AWS Device Farm for testing on real devices in the cloud
|
|
96
|
-
- Nexus/Artifactory for build artifact archiving and versioning
|