Skip to content

Repository files navigation

Loupdate

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)

Quick start (5 minutes)

1. Storage (Backblaze B2)

  1. Create a private bucket (e.g. Loupdate)
  2. Create two Application Keys:
    • loupdate-app-read → Read Only on that bucket → embed in the app
    • loupdate-publish → Read and Write → only on your machine / CI (never in the APK)

Details: docs/hosting-b2.md

2. Android (Kotlin)

implementation("com.loupdate:loupdate-core:0.1.0")
// or include the module from this repo while developing

Theme : 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.

3. Publish an update

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 false

This uploads my-shop/app-<versionCode>.apk and writes my-shop/update.json.

4. Flutter

dependencies:
  loupdate:
    path: ../flutter/loupdate   # or pub.dev later
await Loupdate.init(LoupdateConfig(
  endpoint: '...',
  region: '...',
  bucket: 'Loupdate',
  accessKeyId: '...',
  secretAccessKey: '...',
  appId: 'my-shop',
));
await Loupdate.check();

Bucket layout (multi-app)

Loupdate/                 # one private bucket
  my-shop/update.json
  my-shop/app-42.apk
  my-crm/update.json
  my-crm/app-7.apk

update.json

{
  "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.

Important

  • Host app theme must be Material (Theme.Material3.* or Theme.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.

Repo layout

Path Role
loupdate-core/ Android library
examples/kotlin-app/ Sample app
cli/ loupdate publish
flutter/loupdate/ Flutter plugin
docs/ Hosting guides

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages