> For the complete documentation index, see [llms.txt](https://docs.phptravels.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.phptravels.com/mobile-app.md).

# Mobile App

<figure><img src="/files/hYCSL8GK3U1Wh9ifyDTX" alt=""><figcaption></figcaption></figure>

📱 Flutter 3.x (stable) \
🤖 Android SDK 36\
🍎 iOS 12+\
📦 Version 1.0.1

### Table of Contents

1. Prerequisites & System Requirements
2. Install Flutter SDK
3. Project Setup
4. Configure Domain & API URL
5. Configure App Name & Bundle ID
6. Gradle Setup (Android)
7. Android Signing / Keystore
8. iOS Setup & Signing
9. Build for Android
10. Build for iOS
11. Key Files Reference
12. Pre-Release Checklist

### 1 Prerequisites & System Requirements

#### For Android builds

| Tool             | Minimum Version                | Notes                    |
| ---------------- | ------------------------------ | ------------------------ |
| Flutter SDK      | 3.0.0 (use 3.41.6 recommended) | Stable channel           |
| Dart SDK         | Bundled with Flutter           | SDK ≥ 3.0.0              |
| Android Studio   | Flamingo or later              | Required for SDK Manager |
| Android SDK      | API 36 (Android 16)            | Also install API 21+     |
| Java JDK         | 17 (LTS)                       | OpenJDK 17 recommended   |
| Gradle           | 8.x (auto-downloaded)          | See Section 6            |
| Operating System | Windows 10/11, macOS, Linux    | Any platform             |

#### For iOS builds

⚠️**macOS only.** iOS builds can only be compiled on a Mac with Xcode installed. You cannot build an IPA on Windows or Linux.

| Tool                     | Minimum Version         | Notes                               |
| ------------------------ | ----------------------- | ----------------------------------- |
| macOS                    | Ventura 13+ recommended | Required for iOS builds             |
| Xcode                    | 15.x or later           | Install from Mac App Store          |
| CocoaPods                | 1.12+                   | `sudo gem install cocoapods`        |
| Apple Developer Account  | Paid ($99/year)         | Required for App Store distribution |
| iOS Provisioning Profile | Distribution profile    | Created in developer.apple.com      |

### 2 Install Flutter SDK

#### Step 1 — Download Flutter

Go to **flutter.dev/docs/get-started/install** and download the Flutter SDK for your operating system. Extract it to a location without spaces in the path, for example:

```
# Windows example
C:\flutter

# macOS / Linux example
~/flutter
```

#### Step 2 — Add Flutter to PATH

**Windows:** Add `C:\flutter\bin` to your system *Environment Variables → PATH*.

**macOS/Linux:** Add the following line to your `~/.zshrc` or `~/.bashrc`:

```
export PATH="$HOME/flutter/bin:$PATH"
```

#### Step 3 — Switch to stable channel & required version

```
flutter channel stable
flutter upgrade
flutter --version
```

The project was built with **Flutter 3.41.6**. You can install a specific version with FVM (Flutter Version Manager) if needed:

```
# Optional — use FVM to pin the exact version
dart pub global activate fvm
fvm install 3.41.6
fvm use 3.41.6
```

#### Step 4 — Run Flutter Doctor

```
flutter doctor -v
```

Fix all issues marked with `✗` before continuing. Pay attention to:

* Android toolchain — SDK, build tools, licenses
* Xcode (macOS only)
* Android Studio plugin

#### Step 5 — Accept Android SDK Licenses

```
flutter doctor --android-licenses
```

Type `y` and press Enter for each license prompt.

### 3 Project Setup

#### Step 1 — Open project in your IDE

Open the project folder in **Android Studio** or **VS Code**. The project root is the folder containing `pubspec.yaml`.

#### Step 2 — Install Flutter dependencies

Run the following command from the project root:

```
flutter pub get
```

This downloads all packages listed in `pubspec.yaml` (\~30+ packages).

#### Step 3 — Generate localization files

The app supports 6 languages. Run the code generation step:

```
flutter gen-l10n
```

This generates `lib/l10n/app_localizations.dart` and related files from the ARB files.

ℹ️If you see errors about missing `app_localizations.dart`, always run `flutter gen-l10n` first. This file is auto-generated and not committed to the repository.

#### Step 4 — Verify the build

```
flutter analyze
flutter build apk --debug
```

A successful debug build confirms the environment is set up correctly.

### 4 Configure Domain & API URL

All API calls go through a single base URL file. **This is the only file you need to change to point the app at a different server.**

lib/core/services/common/base\_url.dart

```
const mediaBaseUrl = "https://phptravels.net/";
const baseUrl = "${mediaBaseUrl}api";
const modulesStaysBaseUrl   = "$mediaBaseUrl/modules/stays";
const modulesFlightsBaseUrl = "$mediaBaseUrl/modules/flights";
const modulesUmrahBaseUrl   = "$mediaBaseUrl/modules/umrah";
const flightsAirlinesUrl    = "$mediaBaseUrl/flights-airlines";
```

#### How to change the domain

Replace `https://phptravels.net/` with your own domain. Only change `mediaBaseUrl` — all other URLs are derived from it automatically:

lib/core/services/common/base\_url.dart — after editing

```
const mediaBaseUrl = "https://YOUR-DOMAIN.com/";   // ← change this only
const baseUrl = "${mediaBaseUrl}api";              // auto-derived, do not touch
// … rest remains unchanged …
```

⚠️**Trailing slash is required.** The value of `mediaBaseUrl` must end with a forward slash `/` otherwise API paths will break.\
\
✅ Correct: `"https://yourdomain.com/"`\
❌ Wrong: `"https://yourdomain.com"`

#### API timeout settings

If your server is slow, you can increase the timeout values in the API client:

lib/core/network/api\_client.dart

```
connectTimeout: const Duration(seconds: 15),   // ← increase if needed
receiveTimeout:  const Duration(seconds: 15),   // ← increase if needed
```

#### Deep Link / App Link domain

The app also handles deep links from your domain. Update the deep link host in the Android manifest:

android/app/src/main/AndroidManifest.xml

```
<!-- Find these lines and replace phptravels.net with your domain -->
<data android:scheme="https" android:host="phptravels.net" />
<data android:scheme="https" android:host="www.phptravels.net" />
```

Also update the placeholder in the Gradle build file:

android/app/build.gradle.kts

```
manifestPlaceholders += mapOf(
    "appLinkHost"    to "YOUR-DOMAIN.com",
    "appLinkWwwHost" to "www.YOUR-DOMAIN.com"
)
```

### 5 Configure App Name & Bundle ID

#### Android — Package name & App label

android/app/build.gradle.kts

```
android {
    namespace = "com.phptravels.android"   // ← change to your package name
    ...
}
```

android/app/src/main/AndroidManifest.xml

```
<application
    android:label="phptravels"            <!-- ← change to your app name -->
    ...>
```

#### iOS — Bundle ID & Display Name

ios/Runner/Info.plist

```
<key>CFBundleDisplayName</key>
<string>Phptravels</string>       <!-- ← change to your app name -->

<key>CFBundleName</key>
<string>phptravels</string>       <!-- ← change to your app name -->
```

The iOS Bundle ID (`com.phptravels.app` or similar) is set in Xcode under **Runner → Signing & Capabilities → Bundle Identifier**.

#### App version

pubspec.yaml

```
version: 1.0.1+6   # format: versionName+versionCode
```

The number before `+` is the display version (`1.0.1`). The number after `+` is the internal build number (`6`). Increment the build number with every release.

### 6Gradle Setup (Android)

ℹ️Gradle is the Android build system. Flutter manages most of the Gradle configuration for you. You do **not** need to download Gradle manually — it downloads automatically on the first build.

#### Gradle version used

| File                                               | Setting                | Value              |
| -------------------------------------------------- | ---------------------- | ------------------ |
| `android/gradle/wrapper/gradle-wrapper.properties` | Gradle wrapper version | 8.x (auto-managed) |
| `android/app/build.gradle.kts`                     | Compile SDK            | 36                 |
| `android/app/build.gradle.kts`                     | Target SDK             | 36                 |
| `android/app/build.gradle.kts`                     | Java version           | 17                 |

#### Required: Set Java 17

The project requires **Java 17**. Using a different JDK version will cause build errors. To check your current version:

```
java -version
```

In Android Studio: go to **File → Project Structure → SDK Location → Gradle Settings** and set *Gradle JDK* to JDK 17.

If you have multiple Java versions, set `JAVA_HOME` to point to JDK 17:

```
# Windows (PowerShell)
$env:JAVA_HOME = "C:\Program Files\Java\jdk-17"

# macOS / Linux — add to ~/.zshrc or ~/.bashrc
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
export PATH="$JAVA_HOME/bin:$PATH"
```

#### Gradle memory settings

The project already has optimised JVM memory settings in:

android/gradle.properties

```
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m
android.useAndroidX=true
android.enableJetifier=true
```

⚠️The `-Xmx8G` setting requires at least **8 GB RAM** free for the build. On machines with less RAM, reduce to `-Xmx4G`.

#### Clean Gradle cache (if build fails)

```
# From the project root
flutter clean
flutter pub get

# Also clear the Gradle cache if needed
cd android
./gradlew clean
cd ..
```

#### Updating Gradle wrapper

If you need to update Gradle, edit the wrapper properties file:

android/gradle/wrapper/gradle-wrapper.properties

```
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
```

### 7 Android Signing / Keystore

🔐**Critical:** The keystore file and its passwords are required to publish updates to the Play Store. If you lose the keystore or forget the password, you cannot update the app — you would need to publish it as a brand new app. Keep these files backed up securely.

#### Keystore file location

The release keystore is already included in the project:

```
phptravels_mobile_app/release-key.jks   # ← the keystore file (keep this safe)
```

#### Step 1 — Create key.properties file

Create the file `android/key.properties` (this file is intentionally NOT in the repository for security). It must contain the keystore credentials:

android/key.properties (create this file manually)

```
storePassword=YOUR_KEYSTORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=YOUR_KEY_ALIAS
storeFile=../release-key.jks
```

ℹ️**The path in storeFile is relative to the android/ folder.** Since `release-key.jks` is in the project root and `key.properties` is in the `android/` folder, the path is `../release-key.jks`.

#### Step 2 — Verify Gradle reads key.properties

The Gradle file already reads this automatically. No changes needed:

android/app/build.gradle.kts (already configured)

```
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}

signingConfigs {
    create("release") {
        keyAlias     = keystoreProperties["keyAlias"] as String
        keyPassword  = keystoreProperties["keyPassword"] as String
        storeFile    = file(keystoreProperties["storeFile"] as String)
        storePassword = keystoreProperties["storePassword"] as String
    }
}
```

#### Creating a new keystore (if needed)

If you need to generate a new keystore for a new app identity, run:

```
keytool -genkey -v \
  -keystore release-key.jks \
  -alias my-key-alias \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000
```

You will be asked for: keystore password, key password, your name, organization, and location.

### 8iOS Setup & Signing

🍎This section only applies if you are on a **Mac**. iOS builds cannot be done on Windows.

#### Step 1 — Install CocoaPods

```
sudo gem install cocoapods
```

#### Step 2 — Install iOS dependencies

After running `flutter pub get`, install the iOS native dependencies:

```
cd ios
pod install
cd ..
```

ℹ️Always run `pod install` after `flutter pub get` when working on iOS. If you see "CocoaPods not installed" errors, run `pod repo update` and try again.

#### Step 3 — Open in Xcode

Open the **.xcworkspace** file (not .xcodeproj) in Xcode:

```
open ios/Runner.xcworkspace
```

#### Step 4 — Configure signing in Xcode

1. In Xcode, select the **Runner** project in the left panel.
2. Click the **Runner** target → **Signing & Capabilities** tab.
3. Check *"Automatically manage signing"*.
4. Select your **Apple Developer Team** from the dropdown.
5. Set the **Bundle Identifier** (e.g. `com.yourcompany.phptravels`).

#### Step 5 — Update iOS minimum version (if needed)

ios/Podfile

```
platform :ios, '12.0'   # minimum iOS version
```

#### Step 6 — Update app name in Info.plist

ios/Runner/Info.plist

```
<key>CFBundleDisplayName</key>
<string>Your App Name</string>

<key>CFBundleName</key>
<string>YourApp</string>
```

### 9 Build for Android

#### Debug APK (for testing)

```
flutter build apk --debug
```

Output: `build/app/outputs/flutter-apk/app-debug.apk`

#### Release APK (for direct distribution)

```
flutter build apk --release
```

Output: `build/app/outputs/flutter-apk/app-release.apk`

#### Release App Bundle (for Google Play Store)

```
flutter build appbundle --release
```

Output: `build/app/outputs/bundle/release/app-release.aab`

✅**Google Play Store requires an AAB file**, not an APK. Use `flutter build appbundle` for Play Store submissions. The APK is useful for direct device installation and testing.

#### Split APKs by ABI (smaller download size)

```
flutter build apk --split-per-abi --release
```

This creates separate APKs for arm64, arm, and x86\_64 architectures — each is smaller than a universal APK.

#### Verify the signed APK

```
apksigner verify --verbose build/app/outputs/flutter-apk/app-release.apk
```

#### Install directly on a connected device

```
flutter install
```

### 10 Build for iOS

🍎macOS with Xcode is required. Ensure CocoaPods dependencies are installed (`cd ios && pod install`) before building.

#### Debug build (simulator)

```
flutter build ios --debug --simulator
```

#### Release build (real device / App Store)

```
flutter build ios --release
```

#### Create IPA for App Store Connect

After a successful release build, archive and export from Xcode:

1. In Xcode: **Product → Archive**
2. When archiving is complete: click **Distribute App**
3. Choose **App Store Connect** → Next
4. Choose **Upload** (to upload directly) or **Export** (to save an IPA)
5. Follow the prompts — Xcode handles signing automatically if set up correctly

#### Build IPA via command line

```
# Build first
flutter build ios --release

# Then archive using xcodebuild
cd ios
xcodebuild -workspace Runner.xcworkspace \
           -scheme Runner \
           -sdk iphoneos \
           -configuration Release \
           archive \
           -archivePath build/Runner.xcarchive

# Export IPA
xcodebuild -exportArchive \
           -archivePath build/Runner.xcarchive \
           -exportOptionsPlist ExportOptions.plist \
           -exportPath build/Runner.ipa
```

### 11 Key Files Reference

| File                                       | Platform | Purpose                                                                   |
| ------------------------------------------ | -------- | ------------------------------------------------------------------------- |
| `pubspec.yaml`                             | Both     | App name, version, all Flutter/Dart dependencies, assets                  |
| `lib/core/services/common/base_url.dart`   | Both     | **Main config file.** Change this to point the app to your server domain. |
| `lib/core/network/api_client.dart`         | Both     | HTTP client setup, timeout values, interceptors (auth, cache, retry)      |
| `lib/main.dart`                            | Both     | App entry point, provider initialization, startup sequence                |
| `android/app/build.gradle.kts`             | Android  | Package name, SDK versions, Java version, signing config, ProGuard        |
| `android/app/src/main/AndroidManifest.xml` | Android  | App name, permissions, deep link domains, Firebase config                 |
| `android/key.properties`                   | Android  | **Create manually.** Keystore credentials for release signing.            |
| `release-key.jks`                          | Android  | Android release keystore — keep this file backed up securely!             |
| `android/gradle.properties`                | Android  | Gradle JVM memory, AndroidX settings                                      |
| `ios/Runner/Info.plist`                    | iOS      | App display name, bundle name, permissions descriptions, orientations     |
| `ios/Podfile`                              | iOS      | iOS minimum version, CocoaPods configuration                              |
| `ios/Runner.xcworkspace`                   | iOS      | Open this in Xcode (not .xcodeproj) for iOS development                   |
| `lib/l10n/app_en.arb`                      | Both     | English UI strings — edit to customise app text                           |
| `assets/images/`                           | Both     | App images, logos, icons                                                  |
| `shorebird.yaml`                           | Both     | Shorebird code push configuration (OTA updates)                           |
| `l10n.yaml`                                | Both     | Localization settings — supported languages, ARB file location            |

#### Project structure overview

```
phptravels_mobile_app/
├── lib/
│   ├── main.dart                         # App entry point
│   ├── core/
│   │   ├── services/common/base_url.dart # ← CHANGE DOMAIN HERE
│   │   ├── network/api_client.dart       # HTTP client config
│   │   └── theme/app_theme.dart          # Colors, typography
│   ├── features/                         # flights/ hotels/ cars/ tours/ etc.
│   ├── providers/                        # State management
│   └── routes/                           # Navigation
├── android/
│   ├── app/build.gradle.kts              # Android build config
│   ├── key.properties                    # ← CREATE THIS (keystore credentials)
│   └── gradle.properties                 # Gradle memory settings
├── ios/
│   ├── Runner/Info.plist                 # iOS app config
│   └── Runner.xcworkspace                # Open in Xcode
├── assets/
│   ├── images/                           # App images & logos
│   └── fonts/                            # Inter font family
├── release-key.jks                       # Android signing keystore
└── pubspec.yaml                          # Dependencies & app version
```

### 12 Pre-Release Checklist

#### Environment

* Flutter SDK installed (stable channel, version 3.x)
* `flutter doctor` shows no errors
* Java 17 JDK installed and set as default
* Android SDK with API 36 installed
* All Android SDK licenses accepted (`flutter doctor --android-licenses`)

#### Project configuration

* `lib/core/services/common/base_url.dart` — domain updated to production server
* `pubspec.yaml` — version number and build number incremented
* `android/app/build.gradle.kts` — package name matches your app identity
* `android/app/src/main/AndroidManifest.xml` — app label updated
* `ios/Runner/Info.plist` — CFBundleDisplayName and CFBundleName updated

#### Android signing

* `android/key.properties` file created with correct keystore credentials
* `release-key.jks` file is present in the project root
* Release APK or AAB builds successfully (`flutter build appbundle --release`)

#### iOS signing (macOS only)

* CocoaPods installed and `pod install` run in ios/ folder
* Apple Developer Team selected in Xcode → Signing & Capabilities
* Bundle Identifier matches your Apple Developer Portal entry
* Provisioning profile is valid and not expired

#### Final checks

* `flutter analyze` runs without errors
* App tested on physical device (both Android and iOS)
* Login, search, and booking flows tested end-to-end
* Network requests going to correct production domain
* App icons are correct (not default Flutter icon)
* `release-key.jks` and `android/key.properties` backed up securely

### Quick Command Reference

| Task                   | Command                             |
| ---------------------- | ----------------------------------- |
| Install dependencies   | `flutter pub get`                   |
| Generate localizations | `flutter gen-l10n`                  |
| Run on device (debug)  | `flutter run`                       |
| Static analysis        | `flutter analyze`                   |
| Clean build cache      | `flutter clean`                     |
| Debug APK              | `flutter build apk --debug`         |
| Release APK            | `flutter build apk --release`       |
| Play Store AAB         | `flutter build appbundle --release` |
| iOS release build      | `flutter build ios --release`       |
| Check Flutter version  | `flutter --version`                 |
| List connected devices | `flutter devices`                   |
| Update Flutter         | `flutter upgrade`                   |

PHPTravels Mobile App — Developer Setup Guide  |  **Version 1.0.1**  |  Flutter 3.x Stable

For support contact your development team. Keep `release-key.jks` and keystore passwords in a secure password manager.
