Files

267 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 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", "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 in ['preBuild', 'preDebugBuild', 'preReleaseBuild', '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") {}
}