> 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.phptravels.com/mobile-app.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
