docs: record approved app direction and Android setup scripts

This commit is contained in:
Codex
2026-10-12 22:30:13 +08:00
commit a223798c25
9 changed files with 273 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
# Dot-source this file before using Flutter: . ./scripts/android-env.ps1
$taskProjectRoot = Split-Path -Parent $PSScriptRoot
$taskToolRoot = Join-Path $taskProjectRoot '.tools'
$env:JAVA_HOME = Join-Path $taskToolRoot 'jdk-17'
$env:ANDROID_HOME = Join-Path $taskToolRoot 'android-sdk'
$env:ANDROID_SDK_ROOT = $env:ANDROID_HOME
$env:ANDROID_USER_HOME = Join-Path $taskToolRoot 'android-user'
$env:ANDROID_EMULATOR_HOME = Join-Path $taskToolRoot 'android-user'
$env:ANDROID_AVD_HOME = Join-Path $taskToolRoot 'avd'
$env:GRADLE_USER_HOME = Join-Path $taskToolRoot 'gradle-cache'
$env:PUB_CACHE = Join-Path $taskToolRoot 'pub-cache'
$env:FLUTTER_SUPPRESS_ANALYTICS = 'true'
$taskPathEntries = @(
(Join-Path $taskToolRoot 'flutter/bin'),
(Join-Path $env:JAVA_HOME 'bin'),
(Join-Path $env:ANDROID_HOME 'platform-tools'),
(Join-Path $env:ANDROID_HOME 'cmdline-tools/latest/bin'),
(Join-Path $env:ANDROID_HOME 'emulator')
)
$taskOldPath = @($env:PATH -split ';' | Where-Object { $_ -and $_ -notin $taskPathEntries })
$env:PATH = ($taskPathEntries + $taskOldPath) -join ';'
+14
View File
@@ -0,0 +1,14 @@
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'android-env.ps1')
$taskImagePath = Join-Path $env:ANDROID_HOME 'system-images/android-36/google_apis/x86_64/system.img'
if (-not (Test-Path -LiteralPath $taskImagePath)) { throw 'Run setup-android-sdk.ps1 -WithEmulator first.' }
$taskAvdName = 'hepan_everyday'
$taskAvdConfig = Join-Path $env:ANDROID_AVD_HOME "$taskAvdName.avd/config.ini"
if (Test-Path -LiteralPath $taskAvdConfig) {
Write-Output "Emulator $taskAvdName already exists."
exit 0
}
New-Item -ItemType Directory -Force -Path $env:ANDROID_AVD_HOME | Out-Null
'no' | & avdmanager.bat create avd --name $taskAvdName --package 'system-images;android-36;google_apis;x86_64' --device 'pixel_7'
if ($LASTEXITCODE -ne 0) { throw 'Android virtual device creation failed.' }
Write-Output "Created $taskAvdName (Pixel 7, Android 16)."
+69
View File
@@ -0,0 +1,69 @@
param(
[Parameter(Mandatory = $true)]
[ValidateSet('flutter', 'java', 'android-cli')]
[string]$Tool
)
$ErrorActionPreference = 'Stop'
$taskProjectRoot = Split-Path -Parent $PSScriptRoot
$taskToolRoot = Join-Path $taskProjectRoot '.tools'
$taskDownloads = Join-Path $taskToolRoot 'downloads'
New-Item -ItemType Directory -Force -Path $taskDownloads | Out-Null
$taskPackages = @{
'flutter' = @{
Url = 'https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.47.7-stable.zip'
Sha256 = 'c2c875da25a1a1448d18ee4e8f398b2f6fce888b4775d8f9130538e16d826cb4'
Zip = 'flutter-3.47.7.zip'
Marker = 'flutter/bin/flutter.bat'
}
'java' = @{
Url = 'https://aka.ms/download-jdk/microsoft-jdk-17.0.20.1-windows-x64.zip'
Sha256 = '3d9006956fc8af5601cd24ffc4f468bef48279c7ebd8171b9bdf90d0aabfbf1f'
Zip = 'jdk-17.zip'
Marker = 'jdk-17/bin/java.exe'
}
'android-cli' = @{
Url = 'https://dl.google.com/android/repository/commandlinetools-win-15859902_latest.zip'
Sha256 = '90ae805d20434428bffcb699c290860f19bb5f66a67e6b330067e3de801fb04a'
Zip = 'android-commandline.zip'
Marker = 'android-sdk/cmdline-tools/latest/bin/sdkmanager.bat'
}
}
$taskPackage = $taskPackages[$Tool]
if (Test-Path -LiteralPath (Join-Path $taskToolRoot $taskPackage.Marker)) {
Write-Output "$Tool is already installed."
exit 0
}
$taskArchive = Join-Path $taskDownloads $taskPackage.Zip
Write-Output "Downloading $Tool from the official distribution."
& curl.exe --fail --location --silent --show-error --retry 3 --retry-all-errors --connect-timeout 30 --speed-limit 1024 --speed-time 60 --continue-at - --output $taskArchive $taskPackage.Url
if ($LASTEXITCODE -ne 0) { throw "Download failed: $Tool" }
$taskActualHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $taskArchive).Hash.ToLowerInvariant()
if ($taskActualHash -ne $taskPackage.Sha256) { throw "SHA-256 verification failed: $Tool" }
Write-Output "Verified SHA-256 for $Tool; extracting."
if ($Tool -eq 'flutter') {
& tar.exe -xf $taskArchive -C $taskToolRoot
if ($LASTEXITCODE -ne 0) { throw 'Flutter extraction failed.' }
} else {
$taskStage = Join-Path $taskToolRoot "staging/$Tool"
New-Item -ItemType Directory -Force -Path $taskStage | Out-Null
& tar.exe -xf $taskArchive -C $taskStage
if ($LASTEXITCODE -ne 0) { throw "$Tool extraction failed." }
if ($Tool -eq 'java') {
$taskSource = (Get-ChildItem -LiteralPath $taskStage -Directory | Where-Object Name -Like 'jdk-*' | Select-Object -First 1).FullName
$taskDestination = Join-Path $taskToolRoot 'jdk-17'
} else {
$taskSource = Join-Path $taskStage 'cmdline-tools'
$taskDestination = Join-Path $taskToolRoot 'android-sdk/cmdline-tools/latest'
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $taskDestination) | Out-Null
}
# Validate the resolved paths before moving the unpacked tool directory.
$taskResolvedRoot = [IO.Path]::GetFullPath($taskToolRoot).TrimEnd('\') + '\'
foreach ($taskMovePath in @($taskSource, $taskDestination)) {
if (-not $taskMovePath -or -not [IO.Path]::GetFullPath($taskMovePath).StartsWith($taskResolvedRoot, [StringComparison]::OrdinalIgnoreCase)) {
throw 'Tool path is outside the project tool directory.'
}
}
Move-Item -LiteralPath $taskSource -Destination $taskDestination
}
if (-not (Test-Path -LiteralPath (Join-Path $taskToolRoot $taskPackage.Marker))) { throw "$Tool installation is incomplete." }
Write-Output "Installed $Tool."
+19
View File
@@ -0,0 +1,19 @@
param([switch]$WithEmulator)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'android-env.ps1')
foreach ($taskRequiredPath in @((Join-Path $env:JAVA_HOME 'bin/java.exe'), (Join-Path $env:ANDROID_HOME 'cmdline-tools/latest/bin/sdkmanager.bat'))) {
if (-not (Test-Path -LiteralPath $taskRequiredPath)) { throw "Missing tool: $taskRequiredPath" }
}
$taskLicenseLog = Join-Path $taskToolRoot 'android-license-review.txt'
1..100 | ForEach-Object { 'y' } | & sdkmanager.bat "--sdk_root=$env:ANDROID_HOME" --licenses *> $taskLicenseLog
if ($LASTEXITCODE -ne 0) { throw "SDK license setup failed; inspect $taskLicenseLog" }
Get-Content -LiteralPath $taskLicenseLog -Tail 3
$taskPackages = @('platform-tools', 'platforms/android-36', 'build-tools/36.0.0', 'cmake/3.22.1', 'ndk/28.2.13676358')
if ($WithEmulator) { $taskPackages += @('emulator', 'system-images/android-36/google_apis/x86_64') }
$taskInstallLog = Join-Path $taskToolRoot 'android-sdk-install.txt'
Write-Output ('Installing Android SDK components: ' + ($taskPackages -join ', '))
# Google's current native CLI avoids the legacy Java downloader's stalled socket.
& android.exe --no-metrics "--sdk=$env:ANDROID_HOME" sdk install @taskPackages *> $taskInstallLog
if ($LASTEXITCODE -ne 0) { Get-Content -LiteralPath $taskInstallLog -Tail 20; throw 'Android SDK installation failed.' }
Get-Content -LiteralPath $taskInstallLog -Tail 5
Write-Output 'Android SDK components installed.'
+19
View File
@@ -0,0 +1,19 @@
param([switch]$WithEmulator)
$ErrorActionPreference = 'Stop'
foreach ($taskToolName in @('flutter', 'java', 'android-cli')) {
& (Join-Path $PSScriptRoot 'install-tool.ps1') -Tool $taskToolName
if ($LASTEXITCODE -ne 0) { throw "Tool setup failed: $taskToolName" }
}
. (Join-Path $PSScriptRoot 'android-env.ps1')
& (Join-Path $PSScriptRoot 'setup-android-sdk.ps1') -WithEmulator:$WithEmulator
if ($WithEmulator) { & (Join-Path $PSScriptRoot 'create-android-emulator.ps1') }
& flutter.bat config --android-sdk $env:ANDROID_HOME --jdk-dir $env:JAVA_HOME --no-analytics
if ($LASTEXITCODE -ne 0) { throw 'Flutter configuration failed.' }
$taskDoctorLog = Join-Path $taskToolRoot 'flutter-doctor.txt'
& flutter.bat doctor -v *> $taskDoctorLog
$taskDoctorExit = $LASTEXITCODE
$taskDoctorText = Get-Content -Raw -LiteralPath $taskDoctorLog
Write-Output $taskDoctorText
if ($taskDoctorExit -ne 0 -or $taskDoctorText -notmatch '\[√\] Android toolchain') {
throw 'Android toolchain verification has not passed; inspect the doctor output.'
}