{"id":13607076,"url":"https://github.com/SimonMarquis/InternalAppStore","last_synced_at":"2025-04-12T11:31:28.691Z","repository":{"id":70130510,"uuid":"131399907","full_name":"SimonMarquis/InternalAppStore","owner":"SimonMarquis","description":"📦 Manage your own internal Android App Store.","archived":false,"fork":false,"pushed_at":"2024-04-14T21:21:43.000Z","size":48332,"stargazers_count":504,"open_issues_count":5,"forks_count":63,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-04-16T11:22:04.027Z","etag":null,"topics":["android","appstore","firebase","firebase-auth","firebase-cloud-messaging","firebase-database","firebase-functions","firebase-hosting","firebase-storage"],"latest_commit_sha":null,"homepage":"https://public-app-store.web.app","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/SimonMarquis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2018-04-28T10:27:38.000Z","updated_at":"2024-04-19T15:55:05.867Z","dependencies_parsed_at":"2023-10-24T18:31:50.668Z","dependency_job_id":"cb69e3b6-a2a5-4532-bbd5-2fdbbfe2d835","html_url":"https://github.com/SimonMarquis/InternalAppStore","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonMarquis%2FInternalAppStore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonMarquis%2FInternalAppStore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonMarquis%2FInternalAppStore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SimonMarquis%2FInternalAppStore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SimonMarquis","download_url":"https://codeload.github.com/SimonMarquis/InternalAppStore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248560111,"owners_count":21124594,"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":["android","appstore","firebase","firebase-auth","firebase-cloud-messaging","firebase-database","firebase-functions","firebase-hosting","firebase-storage"],"created_at":"2024-08-01T19:01:15.367Z","updated_at":"2025-04-12T11:31:23.681Z","avatar_url":"https://github.com/SimonMarquis.png","language":"Kotlin","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"art/ic_launcher_web.png\" alt=\"\" width=\"96px\" height=\"96px\"\u003e\n\u003c/div\u003e\n\u003ch3 align=\"center\"\u003eInternal App Store\u003c/h3\u003e\n\u003cp align=\"center\"\u003e\n  Manage your own internal Android App Store.\u003cbr\u003e\n  \u003ca href=\"https://public-app-store.web.app/\"\u003e\u003cstrong\u003eWeb app\u003c/strong\u003e\u003c/a\u003e • \u003ca href=\"https://github.com/SimonMarquis/InternalAppStore/releases\"\u003e\u003cstrong\u003eAndroid app\u003c/strong\u003e\u003c/a\u003e\u003cbr\u003e\n  \u003ca href=\"https://github.com/SimonMarquis/InternalAppStore/actions/workflows/android.yml\"\u003e\u003cimg src=\"https://github.com/SimonMarquis/InternalAppStore/actions/workflows/android.yml/badge.svg\" alt=\"🤖 Android CI\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n![App Store](art/header.png)\n\n## Table of contents\n\n\u003c!-- MarkdownTOC levels=\"2\" --\u003e\n\n- [Demo](#demo)\n- [Features](#features)\n- [Deploy](#deploy)\n- [Settings](#settings)\n- [Backup](#backup)\n- [License](#license)\n\n\u003c!-- /MarkdownTOC --\u003e\n\n## Demo\n\nA public version of the web app is hosted on [public-app-store.web.app](https://public-app-store.web.app).  \nThe latest Android apk can also be downloaded [here](https://github.com/SimonMarquis/InternalAppStore/releases).\n\n## Features\n\n- Public or private access to the store\n  + User roles (anonymous or verified users)\n  + Account restrictions (only admins have write access)\n\n  \u003cbr\u003e\n  \u003cdetails\u003e\n  \u003csummary\u003e📷 \u003cb\u003e\u003ci\u003eScreenshots\u003c/i\u003e\u003c/b\u003e\u003c/summary\u003e\n\n  | Web | Android |\n  |:---:|:---:|\n  | \u003cimg src=\"art/web_sign_in.png\" width=\"500px\" title=\"Login\"\u003e | \u003cimg src=\"art/android_sign_in.png\" width=\"300px\" title=\"Login\"\u003e |\n\n  \u003c/details\u003e\n- Manage multiple applications\n  + Notifications for new applications\n  + Description with html support\n  + Shortcuts for frequent actions\n\n  \u003cbr\u003e\n  \u003cdetails\u003e\n  \u003csummary\u003e📷 \u003cb\u003e\u003ci\u003eScreenshots\u003c/i\u003e\u003c/b\u003e\u003c/summary\u003e\n\n  | Web | Android |\n  |:---:|:---:|\n  | \u003cimg src=\"art/web_applications_admin.png\" width=\"500px\" title=\"List of applications\"\u003e | \u003cimg src=\"art/android_applications.png\" width=\"300px\" title=\"List of applications\"\u003e |\n  | \u003cimg src=\"art/web_applications_add.png\" title=\"Add application\"\u003e |  |\n  | \u003cimg src=\"art/web_applications_edit.png\" title=\"Edit application\"\u003e |  |\n\n  \u003c/details\u003e\n- Manage multiple versions\n  + Notifications for new versions\n  + Upload apks or external links\n  + Changelog with html support\n  + Apk files are cached\n\n  \u003cbr\u003e\n  \u003cdetails\u003e\n  \u003csummary\u003e📷 \u003cb\u003e\u003ci\u003eScreenshots\u003c/i\u003e\u003c/b\u003e\u003c/summary\u003e\n\n  | Web | Android |\n  |:---:|:---:|\n  | \u003cimg src=\"art/web_versions.png\" width=\"500px\" title=\"List of versions\"\u003e | \u003cimg src=\"art/android_versions_downloading.png\" width=\"300px\" title=\"List of versions\"\u003e |\n  | \u003cimg src=\"art/web_versions_add.png\" width=\"500px\" title=\"Add version\"\u003e |  |\n\n  \u003c/details\u003e\n\n## Deploy\n\n\u003e Requirements\n\u003e - [Android Studio](https://developer.android.com/studio/)\n\u003e - [Firebase account](https://console.firebase.google.com)\n\u003e - [Firebase CLI](https://github.com/firebase/firebase-tools)\n\n#### Configure\n\n- Replace `applicationId` with your own unique id in [app/build.gradle](app/build.gradle#L15)\n- Create a Firebase project https://console.firebase.google.com\n- Select `Add Firebase to your Android app` and fill in the form\n- Download the config file `google-services.json` and move it to your [Android app module root directory](app/)\n- In the Firebase Authentication page, enable sign-in methods, then create your first admin user\n- In the Firebase project settings, select `ADD APP` and `Add Firebase to your web app`\n- When using Firebase Hosting and the CLI, [Web SDK auto-configuration](https://firebase.googleblog.com/2017/04/easier-configuration-for-firebase-on-web.html) is [enabled by default](https://github.com/SimonMarquis/InternalAppStore/commit/2b94dd0e7e1614a06a3126f57e2fb69cfeeab257)\n- Verify the configuration of each module\n  + Android: [Store.kt](app/src/main/java/fr/smarquis/appstore/Store.kt#L18-L30)\n  + Web: [index.js](firebase/hosting/index.js#L5-L23)\n  + Firebase Database: use your own domain\n    * [database-private.rules.json (read access)](firebase/database/database-private.rules.json#L19-L20)\n    \u003cdetails\u003e\n    \u003csummary\u003eDatabase schema\u003c/summary\u003e\n\n    ```\n    ├──admins\n    │   └──{$uid}\n    ├──store\n    │   ├──applications\n    │   │   └──{$application_id}\n    │   │       ├──name\n    │   │       ├──packageName\n    │   │       ├──description\n    │   │       ├──image\n    │   │       ├──link_{#}\n    │   │       │   ├──name\n    │   │       │   └──uri\n    │   │       └──silent\n    │   └──versions\n    │       └──{$application_id}\n    │           └──{$version_id}\n    │               ├──name\n    │               ├──description\n    │               ├──timestamp\n    │               ├──apkRef\n    │               ├──apkGeneration\n    │               ├──apkUrl\n    │               ├──silent\n    │               ├──downloads\n    │               └──installs\n    └──analytics\n        ├──downloads\n        │   └──{$application_id}\n        │       └──{$version_id}\n        │           └──{$uid}\n        └──installs\n            └──{$application_id}\n                └──{$version_id}\n                    └──{$uid}\n    ```\n\n    \u003c/details\u003e\n  + Firebase Storage: use your own domain\n    * [storage-private.rules (images)](firebase/storage/storage-private.rules#L6-L7)\n    * [storage-private.rules (apks)](firebase/storage/storage-private.rules#L21-L22)\n    \u003cdetails\u003e\n    \u003csummary\u003eStorage schema\u003c/summary\u003e\n\n    ```\n    └──applications\n        └──{$applicationUid}\n            │──image\n            └──versions\n                └──{$versionUid}.apk\n    ```\n\n    \u003c/details\u003e\n\n#### Initialize\n\n- Initialize Firebase module\n  ```bash\n  # Move to Firebase root directory\n  cd firebase\n  # Initialize Firebase (login popup)\n  firebase login\n  # Set the default Firebase project\n  firebase use --add\n  ```\n- Add your first admin user (`uid` found in Firebase Authentication page)\n  + Firebase Database, add admin `uid`\n    ```bash\n    firebase database:update /admins --data '{\"\u003cadmin-uid\u003e\" : \"\u003cadmin-email\u003e\"}'\n    # On Windows, create a JSON file instead (unsupported JSON input)\n    firebase database:update /admins update.json\n    ```\n  + Firebase Storage, add admin `uid`\n    * [storage-private.rules (images)](firebase/storage/storage-private.rules#L8-L9)\n    * [storage-private.rules (apks)](firebase/storage/storage-private.rules#L23-L24)\n\n#### Deploy\n\n- Test web app on your machine http://localhost:5000\n  ```bash\n  firebase serve\n  ```\n- Deploy all Firebase modules (database, storage, hosting, functions)\n  ```bash\n  firebase deploy\n  ```\n- Sync, build and install Android module from Android Studio\n\n## Settings\n\nA lot of settings can be tweaked in both web and Android apps\n- Store icons and titles\n- Firebase auth providers\n- Maximum apk size\n- Admin write access\n- Store visibility (private or public)\n- …\n\n## Backup\n\n- *Firebase Database* ([Link 1](https://firebase.googleblog.com/2017/12/read-and-write-your-realtime-database.html), [Link 2](https://firebase.google.com/docs/database/backups))\n  ```bash\n  // Backup\n  firebase database:get / --pretty \u003e database.json\n  // Restore\n  firebase database:set / database.json\n  ```\n- *Firebase Storage* ([Link](https://stackoverflow.com/questions/46369844/is-it-a-way-to-backup-data-in-firebase-storage))\n  ```bash\n  // Backup\n  gsutil -m cp -R gs://\u003cbucket_name\u003e .\n  // Restore\n  gsutil -m cp -R . gs://\u003cbucket_name\u003e\n  ```\n\n## License\n\n```\nCopyright 2018 Simon Marquis\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSimonMarquis%2FInternalAppStore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSimonMarquis%2FInternalAppStore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSimonMarquis%2FInternalAppStore/lists"}