Skip to content
This repository has been archived by the owner on Sep 28, 2024. It is now read-only.

Commit

Permalink
🎺 Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonMarquis committed Apr 29, 2018
1 parent 809a2b1 commit 816c6a6
Show file tree
Hide file tree
Showing 104 changed files with 11,790 additions and 5 deletions.
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ captures/

# Keystore files
# Uncomment the following line if you do not want to check your keystore files in.
#*.jks
*.jks

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

# Google Services (e.g. APIs or Firebase)
# google-services.json
google-services.json

### Windows
### https://raw.githubusercontent.com/github/gitignore/master/Global/Windows.gitignore
Expand Down Expand Up @@ -113,5 +113,5 @@ Temporary Items

# Local config
**/.firebaserc
**/database-perso.rules.json
**/storage-perso.rules
**/database-local.rules.json
**/storage-local.rules
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

<!-- MarkdownTOC -->

- [1.0.0](#100)

<!-- /MarkdownTOC -->

## 1.0.0

- 🎺 Initial release!
199 changes: 198 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,201 @@
# Internal App Store
<div align="center">
<img src="art/ic_launcher_web.png" alt="" width="96px" height="96px">
</div>
<h3 align="center">Internal App Store</h3>
<p align="center">
Manage your own internal Android App Store.<br>
<a href=""><strong>Web app</strong></a> • <a href=""><strong>Android app</strong></a>
</p>

<br>

![App Store](art/header.png)

## Table of contents

<!-- MarkdownTOC levels="2" -->

- [Demo](#demo)
- [Features](#features)
- [Deploy](#deploy)
- [Settings](#settings)
- [Backup](#backup)
- [License](#license)

<!-- /MarkdownTOC -->

## Demo

A public version of the web app is hosted on [public-app-store.firebaseapp.com](https://public-app-store.firebaseapp.com/).
The latest Android apk can also be downloaded [here](https://github.com/SimonMarquis/InternalAppStore/releases).

## Features

- Public or private access to the store
- User roles (anonymous or verified users)
- Account restrictions (only admins have write access)
<details>
<summary>📷 <b><i>Screenshots</i></b></summary>

| Web | Android |
|:---:|:---:|
| <img src="art/web_sign_in.png" width="500px" title="Login"> | <img src="art/android_sign_in.png" width="300px" title="Login"> |

</details>
- Manage multiple applications
+ Notifications for new applications
+ Description with html support
+ Shortcuts for frequent actions
<details>
<summary>📷 <b><i>Screenshots</i></b></summary>

| Web | Android |
|:---:|:---:|
| <img src="art/web_applications_add.png" title="Add application"> | |
| <img src="art/web_applications_edit.png" title="Edit application"> | |
| <img src="art/web_applications_admin.png" width="500px" title="List of applications"> | <img src="art/android_applications.png" width="300px" title="List of applications"> |

</details>
- Manage multiple versions
+ Notifications for new versions
+ Upload apks or external links
+ Changelog with html support
+ Apk files are cached
<details>
<summary>📷 <b><i>Screenshots</i></b></summary>

| Web | Android |
|:---:|:---:|
| <img src="art/web_versions_add.png" width="500px" title="Add version"> | |
| <img src="art/web_versions.png" width="500px" title="List of versions"> | <img src="art/android_versions_downloading.png" width="300px" title="List of versions"> |

</details>

## Deploy

> Requirements
> - [Android Studio](https://developer.android.com/studio/)
> - [Firebase account](https://console.firebase.google.com)
> - [Firebase CLI](https://github.com/firebase/firebase-tools)
#### Configure

- Replace `applicationId` with your own unique id in [app/build.gradle](app/build.gradle#L12)
- Create a Firebase project https://console.firebase.google.com
- Select `Add Firebase to your Android app` and fill in the form
- Download the config file `google-services.json` and move it to your [Android app module root directory](app/)
- In the Firebase Authentication page, enable sign-in methods, then create your first admin user
- In the Firebase project settings, select `ADD APP` and `Add Firebase to your web app`
- Copy and replace the config values in [index.js](firebase/hosting/index.js#L4-L10)
- Verify the configuration of each module
+ Android: [Store.kt](app/src/main/java/fr/smarquis/appstore/Store.kt#L11-20)
+ Web: [index.js](firebase/hosting/index.js#L11-23)
+ Firebase Database: use your own domain
* [database-private.rules.json (read access)](firebase/database/database-private.rules.json#L19-20)
<details>
<summary>Database schema</summary>

```
├──admins
│ └──{admin-uid}
└──store
├──applications
│ └──{application-uid}
│ ├──name
│ ├──packageName
│ ├──description
│ ├──image
│ ├──link_{#}
│ │ ├──name
│ │ └──uri
│ └──silent
└──versions
└──{application-uid}
└──{version-uid}
├──name
├──description
├──timestamp
├──apkRef
├──apkGeneration
├──apkUrl
└──silent
```
</details>
+ Firebase Storage: use your own domain
* [storage-private.rules (images)](firebase/storage/storage-private.rules#L6-7)
* [storage-private.rules (apks)](firebase/storage/storage-private.rules#L21-22)
<details>
<summary>Storage schema</summary>
```
└──applications
└──{application-uid}
│──image
└──versions
└──{version-uid}.apk
```
</details>
#### Initialize
- Initialize Firebase module
```bash
# Move to Firebase root directory
cd firebase
# Initialize Firebase (login popup)
firebase login
```
- Add your first admin user (`uid` found in Firebase Authentication page)
+ Firebase Database, add admin `uid`
```bash
firebase database:update /admins --data '{"<admin-uid>" : "<admin-email>"}'
# On Windows, create a JSON file instead (unsupported JSON input)
firebase database:update /admins update.json
```
+ Firebase Storage, add admin `uid`
* [storage-private.rules (images)](firebase/storage/storage-private.rules#L8-9)
* [storage-private.rules (apks)](firebase/storage/storage-private.rules#L23-24)

#### Deploy

- Sync, build and install Android module from Android Studio
- Test web app on your machine http://localhost:5000
```bash
firebase serve
```
- Finally, deploy all Firebase modules (database, storage, hosting, functions)
```bash
firebase deploy
```

## Settings

A lot of settings can be tweaked in both web and Android apps
- Store icons and titles
- Firebase auth providers
- Maximum apk size
- Public with admin write access
- Store visibility (private or public)
- …

## Backup

- *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))
```bash
// Backup
firebase database:get / --pretty > database.json
// Restore
firebase database:set / database.json
```
- *Firebase Storage* ([Link](https://stackoverflow.com/questions/46369844/is-it-a-way-to-backup-data-in-firebase-storage))
```bash
// Backup
gsutil -m cp -R gs://<bucket_name> .
// Restore
gsutil -m cp -R . gs://<bucket_name>
```

## License

Expand Down
3 changes: 3 additions & 0 deletions app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/build
/release
/debug
67 changes: 67 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

apply plugin: 'kotlin-kapt'

def versionMajor = 1
def versionMinor = 0
def versionPatch = 0
def versionBuild = 0

android {
compileSdkVersion 27
defaultConfig {
applicationId "fr.smarquis.appstore"
minSdkVersion 16
targetSdkVersion 27
versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
versionName "${versionMajor}.${versionMinor}.${versionPatch}"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version") {
exclude group: 'org.jetbrains', module: 'annotations'
}
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:customtabs:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.firebaseui:firebase-ui-auth:3.2.2'
implementation 'com.firebaseui:firebase-ui-database:3.2.2'
implementation 'com.firebaseui:firebase-ui-storage:3.2.2'
implementation 'com.google.android.gms:play-services-auth:15.0.0'
implementation 'com.google.firebase:firebase-core:15.0.0'
implementation 'com.google.firebase:firebase-auth:15.0.0'
implementation 'com.google.firebase:firebase-database:15.0.0'
implementation 'com.google.firebase:firebase-storage:15.0.0'
implementation 'com.google.firebase:firebase-messaging:15.0.0'
implementation 'androidx.core:core-ktx:0.3'

implementation ('com.github.bumptech.glide:glide:4.6.1') {
exclude group: "com.android.support"
}
kapt 'com.github.bumptech.glide:compiler:4.6.1'
}



apply plugin: 'com.google.gms.google-services'
7 changes: 7 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package fr.smarquis.appstore

import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("fr.smarquis.appstore", appContext.packageName)
}
}
Loading

0 comments on commit 816c6a6

Please sign in to comment.