Force or suggest in-app updates for Android apps outside the Play Store.
Works with Kotlin / Java and Flutter. Updates are stored on private S3-compatible object storage (Backblaze B2 recommended — free tier, no card, large APKs OK).
Loupdate.init(
this,
LoupdateConfig(
endpoint = "https://s3.eu-central-003.backblazeb2.com",
region = "eu-central-003",
bucket = "Loupdate",
accessKeyId = BuildConfig.LOUPDATE_KEY_ID, // read-only key
secretAccessKey = BuildConfig.LOUPDATE_KEY_SECRET,
appId = "my-shop", // folder in the bucket
)
)
Loupdate.check(this) // call on launch (e.g. MainActivity.onCreate)- Soft update → dismissible dialog
- Force update → full-screen, app blocked until installed
- Download + install inside the app (progress bar)
- Create a private bucket (e.g.
Loupdate) - Create two Application Keys:
loupdate-app-read→ Read Only on that bucket → embed in the apploupdate-publish→ Read and Write → only on your machine / CI (never in the APK)
Details: docs/hosting-b2.md
implementation("com.loupdate:loupdate-core:0.1.0")
// or include the module from this repo while developingTheme : the host app must use a Material theme (Material 3 recommended), e.g. in themes.xml / manifest:
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar" /><application android:theme="@style/Theme.MyApp" ...>Without that, the soft-update dialog (MaterialAlertDialogBuilder) can crash. Force update uses its own Material theme.
See examples/kotlin-app.
cd cli && pip install -e .
export LOUPDATE_ENDPOINT=https://s3.eu-central-003.backblazeb2.com
export LOUPDATE_REGION=eu-central-003
export LOUPDATE_BUCKET=Loupdate
export LOUPDATE_ACCESS_KEY_ID=... # publish key
export LOUPDATE_SECRET_ACCESS_KEY=...
loupdate publish --app my-shop --apk ./app-release.apk --force falseThis uploads my-shop/app-<versionCode>.apk and writes my-shop/update.json.
dependencies:
loupdate:
path: ../flutter/loupdate # or pub.dev laterawait Loupdate.init(LoupdateConfig(
endpoint: '...',
region: '...',
bucket: 'Loupdate',
accessKeyId: '...',
secretAccessKey: '...',
appId: 'my-shop',
));
await Loupdate.check();Loupdate/ # one private bucket
my-shop/update.json
my-shop/app-42.apk
my-crm/update.json
my-crm/app-7.apk
{
"versionCode": 42,
"versionName": "2.1.0",
"apkObject": "my-shop/app-42.apk",
"force": false,
"minVersionCode": 40,
"title": "Nouvelle version",
"message": "Corrections et améliorations.",
"changelog": ["Fix crash", "Perf"],
"sha256": "..."
}Rules: update if versionCode > installed; force if force: true or installed < minVersionCode.
- Host app theme must be Material (
Theme.Material3.*orTheme.MaterialComponents.*). - Sign the new APK with the same keystore as the installed app.
- Use a read-only key in the client; never ship the publish / master key.
- Play Store apps: do not use sideload OTA (policy). Loupdate is for off-Play distribution.
| Path | Role |
|---|---|
loupdate-core/ |
Android library |
examples/kotlin-app/ |
Sample app |
cli/ |
loupdate publish |
flutter/loupdate/ |
Flutter plugin |
docs/ |
Hosting guides |
MIT