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".
95 lines
4.4 KiB
PowerShell
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"
|