param([switch]$InstrumentationOnly) $ErrorActionPreference = 'Stop' $androidRoot = $PSScriptRoot $env:JAVA_HOME = Join-Path $androidRoot '.tools/jdk-staging/jdk-21.0.12.1+1' $signing = @{} Get-Content -LiteralPath (Join-Path $androidRoot '.tools/signing/signing.properties') | ForEach-Object { $parts = $_ -split '=',2 if ($parts.Length -eq 2) { $signing[$parts[0].Trim()] = $parts[1].Trim() } } $env:UCVL_ANDROID_STORE_PASS = $signing['storePassword'] $env:UCVL_ANDROID_KEY_PASS = $signing['keyPassword'] $apkSigner = Join-Path $androidRoot '.tools/android-sdk/build-tools/37.0.0/apksigner.bat' $zipAlign = Join-Path $androidRoot '.tools/android-sdk/build-tools/37.0.0/zipalign.exe' $keyStore = Join-Path $androidRoot '.tools/signing/ucvl-zonghengjia-release.jks' try { if ($InstrumentationOnly) { $inputs = @(Get-ChildItem -LiteralPath (Join-Path $androidRoot 'V2rayNG/app/build/outputs/apk/androidTest/playstore/release') -Filter '*.apk') } else { $inputs = @(Get-ChildItem -LiteralPath (Join-Path $androidRoot 'V2rayNG/app/build/outputs/apk/playstore/release') -Filter 'UCVL-Zonghengjia-1.0.1-*.apk') } if (-not $inputs.Count) { throw 'No candidate APKs were built.' } foreach ($inputFile in $inputs) { $stageFile = Join-Path $androidRoot ('.tools/signing/aligned-' + $inputFile.Name) $outputFile = Join-Path $androidRoot ('releases/' + $inputFile.Name) & $zipAlign -f -p 4 $inputFile.FullName $stageFile if ($LASTEXITCODE) { throw 'APK alignment failed.' } & $apkSigner sign --ks $keyStore --ks-key-alias $signing['keyAlias'] --ks-pass env:UCVL_ANDROID_STORE_PASS --key-pass env:UCVL_ANDROID_KEY_PASS --out $outputFile $stageFile if ($LASTEXITCODE) { throw 'APK signing failed.' } & $apkSigner verify --verbose --print-certs $outputFile if ($LASTEXITCODE) { throw 'APK signature verification failed.' } Get-FileHash -LiteralPath $outputFile -Algorithm SHA256 | Select-Object Path,Hash } } finally { Remove-Item Env:UCVL_ANDROID_STORE_PASS,Env:UCVL_ANDROID_KEY_PASS $signing.Clear() }