diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..0661943
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,54 @@
+# Docker ignore file for Android build
+
+# Build artifacts
+android-build/
+*.apk
+*.aab
+*.o
+*.so
+moc_*.cpp
+ui_*.h
+qrc_*.cpp
+.qmake.stash
+Makefile
+
+# Qt Creator files
+*.pro.user
+*.pro.user.*
+
+# IDE files
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+
+# Git
+.git/
+.gitignore
+.gitattributes
+
+# CI/CD
+.github/
+
+# Documentation (optional, comment out if you want to include)
+*.md
+!BUILD_ANDROID_LOCAL.md
+
+# Temporary files
+tmp/
+temp/
+*.tmp
+
+# macOS
+.DS_Store
+
+# Windows
+Thumbs.db
+desktop.ini
+
+# Qt cache
+qt/
+
+# Logs
+*.log
diff --git a/.github/workflows/mobile.yml b/.github/workflows/mobile.yml
index 1b12702..25be7b5 100644
--- a/.github/workflows/mobile.yml
+++ b/.github/workflows/mobile.yml
@@ -9,57 +9,277 @@ on:
env:
BUILD_TYPE: Release
-# ACTIONS_RUNNER_DEBUG: true
-# ACTIONS_STEP_DEBUG: true
-
jobs:
- ci:
- runs-on: ${{ matrix.os }}
+ android-build:
+ runs-on: ubuntu-22.04
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- strategy:
- matrix:
- os: [ubuntu-20.04]
- #os: [macos-10.15, ubuntu-20.04, windows-2019]
- # version: ['5.9.0', '5.15.1', '6.2.0']
- version: ['5.9.0']
-
- # Ubuntu 18 is not a supported target for Qt 6: https://www.qt.io/blog/qt6-development-hosts-and-targets
- exclude:
- - os: ubuntu-18.04
- version: '6.2.0'
+ QT_VERSION: '6.5.3'
+ ANDROID_API_LEVEL: '34'
+ ANDROID_BUILD_TOOLS_VERSION: '34.0.0'
+ ANDROID_NDK_VERSION: '21.4.7075529'
+
steps:
- - uses: actions/checkout@v2
-
- - name: Install Qt
- if: startsWith(matrix.os, 'ubuntu')
- uses: jurplel/install-qt-action@v2
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: Setup Android SDK
+ uses: android-actions/setup-android@v3
with:
- version: ${{matrix.version}}
- host: linux
- target: 'android'
- arch: 'android_armv7'
- dir: '${{github.workspace}}/qt/'
- install-deps: 'true'
+ api-level: ${{ env.ANDROID_API_LEVEL }}
+ build-tools: ${{ env.ANDROID_BUILD_TOOLS_VERSION }}
+ ndk-version: ${{ env.ANDROID_NDK_VERSION }}
+
+ - name: Configure Android SDK Environment
+ run: |
+ # Ensure correct Android platform is available
+ echo "ANDROID_HOME: $ANDROID_HOME"
+ echo "ANDROID_SDK_ROOT: $ANDROID_SDK_ROOT"
+
+ # List installed platforms BEFORE cleanup
+ echo "Installed Android platforms BEFORE cleanup:"
+ ls -la $ANDROID_HOME/platforms/ || true
+
+ # CRITICAL: Remove corrupted SDK platforms 35 and 36 that cause aapt2 linking errors
+ echo "Removing corrupted Android SDK platforms 35 and 36..."
+ rm -rf $ANDROID_HOME/platforms/android-35* || true
+ rm -rf $ANDROID_HOME/platforms/android-36* || true
+
+ # Ensure we have SDK platform 34
+ if [ ! -d "$ANDROID_HOME/platforms/android-34" ]; then
+ echo "Installing Android SDK Platform 34..."
+ yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platforms;android-34"
+ fi
+
+ # List installed platforms AFTER cleanup
+ echo "Installed Android platforms AFTER cleanup:"
+ ls -la $ANDROID_HOME/platforms/ || true
+
+ # Set ANDROID_SDK_ROOT if not set
+ if [ -z "$ANDROID_SDK_ROOT" ]; then
+ echo "ANDROID_SDK_ROOT=$ANDROID_HOME" >> $GITHUB_ENV
+ fi
+
+ - name: Install aqt
+ run: |
+ python3 -m pip install --upgrade pip
+ python3 -m pip install aqtinstall==3.1.*
+
+ - name: Install Qt for Android
+ run: |
+ # Use Qt 6.5.3 which has better Android support and availability
+ # androidextras is not needed in Qt 6 (integrated into Qt Core)
+ echo "Installing Qt 6.5.3 for Android..."
+
+ # Try android_arm64_v8a first (most common modern architecture)
+ echo "Attempting to install Qt 6.5.3 for android_arm64_v8a..."
+ if python3 -m aqt install-qt linux android 6.5.3 android_arm64_v8a \
+ --outputdir ${{github.workspace}}/qt/; then
+ echo "Successfully installed Qt 6.5.3 for android_arm64_v8a"
+ elif python3 -m aqt install-qt linux android 6.5.3 android_armv7 \
+ --outputdir ${{github.workspace}}/qt/; then
+ echo "Successfully installed Qt 6.5.3 for android_armv7"
+ else
+ echo "ERROR: Failed to install Qt 6.5.3 for Android"
+ echo "Trying to list available versions and architectures..."
+ python3 -m aqt list-qt linux android || true
+ exit 1
+ fi
+
+ # Verify Android Qt was actually installed
+ echo "Verifying Android Qt installation..."
+ if find ${{github.workspace}}/qt -path "*/android*/bin/qmake" -type f | grep -q .; then
+ echo "Android Qt qmake found - installation successful"
+ else
+ echo "ERROR: Android Qt installation failed - no Android qmake found"
+ echo "Directory structure:"
+ ls -la ${{github.workspace}}/qt/
+ exit 1
+ fi
+
+ - name: Install Qt Desktop (needed for qmake)
+ run: |
+ # Install Qt 6.5.3 for desktop to match Android version
+ echo "Installing Qt 6.5.3 for desktop..."
+ python3 -m aqt install-qt linux desktop 6.5.3 gcc_64 \
+ --outputdir ${{github.workspace}}/qt/
+
+ - name: Verify Android environment
+ run: |
+ echo "ANDROID_HOME: $ANDROID_HOME"
+ echo "ANDROID_NDK_HOME: $ANDROID_NDK_HOME"
+ echo "JAVA_HOME: $JAVA_HOME"
+
+ # We're using Qt 6.5.3 for Android
+ echo "Looking for Qt 6.5.3 Android installation..."
+
+ # Find Qt installations
+ echo "Qt directory structure:"
+ find ${{github.workspace}}/qt -name "6.5.3" -type d
+
+ # Find Android qmake specifically (not desktop qmake)
+ # Android Qt is typically in paths containing "android"
+ ANDROID_QMAKE=$(find ${{github.workspace}}/qt -path "*/android*/bin/qmake" -type f | head -1)
+
+ if [ -n "$ANDROID_QMAKE" ]; then
+ ANDROID_QT_DIR=$(dirname $(dirname "$ANDROID_QMAKE"))
+ echo "Android Qt installation found at: $ANDROID_QT_DIR"
+ echo "Android qmake found at: $ANDROID_QMAKE"
+ echo "ANDROID_QT_DIR=$ANDROID_QT_DIR" >> $GITHUB_ENV
+ echo "ANDROID_QMAKE=$ANDROID_QMAKE" >> $GITHUB_ENV
+
+ # Verify qmake version
+ echo "Android qmake version:"
+ "$ANDROID_QMAKE" -version
+ else
+ echo "ERROR: Android qmake not found"
+ echo "Listing all qmake files:"
+ find ${{github.workspace}}/qt -name "qmake" -type f
+ exit 1
+ fi
+
+ # Check if required tools exist
+ which make || echo "make not found"
+ ls -la $ANDROID_HOME/platforms/ || echo "No Android platforms found"
+ ls -la $ANDROID_NDK_HOME/ || echo "NDK not found"
- - name: Build
- if: startsWith(matrix.os, 'ubuntu')
- env:
- ACTIONS_RUNNER_DEBUG: true
- ACTIONS_STEP_DEBUG: true
- working-directory: ${{github.workspace}}
- run: |
- qmake CONFIG+=release
- make
- ls -l
- mv Interrogator.apk AndroidInterrogator.apk
-
- - name: Upload Artifact ${{github.os}}
- if: startsWith(matrix.os, 'ubuntu')
- uses: actions/upload-artifact@v3
+ - name: Configure project for Android
+ run: |
+ set -e # Exit immediately if any command fails
+
+ export ANDROID_SDK_ROOT=$ANDROID_HOME
+ export ANDROID_NDK_ROOT=$ANDROID_NDK_HOME
+
+ # Use the Android qmake we found earlier
+ echo "Using Android qmake from: $ANDROID_QMAKE"
+ echo "Using Android Qt at: $ANDROID_QT_DIR"
+
+ if [ -n "$ANDROID_QMAKE" ] && [ -f "$ANDROID_QMAKE" ]; then
+ export PATH="$(dirname $ANDROID_QMAKE):$PATH"
+
+ # Generate Makefile for Android
+ echo "Configuring project with qmake..."
+ if ! "$ANDROID_QMAKE" -spec android-clang \
+ CONFIG+=release \
+ ANDROID_ABIS=arm64-v8a \
+ Interrogator.pro; then
+ echo "ERROR: qmake configuration failed"
+ exit 1
+ fi
+ else
+ echo "ERROR: Android qmake not found at $ANDROID_QMAKE"
+ find ${{github.workspace}}/qt -name "qmake" -type f
+ exit 1
+ fi
+
+ - name: Build APK
+ run: |
+ set -e # Exit immediately if any command fails
+
+ export ANDROID_SDK_ROOT=$ANDROID_HOME
+ export ANDROID_NDK_ROOT=$ANDROID_NDK_HOME
+
+ # Use the Android qmake path
+ if [ -n "$ANDROID_QMAKE" ]; then
+ export PATH="$(dirname $ANDROID_QMAKE):$PATH"
+ fi
+
+ # Build the Android project
+ echo "Building Android project with make..."
+ if ! make -j$(nproc); then
+ echo "ERROR: Make build failed"
+ exit 1
+ fi
+
+ # Find androiddeployqt tool in the Android Qt directory
+ ANDROIDDEPLOYQT=$(find $ANDROID_QT_DIR -name "androiddeployqt" -type f | head -1)
+
+ if [ -z "$ANDROIDDEPLOYQT" ]; then
+ # Try searching in the whole Qt directory
+ ANDROIDDEPLOYQT=$(find ${{github.workspace}}/qt -path "*/android*/bin/androiddeployqt" -type f | head -1)
+ fi
+
+ echo "Looking for androiddeployqt..."
+ if [ -n "$ANDROIDDEPLOYQT" ] && [ -f "$ANDROIDDEPLOYQT" ]; then
+ echo "Found androiddeployqt at: $ANDROIDDEPLOYQT"
+ # Package APK using androiddeployqt
+ echo "Generating APK with androiddeployqt..."
+ if ! "$ANDROIDDEPLOYQT" \
+ --input android-Interrogator-deployment-settings.json \
+ --output android-build \
+ --android-platform android-${{ env.ANDROID_API_LEVEL }} \
+ --jdk $JAVA_HOME \
+ --gradle \
+ --release; then
+ echo "ERROR: androiddeployqt failed"
+ exit 1
+ fi
+ else
+ echo "ERROR: androiddeployqt not found"
+ echo "Cannot package APK without androiddeployqt"
+ exit 1
+ fi
+
+ # List what was built
+ echo "Files generated:"
+ find . -name "*.apk" -o -name "*.aab" | head -10
+
+ - name: Find and copy APK
+ run: |
+ set -e # Exit immediately if any command fails
+
+ # Look for generated APK files
+ echo "Searching for APK files..."
+ find . -name "*.apk" -type f
+
+ # Copy APK to standard location
+ APK_FILE=$(find . -name "*.apk" -type f | head -1)
+ if [ -n "$APK_FILE" ]; then
+ cp "$APK_FILE" AndroidInterrogator.apk
+ echo "Found APK: $APK_FILE"
+ ls -la AndroidInterrogator.apk
+ else
+ echo "WARNING: No APK found, checking for AAB files..."
+ find . -name "*.aab" -type f
+
+ # If AAB exists, we'd need bundletool to convert to APK
+ AAB_FILE=$(find . -name "*.aab" -type f | head -1)
+ if [ -n "$AAB_FILE" ]; then
+ echo "Found AAB: $AAB_FILE"
+ # For now, just copy the AAB as the output
+ cp "$AAB_FILE" AndroidInterrogator.aab
+ else
+ echo "ERROR: No APK or AAB files were generated"
+ echo "Build appears to have failed"
+ exit 1
+ fi
+ fi
+
+ - name: Upload APK Artifact
+ uses: actions/upload-artifact@v4
+ if: always()
with:
- name: AndroidInterrogator.apk ${{github.os}}
+ name: AndroidInterrogator-Build
path: |
AndroidInterrogator.apk
+ AndroidInterrogator.aab
+ android-build/build/outputs/**/*
+ if-no-files-found: warn
+
+ - name: Upload Build Logs
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: Android-Build-Logs
+ path: |
+ android-build/build/outputs/logs/
+ *.log
+ if-no-files-found: ignore
diff --git a/.gitignore b/.gitignore
index 587c98e..b2c1680 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,4 +53,13 @@ compile_commands.json
*_qmlcache.qrc
-Interrogator.app
\ No newline at end of file
+Interrogator.app
+
+# Android build artifacts
+android-build/
+*.apk
+*.aab
+*-deployment-settings.json
+.gradle/
+build/
+local.properties
\ No newline at end of file
diff --git a/BUILD_ANDROID_DOCKER.md b/BUILD_ANDROID_DOCKER.md
new file mode 100644
index 0000000..e2b9606
--- /dev/null
+++ b/BUILD_ANDROID_DOCKER.md
@@ -0,0 +1,232 @@
+# Building Android APK with Docker
+
+This guide explains how to build the Interrogator Android APK locally using Docker.
+
+## Prerequisites
+
+- Docker installed on your system
+- At least 10GB of free disk space
+- Git (to clone the repository)
+
+## Quick Start
+
+### 1. Build the Docker Image
+
+From the project root directory, run:
+
+```bash
+docker build -f Dockerfile.android -t interrogator-android .
+```
+
+This will create a Docker image with all necessary dependencies:
+- Android SDK and NDK
+- Qt 6.5.3 for Android
+- Build tools and Java JDK 17
+
+**Note:** First build will take 15-30 minutes as it downloads all dependencies (~8GB).
+
+### 2. Build the APK
+
+Run the container to build the APK:
+
+```bash
+docker run --rm -v $(pwd):/workspace -v $(pwd)/build:/build interrogator-android
+```
+
+The APK will be generated at: `./build/Interrogator.apk`
+
+## Detailed Usage
+
+### Building with Custom Options
+
+You can override the build script or run custom commands:
+
+```bash
+# Interactive shell inside container
+docker run --rm -it -v $(pwd):/workspace interrogator-android /bin/bash
+
+# Run specific build commands
+docker run --rm -v $(pwd):/workspace interrogator-android \
+ bash -c "cd /workspace && qmake && make"
+```
+
+### Build Output
+
+The build process creates:
+- `build-android/` - Build artifacts and intermediate files
+- `build/Interrogator.apk` - Final APK file (copied to host)
+
+### Cleaning Build Artifacts
+
+To clean previous builds:
+
+```bash
+# Remove build directory on host
+rm -rf build-android build
+
+# Or clean inside container
+docker run --rm -v $(pwd):/workspace interrogator-android \
+ bash -c "rm -rf /workspace/build-android /workspace/build"
+```
+
+## Architecture Support
+
+The default build targets **arm64-v8a** (64-bit ARM), which works on most modern Android devices.
+
+To build for other architectures, modify the `ANDROID_ABIS` in `docker-build.sh`:
+
+```bash
+# For 32-bit ARM
+ANDROID_ABIS="armeabi-v7a"
+
+# For multiple architectures
+ANDROID_ABIS="arm64-v8a armeabi-v7a"
+```
+
+## Troubleshooting
+
+### Build fails with "androiddeployqt not found"
+
+Ensure the Qt Android installation completed successfully:
+
+```bash
+docker run --rm interrogator-android ls -la /opt/qt/6.5.3/android_arm64_v8a/bin/
+```
+
+### APK not generated
+
+Check the build logs for errors:
+
+```bash
+docker run --rm -v $(pwd):/workspace interrogator-android
+```
+
+Look for compilation errors or missing dependencies in the output.
+
+### Out of disk space
+
+Docker images and builds can be large. Free up space:
+
+```bash
+# Remove unused Docker images
+docker system prune -a
+
+# Check Docker disk usage
+docker system df
+```
+
+## Environment Variables
+
+You can customize the build environment:
+
+```bash
+docker run --rm \
+ -e ANDROID_ABIS="arm64-v8a" \
+ -e BUILD_TYPE="release" \
+ -v $(pwd):/workspace \
+ -v $(pwd)/build:/build \
+ interrogator-android
+```
+
+Available variables:
+- `ANDROID_HOME` - Android SDK location
+- `QT_ANDROID` - Qt Android installation path
+- `ANDROID_NDK_ROOT` - NDK location
+- `BUILD_TYPE` - Build type (release/debug)
+
+## Advanced Usage
+
+### Using a Different Qt Version
+
+Edit `Dockerfile.android` and change the Qt version:
+
+```dockerfile
+RUN aqt install-qt linux desktop 6.6.0 gcc_64 -O ${QT_ROOT} && \
+ aqt install-qt linux android 6.6.0 android_arm64_v8a -O ${QT_ROOT}
+```
+
+Then rebuild the Docker image.
+
+### Caching Qt Installation
+
+To speed up rebuilds, use Docker volumes for Qt:
+
+```bash
+# Create named volume for Qt
+docker volume create qt-cache
+
+# Build with volume
+docker run --rm \
+ -v qt-cache:/opt/qt \
+ -v $(pwd):/workspace \
+ -v $(pwd)/build:/build \
+ interrogator-android
+```
+
+### CI/CD Integration
+
+You can use this Docker image in CI/CD pipelines:
+
+```yaml
+# Example for GitHub Actions
+jobs:
+ build-android:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Build Docker image
+ run: docker build -f Dockerfile.android -t interrogator-android .
+ - name: Build APK
+ run: docker run --rm -v $(pwd):/workspace -v $(pwd)/build:/build interrogator-android
+ - name: Upload APK
+ uses: actions/upload-artifact@v3
+ with:
+ name: android-apk
+ path: build/Interrogator.apk
+```
+
+## File Structure
+
+```
+.
+├── Dockerfile.android # Docker image definition
+├── docker-build.sh # Build script (runs inside container)
+├── BUILD_ANDROID_DOCKER.md # This documentation
+├── Interrogator.pro # Qt project file
+├── android/ # Android-specific files
+│ ├── AndroidManifest.xml
+│ ├── build.gradle
+│ └── res/
+└── build/ # Output directory (host)
+ └── Interrogator.apk # Generated APK
+```
+
+## Benefits of Docker Build
+
+1. **Reproducible**: Same environment every time
+2. **Isolated**: Doesn't affect your host system
+3. **Portable**: Works on Linux, macOS, and Windows
+4. **Clean**: Easy to reset and rebuild
+5. **Version Controlled**: Dockerfile tracks exact dependencies
+
+## Comparison: Docker vs GitHub Actions
+
+| Aspect | Docker (Local) | GitHub Actions (CI) |
+|--------|---------------|---------------------|
+| Setup Time | 15-30 min (first time) | 0 min (pre-configured) |
+| Build Time | 5-10 min | 5-10 min |
+| Cost | Free (uses your hardware) | Free (public repos) |
+| Debugging | Easy (interactive shell) | Harder (log-based) |
+| Consistency | High | Very High |
+| Portability | Very High | Tied to GitHub |
+
+## Support
+
+For issues with Docker builds, check:
+1. Docker daemon is running: `docker ps`
+2. Sufficient disk space: `df -h`
+3. Docker version: `docker --version` (requires v20.10+)
+
+For Qt or Android-specific issues, refer to:
+- [Qt Documentation](https://doc.qt.io/qt-6/)
+- [Android NDK Guide](https://developer.android.com/ndk/guides)
diff --git a/BUILD_ANDROID_LOCAL.md b/BUILD_ANDROID_LOCAL.md
new file mode 100644
index 0000000..df67ab7
--- /dev/null
+++ b/BUILD_ANDROID_LOCAL.md
@@ -0,0 +1,240 @@
+# Local Android APK Build with Docker
+
+This guide explains how to build the Android APK for the Interrogator application locally using Docker.
+
+## Prerequisites
+
+1. **Docker**: Install Docker Desktop or Docker Engine
+ - Windows/Mac: [Docker Desktop](https://www.docker.com/products/docker-desktop/)
+ - Linux: [Docker Engine](https://docs.docker.com/engine/install/)
+
+2. **Docker Compose**: Usually included with Docker Desktop
+ - Linux: May need to install separately
+
+3. **Disk Space**: Ensure you have at least 15GB of free disk space
+ - Qt 6.5.3: ~3GB
+ - Android SDK/NDK: ~5GB
+ - Build artifacts: ~2GB
+
+## Quick Start
+
+### Method 1: Using Docker Compose (Recommended)
+
+1. **Build the Docker image** (first time only):
+ ```bash
+ docker-compose build
+ ```
+
+2. **Run the build**:
+ ```bash
+ docker-compose up
+ ```
+
+3. **Find your APK**:
+ The APK will be in the project root directory as `Interrogator-debug.apk`
+
+### Method 2: Using Docker Directly
+
+1. **Build the Docker image**:
+ ```bash
+ docker build -f Dockerfile.android -t interrogator-android-builder .
+ ```
+
+2. **Run the build container**:
+ ```bash
+ docker run --rm -v $(pwd):/workspace interrogator-android-builder /workspace/scripts/build-android-local.sh
+ ```
+
+3. **Find your APK**:
+ The APK will be in the project root directory as `Interrogator-debug.apk`
+
+## Interactive Build (for debugging)
+
+If you want to enter the container and build manually:
+
+```bash
+# Start an interactive shell in the container
+docker run -it --rm -v $(pwd):/workspace interrogator-android-builder /bin/bash
+
+# Inside the container, run the build script
+/workspace/scripts/build-android-local.sh
+
+# Or build step by step manually:
+mkdir -p android-build && cd android-build
+/opt/qt/6.5.3/android_arm64_v8a/bin/qmake .. ANDROID_ABIS=arm64-v8a
+make -j$(nproc)
+/opt/qt/6.5.3/android_arm64_v8a/bin/androiddeployqt --input android-Interrogator-deployment-settings.json --output android-build --android-platform android-34 --gradle
+```
+
+## Build Configuration
+
+### Environment Variables
+
+You can customize the build by setting environment variables:
+
+```bash
+# Using docker-compose
+QT_VERSION=6.5.3 docker-compose up
+
+# Using docker directly
+docker run --rm \
+ -e QT_VERSION=6.5.3 \
+ -v $(pwd):/workspace \
+ interrogator-android-builder \
+ /workspace/scripts/build-android-local.sh
+```
+
+Available variables:
+- `QT_VERSION`: Qt version to use (default: 6.5.3)
+- `ANDROID_SDK_ROOT`: Android SDK location (default: /opt/android-sdk)
+- `QT_ROOT`: Qt installation directory (default: /opt/qt)
+
+### Build Options
+
+The Docker image includes:
+- **Qt 6.5.3** (Android arm64-v8a and Desktop gcc_64)
+- **Android SDK API 34** (Android 14)
+- **Android Build Tools 34.0.0**
+- **NDK 21.4.7075529**
+- **Java JDK 17**
+
+## Troubleshooting
+
+### Build Fails with "qmake not found"
+
+Ensure the Qt installation completed successfully:
+```bash
+docker run -it interrogator-android-builder ls -la /opt/qt/6.5.3/
+```
+
+### Build Fails with "androiddeployqt not found"
+
+Check if androiddeployqt exists:
+```bash
+docker run -it interrogator-android-builder ls -la /opt/qt/6.5.3/android_arm64_v8a/bin/
+```
+
+### APK Not Generated
+
+1. Check the build logs for errors
+2. Verify Gradle build succeeded
+3. Check android-build directory:
+ ```bash
+ docker run -it -v $(pwd):/workspace interrogator-android-builder find /workspace/android-build -name "*.apk"
+ ```
+
+### Out of Disk Space
+
+If you encounter disk space issues:
+
+1. **Clean Docker cache**:
+ ```bash
+ docker system prune -a --volumes
+ ```
+
+2. **Remove unused images**:
+ ```bash
+ docker image prune -a
+ ```
+
+### Rebuilding the Docker Image
+
+If you need to rebuild the image from scratch:
+
+```bash
+# Using docker-compose
+docker-compose build --no-cache
+
+# Using docker directly
+docker build --no-cache -f Dockerfile.android -t interrogator-android-builder .
+```
+
+## Performance Tips
+
+### Use Build Caches
+
+The docker-compose.yml includes volume caches for Qt and Android SDK:
+
+```yaml
+volumes:
+ qt-cache:/opt/qt
+ android-sdk-cache:/opt/android-sdk
+```
+
+This speeds up subsequent builds significantly.
+
+### Multi-core Builds
+
+The build script uses `make -j$(nproc)` to utilize all available CPU cores. For very slow machines, you can limit this:
+
+```bash
+# Edit scripts/build-android-local.sh and change:
+make -j2 # Use only 2 cores
+```
+
+## Clean Build
+
+To perform a completely clean build:
+
+```bash
+# Remove build artifacts
+rm -rf android-build Interrogator-debug.apk
+
+# Rebuild with docker-compose
+docker-compose down -v # Remove volumes
+docker-compose build --no-cache
+docker-compose up
+```
+
+## Building Different Architectures
+
+The default build targets arm64-v8a. To build for other architectures:
+
+1. Modify `Dockerfile.android` to install the desired Qt architecture:
+ ```dockerfile
+ # For armv7:
+ RUN aqt install-qt linux android ${QT_VERSION} android_armv7 -O ${QT_ROOT}
+
+ # For x86_64:
+ RUN aqt install-qt linux android ${QT_VERSION} android_x86_64 -O ${QT_ROOT}
+ ```
+
+2. Update `scripts/build-android-local.sh` to use the correct architecture in qmake:
+ ```bash
+ ${ANDROID_QMAKE} .. ANDROID_ABIS=armeabi-v7a # for armv7
+ # or
+ ${ANDROID_QMAKE} .. ANDROID_ABIS=x86_64 # for x86_64
+ ```
+
+## CI/CD Integration
+
+You can use this Docker setup in CI/CD pipelines:
+
+```yaml
+# Example GitHub Actions workflow
+- name: Build Android APK with Docker
+ run: |
+ docker-compose build
+ docker-compose up
+
+- name: Upload APK
+ uses: actions/upload-artifact@v3
+ with:
+ name: android-apk
+ path: Interrogator-debug.apk
+```
+
+## Additional Resources
+
+- [Qt for Android Documentation](https://doc.qt.io/qt-6/android.html)
+- [Android SDK Documentation](https://developer.android.com/studio/command-line)
+- [Docker Documentation](https://docs.docker.com/)
+
+## Support
+
+If you encounter issues not covered in this guide, please:
+
+1. Check the build logs carefully
+2. Verify all prerequisites are met
+3. Try a clean rebuild
+4. Open an issue in the repository with full error logs
diff --git a/Dockerfile.android b/Dockerfile.android
new file mode 100644
index 0000000..d3ffc3d
--- /dev/null
+++ b/Dockerfile.android
@@ -0,0 +1,70 @@
+# Dockerfile for building Qt Android APK locally
+FROM ubuntu:22.04
+
+# Prevent interactive prompts during package installation
+ENV DEBIAN_FRONTEND=noninteractive
+
+# Install required system packages
+RUN apt-get update && apt-get install -y \
+ wget \
+ curl \
+ python3 \
+ python3-pip \
+ openjdk-17-jdk \
+ unzip \
+ git \
+ build-essential \
+ libgl1-mesa-dev \
+ libglu1-mesa-dev \
+ libxkbcommon-x11-0 \
+ libxcb-xinerama0 \
+ libxcb-cursor0 \
+ && rm -rf /var/lib/apt/lists/*
+
+# Set up environment variables
+ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
+ENV ANDROID_SDK_ROOT=/opt/android-sdk
+ENV ANDROID_NDK_ROOT=/opt/android-sdk/ndk/21.4.7075529
+ENV QT_VERSION=6.5.3
+ENV QT_ROOT=/opt/qt/${QT_VERSION}
+ENV PATH=${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin:${ANDROID_SDK_ROOT}/platform-tools:${ANDROID_SDK_ROOT}/build-tools/34.0.0:${PATH}
+
+# Install Android SDK Command-line Tools
+RUN mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools && \
+ cd ${ANDROID_SDK_ROOT}/cmdline-tools && \
+ wget -q https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip && \
+ unzip -q commandlinetools-linux-9477386_latest.zip && \
+ rm commandlinetools-linux-9477386_latest.zip && \
+ mv cmdline-tools latest
+
+# Accept Android SDK licenses
+RUN yes | sdkmanager --licenses || true
+
+# Install Android SDK components
+RUN sdkmanager \
+ "platform-tools" \
+ "platforms;android-34" \
+ "build-tools;34.0.0" \
+ "ndk;21.4.7075529"
+
+# Remove corrupted SDK platforms if they exist
+RUN rm -rf ${ANDROID_SDK_ROOT}/platforms/android-35* || true && \
+ rm -rf ${ANDROID_SDK_ROOT}/platforms/android-36* || true
+
+# Install aqt (Another Qt Installer)
+RUN pip3 install aqtinstall
+
+# Install Qt for Android and desktop
+RUN mkdir -p /opt/qt && \
+ aqt install-qt linux desktop ${QT_VERSION} gcc_64 -O /opt/qt && \
+ aqt install-qt linux android ${QT_VERSION} android_arm64_v8a -O /opt/qt
+
+# Set up Qt environment
+ENV ANDROID_QT_ROOT=${QT_ROOT}/android_arm64_v8a
+ENV PATH=${ANDROID_QT_ROOT}/bin:${QT_ROOT}/gcc_64/bin:${PATH}
+
+# Create working directory
+WORKDIR /workspace
+
+# Default command
+CMD ["/bin/bash"]
diff --git a/Interrogator.pro b/Interrogator.pro
index 19f932c..ba06641 100644
--- a/Interrogator.pro
+++ b/Interrogator.pro
@@ -11,6 +11,21 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Interrogator
TEMPLATE = app
+# Android specific configurations
+android {
+ # androidextras module was removed in Qt 6.0
+ # Its functionality is now part of Qt Core
+ greaterThan(QT_MAJOR_VERSION, 5): QT += core-private
+ equals(QT_MAJOR_VERSION, 5): QT += androidextras
+
+ ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
+
+ OTHER_FILES += \
+ android/AndroidManifest.xml \
+ android/build.gradle \
+ android/res/values/libs.xml
+}
+
SOURCES += main.cpp\
mainwindow.cpp \
diff --git a/README-Android-Docker.md b/README-Android-Docker.md
new file mode 100644
index 0000000..936a727
--- /dev/null
+++ b/README-Android-Docker.md
@@ -0,0 +1,174 @@
+# Building Android APK Locally with Docker
+
+This guide explains how to build the Interrogator Android APK on your local machine using Docker.
+
+## Prerequisites
+
+1. **Docker** - Install Docker Desktop or Docker Engine:
+ - **Windows/Mac**: [Docker Desktop](https://www.docker.com/products/docker-desktop)
+ - **Linux**: Docker Engine (via package manager)
+
+2. **Disk Space** - Ensure you have at least 15GB of free disk space for:
+ - Docker image (~8GB)
+ - Build artifacts (~2GB)
+ - Android SDK and Qt (~5GB)
+
+## Quick Start
+
+### 1. Make the build script executable
+
+```bash
+chmod +x build-android-local.sh
+```
+
+### 2. Run the build
+
+```bash
+./build-android-local.sh
+```
+
+The script will:
+1. Build a Docker image with all required tools (Android SDK, NDK, Qt 6.5.3)
+2. Compile the application inside the container
+3. Package the APK
+4. Copy the APK to your current directory as `Interrogator-release.apk`
+
+## Build Process Details
+
+### What the Docker Image Contains
+
+The Docker image (`Dockerfile.android`) includes:
+- Ubuntu 22.04 base
+- Java JDK 17
+- Android SDK Command-line Tools
+- Android SDK Platform 34
+- Android Build Tools 34.0.0
+- Android NDK 21.4.7075529
+- Qt 6.5.3 for Android (arm64-v8a)
+- Qt 6.5.3 for desktop (gcc_64)
+
+### Build Steps
+
+1. **Image Building**: Creates a Docker image with all dependencies (first run takes 10-15 minutes)
+2. **Configuration**: Uses Android qmake to configure the project
+3. **Compilation**: Builds the native library
+4. **Packaging**: Uses androiddeployqt to create the APK
+5. **Output**: Copies the APK to `Interrogator-release.apk`
+
+## Troubleshooting
+
+### Docker Build Fails
+
+**Issue**: Docker build fails with "no space left on device"
+**Solution**:
+```bash
+docker system prune -a # Clean up unused Docker resources
+```
+
+### Build Script Permission Denied
+
+**Issue**: `./build-android-local.sh: Permission denied`
+**Solution**:
+```bash
+chmod +x build-android-local.sh
+```
+
+### APK Not Generated
+
+**Issue**: Build completes but no APK found
+**Solution**: Check the build output inside the Docker container:
+```bash
+docker run --rm -v "$(pwd):/workspace" -w /workspace interrogator-android-builder /bin/bash -c "ls -la android-build/"
+```
+
+## Advanced Usage
+
+### Interactive Docker Shell
+
+To debug build issues, launch an interactive shell:
+
+```bash
+docker run --rm -it -v "$(pwd):/workspace" -w /workspace interrogator-android-builder /bin/bash
+```
+
+Then manually run build commands:
+
+```bash
+export ANDROID_QT_ROOT=/opt/qt/6.5.3/android_arm64_v8a
+export ANDROID_SDK_ROOT=/opt/android-sdk
+
+# Configure
+${ANDROID_QT_ROOT}/bin/qmake Interrogator.pro -spec android-clang
+
+# Build
+make -j$(nproc)
+
+# Package
+${ANDROID_QT_ROOT}/bin/androiddeployqt --input android-build/android-deployment-settings.json --output android-build
+```
+
+### Rebuild Docker Image
+
+If you need to rebuild the Docker image (e.g., to update Qt version):
+
+```bash
+docker build --no-cache -f Dockerfile.android -t interrogator-android-builder .
+```
+
+### Different Android Architectures
+
+To build for different architectures, modify the build script:
+
+- **ARMv7**: Change `android_arm64_v8a` to `android_armv7` and `arm64-v8a` to `armeabi-v7a`
+- **x86_64**: Change to `android_x86_64` and `x86_64`
+
+## Output
+
+After a successful build, you'll find:
+- **Interrogator-release.apk** - The unsigned release APK (ready for testing)
+- **android-build/** - Build artifacts directory
+
+## Next Steps
+
+### Install on Device
+
+To install the APK on an Android device:
+
+```bash
+adb install -r Interrogator-release.apk
+```
+
+### Sign the APK (for distribution)
+
+For publishing to Google Play or distribution, sign the APK:
+
+```bash
+# Generate keystore (one-time)
+keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
+
+# Sign APK
+jarsigner -verbose -sigalg SHA256withRSA -digestalg SHA-256 -keystore my-release-key.keystore Interrogator-release.apk my-key-alias
+
+# Zipalign (optimize)
+zipalign -v 4 Interrogator-release.apk Interrogator-release-signed.apk
+```
+
+## Performance Notes
+
+- **First build**: 15-20 minutes (includes downloading ~8GB of dependencies)
+- **Subsequent builds**: 2-5 minutes (Docker image is cached)
+- **Incremental builds**: 1-2 minutes (if only source code changed)
+
+## Comparison with GitHub Actions
+
+| Aspect | Local Docker Build | GitHub Actions |
+|--------|-------------------|----------------|
+| Speed (first) | 15-20 min | 20-25 min |
+| Speed (subsequent) | 2-5 min | 20-25 min |
+| Requires | Docker, disk space | GitHub account |
+| Cost | Free (local resources) | Free (public repos) |
+| Debugging | Full shell access | Limited logs |
+
+## Support
+
+For issues or questions about local Docker builds, please open an issue on the GitHub repository.
diff --git a/README.md b/README.md
index 5420c04..9fccf38 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,33 @@ Known bugs:

+## Build Instructions
-## Build mac:
+### Build for Mac:
+```bash
qmake CONFIG+=release && make
+```
+
+### Build for Android:
+The project includes an automated GitHub Actions workflow for building Android APKs. The workflow (`/.github/workflows/mobile.yml`) automatically:
+
+1. Sets up Android SDK and NDK
+2. Installs Qt for Android development
+3. Configures the project for Android builds
+4. Generates the APK file
+5. Uploads the APK as a build artifact
+
+To build manually for Android, you need:
+- Qt 5.15.2 or later with Android support
+- Android SDK (API level 30)
+- Android NDK (version 21.4.7075529)
+- Java JDK 11
+
+Build commands:
+```bash
+qmake -spec android-clang CONFIG+=release ANDROID_ABIS=arm64-v8a
+make
+androiddeployqt --input android-Interrogator-deployment-settings.json --output android-build --android-platform android-30 --jdk $JAVA_HOME --gradle --release
+```
+
+The Android build will generate an APK in the `android-build/build/outputs/apk/release/` directory.
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
new file mode 100644
index 0000000..f0129b4
--- /dev/null
+++ b/android/AndroidManifest.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..84be721
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,69 @@
+buildscript {
+ repositories {
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.4.2'
+ }
+}
+
+repositories {
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+}
+
+apply plugin: 'com.android.application'
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+}
+
+android {
+ /*******************************************************
+ * The following variables:
+ * - androidBuildToolsVersion,
+ * - androidCompileSdkVersion
+ * - qtAndroidDir - holds the path to qt android files
+ * needed to build any Qt application
+ * on Android.
+ *
+ * are defined in gradle.properties file. This file is
+ * updated by QtCreator and androiddeployqt tools.
+ * Changing them manually might break the compilation!
+ *******************************************************/
+
+ compileSdkVersion androidCompileSdkVersion
+ buildToolsVersion androidBuildToolsVersion
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = [qtAndroidDir + '/src', 'src', 'java']
+ aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl']
+ res.srcDirs = [qtAndroidDir + '/res', 'res']
+ resources.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ assets.srcDirs = ['assets']
+ jniLibs.srcDirs = ['libs']
+ }
+ }
+
+ lint {
+ abortOnError false
+ }
+
+ // Do not compress Qt binary resources file
+ androidResources {
+ noCompress 'rcc'
+ }
+
+ defaultConfig {
+ resConfig "en"
+ minSdkVersion qtMinSdkVersion
+ targetSdkVersion qtTargetSdkVersion
+ }
+}
\ No newline at end of file
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..279c821
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,5 @@
+androidBuildToolsVersion=34.0.0
+androidCompileSdkVersion=34
+# Note: qtAndroidDir is set by androiddeployqt during build
+qtMinSdkVersion=23
+qtTargetSdkVersion=34
\ No newline at end of file
diff --git a/android/res/drawable/logo.xml b/android/res/drawable/logo.xml
new file mode 100644
index 0000000..b7062fe
--- /dev/null
+++ b/android/res/drawable/logo.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/android/res/values/libs.xml b/android/res/values/libs.xml
new file mode 100644
index 0000000..f5f4633
--- /dev/null
+++ b/android/res/values/libs.xml
@@ -0,0 +1,21 @@
+
+
+
+ - https://download.qt.io/ministro/android/qt5/qt-5.15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docker-build.sh b/docker-build.sh
new file mode 100644
index 0000000..666010a
--- /dev/null
+++ b/docker-build.sh
@@ -0,0 +1,118 @@
+#!/bin/bash
+set -e
+
+echo "=================================="
+echo "Android APK Build Script (Docker)"
+echo "=================================="
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Verify Qt installation
+echo -e "${YELLOW}Verifying Qt installation...${NC}"
+if [ ! -f "${QT_ANDROID}/bin/qmake" ]; then
+ echo -e "${RED}ERROR: Qt Android qmake not found at ${QT_ANDROID}/bin/qmake${NC}"
+ exit 1
+fi
+echo -e "${GREEN}✓ Qt Android found at ${QT_ANDROID}${NC}"
+
+# Verify androiddeployqt
+if [ ! -f "${QT_ANDROID}/bin/androiddeployqt" ]; then
+ echo -e "${RED}ERROR: androiddeployqt not found at ${QT_ANDROID}/bin/androiddeployqt${NC}"
+ exit 1
+fi
+echo -e "${GREEN}✓ androiddeployqt found${NC}"
+
+# Clean previous builds
+echo -e "${YELLOW}Cleaning previous builds...${NC}"
+rm -rf /workspace/build-android
+mkdir -p /workspace/build-android
+cd /workspace/build-android
+
+# Configure with qmake
+echo -e "${YELLOW}Configuring project with qmake...${NC}"
+${QT_ANDROID}/bin/qmake /workspace/Interrogator.pro \
+ -spec android-clang \
+ CONFIG+=release \
+ ANDROID_ABIS="arm64-v8a"
+
+if [ $? -ne 0 ]; then
+ echo -e "${RED}ERROR: qmake configuration failed${NC}"
+ exit 1
+fi
+echo -e "${GREEN}✓ Project configured${NC}"
+
+# Build the project
+echo -e "${YELLOW}Building project...${NC}"
+make -j$(nproc)
+
+if [ $? -ne 0 ]; then
+ echo -e "${RED}ERROR: Build failed${NC}"
+ exit 1
+fi
+echo -e "${GREEN}✓ Build completed${NC}"
+
+# Generate android deployment settings
+echo -e "${YELLOW}Generating Android deployment configuration...${NC}"
+make install INSTALL_ROOT=/workspace/build-android/android-build
+
+# Create deployment JSON
+cat > /workspace/build-android/android-deployment-settings.json <statusBar()->showMessage("there is " + QString(wp->getWrongWordsSize()) + " wrong word(s).");
+ this->statusBar()->showMessage("there is " + QString::number(wp->getWrongWordsSize()) + " wrong word(s).");
}
void MainWindow::on_actionAbout_triggered()
@@ -250,7 +250,7 @@ void MainWindow::on_actionExport_wrong_answers_append_triggered()
void MainWindow::on_actionAk_wrong_answers_only_append_triggered()
{
bool ret = false;
- this->statusBar()->showMessage("there is " + QString(wp->getWrongWordsSize()) + " wrong word(s).");
+ this->statusBar()->showMessage("there is " + QString::number(wp->getWrongWordsSize()) + " wrong word(s).");
ret = wp->getWrongAnswersOnly(true);
if(ret)
{
diff --git a/wordprocessor.cpp b/wordprocessor.cpp
index 4eebdda..1216cb1 100644
--- a/wordprocessor.cpp
+++ b/wordprocessor.cpp
@@ -6,6 +6,8 @@
#include
#include /* srand, rand */
#include /* time */
+#include /* std::shuffle */
+#include /* std::default_random_engine */
wordProcessor::wordProcessor()
{
@@ -157,7 +159,10 @@ void wordProcessor::init()
_allWords = _words.size();
_askedIndex = 0;
std::srand(time(0));
- std::random_shuffle(_words.begin(),_words.end());
+ // Use std::shuffle instead of std::random_shuffle (removed in C++17)
+ std::random_device rd;
+ std::default_random_engine rng(rd());
+ std::shuffle(_words.begin(), _words.end(), rng);
_wrongWords.clear();
}
@@ -225,7 +230,12 @@ bool wordProcessor::openFile(QString fileName)
}
QTextStream in(&file);
+ // Qt 6: Use setEncoding instead of setCodec
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ in.setEncoding(QStringConverter::Utf8);
+#else
in.setCodec("UTF-8");
+#endif
while(!in.atEnd()) {
QString line = in.readLine();
QStringList fields = line.split(_separate[EQUAL]);