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