Files
astromaddie--lambda1-vr/Projects/Android/build.gradle
T
Madison e6b3e26003 Frame: make the menu tile with the Frame's button help at build time
make_frame_tile.py reads the release tile from the git-ignored
assets/background, takes the Quest help off it, draws the Frame's, and
writes it into build/frame-assets. The frame build type's assets override
the release tile with it, a gradle task runs it before mergeFrameAssets.
Quest and Pico builds are untouched. If the tile or Pillow and numpy are
missing, the Frame build goes on with the release tile and a warning.
2026-10-05 16:46:57 +09:00

266 lines
9.4 KiB
Groovy

buildscript {
repositories {
google() // For Gradle 4.0+
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
}
}
apply plugin: 'com.android.application'
// Steam Frame build (./gradlew assembleFrame, see docs/STEAM_FRAME_VR.md).
// The Frame's Android container has no OpenXR loader broker, so the Khronos
// loader goes into the APK. It comes from Maven Central, gets checked against
// this hash and is unpacked into build/ (never committed). Quest builds don't
// touch any of this.
def khronosLoaderVersion = '1.1.63'
def khronosLoaderSha256 = '622419d2f6741c3443a3beb4779af0764318edd01830de967f24c741ebcded73'
def khronosLoaderDir = file("build/openxr-loader/${khronosLoaderVersion}")
def khronosLoaderSo = new File(khronosLoaderDir, 'libopenxr_loader.so')
def fetchKhronosLoader = tasks.register('fetchKhronosLoader') {
outputs.file khronosLoaderSo
doLast {
def url = "https://repo1.maven.org/maven2/org/khronos/openxr/openxr_loader_for_android/${khronosLoaderVersion}/openxr_loader_for_android-${khronosLoaderVersion}.aar"
def aar = new File(khronosLoaderDir, 'openxr_loader_for_android.aar')
khronosLoaderDir.mkdirs()
new URL(url).withInputStream { input -> aar.withOutputStream { it << input } }
def digest = java.security.MessageDigest.getInstance('SHA-256')
aar.eachByte(8192) { buf, len -> digest.update(buf, 0, len) }
def sha = digest.digest().collect { String.format('%02x', it) }.join()
if (sha != khronosLoaderSha256) {
aar.delete()
throw new GradleException("OpenXR loader AAR has the wrong SHA-256 (${sha}), expected ${khronosLoaderSha256}")
}
def zip = new java.util.zip.ZipFile(aar)
try {
def entry = zip.getEntry('jni/arm64-v8a/libopenxr_loader.so')
if (entry == null) throw new GradleException('libopenxr_loader.so (arm64-v8a) is not in the loader AAR')
zip.getInputStream(entry).withStream { input -> khronosLoaderSo.withOutputStream { it << input } }
} finally {
zip.close()
}
aar.delete()
}
}
// Steam Frame build: the menu background tile with the Frame's button mapping on it. The release
// tile (800_1_a_loading.tga, Team Beef's art, git-ignored) has the Quest's help baked in, so
// tools/steam_frame/make_frame_tile.py makes a Frame one into build/frame-assets, and the frame build
// type's assets override the release one with it. Nothing generated is committed, and Quest and Pico
// builds don't see this. If the release tile or Python with Pillow and numpy is missing, the Frame
// APK still builds with the release tile, and this says so.
// Python is -PframePython, $FRAME_PYTHON, tools/steam_frame/.venv, or python3, in that order.
def frameAssetsDir = file('build/frame-assets')
def makeFrameTile = tasks.register('makeFrameTile') {
doLast {
delete frameAssetsDir // never ship a stale tile after the source went away
def venvPython = file('../../tools/steam_frame/.venv/bin/python')
def python = project.findProperty('framePython') ?: System.getenv('FRAME_PYTHON') ?:
(venvPython.exists() ? venvPython.absolutePath : 'python3')
def status = -1
try {
status = exec {
commandLine python, file('../../tools/steam_frame/make_frame_tile.py').absolutePath,
'--src', file('../../assets/background/800_1_a_loading.tga').absolutePath,
'--out', new File(frameAssetsDir, 'background/800_1_a_loading.tga').absolutePath
ignoreExitValue = true
}.exitValue
} catch (Exception e) {
logger.warn("Could not run ${python}: ${e.message}")
}
if (status != 0) {
logger.warn('WARNING: no Frame menu tile, the Frame APK gets the release one (with the Quest button help). ' +
'See "Build" in docs/STEAM_FRAME_VR.md.')
}
}
}
android {
namespace = "com.drbeef.lambda1vr"
// This is the name of the generated apk file, which will have
// -debug.apk or -release.apk appended to it.
// The filename doesn't effect the Android installation process.
// Use only letters to remain compatible with the package name.
project.archivesBaseName = "lambda1vr"
defaultConfig {
// Gradle replaces the manifest package with this value, which must
// be unique on a system. If you don't change it, a new app
// will replace an older one.
applicationId "com.drbeef." + project.archivesBaseName
externalNativeBuild {
ndk {
abiFilters 'arm64-v8a'
}
ndkBuild {
def numProcs = Runtime.runtime.availableProcessors()
arguments "V=0", "-j$numProcs", "-C$project.buildDir.parent", "APP_PLATFORM=android-32", "NDK_TOOLCHAIN_VERSION=clang", "APP_STL=c++_static"
abiFilters 'arm64-v8a'
}
}
minSdkVersion 32
targetSdkVersion 32
// True only in the frame build type
buildConfigField 'boolean', 'STEAM_FRAME', 'false'
}
buildFeatures {
buildConfig true
}
externalNativeBuild {
ndkBuild {
path file('jni/Android.mk')
}
}
signingConfigs {
def keystorePath = (project.hasProperty('key.store')) ?
new File(project.getProperty('key.store')) :
project.file('android.debug.keystore')
def keystorePassword = (project.hasProperty('key.store.password')) ?
project.getProperty('key.store.password') : 'android'
def keystoreKeyAlias = (project.hasProperty('key.alias')) ?
project.getProperty('key.alias') : 'androiddebugkey'
def keystoreKeyPassword = (project.hasProperty('key.alias.password')) ?
project.getProperty('key.alias.password') : 'android'
debug {
storeFile keystorePath
storePassword keystorePassword
keyAlias keystoreKeyAlias
keyPassword keystoreKeyPassword
v2SigningEnabled true
}
release {
storeFile keystorePath
storePassword keystorePassword
keyAlias keystoreKeyAlias
keyPassword keystoreKeyPassword
v2SigningEnabled true
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
debuggable true
jniDebuggable true
externalNativeBuild {
ndkBuild {
arguments "NDK_DEBUG=1","USE_ASAN=1"
}
}
}
release {
signingConfig signingConfigs.release
debuggable false
jniDebuggable false
externalNativeBuild {
ndkBuild {
arguments "NDK_DEBUG=0","USE_ASAN=0"
}
}
}
// Valve Steam Frame (Lepton, Android 11). Same as release, plus the
// Khronos OpenXR loader, a manifest overlay (src/frame) and L1VR_STEAM_FRAME
// for the native code. Signed with the debug key, it's only sideloaded.
frame {
initWith release
matchingFallbacks = ['release']
applicationIdSuffix ".frame"
versionNameSuffix "-frame"
signingConfig signingConfigs.debug
buildConfigField 'boolean', 'STEAM_FRAME', 'true'
externalNativeBuild {
ndkBuild {
arguments "L1VR_STEAM_FRAME=1", "L1VR_OPENXR_LOADER=${khronosLoaderSo.absolutePath}", "APP_PLATFORM=android-30"
}
}
}
}
sourceSets.frame {
// generated by makeFrameTile, wins over the release tile in main
assets.srcDir frameAssetsDir
}
sourceSets.main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['../../java']
jniLibs.srcDir 'libs'
res.srcDirs = ['../../res']
assets.srcDirs = ['../../assets']
jni.srcDirs = ['jni']
}
lintOptions {
checkReleaseBuilds false
disable 'ExpiredTargetSdkVersion'
}
//packagingOptions {
// exclude 'lib/arm64-v8a/libopenxr_loader.so'
//}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
compileSdkVersion = 32
buildToolsVersion = '29.0.3'
ndkVersion '25.1.8937393'
}
// Lepton runs Android 11, the Quest build needs 12L (API 32)
androidComponents {
beforeVariants(selector().withBuildType('frame')) { variantBuilder ->
variantBuilder.minSdk = 30
}
}
// The loader has to be there before ndk-build links against it
tasks.configureEach { task ->
if (task.name == 'preFrameBuild') {
task.dependsOn fetchKhronosLoader
}
if (task.name == 'mergeFrameAssets') {
task.dependsOn makeFrameTile
}
}
dependencies {
implementation "com.android.support:support-compat:28.0.0"
implementation "com.android.support:support-core-utils:28.0.0"
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
repositories {
google()
}
// Workaround to fix issue in Android Studio Chipmunk 2021.2.1 and later
// where opening a project would result in a 'prepareKotlinBuildScriptModel'
// not found error
if (!tasks.findByName("prepareKotlinBuildScriptModel")) {
tasks.register("prepareKotlinBuildScriptModel") {}
}