@craft-native/android 0.0.451 → 0.0.467

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/README.md CHANGED
@@ -292,7 +292,12 @@ native bridge supports device info, clipboard read/write, haptic impact,
292
292
  persistent JSON storage, SQLite queries and transactions, lifecycle and deep-link
293
293
  events, and local notifications. Storage and SQLite survive process relaunch;
294
294
  notifications use `AlarmManager`, so delivery does not require a running
295
- JavaScriptSandbox process. Enable `enableLocalDatabase`,
295
+ JavaScriptSandbox process. Notification groups retain their child membership
296
+ across receiver recreation. Replacing a child updates that membership before
297
+ posting; cancelling or dismissing the last child removes its summary even when
298
+ Android has not yet applied an earlier post or cancellation. Cancelling all
299
+ notifications also clears their saved membership and action tokens.
300
+ Enable `enableLocalDatabase`,
296
301
  `enableLocalNotifications`, and `enableDeepLinks` explicitly. These optional
297
302
  boolean fields are accepted by `CraftAndroidConfig` and `InitOptions.config`;
298
303
  omitting them or setting them to `false` keeps the capabilities disabled. Disabled or
@@ -1178,3 +1183,16 @@ when available. `monospace`/`ui-monospace`, `serif`/`ui-serif` and
1178
1183
  `sans-serif`/`ui-sans-serif`/`system-ui` select platform fonts, retaining requested
1179
1184
  weight, italic style and system text scaling. A missing custom face falls through
1180
1185
  to the next family rather than silently replacing a requested mono font with sans.
1186
+
1187
+ ### Native route parameter constraints
1188
+
1189
+ `nativeScreenConstraints` applies the same decoded parameter rules as the iOS
1190
+ host and browser-safe `craft-native/mobile` matcher. For example,
1191
+ `{ '/:username': { username: { pattern: '[a-z]+', exclude: ['terms'], normalize: 'lowercase' } } }`
1192
+ normalizes decoded parameters and exclusions independently of device locale,
1193
+ then applies a complete case-sensitive pattern and returns normalized parameters.
1194
+ leaves `/terms` to the normal website fallback while `/ava` opens the profile.
1195
+ Patterns match the complete value; use syntax shared by JavaScript, Foundation
1196
+ and Kotlin. Invalid configuration is rejected by the builder, invalid runtime
1197
+ rules fail closed, and query parameters cannot replace path parameters. Static
1198
+ routes retain priority.
package/dist/index.d.ts CHANGED
@@ -1,350 +1 @@
1
- /** Store large native source assets compressed; the host decodes each once on demand. */
2
- export declare function compressNativeSources(target: string): void;
3
- import { type AndroidMapProvider } from './native-map.js';
4
- export type { AndroidMapProvider } from './native-map.js';
5
- /**
6
- * The builder installs a directory of route bundles (stx's `routesDir`) as
7
- * well as the one-file bundle, and the app runs each screen from its own
8
- * route's file. Stacks asks for route bundles only when this is true.
9
- */
10
- /** Build-time proof for Stacks capability mappings, including unreleased source builds. */
11
- export declare const nativeSensorCapabilities: readonly ['motionSensors', 'barometer', 'pedometer'];
12
- export declare const nativeRouteBundles = true;
13
- /**
14
- * The app evaluates stx's shared runtime (`__runtime.js`, stx's
15
- * `sharedRuntime`) in each screen's context before the route's own file.
16
- * Stacks asks stx for it only when this is true: a route file built so
17
- * refuses to run without it.
18
- */
19
- export declare const nativeRouteRuntime = true;
20
- /**
21
- * The app gives a screen its messages a language at a time (stx's
22
- * `messages`, `native-screens/__messages/`): the areas its route uses,
23
- * evaluated ahead of it (an isolate cannot read a file when asked). Stacks leaves the languages
24
- * out of the screens' code only when this is true.
25
- */
26
- export declare const nativeMessages = true;
27
- /** Providers this published builder can generate as real Android map views. */
28
- export declare const nativeMapProviders: readonly ['google', 'maplibre'];
29
- export { runKotlinFixture } from './testing.js';
30
- export { createAndroidEmulator } from './emulator.js';
31
- export type { AndroidEmulatorOptions, AndroidEmulatorSession } from './emulator.js';
32
- /** Package custom fonts and their licenses; removed fonts cannot linger in the app. */
33
- export declare function syncNativeFonts(fonts: CraftAndroidConfig['nativeFonts'], output: string): string[];
34
- /** Oldest Android API level supported by the generated Kotlin runtime. */
35
- export declare const ANDROID_MIN_SDK = 26;
36
- export interface CraftAndroidConfig {
37
- /** Bundled font files keyed by their PostScript font name, used as native fontFamily. */
38
- nativeFonts?: Record<string, {
39
- src: string;
40
- license?: string;
41
- }>;
42
- appName: string;
43
- packageName: string;
44
- renderer?: 'web' | 'native';
45
- /** "system" follows the device; light/dark pin the generated host. */
46
- appearance?: 'light' | 'dark' | 'system';
47
- /** Static native tab-bar styling applied before the page's own tabBar.set call. */
48
- tabBar?: CraftTabBarConfig;
49
- /** Runs from the generated project root before Gradle compiles the app. */
50
- postGenerate?: CraftPostGenerateHook;
51
- version?: string;
52
- versionCode?: number;
53
- darkMode?: boolean;
54
- backgroundColor?: string;
55
- backgroundColorDark?: string;
56
- enableSpeechRecognition?: boolean;
57
- enableAudioRecording?: boolean;
58
- enableHaptics?: boolean;
59
- enableShare?: boolean;
60
- enableCamera?: boolean;
61
- enableBiometric?: boolean;
62
- enablePushNotifications?: boolean;
63
- /** Enable native SQLite queries and transactions. Disabled unless explicitly true. */
64
- enableLocalDatabase?: boolean;
65
- /** Enable native AlarmManager local notification scheduling. Disabled unless explicitly true. */
66
- enableLocalNotifications?: boolean;
67
- enableSecureStorage?: boolean;
68
- enableGeolocation?: boolean;
69
- enableBackgroundLocation?: boolean;
70
- /** Foreground raw Android sensors on native screens; separate from iOS fused motion. */
71
- enableMotionSensors?: boolean;
72
- /** Foreground pressure and session-relative altitude; does not enable background recording. */
73
- enableBarometer?: boolean;
74
- /** Foreground hardware step counters/detectors; requires activity recognition on Android 10+. */
75
- enablePedometer?: boolean;
76
- enableBluetooth?: boolean;
77
- /**
78
- * A Bluetooth heart-rate strap, or a watch broadcasting its heart rate (the
79
- * standard Heart Rate Service), through `craft.heartRate` on a page and the
80
- * `HeartRate` module on a native screen (CraftHeartRate.kt): scan, connect,
81
- * live readings as `craftHeartRate` events, and a recording kept natively,
82
- * in the foreground (a connectedDevice service) while it runs. The iOS
83
- * builder's flag of the same name.
84
- */
85
- enableHeartRate?: boolean;
86
- enableHealthConnect?: boolean;
87
- /** Android Health Services live exercise tracking for native screens. Requires minSdk 30. */
88
- enableHealthServices?: boolean;
89
- /** Google Wallet save-link or native SDK handoff for native screens. */
90
- enableWallet?: boolean;
91
- /**
92
- * The Health Connect data the app reads and writes, by the shared type
93
- * names (`steps`, `sleep`, `workouts`...). The manifest declares only
94
- * these, as Play's health permissions review requires; without it, the
95
- * original set (steps, heart rate, energy, distance, workouts).
96
- */
97
- healthConnect?: {
98
- read?: HealthConnectType[];
99
- write?: HealthConnectType[];
100
- /** Read while the app is in the background (a WorkManager refresh): Android 15's READ_HEALTH_DATA_IN_BACKGROUND. */
101
- background?: boolean;
102
- /** Read further back than the 30 days before the first grant: READ_HEALTH_DATA_HISTORY. */
103
- history?: boolean;
104
- };
105
- enableHealthConnectBackground?: boolean;
106
- enableHealthConnectHistory?: boolean;
107
- /** The app's privacy policy, which Health Connect links to from its permission screen. */
108
- privacyPolicyURL?: string;
109
- enableKeepAwake?: boolean;
110
- enableDeepLinks?: boolean;
111
- /** Reach the person's own devices on the local network over plain HTTP (a Mac companion). */
112
- enableLocalNetwork?: boolean;
113
- urlSchemes?: string[];
114
- /** HTTPS hosts owned by the app; path rules are ordered, with `*` matching any path text. */
115
- /** Ordered path rules: * matches zero or more characters, ? one, and ?* one or more. */
116
- appLinks?: Array<{
117
- host: string;
118
- paths?: Array<{
119
- pattern: string;
120
- exclude?: boolean;
121
- }>;
122
- }>;
123
- trustedOrigins?: string[];
124
- appIconPath?: string;
125
- /**
126
- * The launch splash: a directory laid out as Android resources, holding
127
- * `drawable-<density>/splash_icon.png` (Android 12's splash icon, 288dp
128
- * with its content inside the 192dp circle) and `splash_logo.png` (the
129
- * logo the window background centres before Android 12), with Dark Mode
130
- * ones in `drawable-night-<density>`. ts-images' `generateSplashScreens`
131
- * writes exactly this (`android.resources`). Both sit on `backgroundColor`
132
- * (`backgroundColorDark` at night), the colour the first frame continues.
133
- * Without it, Android 12 shows the launcher icon and older versions the
134
- * background colour.
135
- */
136
- splashResources?: string;
137
- /**
138
- * The small icon in the status bar and on every notification the app
139
- * shows, push or local: an Android vector drawable (`.xml`) or a `.png`,
140
- * white on transparent, since Android draws only its shape. Without one,
141
- * a white Craft mark. Never the launcher icon, which shows as a white
142
- * square.
143
- */
144
- notificationIconPath?: string;
145
- /** The `#RRGGBB` Android tints the notification icon and app name with. The system's own colour without it. */
146
- notificationColor?: string;
147
- googleServicesFile?: string;
148
- /** Native map renderer. MapLibre needs no SDK key; Google remains the default for compatibility. */
149
- mapProvider?: AndroidMapProvider;
150
- /** Google Maps Android SDK key, used only by the Google native map host. */
151
- mapsApiKey?: string;
152
- devServerURL?: string;
153
- hasBundledFallback?: boolean;
154
- /** Android API level, at least ANDROID_MIN_SDK (26), or 30 with Health Services. */
155
- minSdk?: number;
156
- compileSdk?: number;
157
- targetSdk?: number;
158
- /**
159
- * Native renderer: the app's paths and the screen drawing each
160
- * (`/m/workout/:id` → `Workout`), its tabs, and the bundle route of the
161
- * script that runs beside the screens. The same keys as the iOS builder.
162
- */
163
- nativeScreens?: Record<string, string>;
164
- tabs?: Array<{
165
- id: string;
166
- title: string;
167
- symbol?: string;
168
- /** Native selected-tab icon overrides, also supported by navigation.setOptions({ tabItem }). */
169
- selectedSymbol?: string;
170
- selectedIconTint?: string;
171
- selectedIconPulse?: boolean;
172
- }>;
173
- nativeApp?: string;
174
- /**
175
- * The secure-storage key the signed-in account's token lives under
176
- * (default `auth.token`). `craft.session` follows it on every native
177
- * screen, and a change of it is `SESSION_CHANGED { key, token, previous }`.
178
- */
179
- sessionTokenKey?: string;
180
- /** Wake the app script every so often (`craftBackgroundRefresh`), through WorkManager. */
181
- backgroundRefresh?: {
182
- enabled?: boolean;
183
- minimumIntervalMinutes?: number;
184
- };
185
- /**
186
- * Crash and error reporting to bughq (CraftCrashReporter.kt): uncaught JVM
187
- * exceptions, ANRs and native crashes (ApplicationExitInfo), uncaught
188
- * JavaScript errors, and what the page sends through `craft.crashReporter`.
189
- * Queued on disk and sent when online. Release builds are minified: upload
190
- * `app/build/outputs/mapping/release/mapping.txt` so bughq can retrace.
191
- */
192
- crashReporting?: {
193
- /** The bughq project's public ingest key. */
194
- key: string;
195
- /** Default https://bughq.org. */
196
- host?: string;
197
- /** Default `production`. */
198
- environment?: string;
199
- /** Default `<versionName>+<versionCode>`, e.g. `1.0.0+41`. */
200
- release?: string;
201
- /** One session per launch, for crash-free sessions. Default on. */
202
- sessions?: boolean;
203
- };
204
- }
205
- export interface CraftTabBarConfig {
206
- selection?: {
207
- /** The selected tab indicator's corner radius in dp; omitted keeps the default. */
208
- cornerRadius?: number;
209
- /** The selected tab indicator fill as #RRGGBB. */
210
- color?: string;
211
- };
212
- }
213
- /** A declared command Craft runs after the native project has been generated. */
214
- export interface CraftPostGenerateHook {
215
- command: string;
216
- args?: string[];
217
- }
218
- /** The shared health data types (the iOS builder's HealthKit names). */
219
- export type HealthConnectType = 'steps' | 'heartRate' | 'activeEnergy' | 'distance' | 'workouts' | 'restingHeartRate' | 'heartRateVariability' | 'bodyMass' | 'sleep' | 'mindful' | 'dietaryEnergy' | 'dietaryProtein' | 'dietaryCarbohydrates' | 'dietaryFat' | 'bloodGlucose' | 'insulinDelivery';
220
- /**
221
- * The Health Connect permissions behind each type, for reading and for
222
- * writing. CraftNativeHealth.kt asks for the same ones; a permission the
223
- * manifest does not declare is refused without a prompt.
224
- */
225
- export declare const HEALTH_CONNECT_PERMISSIONS: Record<HealthConnectType, {
226
- read: string[];
227
- write: string[];
228
- }>;
229
- /** Every `android.permission.health.*` the app's Health Connect types need. */
230
- export declare function healthConnectPermissions(config: Pick<CraftAndroidConfig, 'healthConnect'>): string[];
231
- export interface InitOptions {
232
- name: string;
233
- packageName?: string;
234
- output: string;
235
- config?: Partial<CraftAndroidConfig>;
236
- /**
237
- * Where to find the Zig runtime's `<abi>/libcraft.so`.
238
- *
239
- * `null` means no runtime regardless of the environment; `undefined` falls
240
- * through to `CRAFT_ANDROID_RUNTIME`. Same shape as the iOS builder's
241
- * `runtimeDir`.
242
- */
243
- runtimeDir?: string | null;
244
- }
245
- export interface BuildOptions {
246
- htmlPath?: string;
247
- nativeBundlePath?: string;
248
- /**
249
- * Native renderer: the app's icons as vectors (`{ viewBox, strokeWidth,
250
- * icons: { name: svgBody } }`, keyed by Iconify name and SF Symbol), which
251
- * `<Icon>`, the tab bar and the bar buttons draw. Without it they fall
252
- * back to the glyphs Android's fonts have.
253
- */
254
- iconsPath?: string;
255
- devServer?: string;
256
- output: string;
257
- release?: boolean;
258
- /**
259
- * An Android App Bundle (`bundleRelease`, `.aab`), what Google Play takes,
260
- * rather than an APK. Signed with CRAFT_ANDROID_KEYSTORE,
261
- * CRAFT_ANDROID_KEYSTORE_PASSWORD, CRAFT_ANDROID_KEY_ALIAS and
262
- * CRAFT_ANDROID_KEY_PASSWORD when they are set.
263
- */
264
- bundle?: boolean;
265
- compile?: boolean;
266
- /** Same meaning as `InitOptions.runtimeDir`; refreshes what init installed. */
267
- runtimeDir?: string | null;
268
- }
269
- /**
270
- * Run the app's declared generator hook without invoking a shell.
271
- *
272
- * A hook gets the generated project as its cwd and explicit metadata so a
273
- * patch can target the right platform and phase without guessing from paths.
274
- */
275
- export declare function runPostGenerateHook(hook: CraftPostGenerateHook | undefined, output: string, phase?: 'build'): void;
276
- export interface OpenOptions {
277
- output: string;
278
- }
279
- export interface RunOptions {
280
- device?: string;
281
- output: string;
282
- }
283
- /** A splash file, by its place under `res/` (`drawable-night-xxhdpi/splash_icon.png`). */
284
- export interface AndroidSplashFile {
285
- folder: string;
286
- name: 'splash_icon.png' | 'splash_logo.png';
287
- path: string;
288
- }
289
- /**
290
- * The splash files in a resources directory: `splash_icon.png` and
291
- * `splash_logo.png` in each `drawable[-night][-<density>]` folder. A directory
292
- * with neither is a mistake, not an app without a splash.
293
- */
294
- export declare function androidSplashFiles(resources: string): AndroidSplashFile[];
295
- /**
296
- * The launch theme the activity starts in, and the theme it swaps to before
297
- * its first frame. Android 12 and later draw their splash from
298
- * `windowSplashScreen*`; earlier versions draw the window background, here
299
- * the logo centred on the background colour. Either way the colour is the
300
- * app's own `background`, so nothing flashes when the first frame replaces it.
301
- */
302
- export declare function androidLaunchThemes(splash: Pick<AndroidSplashFile, 'name'>[]): {
303
- base: string;
304
- v31: string;
305
- background?: string;
306
- };
307
- export declare function syncAndroidWebAssets(source: string, output: string): void;
308
- export declare function renderAndroidPermissions(config: CraftAndroidConfig): string;
309
- export declare function renderAndroidDeepLinks(config: CraftAndroidConfig): string;
310
- /**
311
- * Where the runtime directory comes from when the caller does not say.
312
- *
313
- * The same shape as `CRAFT_BIN` and the iOS builder's `CRAFT_IOS_RUNTIME`: an
314
- * explicit override for the monorepo dev loop, not a lookup path. Shipping the
315
- * runtime to real apps means putting these libraries in the pantry package
316
- * beside the `craft` binary, which is a distribution decision this function
317
- * does not make.
318
- */
319
- export declare function resolveRuntimeDir(override?: string | null): string | null;
320
- /**
321
- * Copy the Zig runtime into the generated project as
322
- * `app/src/main/jniLibs/<abi>/libcraft.so`.
323
- *
324
- * That path is AGP's default `jniLibs.srcDirs`, so nothing in the Gradle
325
- * templates has to know about it — the library is packaged into the APK and
326
- * `System.loadLibrary("craft")` finds it because the file is named for the
327
- * `craft` it asks for.
328
- *
329
- * Until this existed, nothing put the library anywhere. `CraftNative` caught
330
- * the `UnsatisfiedLinkError`, set `isAvailable = false`, and every action fell
331
- * through to the Kotlin shim — by design, so an app with no runtime still
332
- * works, which is also why nobody noticed that *every* generated app was in
333
- * that state and the whole Android half of the Zig bridge had never run.
334
- *
335
- * Returns true when a runtime was installed.
336
- */
337
- export declare function installRuntime(output: string, runtimeDir: string): boolean;
338
- export declare function init(options: InitOptions): Promise<void>;
339
- /**
340
- * Build Android project
341
- */
342
- export declare function build(options: BuildOptions): Promise<void>;
343
- /**
344
- * Open Android project in Android Studio
345
- */
346
- export declare function open(options: OpenOptions): Promise<void>;
347
- /**
348
- * Run on Android device or emulator
349
- */
350
- export declare function run(options: RunOptions): Promise<void>;
1
+ export * from './internal/android/src/index.js'