Big changes
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Builds, verifies, and installs a signed Memby release on an Android TV.
|
||||
|
||||
.DESCRIPTION
|
||||
Uses the permanent signing configuration stored in the current Windows user's
|
||||
MEMBY_KEYSTORE environment variables. The APK is installed directly with ADB;
|
||||
no Gitea release or update server is required.
|
||||
|
||||
.EXAMPLE
|
||||
.\deploy-tv.ps1
|
||||
|
||||
.EXAMPLE
|
||||
.\deploy-tv.ps1 -Device 10.0.0.238:35343 -SkipTests
|
||||
#>
|
||||
|
||||
#Requires -Version 7.2
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter()]
|
||||
[ValidatePattern('^[A-Za-z0-9._:-]+$')]
|
||||
[string] $Device = '10.0.0.238:35343',
|
||||
|
||||
[Parameter()]
|
||||
[switch] $SkipTests
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = $PSScriptRoot
|
||||
$packageName = 'com.ponzischeme89.memby'
|
||||
|
||||
function Invoke-Checked {
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
[string] $FilePath,
|
||||
|
||||
[Parameter()]
|
||||
[string[]] $Arguments = @()
|
||||
)
|
||||
|
||||
& $FilePath @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "'$FilePath' failed with exit code $LASTEXITCODE."
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AndroidSdk {
|
||||
if ($env:ANDROID_HOME -and (Test-Path -LiteralPath $env:ANDROID_HOME)) {
|
||||
return $env:ANDROID_HOME
|
||||
}
|
||||
|
||||
$propertiesPath = Join-Path $root 'local.properties'
|
||||
if (Test-Path -LiteralPath $propertiesPath) {
|
||||
$sdkLine = Get-Content -LiteralPath $propertiesPath |
|
||||
Where-Object { $_ -match '^sdk\.dir=' } |
|
||||
Select-Object -First 1
|
||||
if ($sdkLine) {
|
||||
$sdkPath = $sdkLine.Substring($sdkLine.IndexOf('=') + 1).
|
||||
Replace('\:', ':').
|
||||
Replace('\\', '\')
|
||||
if (Test-Path -LiteralPath $sdkPath) {
|
||||
return $sdkPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw 'Android SDK not found. Set ANDROID_HOME or sdk.dir in local.properties.'
|
||||
}
|
||||
|
||||
function Import-UserSigningEnvironment {
|
||||
foreach ($name in @(
|
||||
'MEMBY_KEYSTORE',
|
||||
'MEMBY_KEYSTORE_PASSWORD',
|
||||
'MEMBY_KEY_ALIAS',
|
||||
'MEMBY_KEY_PASSWORD'
|
||||
)) {
|
||||
$value = [Environment]::GetEnvironmentVariable($name, 'Process')
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
$value = [Environment]::GetEnvironmentVariable($name, 'User')
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($value)) {
|
||||
throw "Release signing variable $name is not configured."
|
||||
}
|
||||
[Environment]::SetEnvironmentVariable($name, $value, 'Process')
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $env:MEMBY_KEYSTORE -PathType Leaf)) {
|
||||
throw "Release keystore not found: $env:MEMBY_KEYSTORE"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '╭─ Memby TV deployment' -ForegroundColor Magenta
|
||||
Write-Host "│ Device $Device" -ForegroundColor DarkGray
|
||||
Write-Host '│ Build signed release' -ForegroundColor DarkGray
|
||||
Write-Host '╰─' -ForegroundColor Magenta
|
||||
Write-Host ''
|
||||
|
||||
Import-UserSigningEnvironment
|
||||
$sdk = Get-AndroidSdk
|
||||
$adb = Join-Path $sdk 'platform-tools\adb.exe'
|
||||
if (-not (Test-Path -LiteralPath $adb -PathType Leaf)) {
|
||||
throw "ADB not found: $adb"
|
||||
}
|
||||
|
||||
$buildTools = Get-ChildItem -LiteralPath (Join-Path $sdk 'build-tools') -Directory |
|
||||
Sort-Object { [version]$_.Name } -Descending |
|
||||
Select-Object -First 1
|
||||
if (-not $buildTools) {
|
||||
throw 'Android SDK Build Tools are not installed.'
|
||||
}
|
||||
$apkSigner = Join-Path $buildTools.FullName 'apksigner.bat'
|
||||
if (-not (Test-Path -LiteralPath $apkSigner -PathType Leaf)) {
|
||||
throw "APK signer not found: $apkSigner"
|
||||
}
|
||||
|
||||
$jdkHome = 'C:\Program Files\Android\Android Studio\jbr'
|
||||
if (Test-Path -LiteralPath $jdkHome) {
|
||||
$env:JAVA_HOME = $jdkHome
|
||||
}
|
||||
|
||||
Write-Host '● Building release APK' -ForegroundColor Cyan
|
||||
$gradleArguments = @('--console=plain')
|
||||
if (-not $SkipTests) {
|
||||
$gradleArguments += 'testDebugUnitTest'
|
||||
}
|
||||
$gradleArguments += 'assembleRelease'
|
||||
Invoke-Checked -FilePath (Join-Path $root 'gradlew.bat') -Arguments $gradleArguments
|
||||
|
||||
$apk = Join-Path $root 'app\build\outputs\apk\release\app-release.apk'
|
||||
if (-not (Test-Path -LiteralPath $apk -PathType Leaf)) {
|
||||
$unsigned = Join-Path $root 'app\build\outputs\apk\release\app-release-unsigned.apk'
|
||||
if (Test-Path -LiteralPath $unsigned) {
|
||||
throw 'Gradle produced an unsigned APK; deployment was stopped.'
|
||||
}
|
||||
throw "Release APK not found: $apk"
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '● Verifying release signature' -ForegroundColor Cyan
|
||||
Invoke-Checked -FilePath $apkSigner -Arguments @(
|
||||
'verify',
|
||||
'--verbose',
|
||||
'--print-certs',
|
||||
$apk
|
||||
)
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '● Connecting to Android TV' -ForegroundColor Cyan
|
||||
& $adb connect $Device
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Unable to connect to Android TV at $Device."
|
||||
}
|
||||
Invoke-Checked -FilePath $adb -Arguments @('-s', $Device, 'get-state')
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '● Installing release' -ForegroundColor Cyan
|
||||
Invoke-Checked -FilePath $adb -Arguments @(
|
||||
'-s', $Device,
|
||||
'install',
|
||||
'-r',
|
||||
'--no-streaming',
|
||||
$apk
|
||||
)
|
||||
|
||||
$packageDetails = & $adb -s $Device shell dumpsys package $packageName
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'The APK installed, but its package details could not be read.'
|
||||
}
|
||||
$versionName = (
|
||||
$packageDetails |
|
||||
Select-String -Pattern 'versionName=([^\s]+)' |
|
||||
Select-Object -First 1
|
||||
).Matches.Groups[1].Value
|
||||
if ([string]::IsNullOrWhiteSpace($versionName)) {
|
||||
throw "Installed package $packageName was not found."
|
||||
}
|
||||
|
||||
$resolveOutput = & $adb -s $Device shell cmd package resolve-activity --brief `
|
||||
-a android.intent.action.MAIN `
|
||||
-c android.intent.category.LEANBACK_LAUNCHER `
|
||||
$packageName
|
||||
$component = $resolveOutput |
|
||||
Where-Object { $_.Trim() -match '^[A-Za-z0-9._]+/[A-Za-z0-9._$]+$' } |
|
||||
Select-Object -Last 1
|
||||
if ($LASTEXITCODE -eq 0 -and $component) {
|
||||
$component = $component.Trim()
|
||||
Invoke-Checked -FilePath $adb -Arguments @(
|
||||
'-s', $Device,
|
||||
'shell', 'am', 'start',
|
||||
'-n', $component
|
||||
)
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "✓ Memby $versionName installed on $Device" -ForegroundColor Green
|
||||
Write-Host " Package: $packageName" -ForegroundColor DarkGray
|
||||
Write-Host " APK: $apk" -ForegroundColor DarkGray
|
||||
Reference in New Issue
Block a user