flet-box 1.0.4 → 1.0.6
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 +10 -0
- package/bin/cli.js +23 -7
- package/bin/commands/checkApi.js +761 -0
- package/bin/commands/create.js +77 -5
- package/bin/utils/dtsProps.js +191 -0
- package/bin/utils/moduleExports.js +165 -0
- package/bin/utils/neutralise.js +64 -0
- package/bin/utils/templates.js +366 -27
- package/docs/CONTRIBUTING.md +156 -0
- package/docs/README.md +68 -0
- package/docs/arquitectura.md +164 -0
- package/docs/cli/README.md +542 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/app-templates.md +197 -0
- package/docs/guides/compatibility.md +95 -0
- package/docs/guides/embedding.md +284 -0
- package/docs/guides/first-app.md +208 -0
- package/docs/guides/frontend-services.md +171 -0
- package/docs/guides/minification-and-protection.md +260 -0
- package/docs/guides/mobile-and-platforms.md +439 -0
- package/docs/guides/online-updates.md +196 -0
- package/docs/guides/router.md +282 -0
- package/docs/guides/state.md +283 -0
- package/docs/guides/syntax-philosophy.md +150 -0
- package/docs/guides/utilities.md +241 -0
- package/docs/guides/widget-structure.md +163 -0
- package/docs/server/README.md +68 -0
- package/docs/server/START_HERE.md +121 -0
- package/docs/server/api.md +225 -0
- package/docs/server/data-services.md +300 -0
- package/docs/server/deployment.md +113 -0
- package/docs/server/security.md +196 -0
- package/docs/services/README.md +79 -0
- package/docs/services/RamStore.md +84 -0
- package/docs/services/Session.md +84 -0
- package/docs/services/Storage.md +88 -0
- package/docs/services/http.md +86 -0
- package/docs/tools/README.md +138 -0
- package/docs/tools/animation.md +87 -0
- package/docs/tools/async-ids-log.md +80 -0
- package/docs/tools/device.md +132 -0
- package/docs/tools/introspection.md +67 -0
- package/docs/tools/lists.md +96 -0
- package/docs/tools/markdown.md +79 -0
- package/docs/tools/reactivity.md +288 -0
- package/docs/tools/state.md +103 -0
- package/docs/tools/styling.md +92 -0
- package/docs/tools/text-and-time.md +89 -0
- package/docs/tools/theme.md +102 -0
- package/docs/tools/validation.md +75 -0
- package/docs/tools/visual-effects.md +84 -0
- package/docs/widget/Accordion.md +144 -0
- package/docs/widget/AdMob.md +144 -0
- package/docs/widget/AdSense.md +133 -0
- package/docs/widget/AdaptiveScaffold.md +105 -0
- package/docs/widget/AlertDialog.md +103 -0
- package/docs/widget/AnimatedBox.md +130 -0
- package/docs/widget/AnimatedText.md +123 -0
- package/docs/widget/AppBar.md +118 -0
- package/docs/widget/Audio.md +135 -0
- package/docs/widget/Avatar.md +119 -0
- package/docs/widget/Badge.md +128 -0
- package/docs/widget/BottomNavigation.md +116 -0
- package/docs/widget/BottomSheet.md +125 -0
- package/docs/widget/Button.md +137 -0
- package/docs/widget/COMMON_PROPS.md +150 -0
- package/docs/widget/Card.md +125 -0
- package/docs/widget/Carousel.md +151 -0
- package/docs/widget/Chart.md +151 -0
- package/docs/widget/Checkbox.md +118 -0
- package/docs/widget/Chip.md +126 -0
- package/docs/widget/CircularBar.md +168 -0
- package/docs/widget/CircularChart.md +164 -0
- package/docs/widget/CodeViewer.md +130 -0
- package/docs/widget/CollapsibleSideBar.md +112 -0
- package/docs/widget/Column.md +129 -0
- package/docs/widget/Container.md +136 -0
- package/docs/widget/DataTable.md +150 -0
- package/docs/widget/Divider.md +109 -0
- package/docs/widget/DraggBox.md +129 -0
- package/docs/widget/Drawer.md +135 -0
- package/docs/widget/DrawerItem.md +98 -0
- package/docs/widget/Dropdown.md +139 -0
- package/docs/widget/DroppBox.md +152 -0
- package/docs/widget/FloatingActionButton.md +120 -0
- package/docs/widget/GridView.md +140 -0
- package/docs/widget/Icon.md +117 -0
- package/docs/widget/Image.md +125 -0
- package/docs/widget/Input.md +151 -0
- package/docs/widget/Inspector.md +92 -0
- package/docs/widget/InstallButton.md +128 -0
- package/docs/widget/ListTile.md +132 -0
- package/docs/widget/ListView.md +138 -0
- package/docs/widget/Markdown.md +175 -0
- package/docs/widget/MatrixRain.md +122 -0
- package/docs/widget/Modal.md +129 -0
- package/docs/widget/Pagination.md +135 -0
- package/docs/widget/ParallaxBox.md +128 -0
- package/docs/widget/ProgressBar.md +130 -0
- package/docs/widget/QRCode.md +117 -0
- package/docs/widget/README.md +188 -0
- package/docs/widget/Radio.md +123 -0
- package/docs/widget/Rating.md +131 -0
- package/docs/widget/Row.md +131 -0
- package/docs/widget/START_HERE.md +146 -0
- package/docs/widget/Scaffold.md +152 -0
- package/docs/widget/Skeleton.md +130 -0
- package/docs/widget/Slider.md +146 -0
- package/docs/widget/SnackBar.md +102 -0
- package/docs/widget/Stack.md +128 -0
- package/docs/widget/Stepper.md +145 -0
- package/docs/widget/Switch.md +118 -0
- package/docs/widget/Tabs.md +124 -0
- package/docs/widget/Text.md +133 -0
- package/docs/widget/Tooltip.md +145 -0
- package/docs/widget/TreeView.md +176 -0
- package/docs/widget/Video.md +127 -0
- package/docs/widget/_template.md +61 -0
- package/package.json +3 -2
- package/src/animations/animate.js +180 -70
- package/src/animations/index.js +1 -0
- package/src/create-index.sh +1 -1
- package/src/index.d.ts +45 -22
- package/src/index.js +1 -0
- package/src/navigations/AdaptiveScaffold.js +11 -2
- package/src/navigations/BottomNavigation.js +10 -3
- package/src/navigations/Tabs.js +6 -2
- package/src/tools/useState.js +54 -63
- package/src/widget-factory/assignProps.js +23 -1
- package/src/widget-factory/processProps.js +10 -3
- package/src/widget-factory/reactiveValue.js +43 -18
- package/src/widget-factory/translateProps.js +777 -901
- package/src/widgets/AlertDialog.js +7 -5
- package/src/widgets/Checkbox.js +9 -7
- package/src/widgets/CircularBar.js +12 -1
- package/src/widgets/FloatingActionButton.js +4 -7
- package/src/widgets/Image.js +5 -7
- package/src/widgets/Input.js +92 -0
- package/src/widgets/ListView.js +73 -29
- package/src/widgets/Pagination.js +6 -3
- package/src/widgets/ProgressBar.js +16 -13
- package/src/widgets/Radio.js +6 -7
- package/src/widgets/Slider.js +23 -4
- package/src/widgets/Stack.js +36 -3
- package/src/widgets/Stepper.js +4 -3
- package/src/widgets/Switch.js +3 -4
- package/src/widgets/TreeView.js +0 -1
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
# Build FletBox for mobile and other platforms
|
|
2
|
+
|
|
3
|
+
> **Level: Advanced.** This page is for shipping — skip it on a first read. It follows [minification and protection](minification-and-protection.md) in the book's reading path.
|
|
4
|
+
|
|
5
|
+
FletBox applications can be built for the web and then packaged for mobile with Capacitor. The same frontend code can become a website, PWA, Android app, or iOS app.
|
|
6
|
+
|
|
7
|
+
## The general flow
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
FletBox source
|
|
11
|
+
|
|
|
12
|
+
| npm run build
|
|
13
|
+
v
|
|
14
|
+
Web build / dist
|
|
15
|
+
|
|
|
16
|
+
| Capacitor sync
|
|
17
|
+
v
|
|
18
|
+
Android project iOS project
|
|
19
|
+
| |
|
|
20
|
+
APK / AAB App Store app
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Capacitor packages the compiled web application inside a native shell. You can add native Capacitor plugins later when the app needs device features.
|
|
24
|
+
|
|
25
|
+
## Requirements
|
|
26
|
+
|
|
27
|
+
### For every platform
|
|
28
|
+
|
|
29
|
+
- Node.js 18 or newer.
|
|
30
|
+
- npm.
|
|
31
|
+
- A working FletBox project.
|
|
32
|
+
- A production build that creates the directory configured as Capacitor's `webDir`.
|
|
33
|
+
|
|
34
|
+
### For Android
|
|
35
|
+
|
|
36
|
+
- Android Studio.
|
|
37
|
+
- Android SDK.
|
|
38
|
+
- Java/JDK compatible with the Android Gradle project.
|
|
39
|
+
- An emulator or physical Android device for testing.
|
|
40
|
+
|
|
41
|
+
### For iOS
|
|
42
|
+
|
|
43
|
+
- macOS.
|
|
44
|
+
- Xcode.
|
|
45
|
+
- CocoaPods when required by installed plugins.
|
|
46
|
+
- An Apple developer account for device distribution and App Store publishing.
|
|
47
|
+
|
|
48
|
+
## Prepare the web build
|
|
49
|
+
|
|
50
|
+
From the FletBox project:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install
|
|
54
|
+
npm run build
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Check that the build output exists before syncing Capacitor:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
dist/
|
|
61
|
+
├── index.html
|
|
62
|
+
└── src/
|
|
63
|
+
└── app.js
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Your Capacitor configuration must point `webDir` to that output directory, commonly `dist`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"appId": "com.example.myapp",
|
|
71
|
+
"appName": "My FletBox App",
|
|
72
|
+
"webDir": "dist"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The exact configuration file may be `capacitor.config.ts`, `capacitor.config.json`, or another format depending on how Capacitor was initialized.
|
|
77
|
+
|
|
78
|
+
## Install Capacitor
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install @capacitor/core @capacitor/cli
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Initialize Capacitor:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx cap init
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The command asks for:
|
|
91
|
+
|
|
92
|
+
- App name.
|
|
93
|
+
- App package id, such as `com.example.myapp`.
|
|
94
|
+
- Web output directory.
|
|
95
|
+
|
|
96
|
+
Use a stable package id. Changing it later can create a different application in app stores.
|
|
97
|
+
|
|
98
|
+
## Android
|
|
99
|
+
|
|
100
|
+
Projects created with `flet-box create` already include Capacitor's Android
|
|
101
|
+
configuration and commands for adding the platform, building the web assets,
|
|
102
|
+
and generating launcher icons from `assets/logo.png`. See the [CLI Android
|
|
103
|
+
workflow](../cli/README.md#create-an-android-app).
|
|
104
|
+
|
|
105
|
+
To build a debug APK from one of these generated projects, run
|
|
106
|
+
`flet-box build android`. It initializes the Android platform on first use,
|
|
107
|
+
synchronizes the web assets and launcher icons, and compiles the APK.
|
|
108
|
+
It installs missing npm project dependencies and prints the absolute APK path.
|
|
109
|
+
Android Studio, Java, and the Android SDK remain system prerequisites and must
|
|
110
|
+
be installed separately.
|
|
111
|
+
|
|
112
|
+
### Add Android to the project
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm install @capacitor/android
|
|
116
|
+
npx cap add android
|
|
117
|
+
npx cap sync android
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Run the web build before each sync when frontend files changed:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm run build
|
|
124
|
+
npx cap sync android
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Open Android Studio
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx cap open android
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If Android Studio is installed in a custom location on macOS:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
export CAPACITOR_ANDROID_STUDIO_PATH="/Applications/Android Studio.app"
|
|
137
|
+
npx cap open android
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Remove the custom override when it is no longer needed:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
unset CAPACITOR_ANDROID_STUDIO_PATH
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Run on an emulator or device
|
|
147
|
+
|
|
148
|
+
You can open the project in Android Studio and use the Run button, or use Capacitor's command when a device is configured:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npx cap run android
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
For a physical device, enable developer mode and USB debugging on the device.
|
|
155
|
+
|
|
156
|
+
### Build a debug APK
|
|
157
|
+
|
|
158
|
+
From the project root:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npm run build
|
|
162
|
+
npx cap sync android
|
|
163
|
+
cd android
|
|
164
|
+
./gradlew assembleDebug --warning-mode all
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
On macOS, the generated debug APK is normally located at:
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
android/app/build/outputs/apk/debug/app-debug.apk
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The debug APK is for local testing and should not be published as the production release.
|
|
174
|
+
|
|
175
|
+
### Build a release APK
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
cd android
|
|
179
|
+
./gradlew assembleRelease
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
A release build must be signed before distribution. Configure a release signing key in the Android project and keep the keystore outside source control.
|
|
183
|
+
|
|
184
|
+
### Build an Android App Bundle
|
|
185
|
+
|
|
186
|
+
Google Play normally expects an Android App Bundle:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
cd android
|
|
190
|
+
./gradlew bundleRelease
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The output is normally located at:
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
android/app/build/outputs/bundle/release/app-release.aab
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## iOS
|
|
200
|
+
|
|
201
|
+
Projects created with `flet-box create` include Capacitor's iOS platform and
|
|
202
|
+
scripts. On macOS, install the full Xcode app, an iOS simulator runtime, and
|
|
203
|
+
CocoaPods (`sudo gem install cocoapods` and `pod setup`). Then run
|
|
204
|
+
`flet-box build ios` to initialize the platform on first use, synchronize the
|
|
205
|
+
web assets, regenerate the app icon, launch images and launch screen from
|
|
206
|
+
`assets/logo.png`, and build an iOS Simulator `.app`. The command prints the
|
|
207
|
+
absolute app path, normally
|
|
208
|
+
`ios/build/Build/Products/Debug-iphonesimulator/App.app`, which installs with
|
|
209
|
+
`xcrun simctl install booted <path>`.
|
|
210
|
+
|
|
211
|
+
For real devices, `flet-box build ios --archive` writes
|
|
212
|
+
`ios/build/App.xcarchive` for the `iphoneos` SDK. The archive is unsigned: open
|
|
213
|
+
it in Xcode with a signing team to export an IPA.
|
|
214
|
+
|
|
215
|
+
The Command Line Tools are not enough. `xcodebuild` is only a stub there and
|
|
216
|
+
there is no simulator runtime, so the build command refuses to start and prints
|
|
217
|
+
the `xcode-select -s /Applications/Xcode.app/Contents/Developer` fix instead of
|
|
218
|
+
failing later inside Xcode. CocoaPods is checked too, because Capacitor links
|
|
219
|
+
its native layer with Pods.
|
|
220
|
+
|
|
221
|
+
### Capacitor origin
|
|
222
|
+
|
|
223
|
+
Both platforms serve the app from a local HTTPS origin
|
|
224
|
+
(`https://localhost`), configured with `androidScheme` and `iosScheme` in
|
|
225
|
+
`capacitor.config.json`. A remote API has to allow that origin in its CORS
|
|
226
|
+
configuration.
|
|
227
|
+
|
|
228
|
+
### Add iOS to the project
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npm install @capacitor/ios
|
|
232
|
+
npx cap add ios
|
|
233
|
+
npx cap sync ios
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
After frontend changes:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
npm run build
|
|
240
|
+
npx cap sync ios
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Open Xcode
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
npx cap open ios
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Select a simulator or connected device in Xcode, configure the signing team, and run the application.
|
|
250
|
+
|
|
251
|
+
For App Store distribution, configure:
|
|
252
|
+
|
|
253
|
+
- Bundle identifier.
|
|
254
|
+
- Signing team.
|
|
255
|
+
- Development and distribution certificates.
|
|
256
|
+
- Provisioning profile.
|
|
257
|
+
- App icons and launch assets.
|
|
258
|
+
- Privacy descriptions for any native plugins.
|
|
259
|
+
|
|
260
|
+
## Capacitor assets
|
|
261
|
+
|
|
262
|
+
Install the asset helper:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
npm install -D @capacitor/assets
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Prepare source icons according to the Capacitor assets requirements, then generate platform assets with the relevant Capacitor assets command for your project version.
|
|
269
|
+
|
|
270
|
+
Review the generated icons in Android Studio and Xcode before publishing.
|
|
271
|
+
|
|
272
|
+
## Update Capacitor
|
|
273
|
+
|
|
274
|
+
Update the core packages together:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
npm install @capacitor/core@latest @capacitor/cli@latest @capacitor/android@latest
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
For iOS projects, include the iOS package too:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npm install @capacitor/ios@latest
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Then synchronize native projects:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
npx cap sync android
|
|
290
|
+
npx cap sync ios
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Read the Capacitor migration notes before updating a major version.
|
|
294
|
+
|
|
295
|
+
## macOS permission fixes
|
|
296
|
+
|
|
297
|
+
If Gradle cannot execute on macOS:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
cd android
|
|
301
|
+
chmod +x gradlew
|
|
302
|
+
xattr -c gradlew
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Then retry:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
./gradlew assembleDebug --warning-mode all
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
`chmod` makes the script executable. `xattr -c` removes macOS quarantine metadata from that local script. Only do this for project files you trust.
|
|
312
|
+
|
|
313
|
+
## PWA alternative
|
|
314
|
+
|
|
315
|
+
A FletBox app can also be installed as a Progressive Web App without Capacitor:
|
|
316
|
+
|
|
317
|
+
```javascript
|
|
318
|
+
import { installPWA, isPWAInstalled } from "flet-box";
|
|
319
|
+
|
|
320
|
+
if (!isPWAInstalled()) {
|
|
321
|
+
installPWA();
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
A PWA needs:
|
|
326
|
+
|
|
327
|
+
- A valid web manifest.
|
|
328
|
+
- A registered service worker.
|
|
329
|
+
- HTTPS in production, except for localhost.
|
|
330
|
+
- Icons in the expected sizes.
|
|
331
|
+
|
|
332
|
+
PWA installation depends on browser and platform support.
|
|
333
|
+
|
|
334
|
+
## Desktop options
|
|
335
|
+
|
|
336
|
+
Capacitor targets Android and iOS. For desktop packaging, consider a desktop shell such as Electron or Tauri around the same `dist` output.
|
|
337
|
+
|
|
338
|
+
The general idea remains:
|
|
339
|
+
|
|
340
|
+
```text
|
|
341
|
+
npm run build
|
|
342
|
+
package dist with the desktop tool
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Desktop packaging requires its own application configuration, signing, and distribution process.
|
|
346
|
+
|
|
347
|
+
## Updating the app after code changes
|
|
348
|
+
|
|
349
|
+
Use this cycle:
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
npm run build
|
|
353
|
+
npx cap sync android
|
|
354
|
+
npx cap open android
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
For iOS, replace the Android command:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
npm run build
|
|
361
|
+
npx cap sync ios
|
|
362
|
+
npx cap open ios
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
`cap sync` copies the current web build and updates native dependencies. It does not replace the need to rebuild the web application first.
|
|
366
|
+
|
|
367
|
+
## Troubleshooting
|
|
368
|
+
|
|
369
|
+
### Capacitor cannot find the web directory
|
|
370
|
+
|
|
371
|
+
Check that:
|
|
372
|
+
|
|
373
|
+
1. `npm run build` completed successfully.
|
|
374
|
+
2. The output directory exists.
|
|
375
|
+
3. `webDir` points to that directory.
|
|
376
|
+
|
|
377
|
+
### Android Studio does not open
|
|
378
|
+
|
|
379
|
+
Set the path temporarily:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
export CAPACITOR_ANDROID_STUDIO_PATH="/Applications/Android Studio.app"
|
|
383
|
+
npx cap open android
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### Gradle says permission denied
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
cd android
|
|
390
|
+
chmod +x gradlew
|
|
391
|
+
xattr -c gradlew
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### The native app shows an old version
|
|
395
|
+
|
|
396
|
+
Rebuild and synchronize:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
npm run build
|
|
400
|
+
npx cap sync android
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Then rebuild from Android Studio or Gradle.
|
|
404
|
+
|
|
405
|
+
### The APK installs but the screen is blank
|
|
406
|
+
|
|
407
|
+
Check:
|
|
408
|
+
|
|
409
|
+
- The `webDir` configuration.
|
|
410
|
+
- That `dist/index.html` exists.
|
|
411
|
+
- That asset paths work from the packaged app.
|
|
412
|
+
- Browser console logs through Android Studio or Safari Web Inspector.
|
|
413
|
+
- That the app does not depend on a development server URL.
|
|
414
|
+
|
|
415
|
+
### The app works in the browser but not on the device
|
|
416
|
+
|
|
417
|
+
Check absolute URLs, CORS, secure connections, permissions, and native plugin configuration. A mobile WebView is not identical to a desktop browser.
|
|
418
|
+
|
|
419
|
+
## Release checklist
|
|
420
|
+
|
|
421
|
+
- Build from a clean working tree.
|
|
422
|
+
- Update the app version.
|
|
423
|
+
- Run `npm run build`.
|
|
424
|
+
- Run `npx cap sync`.
|
|
425
|
+
- Test on a real device.
|
|
426
|
+
- Verify icons, splash screen, orientation, and deep links.
|
|
427
|
+
- Configure release signing.
|
|
428
|
+
- Remove development URLs and debug credentials.
|
|
429
|
+
- Confirm API endpoints use HTTPS.
|
|
430
|
+
- Generate an APK for direct testing or an AAB for Google Play.
|
|
431
|
+
- Keep signing keys and certificates out of Git.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Continue reading
|
|
436
|
+
|
|
437
|
+
- **Previous:** [Minify and protect a FletBox build](minification-and-protection.md)
|
|
438
|
+
- **Next:** [Compatibility and support](compatibility.md) — Appendix C
|
|
439
|
+
- **Index:** [Guides index](README.md) · [The FletBox Book](../README.md)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Ship updates without the store (OTA / online updates)
|
|
2
|
+
|
|
3
|
+
> **Level: Advanced.** This page is for shipping — skip it on a first read. It follows [Add FletBox to an existing page](embedding.md) in the book's reading path.
|
|
4
|
+
|
|
5
|
+
FletBox apps are 100% web at their core: the Android/iOS build is a thin native shell (Capacitor) around a web bundle. That means the **web layer can update itself over the air**: you publish the app to the store **once**, and every later change to your UI/logic reaches installed apps the next time they open — no new store submission, no user download of the whole app.
|
|
6
|
+
|
|
7
|
+
This page explains the whole pipeline: what `flet-box release` does, what the `config.json` manifest contains, what the running app does with it, and — critically — **what OTA can and cannot change**.
|
|
8
|
+
|
|
9
|
+
## The pipeline at a glance
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
you edit source code
|
|
13
|
+
|
|
|
14
|
+
| flet-box release (bumps version, rebuilds www/, git tag v1.0.1)
|
|
15
|
+
v
|
|
16
|
+
git tag v1.0.1 pushed to GitHub
|
|
17
|
+
|
|
|
18
|
+
| GitHub Actions (on: tags v*)
|
|
19
|
+
v
|
|
20
|
+
www/ deployed to GitHub Pages <- the ONLY place an update is published
|
|
21
|
+
|
|
|
22
|
+
| app opens (web or installed mobile app)
|
|
23
|
+
v
|
|
24
|
+
loader.js fetches <update.url>/config.json
|
|
25
|
+
|
|
|
26
|
+
| hash differs from the running bundle?
|
|
27
|
+
+-- no -> run the bundle already on the device
|
|
28
|
+
+-- yes -> show "Update available" dialog
|
|
29
|
+
| Accept
|
|
30
|
+
v
|
|
31
|
+
download bundle, verify sha256, store it, run it
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Three invariants make this safe:
|
|
35
|
+
|
|
36
|
+
1. **Updates are published only by release tags.** Ordinary `git push` runs CI (so breakage is caught) but never publishes, so a half-finished test build can never reach your users.
|
|
37
|
+
2. **The app verifies integrity.** A downloaded bundle is executed only if its sha256 matches the hash in `config.json`.
|
|
38
|
+
3. **The app always launches.** Offline, a wrong URL, a hash mismatch, or a declined dialog all fall back to the bundle already on the device. OTA can never brick the app.
|
|
39
|
+
|
|
40
|
+
## Cutting a release
|
|
41
|
+
|
|
42
|
+
Work on your code freely and build preview bundles as often as you like — **the version number does not move** on a normal build. When the code is stable and you want it to reach users:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
flet-box release # bump PATCH (1.0.0 -> 1.0.1), rebuild, commit, tag v1.0.1
|
|
46
|
+
flet-box release --minor # bump MINOR (1.0.0 -> 1.1.0)
|
|
47
|
+
flet-box release --major # bump MAJOR (1.0.0 -> 2.0.0)
|
|
48
|
+
flet-box release --push # also push the commit and the tag to origin
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`flet-box release` does, in order:
|
|
52
|
+
|
|
53
|
+
1. Refuses to run if the working tree has uncommitted changes (the tag must capture exactly what you release).
|
|
54
|
+
2. Bumps the version in `package.json` using the odometer scheme below.
|
|
55
|
+
3. Rebuilds the production bundle (`www/`), which regenerates `www/config.json` with the new version and the sha256 of the new bundle.
|
|
56
|
+
4. Commits the version bump and creates the annotated tag `vX.Y.Z`.
|
|
57
|
+
5. Optionally pushes (`--push`), which triggers the CI deploy.
|
|
58
|
+
|
|
59
|
+
If the build fails, the version bump is rolled back so a failed release leaves no trace.
|
|
60
|
+
|
|
61
|
+
### Odometer versioning
|
|
62
|
+
|
|
63
|
+
Versions are `MAJOR.MINOR.PATCH` where **MAJOR grows without bound** and **MINOR/PATCH are single digits (0–9)** that carry like an odometer:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
1.0.8 -> 1.0.9 -> 1.1.0 -> ... -> 1.9.9 -> 2.0.0 -> ... -> 9.9.9 -> 10.0.0
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
When a position passes 9 it resets to 0 and carries into the position on its left. MAJOR never caps, so you can never run out of versions.
|
|
70
|
+
|
|
71
|
+
## The `config.json` manifest
|
|
72
|
+
|
|
73
|
+
Every bundle ships a small manifest at `www/config.json`. This is what a running app fetches (a ~200-byte check, not the whole bundle):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"version": "1.0.1",
|
|
78
|
+
"hash": "494ca992aecf2de1e32680eae56405ec42baaa9b455248a4999df2edb76ad0b9",
|
|
79
|
+
"builtAt": "2026-10-11T19:53:24.524Z",
|
|
80
|
+
"bundle": "src/app.js",
|
|
81
|
+
"size": 36132,
|
|
82
|
+
"minNativeVersion": "0.0.0",
|
|
83
|
+
"update": {
|
|
84
|
+
"url": "https://kuko53348.github.io/my-app/",
|
|
85
|
+
"mode": "prompt",
|
|
86
|
+
"channel": "stable",
|
|
87
|
+
"mandatory": false,
|
|
88
|
+
"notes": "Fixed the login timeout."
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Field | Meaning |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `version` | Human-readable label from `package.json` (shown in the dialog). |
|
|
96
|
+
| `hash` | sha256 of the bundle. **This is what drives the update decision**, not the version. |
|
|
97
|
+
| `bundle` | Path of the bundle relative to the update URL. |
|
|
98
|
+
| `size` | Bundle size in bytes (shown in the dialog as KB). |
|
|
99
|
+
| `minNativeVersion` | Oldest native shell this bundle supports. Older shells are told to update from the store instead. |
|
|
100
|
+
| `update.url` | Where `config.json` and the bundle are published (your GitHub Pages site). |
|
|
101
|
+
| `update.mode` | `prompt` (ask the user, default) or `auto` (download silently). |
|
|
102
|
+
| `update.mandatory` | `true` hides the "Later" button so the update cannot be skipped. |
|
|
103
|
+
| `update.notes` | Release notes shown in the dialog. |
|
|
104
|
+
| `update.channel` | Label for rollout channels (e.g. `stable`, `beta`). |
|
|
105
|
+
|
|
106
|
+
### Where the update URL comes from
|
|
107
|
+
|
|
108
|
+
`update.url` is resolved automatically, in this order:
|
|
109
|
+
|
|
110
|
+
1. `update.url` in `fletbox.config.json` at your project root (explicit wins).
|
|
111
|
+
2. Derived from the `repository` field of `package.json`, mapped to GitHub Pages: `https://<user>.github.io/<repo>/`.
|
|
112
|
+
3. Derived from the **current project's** git remote `origin` (when it is a GitHub URL). This means `flet-box createBundle` always points at the project it is built in, never at the flet-box framework installed as a dependency.
|
|
113
|
+
4. If none of these exist, OTA is **disabled** and the bundle simply runs what shipped in it.
|
|
114
|
+
|
|
115
|
+
To configure it by hand, create `fletbox.config.json`:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"update": {
|
|
120
|
+
"url": "https://kuko53348.github.io/my-app/",
|
|
121
|
+
"mode": "prompt",
|
|
122
|
+
"mandatory": false,
|
|
123
|
+
"notes": "",
|
|
124
|
+
"minNativeVersion": "0.0.0",
|
|
125
|
+
"channel": "stable"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## What the app does on launch
|
|
131
|
+
|
|
132
|
+
`www/loader.js` (wired in automatically as the module entry of every production bundle) runs **before** your app:
|
|
133
|
+
|
|
134
|
+
1. Reads the shipped `config.json` to learn the update URL and the hash of the bundle on the device.
|
|
135
|
+
2. Fetches the remote `config.json` with `cache: no-store` and a short timeout.
|
|
136
|
+
3. If the remote hash equals the running hash, it logs "up to date" and starts the app immediately.
|
|
137
|
+
4. If they differ, it either downloads silently (`mode: "auto"` or `mandatory`) or shows the **Update available** dialog with the version change, your release notes, and the download size, offering **Later** / **Update now**.
|
|
138
|
+
5. On accept it downloads the bundle, recomputes its sha256, and only runs it if the hash matches. The bundle is then kept in Cache Storage so the next launch uses it even offline.
|
|
139
|
+
|
|
140
|
+
The dialog is plain HTML/CSS rendered by the loader itself, so it appears before the framework (and your UI) loads.
|
|
141
|
+
|
|
142
|
+
## What OTA can and cannot change
|
|
143
|
+
|
|
144
|
+
OTA replaces the **web layer only** — the files inside `www/`.
|
|
145
|
+
|
|
146
|
+
| Updates over the air | Needs a new store submission |
|
|
147
|
+
| --- | --- |
|
|
148
|
+
| UI, screens, widgets, styles | New native plugins / Capacitor version |
|
|
149
|
+
| App logic and routing | New Android/iOS permissions |
|
|
150
|
+
| Text, images, fonts, assets in `www/` | Changes to `AndroidManifest.xml` / `Info.plist` |
|
|
151
|
+
| Bug fixes and new JS features | Native code or signing changes |
|
|
152
|
+
| Anything inside the bundle | Anything that changes the app's identity or purpose |
|
|
153
|
+
|
|
154
|
+
Rule of thumb: if the change lives in `src/` (your FletBox code) it ships OTA; if it lives in the native shell it goes through the store. The `minNativeVersion` field exists for the boundary case where a new web bundle needs a newer shell: older shells skip the OTA and you direct users to the store update.
|
|
155
|
+
|
|
156
|
+
## Store policy (read this before relying on OTA)
|
|
157
|
+
|
|
158
|
+
Both stores permit over-the-air updates of **interpreted code** (JavaScript in a WebView counts), with conditions. This is a summary, not legal advice — check the current policy text before shipping.
|
|
159
|
+
|
|
160
|
+
- **Google Play** (Device and Network Abuse policy): apps may not download and execute code that changes the app's behavior outside a virtual machine/interpreter. Code running in an interpreter (your JS in the Capacitor WebView) **is** allowed. You may add features and fix bugs OTA; you may not push new APKs or escalate permissions OTA.
|
|
161
|
+
- **Apple (App Review Guideline 2.5.2)**: interpreted code may be updated OTA only if it does not change the **primary purpose** of the app. Patches, minor features, and assets are fine; turning a catalog app into a payment app (or anything that changes what the app fundamentally is) requires review.
|
|
162
|
+
|
|
163
|
+
Because of these rules, keep OTA updates within the app's existing purpose, and never use OTA to request new permissions or swap the native shell.
|
|
164
|
+
|
|
165
|
+
## Offline behaviour and the service worker
|
|
166
|
+
|
|
167
|
+
The generated service worker uses a hybrid strategy so OTA and offline coexist:
|
|
168
|
+
|
|
169
|
+
- **Updatable shell** (`index.html`, `loader.js`, `config.json`, `src/app.js`): network-first. Online users always get fresh bytes, so a new release is picked up immediately and the worker never serves a stale `app.js`. Offline, the last cached copy is used.
|
|
170
|
+
- **Static assets** (fonts, icons, images, css): cache-first, since they are immutable per release.
|
|
171
|
+
- **Cross-origin requests** (your remote `config.json` and bundle) are left to the network and are never cached by the worker.
|
|
172
|
+
|
|
173
|
+
Downloaded OTA bundles live in a **separate** cache (`fletbox-ota`) owned by the loader, so a service-worker update never wipes an installed OTA bundle.
|
|
174
|
+
|
|
175
|
+
## Requirements and troubleshooting
|
|
176
|
+
|
|
177
|
+
Requirements: a **public** GitHub repository, GitHub Pages enabled (Settings → Pages → Source = "GitHub Actions"), and the workflow from `flet-box create` (it already deploys `www/` on `v*` tags). GitHub Pages and Actions are free for public repos.
|
|
178
|
+
|
|
179
|
+
| Symptom | Likely cause |
|
|
180
|
+
| --- | --- |
|
|
181
|
+
| Build prints "THIS APP DOES NOT SUPPORT OTA UPDATES" | No public GitHub repo is reachable from the project (no `origin` remote, a non-GitHub remote, or nothing configured). The app still works — it runs the bundle it shipped with. Create the repo, push it, and rebuild. |
|
|
182
|
+
| No dialog, app runs old code | `update.url` missing/incorrect, or the tag was never pushed (CI never published). |
|
|
183
|
+
| `hash mismatch` in console | The published `config.json` and bundle are from different builds. Re-run `flet-box release` so both are published together. |
|
|
184
|
+
| Dialog appears but download fails | The Pages site is not reachable/CORS-blocked from the app origin. Pages serves with permissive headers; check you are not behind a proxy that strips them. |
|
|
185
|
+
| Update applies but reverts on next launch | Cache Storage unavailable (private browsing). The bundle runs once but cannot persist. |
|
|
186
|
+
| Want to force a clean state | Clear site data for the app origin (this removes the OTA cache and localStorage entry). |
|
|
187
|
+
|
|
188
|
+
Because the decision is hash-based, two builds of identical source produce the same hash and no spurious update is offered; only a real content change triggers the dialog.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Continue reading
|
|
193
|
+
|
|
194
|
+
- **Previous:** [Add FletBox to an existing page](embedding.md)
|
|
195
|
+
- **Next:** none — you reached the end of the book.
|
|
196
|
+
- **Index:** [Guides index](README.md) · [The FletBox Book](../README.md)
|