207 lines
11 KiB
PowerShell
207 lines
11 KiB
PowerShell
<#
|
|
Build helper for Android (Windows PowerShell)
|
|
|
|
What it does:
|
|
- Checks for required commands (`npm`, `rustup`, `cargo`, `cargo-ndk`)
|
|
- Builds frontend (runs `npm run build` if `dist`/`build` not present)
|
|
- Copies frontend files from `dist` or `src` into `android/app/src/main/assets`
|
|
- Builds Rust native libs using `cargo-ndk` (if available) for `aarch64` and `armv7`
|
|
- Copies produced `.so` files into `android/app/src/main/jniLibs/*`
|
|
|
|
Note: This script prepares the Android project. To produce the APK, open `android/` in Android Studio and run Build -> Assemble, or run `gradlew assembleDebug` locally.
|
|
#>
|
|
|
|
Set-StrictMode -Version Latest
|
|
|
|
function Check-Command($name) {
|
|
$which = Get-Command $name -ErrorAction SilentlyContinue
|
|
return $which -ne $null
|
|
}
|
|
|
|
Write-Output "Starting Android prep script..."
|
|
|
|
if (-not (Check-Command npm)) { Write-Warning "npm not found in PATH. Install Node.js to build frontend." }
|
|
if (-not (Check-Command rustup)) { Write-Warning "rustup not found in PATH. Install Rust toolchain." }
|
|
if (-not (Check-Command cargo)) { Write-Warning "cargo not found in PATH." }
|
|
|
|
$cargoNdkAvailable = Check-Command cargo-ndk
|
|
if (-not $cargoNdkAvailable) { Write-Warning "cargo-ndk not found. Native libs will not be built. Install via 'cargo install cargo-ndk'" }
|
|
|
|
# Determine repository root (parent of the scripts folder)
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
$root = Split-Path -Parent $scriptDir
|
|
Push-Location $root
|
|
|
|
# Prefer Tauri-generated Android Studio project (tauri android init)
|
|
$androidRoot = Join-Path $root 'src-tauri\gen\android'
|
|
if (-not (Test-Path $androidRoot)) {
|
|
# Legacy fallback (non-Tauri project)
|
|
$androidRoot = Join-Path $root 'android'
|
|
}
|
|
|
|
function Escape-LocalPropertiesPath([string]$p) {
|
|
# local.properties expects ':' escaped and backslashes doubled on Windows.
|
|
# Use plain string replacements to avoid regex escaping pitfalls.
|
|
return ($p.Replace('\', '\\').Replace(':', '\:'))
|
|
}
|
|
|
|
# Ensure Android SDK/NDK locations are set for Gradle (local.properties)
|
|
$sdkRoot = $env:ANDROID_SDK_ROOT
|
|
if (-not $sdkRoot) { $sdkRoot = $env:ANDROID_HOME }
|
|
if (-not $sdkRoot) { $sdkRoot = Join-Path $env:LOCALAPPDATA 'Android\Sdk' }
|
|
|
|
$ndkRoot = $env:ANDROID_NDK_ROOT
|
|
if (-not $ndkRoot) { $ndkRoot = $env:ANDROID_NDK_HOME }
|
|
if (-not $ndkRoot -and (Test-Path (Join-Path $sdkRoot 'ndk'))) {
|
|
$ndkVersions = Get-ChildItem -Path (Join-Path $sdkRoot 'ndk') -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending
|
|
if ($ndkVersions -and (@($ndkVersions)).Count -gt 0) { $ndkRoot = @($ndkVersions)[0].FullName }
|
|
}
|
|
|
|
if (Test-Path $androidRoot) {
|
|
$localPropsPath = Join-Path $androidRoot 'local.properties'
|
|
$lines = @()
|
|
if ($sdkRoot) { $lines += "sdk.dir=$(Escape-LocalPropertiesPath $sdkRoot)" }
|
|
if ($ndkRoot) { $lines += "ndk.dir=$(Escape-LocalPropertiesPath $ndkRoot)" }
|
|
if ($lines.Count -gt 0) {
|
|
Set-Content -Path $localPropsPath -Value ($lines -join "`n") -Encoding ASCII
|
|
Write-Output "Wrote Android SDK/NDK config to: $localPropsPath"
|
|
}
|
|
}
|
|
|
|
# Build frontend (optional)
|
|
Write-Output "Preparing frontend files..."
|
|
$distDirs = @('dist','build')
|
|
$foundDist = $null
|
|
foreach ($d in $distDirs) {
|
|
if (Test-Path (Join-Path $root $d)) { $foundDist = $d; break }
|
|
}
|
|
|
|
if (-not $foundDist) {
|
|
# IMPORTANT: `npm run build` in this repo runs `tauri build`, which is a desktop bundling step.
|
|
# For Android prep we only need web assets, so we fall back to copying `src/` as assets.
|
|
Write-Warning "No dist/build output found — copying `src/` as assets (skipping `npm run build` to avoid desktop bundling)."
|
|
}
|
|
|
|
$assetsDst = Join-Path $androidRoot 'app\src\main\assets'
|
|
if (-not (Test-Path $assetsDst)) { New-Item -ItemType Directory -Path $assetsDst -Force | Out-Null }
|
|
|
|
if ($foundDist) {
|
|
Write-Output "Copying frontend from '$foundDist' to Android assets..."
|
|
robocopy (Join-Path $root $foundDist) $assetsDst /MIR | Out-Null
|
|
} else {
|
|
Write-Output "Copying raw 'src' to Android assets..."
|
|
robocopy (Join-Path $root 'src') $assetsDst /MIR | Out-Null
|
|
}
|
|
|
|
# Build native libs if cargo-ndk available
|
|
if ($cargoNdkAvailable) {
|
|
Write-Output "Building Rust native libs via cargo-ndk from project root: $root"
|
|
try {
|
|
# Build from the Rust crate directory `src-tauri`
|
|
$crateDir = Join-Path $root 'src-tauri'
|
|
if (-not (Test-Path (Join-Path $crateDir 'Cargo.toml'))) {
|
|
Write-Warning "Cargo.toml not found in src-tauri; skipping native build."
|
|
} else {
|
|
# Prefer Ninja generator for CMake if available (avoids Visual Studio generator issues)
|
|
# Restore env vars at the end so we don't pollute the current PowerShell session.
|
|
$oldCmakeGenerator = $env:CMAKE_GENERATOR
|
|
$oldCmakeMakeProgram = $env:CMAKE_MAKE_PROGRAM
|
|
$ninjaCmd = Get-Command ninja -ErrorAction SilentlyContinue
|
|
if ($ninjaCmd) {
|
|
Write-Output "Ninja detected at $($ninjaCmd.Source); setting CMake generator to Ninja."
|
|
$env:CMAKE_GENERATOR = 'Ninja'
|
|
$env:CMAKE_MAKE_PROGRAM = $ninjaCmd.Source
|
|
} else {
|
|
Write-Warning "Ninja not found in PATH. Installing Ninja or adding it to PATH is strongly recommended to avoid Visual Studio CMake generator on Windows."
|
|
}
|
|
|
|
# Attempt to locate Android NDK if environment variables are not set
|
|
if (-not $env:ANDROID_NDK_ROOT -and -not $env:ANDROID_NDK_HOME) {
|
|
$candidates = @()
|
|
if ($env:ANDROID_SDK_ROOT) { $candidates += Join-Path $env:ANDROID_SDK_ROOT 'ndk' }
|
|
if ($env:ANDROID_HOME) { $candidates += Join-Path $env:ANDROID_HOME 'ndk' }
|
|
$candidates += Join-Path $env:LOCALAPPDATA 'Android\sdk\ndk'
|
|
$candidates += Join-Path $env:USERPROFILE 'AppData\Local\Android\sdk\ndk'
|
|
$candidates += 'C:\Program Files (x86)\Android\AndroidNDK'
|
|
|
|
foreach ($cand in $candidates) {
|
|
if (Test-Path $cand) {
|
|
$versions = Get-ChildItem -Path $cand -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending
|
|
if ($versions -and (@($versions)).Count -gt 0) {
|
|
$ndkPath = @($versions)[0].FullName
|
|
Write-Output "Detected Android NDK at: $ndkPath"
|
|
$env:ANDROID_NDK_ROOT = $ndkPath
|
|
$env:ANDROID_NDK = $ndkPath
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (-not $env:ANDROID_NDK_ROOT) { Write-Warning "ANDROID_NDK_ROOT/ANDROID_NDK not set and no NDK found in common locations. Set ANDROID_NDK_ROOT to your NDK path." }
|
|
} else {
|
|
Write-Output "Using existing ANDROID_NDK_ROOT: $($env:ANDROID_NDK_ROOT)"
|
|
if (-not $env:ANDROID_NDK) { $env:ANDROID_NDK = $env:ANDROID_NDK_ROOT }
|
|
}
|
|
|
|
# Ensure expected external binary placeholders exist so Tauri bundling doesn't fail
|
|
$binariesDir = Join-Path $crateDir 'binaries'
|
|
if (-not (Test-Path $binariesDir)) { New-Item -ItemType Directory -Path $binariesDir -Force | Out-Null }
|
|
$placeholder1 = Join-Path $binariesDir 'RadioPlayer-aarch64-linux-android'
|
|
$placeholder2 = Join-Path $binariesDir 'RadioPlayer-armv7-linux-androideabi'
|
|
if (-not (Test-Path $placeholder1)) { New-Item -ItemType File -Path $placeholder1 -Force | Out-Null; Write-Output "Created placeholder: $placeholder1" }
|
|
if (-not (Test-Path $placeholder2)) { New-Item -ItemType File -Path $placeholder2 -Force | Out-Null; Write-Output "Created placeholder: $placeholder2" }
|
|
|
|
# If a previous build used a different CMake generator (e.g., Visual Studio), aws-lc-sys can fail with
|
|
# "Does not match the generator used previously". Clean only the aws-lc-sys CMake build dirs.
|
|
$awsLcBuildDirs = Get-ChildItem -Path (Join-Path $crateDir 'target') -Recurse -Directory -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.Name -like 'aws-lc-sys-*' }
|
|
foreach ($d in @($awsLcBuildDirs)) {
|
|
$cmakeBuildDir = Join-Path $d.FullName 'out\build'
|
|
$cmakeCache = Join-Path $cmakeBuildDir 'CMakeCache.txt'
|
|
if (Test-Path $cmakeCache) {
|
|
Write-Output "Cleaning stale CMake cache for aws-lc-sys: $cmakeBuildDir"
|
|
Remove-Item -Path $cmakeBuildDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
Push-Location $crateDir
|
|
try {
|
|
# Use API 24 to ensure libc symbols like getifaddrs/freeifaddrs are available.
|
|
# Build only the library to avoid linking the desktop binary for Android.
|
|
Write-Output "Running: cargo ndk -t arm64-v8a -t armeabi-v7a -P 24 build --release --lib (in $crateDir)"
|
|
cargo ndk -t arm64-v8a -t armeabi-v7a -P 24 build --release --lib
|
|
} finally {
|
|
Pop-Location
|
|
if ($null -eq $oldCmakeGenerator) { Remove-Item Env:\CMAKE_GENERATOR -ErrorAction SilentlyContinue } else { $env:CMAKE_GENERATOR = $oldCmakeGenerator }
|
|
if ($null -eq $oldCmakeMakeProgram) { Remove-Item Env:\CMAKE_MAKE_PROGRAM -ErrorAction SilentlyContinue } else { $env:CMAKE_MAKE_PROGRAM = $oldCmakeMakeProgram }
|
|
}
|
|
|
|
# Search for produced .so files under src-tauri/target
|
|
$soFiles = Get-ChildItem -Path (Join-Path $crateDir 'target') -Recurse -Filter "*.so" -ErrorAction SilentlyContinue
|
|
if (-not $soFiles) {
|
|
Write-Warning "No .so files found after build. Check cargo-ndk output above for errors."
|
|
} else {
|
|
foreach ($f in @($soFiles)) {
|
|
$full = $f.FullName
|
|
if ($full -match 'aarch64|aarch64-linux-android|arm64-v8a') { $abi = 'arm64-v8a' }
|
|
elseif ($full -match 'armv7|armv7-linux-androideabi|armeabi-v7a') { $abi = 'armeabi-v7a' }
|
|
else { continue }
|
|
|
|
$dst = Join-Path $androidRoot "app\src\main\jniLibs\$abi"
|
|
if (-not (Test-Path $dst)) { New-Item -ItemType Directory -Path $dst -Force | Out-Null }
|
|
Copy-Item $full -Destination $dst -Force
|
|
Write-Output "Copied $($f.Name) -> $dst"
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
Write-Warning "cargo-ndk build failed. Exception: $($_.Exception.Message)"
|
|
if ($_.ScriptStackTrace) { Write-Output $_.ScriptStackTrace }
|
|
}
|
|
} else {
|
|
Write-Warning "Skipping native lib build (cargo-ndk missing)."
|
|
}
|
|
|
|
Write-Output "Android prep complete. Open '$androidRoot' in Android Studio and build the APK (or run './gradlew assembleDebug' in that folder)."
|
|
|
|
Pop-Location
|