mirror of
https://github.com/astromaddie/lambda1-vr.git
synced 2026-10-23 11:00:16 +02:00
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.
266 lines
9.4 KiB
Groovy
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") {}
|
|
} |