> ## Documentation Index
> Fetch the complete documentation index at: https://docs.startmyvpn.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Android App Configuration

> Step-by-step guide to configure, brand, and publish the Android VPN app.

The Android VPN app is a native Kotlin / Jetpack Compose application that connects to the **StartMyVPN backend** over the same REST API used by the web frontend. It supports both **WireGuard** and **OpenVPN**, and ships with a guest-mode flow, Google Play Billing, AdMob, Firebase Analytics & Crashlytics, and TLS certificate pinning.

<Warning>
  This app is a **client** for the StartMyVPN SaaS platform and will not function without it. You must have the StartMyVPN backend installed and running on your own server before this app can be used:

  **[StartMyVPN — WireGuard & OpenVPN SaaS Platform](https://startmyvpn.com)**
</Warning>

***

## Prerequisites

* **Android Studio** Hedgehog (2023.1.1) or newer
* **JDK 11**
* **Android SDK** with API 26 (min) and API 36 (target) platforms installed
* **Android NDK** `27.2.12479018` — required to build the OpenVPN native module
* A **Firebase** project for Analytics and Crashlytics
* A **Google Play Console** developer account (required to publish and to test in-app billing)
* A deployed copy of the **StartMyVPN backend** reachable over HTTPS
* The Android app source code (from your purchase)

***

## Project Layout

```
app/
├── build.gradle.kts
├── google-services.json        (placeholder — replace with your own)
├── libs/
│   └── wireguard-tunnel.aar    (NOT included — see Step 2)
└── src/main/
    ├── AndroidManifest.xml
    ├── java/com/lunecore/vpn/
    │   ├── LuneVpnApp.kt       (Application class)
    │   ├── MainActivity.kt
    │   ├── ads/                (AdMob integration)
    │   ├── billing/            (Google Play Billing)
    │   ├── data/
    │   │   ├── local/          (EncryptedSharedPreferences)
    │   │   ├── model/          (User, Server, Plan, AppConfig)
    │   │   └── remote/         (Retrofit API + Repository)
    │   ├── ui/                 (Compose screens + ViewModels)
    │   └── vpn/                (VpnManager, VpnTunnelService)
    └── res/xml/
        └── network_security_config.xml

ics-openvpn/                    (OpenVPN library module, native C++ via CMake)
```

***

## Step 1 — Open the Project

Open the project root folder in Android Studio. Let Gradle sync complete. The initial sync will fail until you complete Steps 2 and 3 below — that is expected.

<Note>
  Make sure the NDK version matches the one declared in `app/build.gradle.kts`. You can install it via *Android Studio → SDK Manager → SDK Tools → NDK (Side by side)*.
</Note>

***

## Step 2 — Add the WireGuard Library

The WireGuard tunnel library (`wireguard-tunnel.aar`) is a native dependency that is not bundled with the release package. You can either:

* Build it from source: [wireguard-android](https://github.com/nicoschmdt/wireguard-android) — follow its build instructions to produce `tunnel-release.aar` and rename it to `wireguard-tunnel.aar`.
* Or obtain a compatible prebuilt copy.

Place the final file at:

```
app/libs/wireguard-tunnel.aar
```

Without this file, Gradle sync will fail with an unresolved reference to `com.wireguard.android:tunnel`.

***

## Step 3 — Configure Firebase

1. Go to the [Firebase Console](https://console.firebase.google.com/) and create a new project.
2. Add an **Android app** with the package name you plan to use (e.g. `com.yourcompany.vpn`).
3. Download `google-services.json`.
4. Replace the placeholder file at `app/google-services.json` with your download.

The project uses Firebase for Analytics and Crashlytics. Without a valid `google-services.json` the project will **not compile** — this is enforced by the Google Services Gradle plugin.

***

## Step 4 — Set the Package Name

Pick a unique Android application ID (reverse-DNS, all lowercase, e.g. `com.yourcompany.vpn`). Update it in **all** of the following places:

### `app/build.gradle.kts`

```kotlin theme={null}
android {
    namespace = "com.yourcompany.vpn"

    defaultConfig {
        applicationId = "com.yourcompany.vpn"
        // ...
    }
}
```

### `app/google-services.json`

The `client[].client_info.android_client_info.package_name` field must match your `applicationId` exactly. If it does not, the Google Services plugin will throw an error at build time.

### `app/src/main/AndroidManifest.xml`

Update the deep-link host (see Step 7) and any `tools:replace` references that include a package path.

<Tip>
  You can use Android Studio's *Refactor → Rename* on the `com.lunecore.vpn` Java package to rename the source tree in one pass. Do this **before** changing `namespace` and `applicationId`, then resync Gradle.
</Tip>

***

## Step 5 — Configure the Backend URL

Open:

```
app/src/main/java/com/lunecore/vpn/data/remote/ApiClient.kt
```

Set your backend base URL:

```kotlin theme={null}
private const val BASE_URL = "https://vpn.yourdomain.com/api/v1/"
```

<Warning>
  The URL **must** end with `/api/v1/` (including the trailing slash). Retrofit concatenates endpoint paths directly to this base.
</Warning>

***

## Step 6 — Certificate Pinning

The app pins your backend's TLS certificate via Android's network security config to prevent MITM attacks.

Open `app/src/main/res/xml/network_security_config.xml` and:

1. Replace `yourdomain.com` with your actual API domain.

2. Generate the SPKI SHA-256 hashes for your leaf certificate and its intermediate CA:

   ```bash theme={null}
   # Leaf certificate pin
   openssl s_client -connect vpn.yourdomain.com:443 -servername vpn.yourdomain.com 2>/dev/null \
     | openssl x509 -pubkey -noout \
     | openssl pkey -pubin -outform DER \
     | openssl dgst -sha256 -binary \
     | base64
   ```

3. Replace the placeholder `YOUR_LEAF_CERT_PIN_HASH` and `YOUR_CA_CERT_PIN_HASH` values with your computed hashes.

<Note>
  You should always pin **two** hashes: the current leaf (or its SPKI) and the issuing intermediate. When your certificate rotates, the intermediate will usually still match, preventing a hard outage.
</Note>

***

## Step 7 — Deep Links & Universal Links

The app handles password-reset and email-verification deep links of the form:

```
https://vpn.yourdomain.com/reset-password/{token}?email=user@example.com
```

In `app/src/main/AndroidManifest.xml`, find the `<intent-filter>` with `<data android:host="..."/>` and set the host to your domain:

```xml theme={null}
<data android:scheme="https" android:host="vpn.yourdomain.com"/>
```

For Android App Links to verify automatically (no "Open with" dialog), your web server must serve a Digital Asset Links file at:

```
https://vpn.yourdomain.com/.well-known/assetlinks.json
```

The backend generates this automatically once you've added your app's SHA-256 signing fingerprint in the admin panel.

***

## Step 8 — AdMob (optional)

If you want to display ads:

1. Create an [AdMob account](https://admob.google.com) and register your Android app.

2. Update the AdMob App ID in `app/src/main/AndroidManifest.xml`:

   ```xml theme={null}
   <meta-data
       android:name="com.google.android.gms.ads.APPLICATION_ID"
       android:value="ca-app-pub-XXXXXXXXXXXXXXXX~XXXXXXXXXX" />
   ```

3. Update the individual ad unit IDs in:
   * `app/src/main/java/com/lunecore/vpn/ads/AdConfig.kt`
   * `app/src/main/java/com/lunecore/vpn/ads/InterstitialAdManager.kt`
   * `app/src/main/java/com/lunecore/vpn/ads/AppOpenAdManager.kt`

If you do not want ads at all, set the ad unit IDs to empty strings and remove the `<meta-data>` entry — or simply toggle `ads_enabled` to `false` on your backend's `/api/v1/app-config` endpoint to hide the ad UI server-side without any code changes.

***

## Step 9 — Google Play Billing

In-app purchases are mapped to your backend's plan catalog. To wire them up:

1. In **Google Play Console**, create your in-app products or subscriptions.
2. Use product IDs that match the ones you configure on your backend's plans (or map them in the admin panel).
3. Upload a signed release build to an internal test track before testing billing — Google Play Billing does **not** work on debug builds distributed outside Play.

The backend verifies purchase tokens server-side via the Google Play Developer API, so make sure you've configured a service account and granted it access in Play Console → *API access*.

***

## Step 10 — App Branding

### App Name

Change the `app_name` string resource in:

```
app/src/main/res/values/strings.xml
```

Also update the localized copies in `values-*` folders if you want a different translated name.

### App Icon

Replace the launcher icons under `app/src/main/res/mipmap-*/` with your own. The easiest way is to use Android Studio's *File → New → Image Asset* wizard with a 1024×1024 master icon.

### Theme Colors

The Material 3 color scheme lives at:

```
app/src/main/java/com/lunecore/vpn/ui/theme/
```

Edit `Color.kt` and `Theme.kt` to match your brand palette.

### Splash / Hero imagery

Brand imagery used on the home screen and onboarding is under `app/src/main/res/drawable/`. Replace PNGs and vector assets as needed.

***

## Step 11 — Build & Sign a Release

### 1. Create a keystore

```bash theme={null}
keytool -genkey -v -keystore release.jks \
    -keyalg RSA -keysize 2048 -validity 10000 \
    -alias your-alias
```

Store this file **outside** the project directory and back it up. If you lose it, you cannot publish updates to the app on Google Play.

### 2. Configure signing

In Android Studio: *Build → Generate Signed Bundle / APK → Android App Bundle*, then either paste the keystore path each time or create a `signingConfig` in `app/build.gradle.kts` that reads from a local `keystore.properties` file (never committed).

### 3. Build an AAB

```bash theme={null}
./gradlew :app:bundleRelease
```

The output will be at `app/build/outputs/bundle/release/app-release.aab`.

### 4. Upload to Google Play

1. Create your app in the [Play Console](https://play.google.com/console).
2. Upload your first AAB to an internal test track.
3. Fill out the store listing, content rating, data safety form, and privacy policy URL.
4. Once internal testing is stable, promote to closed / open testing, then production.

<Warning>
  VPN apps go through additional policy review on Google Play. You must truthfully fill out the "VPN service" declaration in the app content section. Apps that use the `VpnService` API for anything other than providing a user-facing VPN will be rejected.
</Warning>

***

## Step 12 — Backend Requirements

The Android client consumes the REST API exposed by the **StartMyVPN** backend. The key endpoints it calls are:

| Endpoint                                | Purpose                                                |
| --------------------------------------- | ------------------------------------------------------ |
| `POST /api/v1/auth/login`               | Email/password login                                   |
| `POST /api/v1/auth/register`            | Registration                                           |
| `POST /api/v1/auth/guest`               | Guest / anonymous device login                         |
| `POST /api/v1/auth/claim`               | Convert a guest account to a full account              |
| `POST /api/v1/auth/forgot-password`     | Send password-reset email                              |
| `POST /api/v1/auth/reset-password`      | Consume password-reset token                           |
| `POST /api/v1/auth/resend-verification` | Resend the email-verification mail                     |
| `PUT  /api/v1/auth/change-email`        | Change email address                                   |
| `GET  /api/v1/user`                     | Current user + active service                          |
| `PUT  /api/v1/account/password`         | Change password                                        |
| `GET  /api/v1/servers`                  | Full server list                                       |
| `GET  /api/v1/free-servers`             | Free-tier servers                                      |
| `GET  /api/v1/premium-servers`          | Premium-tier servers                                   |
| `GET  /api/v1/servers/{id}/wireguard`   | On-demand WireGuard config                             |
| `GET  /api/v1/user/openvpn-credentials` | OpenVPN username/password                              |
| `GET  /api/v1/plans`                    | Plan catalog                                           |
| `POST /api/v1/iap/verify`               | Play Billing purchase verification                     |
| `POST /api/v1/iap/guest-verify`         | Play Billing verification for guests                   |
| `POST /api/v1/iap/restore`              | Restore a previous purchase                            |
| `GET  /api/v1/app-config`               | Runtime feature flags (ads, maintenance, force-update) |

All of these endpoints are implemented by the StartMyVPN backend out-of-the-box. If you have customized any of these paths on your backend, update the Retrofit interface in:

```
app/src/main/java/com/lunecore/vpn/data/remote/ApiService.kt
```

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Gradle sync fails with 'Could not find com.wireguard.android:tunnel'">
    You have not placed `wireguard-tunnel.aar` at `app/libs/wireguard-tunnel.aar`. See Step 2.
  </Accordion>

  <Accordion title="'File google-services.json is missing' at build time">
    You have not replaced the placeholder `app/google-services.json` with a real file from your Firebase project. See Step 3.
  </Accordion>

  <Accordion title="OpenVPN native build fails ('NDK not configured')">
    Install NDK `27.2.12479018` via Android Studio → SDK Manager → SDK Tools → NDK (Side by side). The OpenVPN module uses CMake and requires this exact NDK version or newer.
  </Accordion>

  <Accordion title="The VPN connects but no traffic flows">
    Check that your server's WireGuard or OpenVPN config is valid by testing it on desktop first. Also verify that the API returns a `config` string in the expected format on `GET /api/v1/servers/{id}/config`.
  </Accordion>

  <Accordion title="Play Billing returns 'Item unavailable'">
    You are either testing on a debug build (billing requires a signed build distributed via Play), your product IDs do not match what is configured in Play Console, or the account you are testing with is not on a test/license list in Play Console.
  </Accordion>

  <Accordion title="Certificate pinning failures in production">
    Your pins in `network_security_config.xml` do not match the actual certificate chain served by your domain. Regenerate with `openssl` and verify by running the app in debug with `OkHttp` logging enabled.
  </Accordion>
</AccordionGroup>

***

## Quick Checklist

<Steps>
  <Step title="WireGuard AAR">Place `wireguard-tunnel.aar` at `app/libs/`.</Step>
  <Step title="Firebase">Replace `app/google-services.json` with your own.</Step>
  <Step title="Package name">Update `namespace` and `applicationId` in `app/build.gradle.kts` and in `google-services.json`.</Step>
  <Step title="Backend URL">Set `BASE_URL` in `ApiClient.kt`.</Step>
  <Step title="Cert pinning">Update domain + SPKI hashes in `network_security_config.xml`.</Step>
  <Step title="Deep links">Update the host in the `<intent-filter>` of `AndroidManifest.xml`.</Step>
  <Step title="AdMob">Update App ID and ad unit IDs (or disable ads server-side).</Step>
  <Step title="Branding">Update `app_name`, launcher icons, theme colors, and drawables.</Step>
  <Step title="Sign & build">Generate a keystore, create a signing config, and build an AAB.</Step>
  <Step title="Publish">Upload to Google Play internal testing, then promote to production.</Step>
</Steps>
