@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,723 @@
|
|
|
1
|
+
# Extending Titanium
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Extending Titanium](#extending-titanium)
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [1. Module Architecture (Core Concepts)](#1-module-architecture-core-concepts)
|
|
8
|
+
- [Proxy-View Relationship](#proxy-view-relationship)
|
|
9
|
+
- [2. Module Debugging in Xcode (iOS)](#2-module-debugging-in-xcode-ios)
|
|
10
|
+
- [3. Upgrading to SDK 9.0.0+ (Android)](#3-upgrading-to-sdk-900-android)
|
|
11
|
+
- [4. Hyperloop](#4-hyperloop)
|
|
12
|
+
- [What is Hyperloop?](#what-is-hyperloop)
|
|
13
|
+
- [Prerequisites](#prerequisites)
|
|
14
|
+
- [Hyperloop Basics](#hyperloop-basics)
|
|
15
|
+
- [iOS Hyperloop Examples](#ios-hyperloop-examples)
|
|
16
|
+
- [Access iOS Frameworks](#access-ios-frameworks)
|
|
17
|
+
- [Access UIKit](#access-uikit)
|
|
18
|
+
- [Make Native HTTP Request](#make-native-http-request)
|
|
19
|
+
- [Access CoreBluetooth (Bluetooth LE)](#access-corebluetooth-bluetooth-le)
|
|
20
|
+
- [Access AVFoundation (Camera/Video)](#access-avfoundation-cameravideo)
|
|
21
|
+
- [Access Address Book (Contacts)](#access-address-book-contacts)
|
|
22
|
+
- [Access CoreLocation (Enhanced)](#access-corelocation-enhanced)
|
|
23
|
+
- [Android Hyperloop Examples](#android-hyperloop-examples)
|
|
24
|
+
- [Access Android Frameworks](#access-android-frameworks)
|
|
25
|
+
- [Access Vibrator](#access-vibrator)
|
|
26
|
+
- [Access TelephonyManager](#access-telephonymanager)
|
|
27
|
+
- [Access WiFi Manager](#access-wifi-manager)
|
|
28
|
+
- [Access PackageManager](#access-packagemanager)
|
|
29
|
+
- [Hyperloop Best Practices](#hyperloop-best-practices)
|
|
30
|
+
- [3. Native Module Development](#3-native-module-development)
|
|
31
|
+
- [When to Create Native Modules](#when-to-create-native-modules)
|
|
32
|
+
- [Android Module Development](#android-module-development)
|
|
33
|
+
- [Quick Start](#quick-start)
|
|
34
|
+
- [Use in Titanium app](#use-in-titanium-app)
|
|
35
|
+
- [Common Android Module Patterns](#common-android-module-patterns)
|
|
36
|
+
- [iOS Module Development](#ios-module-development)
|
|
37
|
+
- [Quick Start](#quick-start-1)
|
|
38
|
+
- [Common iOS Module Patterns](#common-ios-module-patterns)
|
|
39
|
+
- [Module Distribution](#module-distribution)
|
|
40
|
+
- [Packaging](#packaging)
|
|
41
|
+
- [Installing Module](#installing-module)
|
|
42
|
+
- [Module Configuration in tiapp.xml](#module-configuration-in-tiappxml)
|
|
43
|
+
- [4. Choosing Between Hyperloop and Native Modules](#4-choosing-between-hyperloop-and-native-modules)
|
|
44
|
+
- [Use Hyperloop When](#use-hyperloop-when)
|
|
45
|
+
- [Use Native Modules When](#use-native-modules-when)
|
|
46
|
+
- [5. Finding and Using Third-Party Modules](#5-finding-and-using-third-party-modules)
|
|
47
|
+
- [Ti\_slack Marketplace](#ti_slack-marketplace)
|
|
48
|
+
- [Popular Third-Party Modules](#popular-third-party-modules)
|
|
49
|
+
- [Using Third-Party Modules](#using-third-party-modules)
|
|
50
|
+
- [Best Practices Summary](#best-practices-summary)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 1. Module Architecture (Core Concepts)
|
|
55
|
+
|
|
56
|
+
Titanium modules are based on a native class hierarchy that communicates with JavaScript:
|
|
57
|
+
|
|
58
|
+
- **Proxy**: Base class that binds native code with JS. Maintains object state.
|
|
59
|
+
- **Module**: A special Proxy that defines a namespace (e.g., `Ti.UI`). Only one per project is allowed.
|
|
60
|
+
- **ViewProxy**: Proxy specialized in rendering views. Manages the native view's lifecycle.
|
|
61
|
+
- **View**: The actual visual representation (e.g., a `UIButton` or an Android `UIView`).
|
|
62
|
+
|
|
63
|
+
### Proxy-View Relationship
|
|
64
|
+
The `ViewProxy` maintains properties in JS even if the native view does not exist yet. When the view is added to the hierarchy, the Proxy instantiates the native `View` and passes all accumulated properties to it.
|
|
65
|
+
|
|
66
|
+
## 2. Module Debugging in Xcode (iOS)
|
|
67
|
+
|
|
68
|
+
You can debug your native module directly within a Titanium project:
|
|
69
|
+
|
|
70
|
+
1. Open the generated Xcode project from your test app at `build/iphone/<App>.xcodeproj`.
|
|
71
|
+
2. Drag the module project (`.xcodeproj`) into the app project in Xcode.
|
|
72
|
+
3. In the app, go to **Build Phases > Dependencies** and add the module.
|
|
73
|
+
4. In **Link Binary With Libraries**, add the module's `.a` library or framework.
|
|
74
|
+
5. Set a breakpoint in your native code and launch the app from Xcode.
|
|
75
|
+
|
|
76
|
+
## 3. Upgrading to SDK 9.0.0+ (Android)
|
|
77
|
+
|
|
78
|
+
Titanium 9.0.0 introduced major changes in Android:
|
|
79
|
+
|
|
80
|
+
- **AndroidX**: Legacy support libraries are no longer supported. You must migrate your Java/Kotlin code to AndroidX.
|
|
81
|
+
- **Gradle**: Modules now use Gradle for dependencies. Create an `android/build.gradle` file instead of manually copying `.jar` files to `lib/`.
|
|
82
|
+
- **Architectures**: It is mandatory to include `arm64-v8a` and `x86_64` in the `manifest` file.
|
|
83
|
+
|
|
84
|
+
**Example module `build.gradle`:**
|
|
85
|
+
```gradle
|
|
86
|
+
dependencies {
|
|
87
|
+
implementation 'com.google.android.material:material:1.1.0'
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 4. Hyperloop
|
|
92
|
+
|
|
93
|
+
### What is Hyperloop?
|
|
94
|
+
|
|
95
|
+
Hyperloop provides direct JavaScript access to native iOS and Android APIs without writing wrapper code. You can call native methods, create native objects, and interact with platform frameworks directly.
|
|
96
|
+
|
|
97
|
+
### Prerequisites
|
|
98
|
+
|
|
99
|
+
**For iOS**:
|
|
100
|
+
- Requires `ti.hyperloop` module in `tiapp.xml`
|
|
101
|
+
- Only works with Classic Titanium project (not Alloy initially, now supported)
|
|
102
|
+
- iOS 7+ deployment target
|
|
103
|
+
|
|
104
|
+
**For Android**:
|
|
105
|
+
- Requires `ti.hyperloop` module in `tiapp.xml`
|
|
106
|
+
- Android 4.0+ (API Level 14+)
|
|
107
|
+
|
|
108
|
+
**Enable in tiapp.xml**:
|
|
109
|
+
```xml
|
|
110
|
+
<modules>
|
|
111
|
+
<module platform="iphone">ti.hyperloop</module>
|
|
112
|
+
<module platform="android">ti.hyperloop</module>
|
|
113
|
+
</modules>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Hyperloop Basics
|
|
117
|
+
|
|
118
|
+
The pattern for accessing native APIs:
|
|
119
|
+
```javascript
|
|
120
|
+
const NativeClass = require('path.to.NativeClass');
|
|
121
|
+
const instance = new NativeClass();
|
|
122
|
+
instance.methodName();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### iOS Hyperloop Examples
|
|
126
|
+
|
|
127
|
+
#### Access iOS Frameworks
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
// Access Foundation framework
|
|
131
|
+
const NSString = require('Foundation/NSString');
|
|
132
|
+
const NSMutableString = require('Foundation/NSMutableString');
|
|
133
|
+
|
|
134
|
+
// Create string
|
|
135
|
+
const str = NSString.stringWithString('Hello from Hyperloop');
|
|
136
|
+
Ti.API.info(`Length: ${str.length()}`);
|
|
137
|
+
|
|
138
|
+
// Mutable string
|
|
139
|
+
const mutable = NSMutableString.alloc().initWithString('Hello');
|
|
140
|
+
mutable.appendString(' Hyperloop');
|
|
141
|
+
Ti.API.info(mutable); // "Hello Hyperloop"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Access UIKit
|
|
145
|
+
|
|
146
|
+
```javascript
|
|
147
|
+
const UIViewController = require('UIKit/UIViewController');
|
|
148
|
+
const UIColor = require('UIKit/UIColor');
|
|
149
|
+
|
|
150
|
+
// Create native view controller
|
|
151
|
+
const controller = UIViewController.alloc().init();
|
|
152
|
+
|
|
153
|
+
// Set background color
|
|
154
|
+
controller.view().setBackgroundColor(
|
|
155
|
+
UIColor.redColor()
|
|
156
|
+
);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### Make Native HTTP Request
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
const NSURL = require('Foundation/NSURL');
|
|
163
|
+
const NSURLRequest = require('Foundation/NSURLRequest');
|
|
164
|
+
const NSURLSession = require('Foundation/NSURLSession');
|
|
165
|
+
|
|
166
|
+
const url = NSURL.URLWithString('https://api.example.com/data');
|
|
167
|
+
const request = NSURLRequest.requestWithURL(url);
|
|
168
|
+
|
|
169
|
+
const session = NSURLSession.sharedSession();
|
|
170
|
+
const task = session.dataTaskWithRequestCompletionHandler(request, (data, response, error) => {
|
|
171
|
+
if (!error) {
|
|
172
|
+
Ti.API.info('Response received');
|
|
173
|
+
// Process data
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
task.resume();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Access CoreBluetooth (Bluetooth LE)
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
var CBCentralManager = require('CoreBluetooth/CBCentralManager');
|
|
184
|
+
|
|
185
|
+
var central = CBCentralManager.alloc().initWithDelegateQueueOptions(
|
|
186
|
+
null, // delegate
|
|
187
|
+
null // queue
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// Check Bluetooth state
|
|
191
|
+
var state = central.state();
|
|
192
|
+
if (state === 5) { // CBCentralManagerStatePoweredOn
|
|
193
|
+
// Start scanning
|
|
194
|
+
central.scanForPeripheralsWithServicesOptions(null, null);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### Access AVFoundation (Camera/Video)
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
var AVCaptureDevice = require('AVFoundation/AVCaptureDevice');
|
|
202
|
+
|
|
203
|
+
// Get back camera
|
|
204
|
+
var devices = AVCaptureDevice.devicesWithMediaType('vide');
|
|
205
|
+
var backCamera = null;
|
|
206
|
+
|
|
207
|
+
for (var i = 0; i < devices.count(); i++) {
|
|
208
|
+
var device = devices.objectAtIndex(i);
|
|
209
|
+
if (device.position() === 1) { // AVCaptureDevicePositionBack
|
|
210
|
+
backCamera = device;
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Configure camera
|
|
216
|
+
if (backCamera) {
|
|
217
|
+
backCamera.lockForConfiguration(null);
|
|
218
|
+
backCamera.setFlashMode(1); // AVCaptureFlashModeOn
|
|
219
|
+
backCamera.unlockForConfiguration();
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Access Address Book (Contacts)
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
var ABAddressBook = require('AddressBook/ABAddressBook');
|
|
227
|
+
|
|
228
|
+
var addressBook = ABAddressBook.create();
|
|
229
|
+
var people = addressBook.people();
|
|
230
|
+
|
|
231
|
+
for (var i = 0; i < people.count(); i++) {
|
|
232
|
+
var person = people.objectAtIndex(i);
|
|
233
|
+
var firstName = person.valueForProperty(0); // kABPersonFirstNameProperty
|
|
234
|
+
Ti.API.info('Contact: ' + firstName);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Access CoreLocation (Enhanced)
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
var CLLocationManager = require('CoreLocation/CLLocationManager');
|
|
242
|
+
var CLLocation = require('CoreLocation/CLLocation');
|
|
243
|
+
|
|
244
|
+
var locationManager = CLLocationManager.alloc().init();
|
|
245
|
+
locationManager.setDelegate(null);
|
|
246
|
+
locationManager.setDesiredAccuracy(3); // kCLLocationAccuracyBest
|
|
247
|
+
locationManager.startUpdatingLocation();
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Android Hyperloop Examples
|
|
251
|
+
|
|
252
|
+
#### Access Android Frameworks
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
const Context = require('android.content.Context');
|
|
256
|
+
const Activity = require('android.app.Activity');
|
|
257
|
+
const Toast = require('android.widget.Toast');
|
|
258
|
+
|
|
259
|
+
// Get current activity
|
|
260
|
+
const activity = Ti.Android.currentActivity;
|
|
261
|
+
|
|
262
|
+
// Show toast
|
|
263
|
+
Toast.makeText(
|
|
264
|
+
activity,
|
|
265
|
+
'Hello from Hyperloop',
|
|
266
|
+
Toast.LENGTH_SHORT
|
|
267
|
+
).show();
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### Access Vibrator
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
const Vibrator = require('android.os.Vibrator');
|
|
274
|
+
const Context = require('android.content.Context');
|
|
275
|
+
|
|
276
|
+
const activity = Ti.Android.currentActivity;
|
|
277
|
+
const vibrator = activity.getSystemService(Context.VIBRATOR_SERVICE);
|
|
278
|
+
|
|
279
|
+
// Vibrate for 500ms
|
|
280
|
+
vibrator.vibrate(500);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### Access TelephonyManager
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
const TelephonyManager = require('android.telephony.TelephonyManager');
|
|
287
|
+
const Context = require('android.content.Context');
|
|
288
|
+
|
|
289
|
+
const activity = Ti.Android.currentActivity;
|
|
290
|
+
const tm = activity.getSystemService(Context.TELEPHONY_SERVICE);
|
|
291
|
+
|
|
292
|
+
// Get device ID
|
|
293
|
+
const deviceId = tm.getDeviceId();
|
|
294
|
+
Ti.API.info(`Device ID: ${deviceId}`);
|
|
295
|
+
|
|
296
|
+
// Get phone state
|
|
297
|
+
const state = tm.getCallState();
|
|
298
|
+
if (state === 0) {
|
|
299
|
+
Ti.API.info('Phone idle');
|
|
300
|
+
} else if (state === 1) {
|
|
301
|
+
Ti.API.info('Phone ringing');
|
|
302
|
+
} else if (state === 2) {
|
|
303
|
+
Ti.API.info('Phone offhook');
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### Access WiFi Manager
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
const WifiManager = require('android.net.wifi.WifiManager');
|
|
311
|
+
const Context = require('android.content.Context');
|
|
312
|
+
|
|
313
|
+
const activity = Ti.Android.currentActivity;
|
|
314
|
+
const wifi = activity.getSystemService(Context.WIFI_SERVICE);
|
|
315
|
+
|
|
316
|
+
// Check WiFi enabled
|
|
317
|
+
if (wifi.isWifiEnabled()) {
|
|
318
|
+
// Get connection info
|
|
319
|
+
const info = wifi.getConnectionInfo();
|
|
320
|
+
const ssid = info.getSSID();
|
|
321
|
+
const speed = info.getLinkSpeed();
|
|
322
|
+
Ti.API.info(`Connected to: ${ssid} at ${speed} Mbps`);
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### Access PackageManager
|
|
327
|
+
|
|
328
|
+
```javascript
|
|
329
|
+
const PackageManager = require('android.content.pm.PackageManager');
|
|
330
|
+
|
|
331
|
+
const activity = Ti.Android.currentActivity;
|
|
332
|
+
const pm = activity.getPackageManager();
|
|
333
|
+
|
|
334
|
+
// Get installed apps
|
|
335
|
+
const packages = pm.getInstalledApplications(0);
|
|
336
|
+
for (let i = 0; i < packages.size(); i++) {
|
|
337
|
+
const pkg = packages.get(i);
|
|
338
|
+
const appName = pm.getApplicationLabel(pkg);
|
|
339
|
+
Ti.API.info(`App: ${appName}`);
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Hyperloop Best Practices
|
|
344
|
+
|
|
345
|
+
1. **Check platform availability** - Use `Ti.Platform.osname` to branch code
|
|
346
|
+
2. **Handle errors** - Native calls can throw exceptions
|
|
347
|
+
3. **Memory management** - Be aware of native object lifecycles
|
|
348
|
+
4. **Test thoroughly** - Native APIs have platform-specific behaviors
|
|
349
|
+
5. **Document requirements** - Note platform versions and permissions needed
|
|
350
|
+
6. **Use try-catch** - Wrap native calls for safety
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
try {
|
|
354
|
+
const NativeClass = require('path.to.NativeClass');
|
|
355
|
+
const instance = new NativeClass();
|
|
356
|
+
// Use instance
|
|
357
|
+
} catch (e) {
|
|
358
|
+
Ti.API.error(`Hyperloop error: ${e.message}`);
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## 3. Native Module Development
|
|
363
|
+
|
|
364
|
+
### When to Create Native Modules
|
|
365
|
+
|
|
366
|
+
Create a native module when you need to:
|
|
367
|
+
- Reuse native code across multiple Titanium apps
|
|
368
|
+
- Distribute functionality to other developers
|
|
369
|
+
- Implement complex native functionality not suitable for Hyperloop
|
|
370
|
+
- Maintain a stable API regardless of native SDK changes
|
|
371
|
+
|
|
372
|
+
### Android Module Development
|
|
373
|
+
|
|
374
|
+
#### Quick Start
|
|
375
|
+
|
|
376
|
+
1. **Create module structure**:
|
|
377
|
+
```
|
|
378
|
+
com.example.mymodule/
|
|
379
|
+
├── src/
|
|
380
|
+
│ └── com/
|
|
381
|
+
│ └── example/
|
|
382
|
+
│ └── mymodule/
|
|
383
|
+
│ ├── ExampleModule.java
|
|
384
|
+
│ └── ExampleProxy.java
|
|
385
|
+
├── build.properties
|
|
386
|
+
├── build.xml
|
|
387
|
+
├── timodule.xml
|
|
388
|
+
└── LICENSE
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
2. **Module Java class**:
|
|
392
|
+
|
|
393
|
+
```java
|
|
394
|
+
package com.example.mymodule;
|
|
395
|
+
|
|
396
|
+
import org.appcelerator.kroll.KrollModule;
|
|
397
|
+
import org.appcelerator.kroll.annotations.KrollModule;
|
|
398
|
+
|
|
399
|
+
@KrollModule(name="MyModule", id="com.example.mymodule")
|
|
400
|
+
public class ExampleModule extends KrollModule {
|
|
401
|
+
|
|
402
|
+
public ExampleModule() {
|
|
403
|
+
super();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
@Kroll.method
|
|
407
|
+
public String helloWorld() {
|
|
408
|
+
return "Hello from native module!";
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
@Kroll.method
|
|
412
|
+
public int add(int a, int b) {
|
|
413
|
+
return a + b;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
@Kroll.getProperty
|
|
417
|
+
public String getVersion() {
|
|
418
|
+
return "1.0.0";
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
3. **timodule.xml**:
|
|
424
|
+
```xml
|
|
425
|
+
<module>
|
|
426
|
+
<description>My Example Module</description>
|
|
427
|
+
<version>1.0.0</version>
|
|
428
|
+
<platform>android</platform>
|
|
429
|
+
<min-sdk>3.0.0.GA</min-sdk>
|
|
430
|
+
</module>
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
4. **Build and package**:
|
|
434
|
+
```bash
|
|
435
|
+
ant clean
|
|
436
|
+
ant package
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### Use in Titanium app
|
|
440
|
+
|
|
441
|
+
```javascript
|
|
442
|
+
const myModule = require('com.example.mymodule');
|
|
443
|
+
Ti.API.info(myModule.helloWorld()); // "Hello from native module!"
|
|
444
|
+
Ti.API.info(myModule.add(5, 3)); // 8
|
|
445
|
+
Ti.API.info(myModule.version); // "1.0.0"
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
#### Common Android Module Patterns
|
|
449
|
+
|
|
450
|
+
**Accessing Android APIs**:
|
|
451
|
+
|
|
452
|
+
```java
|
|
453
|
+
import android.content.Context;
|
|
454
|
+
import android.location.LocationManager;
|
|
455
|
+
|
|
456
|
+
@Kroll.method
|
|
457
|
+
public boolean isGPSEnabled() {
|
|
458
|
+
LocationManager lm = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
|
|
459
|
+
return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
**Firing events to JavaScript**:
|
|
464
|
+
|
|
465
|
+
```java
|
|
466
|
+
import org.appcelerator.kroll.KrollDict;
|
|
467
|
+
|
|
468
|
+
@Kroll.method
|
|
469
|
+
public void triggerEvent() {
|
|
470
|
+
KrollDict data = new KrollDict();
|
|
471
|
+
data.put("message", "Hello from native!");
|
|
472
|
+
fireEvent("myEvent", data);
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**Receiving events from JavaScript**:
|
|
477
|
+
|
|
478
|
+
```java
|
|
479
|
+
@Kroll.method
|
|
480
|
+
public void startService() {
|
|
481
|
+
// Start service and listen for events
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### iOS Module Development
|
|
486
|
+
|
|
487
|
+
#### Quick Start
|
|
488
|
+
|
|
489
|
+
1. **Create module with Template**:
|
|
490
|
+
```bash
|
|
491
|
+
# Use Titanium CLI
|
|
492
|
+
titanium create --type module --id com.example.mymodule --name MyModule --platform ios
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
2. **Module Structure**:
|
|
496
|
+
```
|
|
497
|
+
com.example.mymodule/
|
|
498
|
+
├── Classes/
|
|
499
|
+
│ ├── ComExampleMymoduleModule.h
|
|
500
|
+
│ ├── ComExampleMymoduleModule.m
|
|
501
|
+
│ └── ComExampleMymoduleProxy.h
|
|
502
|
+
├── documentation/
|
|
503
|
+
│ └── index.md
|
|
504
|
+
├── assets/
|
|
505
|
+
├── iphone/
|
|
506
|
+
│ └── MyModule_Prefix.pch
|
|
507
|
+
├── timodule.xml
|
|
508
|
+
└── LICENSE
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
3. **Module Implementation** (ComExampleMymoduleModule.m):
|
|
512
|
+
|
|
513
|
+
```objc
|
|
514
|
+
#import "ComExampleMymoduleModule.h"
|
|
515
|
+
|
|
516
|
+
@implementation ComExampleMymoduleModule
|
|
517
|
+
|
|
518
|
+
#pragma mark Internal
|
|
519
|
+
|
|
520
|
+
- (id)moduleGUID {
|
|
521
|
+
return @"com.example.mymodule";
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
- (NSString *)moduleName {
|
|
525
|
+
return @"MyModule";
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
#pragma mark Lifecycle
|
|
529
|
+
|
|
530
|
+
- (void)startup {
|
|
531
|
+
[super startup];
|
|
532
|
+
DebugLog(@"[DEBUG] MyModule initialized");
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
- (void)shutdown:(id)sender {
|
|
536
|
+
[super shutdown:sender];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
#pragma mark Cleanup
|
|
540
|
+
|
|
541
|
+
- (void)dealloc {
|
|
542
|
+
[super dealloc];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
#pragma Public APIs
|
|
546
|
+
|
|
547
|
+
- (NSString*)version {
|
|
548
|
+
return @"1.0.0";
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
- (NSString*)helloWorld {
|
|
552
|
+
return @"Hello from native module!";
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
- (NSNumber*)add:(NSNumber*)a with:(NSNumber*)b {
|
|
556
|
+
return [NSNumber numberWithInt:[a intValue] + [b intValue]];
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
@end
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
4. **timodule.xml**:
|
|
563
|
+
```xml
|
|
564
|
+
<module>
|
|
565
|
+
<description>My Example Module</description>
|
|
566
|
+
<version>1.0.0</version>
|
|
567
|
+
<platform>iphone</platform>
|
|
568
|
+
<min-sdk>3.0.0.GA</min-sdk>
|
|
569
|
+
</module>
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
5. **Build and package**:
|
|
573
|
+
```bash
|
|
574
|
+
./build.py
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
6. **Use in Titanium app**:
|
|
578
|
+
|
|
579
|
+
```javascript
|
|
580
|
+
const myModule = require('com.example.mymodule');
|
|
581
|
+
Ti.API.info(myModule.helloWorld()); // "Hello from native module!"
|
|
582
|
+
Ti.API.info(myModule.add(5, {with: 3})); // 8
|
|
583
|
+
Ti.API.info(myModule.version); // "1.0.0"
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### Common iOS Module Patterns
|
|
587
|
+
|
|
588
|
+
**Accessing iOS Frameworks**:
|
|
589
|
+
|
|
590
|
+
```objc
|
|
591
|
+
#import <CoreLocation/CoreLocation.h>
|
|
592
|
+
|
|
593
|
+
- (void)startTracking {
|
|
594
|
+
CLLocationManager *manager = [[CLLocationManager alloc] init];
|
|
595
|
+
[manager setDelegate:self];
|
|
596
|
+
[manager startUpdatingLocation];
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
**Firing events to JavaScript**:
|
|
601
|
+
|
|
602
|
+
```objc
|
|
603
|
+
- (void)locationUpdated:(CLLocation*)location {
|
|
604
|
+
NSDictionary *event = @{
|
|
605
|
+
@"latitude": [NSNumber numberWithDouble:location.coordinate.latitude],
|
|
606
|
+
@"longitude": [NSNumber numberWithDouble:location.coordinate.longitude]
|
|
607
|
+
};
|
|
608
|
+
[self fireEvent:@"locationUpdate" withObject:event];
|
|
609
|
+
}
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
**View Proxies** (for custom UI components):
|
|
613
|
+
|
|
614
|
+
```objc
|
|
615
|
+
@interface MyViewProxy : TiViewProxy {
|
|
616
|
+
UIView *myView;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
- (UIView *)view {
|
|
620
|
+
if (myView == nil) {
|
|
621
|
+
myView = [[MyCustomView alloc] initWithFrame:[self frame]];
|
|
622
|
+
}
|
|
623
|
+
return myView;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
@end
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Module Distribution
|
|
630
|
+
|
|
631
|
+
#### Packaging
|
|
632
|
+
|
|
633
|
+
Both platforms create a `.zip` file that can be distributed:
|
|
634
|
+
|
|
635
|
+
```bash
|
|
636
|
+
# For iOS
|
|
637
|
+
./build.py -d
|
|
638
|
+
|
|
639
|
+
# For Android
|
|
640
|
+
ant dist
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
#### Installing Module
|
|
644
|
+
|
|
645
|
+
1. **Local installation**: Extract to `/Library/Application Support/Titanium/modules/`
|
|
646
|
+
2. **Global installation**: Use `gittio` or `npm` for publishing
|
|
647
|
+
3. **Project-specific**: Place in app's `modules/` directory
|
|
648
|
+
|
|
649
|
+
#### Module Configuration in tiapp.xml
|
|
650
|
+
|
|
651
|
+
```xml
|
|
652
|
+
<modules>
|
|
653
|
+
<module platform="android" version="1.0.0">com.example.mymodule</module>
|
|
654
|
+
<module platform="iphone" version="1.0.0">com.example.mymodule</module>
|
|
655
|
+
</modules>
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
## 4. Choosing Between Hyperloop and Native Modules
|
|
659
|
+
|
|
660
|
+
### Use Hyperloop When
|
|
661
|
+
|
|
662
|
+
- Prototyping native API access
|
|
663
|
+
- App-specific native functionality (not reusable)
|
|
664
|
+
- One-off native API calls
|
|
665
|
+
- Quick integration with platform features
|
|
666
|
+
- Don't need to distribute code
|
|
667
|
+
|
|
668
|
+
### Use Native Modules When
|
|
669
|
+
|
|
670
|
+
- Creating reusable components
|
|
671
|
+
- Distributing to other developers
|
|
672
|
+
- Complex native logic with state management
|
|
673
|
+
- Need stable API abstraction
|
|
674
|
+
- Performance-critical code paths
|
|
675
|
+
- Custom UI components
|
|
676
|
+
|
|
677
|
+
## 5. Finding and Using Third-Party Modules
|
|
678
|
+
|
|
679
|
+
### Ti_slack Marketplace
|
|
680
|
+
|
|
681
|
+
Search for existing modules at:
|
|
682
|
+
- https://fromzerotoapp.com/modules/
|
|
683
|
+
- https://github.com/search?q=titanium+module
|
|
684
|
+
|
|
685
|
+
### Popular Third-Party Modules
|
|
686
|
+
|
|
687
|
+
- **ti.map** - Enhanced mapping (Google Maps, Apple Maps)
|
|
688
|
+
- **ti.paint** - Drawing/signature capture
|
|
689
|
+
- **ti.barcode** - Barcode/QR scanning
|
|
690
|
+
- **ti.admob** - AdMob integration
|
|
691
|
+
- **ti.facebook** - Facebook SDK
|
|
692
|
+
- **ti.googleplus** - Google+ SDK
|
|
693
|
+
- **ti.oauth2** - OAuth 2.0 client
|
|
694
|
+
|
|
695
|
+
### Using Third-Party Modules
|
|
696
|
+
|
|
697
|
+
1. **Download** module zip
|
|
698
|
+
2. **Extract** to modules directory
|
|
699
|
+
3. **Add to tiapp.xml**:
|
|
700
|
+
|
|
701
|
+
```xml
|
|
702
|
+
<modules>
|
|
703
|
+
<module platform="android">com.mapbox.map</module>
|
|
704
|
+
<module platform="iphone">com.mapbox.map</module>
|
|
705
|
+
</modules>
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
4. **Require in code**:
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
const Mapbox = require('com.mapbox.map');
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
## Best Practices Summary
|
|
715
|
+
|
|
716
|
+
1. **Try built-in APIs first** - Titanium may already have what you need
|
|
717
|
+
2. **Prefer Hyperloop for simple cases** - Less overhead
|
|
718
|
+
3. **Create modules for reusable code** - Better distribution
|
|
719
|
+
4. **Handle platform differences** - Branch code appropriately
|
|
720
|
+
5. **Document dependencies** - Note SDK versions and requirements
|
|
721
|
+
6. **Test on real devices** - Simulators may not support all features
|
|
722
|
+
7. **Version your modules** - Semantic versioning for compatibility
|
|
723
|
+
8. **Provide examples** - Help users understand usage patterns
|