{"id":19260603,"url":"https://github.com/evant/self-update","last_synced_at":"2025-04-21T16:32:06.309Z","repository":{"id":257897487,"uuid":"868255384","full_name":"evant/self-update","owner":"evant","description":"A system for self-updating your android app.","archived":false,"fork":false,"pushed_at":"2024-10-22T01:51:02.000Z","size":231,"stargazers_count":31,"open_issues_count":9,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-22T12:00:08.498Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-05T22:05:57.000Z","updated_at":"2024-10-22T01:51:05.000Z","dependencies_parsed_at":"2024-10-22T08:03:18.186Z","dependency_job_id":"76885c60-a6bb-4361-b7f0-15f761ae4844","html_url":"https://github.com/evant/self-update","commit_stats":null,"previous_names":["evant/self-update"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fself-update","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fself-update/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fself-update/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fself-update/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evant","download_url":"https://codeload.github.com/evant/self-update/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223871483,"owners_count":17217564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T19:21:59.276Z","updated_at":"2025-04-21T16:32:06.302Z","avatar_url":"https://github.com/evant.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Self Update\n\nA system for self-updating your android app.\n\n**Work in progress!** Not production-ready, apis may change in a backwards-incompatible way.\n\n## Setup\n\n### Gradle Plugin\n\nAdd the gradle plugin to you project\n```kotlin\nplugins {\n    id(\"me.tatarka.android.selfupdate\")\n}\n```\nAnd run\n```kotlin\n./gradlew packageSelfUpdate\n```\n\nThis plugin will generate a json manifest file to represent updates as well as extract the necessary\napk artifacts. You can find the output in `app/build/outputs/selfupdate/[debug/release]`. You can\nhost these files however you like, the app will just need the url to the manifest.json. We are going\nto use python to start a simple web server for the remainder of this documentation.\n\n```shell\ncd app/build/outputs/selfupdate/debug\npyhton3 -m http.server\n```\n\n#### Manifest customization\n\nYou can set specific tags and release notes on the manifest either globally, or per-variant.\n\n```kotlin\n// build.gradle.kts\nselfUpdate {\n    notes = \"Notes for this release\"\n}\n\nandroid {\n   buildTypes {\n       debug {\n           selfUpdate {\n               // disable for debug builds\n               enabled = false\n           }\n       }\n       release {\n           selfUpdate {\n               // add a release tag\n               tags = setOf(\"release\")\n           }\n       }\n   } \n}\n```\n\n#### Base Manifest\n\nYou can base your release off of an existing manifest, this allows you to keep a record of multiple\nreleases.\n\n```kotlin\n// build.gradle.kts\nandroid {\n    buildTypes {\n        release {\n            selfUpdate {\n                base {\n                    // Point to an existing manifest file to add too.\n                    manifest = file(\"manifest.json\")\n                    // This will update the manifest with the current release\n                    // when you run ./gradlew packageSelfUpdate\n                    update = true\n                }\n            }\n        }\n    }\n}\n```\n\n#### Universal apks\n\nYou can additionally package a universal apk and include it in the manifest. This won't be used by\nself-update but can be useful for direct linking an initial download and for other tooling that\ndoesn't support apk splits.\n\n```kotlin\n// build.gradle.kts\nselfUpdate {\n    includeUniveral = true\n}\n```\n\n#### Merge manifests\n\nYou can merge all your variants into a single manifest. This allows you to have a single url to\nfetch from. Each variant release will be tagged by that variant's name.\n\n```kotlin\n// build.gradle.kts\nselfUpdate {\n    mergeVariants = true\n}\n```\n\nNote: The output will now be directly under `app/build/outputs/selfupdate` and no subfolders will be\ncreated.\n\n### Library\n\nAdd the library to your app\n```kotlin\nimplementation(\"me.tatarka.android.selfupdate:self-update-core\")\n```\n\nAn update flow works as follows:\n\n1. Fetch possible updates from your hosted manifest. You can then prompt the user to update to the \n   latest or present them a list to choose from.\n   ```kotlin\n   val selfUpdate = SelfUpdate(context)\n   val releases = selfUpdate.check(\n      manifestUrl = \"http://10.0.0.18:8000/manifest.json\",\n      tags = setOf(\"release\"), // optionally filter releases by one or more tags\n      onlyUpgrades = true, // set false to return previous releases\n   )\n   ```\n2. Optinally download a given release.\n   ```kotlin\n   try {\n      selfUpdate.download(release, onProgress = { progress -\u003e /* Download/Install progress */})\n   } catch (e: IOException) {\n      // failed to download, calling download again will resume where it left off\n   }\n   ```\n4. Install a given release, will also download if not downloaded already.\n   Note: it's likely this will prompt the user so you should consider when to do this.\n   ```kotlin\n   try {\n      selfUpdate.install(release, onProgress = { progress -\u003e /* Download/Install progress */})\n   } catch (e: IOException) {\n      // either failed to download or install\n   }\n   // on success it's likely your app process is killed so anything after this would be unreachable.\n   ```\n\n#### Listening for Updates\n\nYou can optionally listen for update broadcasts, for example, to show a notification to the user.\n\n1. Create your broadcast receiver\n   ```kotlin\n   class MyUpdateReceiver : SelfUpdateReceiver() {\n      override fun onUpdate(context: Context) {\n          // show notification\n      }\n   }\n   ```\n2. Declare in your manifest, replacing the default one.\n   ```xml\n   \u003capplication\u003e\n       \u003creceiver\n           android:name=\"me.tatarka.android.selfupdate.SelfUpdateReceiver\"\n           tools:node=\"remove\" /\u003e\n\n       \u003creceiver android:name=\".MyUpdateReceiver\"\u003e\n           \u003cmeta-data\n               android:name=\"me.tatarka.android.selfupdate.SelfUpdateReceiver\"\n               android:value=\"true\" /\u003e\n       \u003c/receiver\u003e\n   \u003c/application\u003e \n   ```\n\n### Manifest Format\n\nThe manifest format is as follows. If you don't wish to use the gradle plugin you can write it by\nhand or generate it using some other method.\n\n```json5\n{\n   // A list of releases. These may be in any order but it's recommend you place the newer ones first.\n   \"releases\": [\n      {\n         // The version name of the release (equivalent to android:versionName in AndroidManifest.xml)\n         \"version_name\": \"1.0\",\n         // The version code of the release (equivalent to android:versionCode in AndroidManifest.xml)\n         \"version_code\": 1,\n         // A list or arbitrary tags for the release, can be used for filtering. (optional)\n         \"tags\": [\"release\"],\n         // Notes for the release which may be shown to the user. (optional)\n         \"notes\": \"Release notes\",\n         // The minimum sdk version for the release. (optional)\n         \"minSdk\": 21,\n         // The maximum sdk version for the release. (optional)\n         \"maxSdk\": 34,\n         // Versioning metadata to ensure this release is compatible with the library that's \n         // performing the update.\n         \"meta\": {\n            // The version of self-update that this release was generated with.\n            \"version\": 1,\n            // The version of self-update that this release is compatible with.\n            \"feature_version\": 1\n         },\n         // A list of artifacts for this release. A subset will be picked for a specific device.\n         \"artifacts\": [\n            {\n               // The path to the artifact. Say you have this manifest hosted at\n               // https://example.com/release/manifest.json\n               // This can be:\n               // 1. a relative path (base.apk -\u003e https://example.com/release/base.apk)\n               // 2. a domain-absolute path (/base.apk -\u003e https://example.com/base.apk)\n               // 3. a full url (https://cdn.example.com/base.apk)\n               \"path\": \"base.apk\",\n               // If this artifact is universal. (optional)\n               // Skipped by self-update but may be useful for installing with other tooling. \n               \"universal\": false,\n               // The minSdk for this artifact. This should be at least the release's minSdk. (optional)\n               \"minSdk\": 21,\n               // The abi for this artifact. (optional) \n               \"abi\": \"armabi_v7a\",\n               // The density (dpi) for this artifact. (optional)\n               \"density\": 320,\n               // The language for this artifact. (optional)\n               \"language\": \"en\",\n               // The apk checksums are returned from apksigner. (optional)\n               // The format is: signingVersion:algorithm:base64UrlEncodedValue\n               // Currently v2:sha256 \u0026 v2:sha512 are supported.\n               // While this argument is optional it is highly recommend you provide it.\n               \"checksums\": [\n                  \"v2:sha256:\"\n               ]\n            }\n         ]\n      }\n   ]\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fself-update","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevant%2Fself-update","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fself-update/lists"}