pithos/mobile/android/build.ps1
Local Dev 083a2e1db8 Pithos for Android: the browser app on a phone, with Save to Pithos
A first Pithos app for phones. It runs the browser app in a WebView and
answers the page's own files from the APK under the gateway's origin, so
the page stays the same-origin client it was designed as and the files
are still encrypted and decrypted in the page.

What the phone adds: "Save to Pithos" in other apps' share menus (the
files wait in a bar until a folder is open), downloads written to the
Downloads folder, the system file picker for uploads, and outside links
opened in the phone's browser.

The browser app learns the two hooks (window.PithosAndroid) and says
plainly when a browser is too old to sign in, instead of a bare
"NotSupportedError".
2026-10-07 23:06:33 +02:00

95 lines
4.4 KiB
PowerShell

# Builds Pithos for Android with the bare Android SDK: no Gradle, no AGP.
# Toolchain: JDK 8 + build-tools 30.0.3 + platform android-30.
# The page is Pithos/web, copied into the APK's assets at build time.
# Usage: powershell -File build.ps1 -> build\pithos-debug.apk (debug key)
# powershell -File build.ps1 -Release -> build\pithos-v<version>.apk (release key)
param([switch]$Release)
$ErrorActionPreference = "Stop"
$VERSION = "0.1.0"
$VERSION_CODE = 1
$SDK = "$env:LOCALAPPDATA\Android\Sdk"
$BT = "$SDK\build-tools\30.0.3"
$PLATFORM = "$SDK\platforms\android-30\android.jar"
$JDK = "C:\Program Files\Java\jdk1.8.0_202"
$ROOT = $PSScriptRoot
$WEB = Resolve-Path "$ROOT\..\..\web"
$OUT = "$ROOT\build"
$env:JAVA_HOME = $JDK
$env:Path = "$JDK\bin;$env:Path"
if (Test-Path $OUT) { Remove-Item -Recurse -Force $OUT }
New-Item -ItemType Directory -Force "$OUT\classes", "$OUT\dex", "$OUT\gen", "$OUT\assets\web" | Out-Null
Write-Host "[0/6] page + version"
Copy-Item -Recurse "$WEB\*" "$OUT\assets\web\"
@"
package st.silentmode.pithos;
final class BuildInfo { static final String VERSION = "$VERSION"; private BuildInfo() {} }
"@ | Set-Content -Encoding ASCII "$OUT\gen\BuildInfo.java"
$manifest = (Get-Content -Raw "$ROOT\AndroidManifest.xml") `
-replace 'android:versionCode="\d+"', "android:versionCode=`"$VERSION_CODE`"" `
-replace 'android:versionName="[^"]*"', "android:versionName=`"$VERSION`""
Set-Content -Encoding UTF8 "$OUT\AndroidManifest.xml" $manifest
Write-Host "[1/6] aapt2 compile+link"
& "$BT\aapt2.exe" compile --dir "$ROOT\res" -o "$OUT\res.zip"
if ($LASTEXITCODE -ne 0) { throw "aapt2 compile failed" }
& "$BT\aapt2.exe" link -o "$OUT\app-unsigned.apk" -I $PLATFORM --manifest "$OUT\AndroidManifest.xml" `
--java "$OUT\gen" --min-sdk-version 24 --target-sdk-version 30 -A "$OUT\assets" "$OUT\res.zip"
if ($LASTEXITCODE -ne 0) { throw "aapt2 link failed" }
Write-Host "[2/6] javac"
$sources = Get-ChildItem "$ROOT\src","$OUT\gen" -Recurse -Filter *.java | ForEach-Object { $_.FullName }
& "$JDK\bin\javac.exe" -source 1.8 -target 1.8 -encoding UTF-8 -Xlint:-options `
-bootclasspath $PLATFORM -classpath $PLATFORM -d "$OUT\classes" @sources
if ($LASTEXITCODE -ne 0) { throw "javac failed" }
Write-Host "[3/6] d8"
$classesDir = "$OUT\classes"
Push-Location $classesDir
$classes = Get-ChildItem -Recurse -Filter *.class | ForEach-Object { $_.FullName.Substring($classesDir.Length + 1) }
& "$BT\d8.bat" --release --min-api 24 --lib $PLATFORM --output "$OUT\dex" @classes
Pop-Location
if ($LASTEXITCODE -ne 0) { throw "d8 failed" }
Write-Host "[4/6] add classes.dex"
Push-Location "$OUT\dex"
& "$JDK\bin\jar.exe" uf "$OUT\app-unsigned.apk" classes.dex
Pop-Location
if ($LASTEXITCODE -ne 0) { throw "jar failed" }
Write-Host "[5/6] zipalign"
& "$BT\zipalign.exe" -f -p 4 "$OUT\app-unsigned.apk" "$OUT\app-aligned.apk"
if ($LASTEXITCODE -ne 0) { throw "zipalign failed" }
Write-Host "[6/6] sign"
if ($Release) {
# Generated once, then REUSED FOREVER: Android installs updates only when
# they are signed by the same key. Keep both files out of git, backed up.
$ks = "$ROOT\release.keystore"
$passFile = "$ROOT\release-keystore-password.txt"
if (-not (Test-Path $passFile)) { throw "missing $passFile (put the keystore password in it first)" }
$pass = (Get-Content $passFile -Raw).Trim()
if (-not (Test-Path $ks)) {
& "$JDK\bin\keytool.exe" -genkeypair -keystore $ks -storepass $pass -keypass $pass `
-alias pithos -keyalg RSA -keysize 4096 -validity 14000 -dname "CN=Pithos,O=Silent Mode"
if ($LASTEXITCODE -ne 0) { throw "keytool failed" }
Write-Host "NOTE: new release key created. BACK UP $ks and $passFile."
}
$apk = "$OUT\pithos-v$VERSION.apk"
& "$BT\apksigner.bat" sign --ks $ks --ks-key-alias pithos --ks-pass "pass:$pass" --key-pass "pass:$pass" --out $apk "$OUT\app-aligned.apk"
} else {
$ks = "$ROOT\debug.keystore"
if (-not (Test-Path $ks)) {
& "$JDK\bin\keytool.exe" -genkeypair -keystore $ks -storepass android -keypass android `
-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=Android Debug,O=Android,C=US"
if ($LASTEXITCODE -ne 0) { throw "keytool failed" }
}
$apk = "$OUT\pithos-debug.apk"
& "$BT\apksigner.bat" sign --ks $ks --ks-pass pass:android --key-pass pass:android --out $apk "$OUT\app-aligned.apk"
}
if ($LASTEXITCODE -ne 0) { throw "apksigner failed" }
Write-Host "OK -> $apk"