param( [switch]$InstrumentationOnly, [ValidatePattern('^\d+\.\d+\.\d+$')][string]$Version = '1.0.3', [string]$InputDirectory = '', [ValidatePattern('^[a-z0-9.-]*$')][string]$TestRevision = '' ) $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 ($InputDirectory) { $inputs = @(Get-ChildItem -LiteralPath ([IO.Path]::GetFullPath($InputDirectory)) -Filter '*.apk') if (-not $InstrumentationOnly) { $inputs = @($inputs | Where-Object Name -Like "UCVL-Zonghengjia-$Version-*.apk") } } elseif ($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-$Version-*.apk") } if (-not $inputs.Count) { throw 'No candidate APKs were built.' } foreach ($inputFile in $inputs) { $stageFile = Join-Path $androidRoot ('.tools/signing/aligned-' + $inputFile.Name) $revision = if ($TestRevision) { "-$TestRevision" } else { '' } if ($TestRevision -and -not $InstrumentationOnly) { throw 'TestRevision is only for instrumentation artifacts' } $outputName = if ($InstrumentationOnly) { $inputFile.BaseName + "-$Version$revision.apk" } else { $inputFile.Name } $outputFile = Join-Path $androidRoot ('releases/' + $outputName) if (Test-Path -LiteralPath $outputFile) { throw "Refusing to overwrite existing signed artifact: $outputName" } & $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() }