scripts/build-android.ps1
Rama main · réplica de lectura del repositorio original.
<#
Builds an installable, signed ARM64 release APK without requiring Windows
Developer Mode.
Tauri normally creates a JNI symlink on Windows. This script lets Tauri
compile Rust into an ASCII-only target directory, copies the library, strips
debug symbols, and asks Gradle to package the APK.
#>
[CmdletBinding()]
param(
[string]$ToolRoot = (Join-Path $env:LOCALAPPDATA "unigate-android-tools")
)
$ErrorActionPreference = "Stop"
$projectRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
# Магазины не принимают debug-сборки, а Android не даёт обновить APK, подписанный
# другим сертификатом, поэтому ключ обязателен: без него сборка обязана упасть, а
# не выпустить несовместимый пакет.
$keystore = $env:UNIGATE_ANDROID_KEYSTORE
if ([string]::IsNullOrWhiteSpace($keystore)) {
throw "UNIGATE_ANDROID_KEYSTORE is not set (path to the release .jks)"
}
$keystore = (Resolve-Path -LiteralPath $keystore).Path
if ([string]::IsNullOrWhiteSpace($env:UNIGATE_ANDROID_KEYSTORE_PASSWORD)) {
throw "UNIGATE_ANDROID_KEYSTORE_PASSWORD is not set"
}
$keyAlias = $env:UNIGATE_ANDROID_KEY_ALIAS
if ([string]::IsNullOrWhiteSpace($keyAlias)) { $keyAlias = "unigate" }
$sdkDir = Join-Path $ToolRoot "android-sdk"
$ndkDir = Join-Path $sdkDir "ndk\28.0.13004108"
$targetDir = Join-Path $env:LOCALAPPDATA "unigate-android-target"
$aar = Join-Path $projectRoot "src-tauri\gen\android\app\libs\libbox.aar"
$androidIcons = Join-Path $projectRoot "src-tauri\icons\android"
$androidResources = Join-Path $projectRoot "src-tauri\gen\android\app\src\main\res"
$geoipSource = Join-Path $projectRoot "src-tauri\binaries\geoip-ru.srs"
$androidAssets = Join-Path $projectRoot "src-tauri\gen\android\app\src\main\assets"
$awgSourceDir = Join-Path $projectRoot "awg-shim"
$libboxNeedsBuild = -not (Test-Path -LiteralPath $aar)
if (-not $libboxNeedsBuild) {
$libboxTime = (Get-Item -LiteralPath $aar).LastWriteTimeUtc
$libboxInputs = @(
Get-Item -LiteralPath (Join-Path $PSScriptRoot "build-libbox-android.ps1")
Get-ChildItem -LiteralPath $awgSourceDir -Recurse -File |
Where-Object { $_.Extension -eq ".go" -or $_.Name -in @("go.mod", "go.sum") }
)
$libboxNeedsBuild = $libboxInputs |
Where-Object { $_.LastWriteTimeUtc -gt $libboxTime } |
Select-Object -First 1
}
if ($libboxNeedsBuild) {
& (Join-Path $PSScriptRoot "build-libbox-android.ps1") -ToolRoot $ToolRoot
}
# `tauri android init` starts with the generic Tauri launcher. Keep Android
# launcher/notification artwork synchronized with the desktop UniGate icon.
Get-ChildItem -LiteralPath $androidIcons -Directory | ForEach-Object {
Copy-Item -LiteralPath $_.FullName -Destination $androidResources -Recurse -Force
}
if (-not (Test-Path -LiteralPath $geoipSource)) {
throw "geoip-ru.srs is missing. Run the platform fetch script first."
}
New-Item -ItemType Directory -Force -Path $androidAssets | Out-Null
Copy-Item -LiteralPath $geoipSource -Destination (Join-Path $androidAssets "geoip-ru.srs") -Force
$env:JAVA_HOME = Join-Path $ToolRoot "jdk-17"
$env:ANDROID_HOME = $sdkDir
$env:ANDROID_SDK_ROOT = $sdkDir
$env:NDK_HOME = $ndkDir
$env:CARGO_TARGET_DIR = $targetDir
# Свойства через ORG_GRADLE_PROJECT_* передаёт клиент Gradle, поэтому они доходят
# до сборки даже при уже запущенном демоне с другим окружением.
$env:ORG_GRADLE_PROJECT_unigateKeystore = $keystore
$env:ORG_GRADLE_PROJECT_unigateKeystorePassword = $env:UNIGATE_ANDROID_KEYSTORE_PASSWORD
$env:ORG_GRADLE_PROJECT_unigateKeyAlias = $keyAlias
if (-not [string]::IsNullOrWhiteSpace($env:UNIGATE_ANDROID_KEY_PASSWORD)) {
$env:ORG_GRADLE_PROJECT_unigateKeyPassword = $env:UNIGATE_ANDROID_KEY_PASSWORD
}
$buildStarted = Get-Date
Push-Location $projectRoot
try {
# A non-zero result is expected when Windows disallows Tauri's final symlink.
& npm.cmd run tauri -- android build --target aarch64
$tauriExit = $LASTEXITCODE
$rustLibrary = Join-Path $targetDir "aarch64-linux-android\release\libunigate_lib.so"
if (-not (Test-Path -LiteralPath $rustLibrary)) {
throw "Rust Android library was not produced (Tauri exit code $tauriExit)"
}
if ((Get-Item -LiteralPath $rustLibrary).LastWriteTime -lt $buildStarted) {
throw "Rust Android library is stale (Tauri exit code $tauriExit)"
}
$jniLibrary = Join-Path $projectRoot "src-tauri\gen\android\app\src\main\jniLibs\arm64-v8a\libunigate_lib.so"
New-Item -ItemType Directory -Force -Path (Split-Path $jniLibrary) | Out-Null
$jniIsCurrent = (Test-Path -LiteralPath $jniLibrary) -and
((Get-FileHash -Algorithm SHA256 -LiteralPath $rustLibrary).Hash -eq
(Get-FileHash -Algorithm SHA256 -LiteralPath $jniLibrary).Hash)
if ($jniIsCurrent) {
Write-Host "JNI library already points to the Rust build; skipping copy."
} else {
Copy-Item -LiteralPath $rustLibrary -Destination $jniLibrary -Force
}
$strip = Join-Path $ndkDir "toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-strip.exe"
& $strip --strip-unneeded $jniLibrary
if ($LASTEXITCODE -ne 0) { throw "Failed to strip Rust debug symbols" }
Push-Location (Join-Path $projectRoot "src-tauri\gen\android")
try {
& .\gradlew.bat :app:assembleArm64Release -x :app:rustBuildArm64Release --rerun-tasks
if ($LASTEXITCODE -ne 0) { throw "Gradle APK build failed" }
} finally {
Pop-Location
}
} finally {
Pop-Location
}
$apk = Join-Path $projectRoot "src-tauri\gen\android\app\build\outputs\apk\arm64\release\app-arm64-release.apk"
if (-not (Test-Path -LiteralPath $apk)) {
# Без подключённого signingConfig Gradle кладёт рядом *-unsigned.apk.
throw "Signed APK was not produced (check the signing configuration)"
}
$version = (Get-Content -LiteralPath (Join-Path $projectRoot "package.json") -Raw | ConvertFrom-Json).version
$releaseDir = Join-Path $projectRoot "dist\android"
$releaseApk = Join-Path $releaseDir "UniGate_${version}_android_arm64.apk"
New-Item -ItemType Directory -Force -Path $releaseDir | Out-Null
Copy-Item -LiteralPath $apk -Destination $releaseApk -Force
Write-Host "APK ready: $releaseApk"