From 4dfe0073bc1c821e311f86ff64246a3f1089f1f7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 10 Jan 2018 17:18:30 -0800 Subject: [PATCH] Do asset merging post-build --- android/app/build.gradle | 67 +++++++++++++++++----- android/build.gradle | 119 ++++++++++++++++----------------------- 2 files changed, 101 insertions(+), 85 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 0d07848820..f35398ef2f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -2,6 +2,8 @@ apply plugin: 'com.android.application' android { compileSdkVersion 26 + buildToolsVersion '27.0.3' + defaultConfig { applicationId "io.highfidelity.hifiinterface" minSdkVersion 24 @@ -24,31 +26,68 @@ android { } } } - buildTypes { - applicationVariants.all { variant -> - variant.outputs.all { - if (RELEASE_NUMBER != '0') { - outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk" - } - } - } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + externalNativeBuild { cmake { path '../../CMakeLists.txt' } } - buildToolsVersion '27.0.3' - dexOptions { - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + + applicationVariants.all { variant -> + // Our asset contents depend on items produced in the CMake build + // so our merge has to depend on the external native build + variant.externalNativeBuildTasks.each { task -> + variant.mergeResources.dependsOn(task) + } + + variant.mergeAssets.doLast { + def assetList = new LinkedList() + def youngestLastModified = 0 + + // Copy the compiled resources generated by the external native build + copy { + from new File(projectDir, "../../interface/compiledResources") + into outputDir + eachFile { details -> + youngestLastModified = Math.max(youngestLastModified, details.lastModified) + assetList.add(details.path) + } + } + + // Copy the scripts directory + copy { + from new File(projectDir, "../../scripts") + into new File(outputDir, "scripts") + eachFile { details-> + youngestLastModified = Math.max(youngestLastModified, details.lastModified) + assetList.add("scripts/" + details.path) + } + } + + // Write a list of files to be unpacked to the cache folder + new File(outputDir, 'cache_assets.txt').withWriter { out -> + out.println(Long.toString(youngestLastModified)) + assetList.each { file -> out.println(file) } + } + } + + variant.outputs.all { + if (RELEASE_NUMBER != '0') { + outputFileName = "app_" + RELEASE_NUMBER + "_" + RELEASE_TYPE + ".apk" + } + } } } diff --git a/android/build.gradle b/android/build.gradle index 96ca5472e9..a5cb8b7614 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -431,9 +431,55 @@ task extractGvrBinaries(dependsOn: extractDependencies) { } } } - } +def generateAssetsFileList = { + def assetsPath = "${appDir}/src/main/assets/" + def addedByAndroidDeployQtName = "--Added-by-androiddeployqt--/" + + def addedByAndroidDeployQtPath = assetsPath + addedByAndroidDeployQtName + + def addedByAndroidDeployQt = new File(addedByAndroidDeployQtPath) + if (!addedByAndroidDeployQt.exists() && !addedByAndroidDeployQt.mkdirs()) { + throw new GradleScriptException("Failed to create directory " + addedByAndroidDeployQtPath, null); + } + def outputFilename = "/qt_cache_pregenerated_file_list" + def outputFile = new File(addedByAndroidDeployQtPath + outputFilename); + Map> directoryContents = new TreeMap<>(); + + def dir = new File(assetsPath) + dir.eachFileRecurse (FileType.ANY) { file -> + + def name = file.path.substring(assetsPath.length()) + int slashIndex = name.lastIndexOf('/') + def pathName = slashIndex >= 0 ? name.substring(0, slashIndex) : "/" + def fileName = slashIndex >= 0 ? name.substring(pathName.length() + 1) : name + if (!fileName.isEmpty() && file.isDirectory() && !fileName.endsWith("/")) { + fileName += "/" + } + + if (!directoryContents.containsKey(pathName)) { + directoryContents[pathName] = new ArrayList() + } + if (!fileName.isEmpty()) { + directoryContents[pathName].add(fileName); + } + } + DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile)); + for (Map.Entry> e: directoryContents.entrySet()) { + def entryList = e.getValue() + fos.writeInt(e.key.length()*2); // 2 bytes per char + fos.writeChars(e.key); + fos.writeInt(entryList.size()); + for (String entry: entryList) { + fos.writeInt(entry.length()*2); + fos.writeChars(entry); + } + } + fos.close(); +} + + // Copy required Qt main libraries and required plugins based on the predefined list here // FIXME eventually we would like to use the readelf functionality to automatically detect dependencies // from our built applications and use that during the full build process. However doing so would mean @@ -446,6 +492,7 @@ task qtBundle { //def qmlImportFolder = new File("${projectDir}/app/src/main/cpp") scanQmlImports(qmlImportFolder) generateLibsXml() + generateAssetsFileList() } } @@ -458,77 +505,7 @@ task cleanDependencies(type: Delete) { delete 'app/src/main/res/values/libs.xml' } -task generateAssetsFileList() { - doLast { - def assetsPath = "${appDir}/src/main/assets/" - def addedByAndroidDeployQtName = "--Added-by-androiddeployqt--/" - def addedByAndroidDeployQtPath = assetsPath + addedByAndroidDeployQtName - - def addedByAndroidDeployQt = new File(addedByAndroidDeployQtPath) - if (!addedByAndroidDeployQt.exists() && !addedByAndroidDeployQt.mkdirs()) { - throw new GradleScriptException("Failed to create directory " + addedByAndroidDeployQtPath, null); - } - def outputFilename = "/qt_cache_pregenerated_file_list" - def outputFile = new File(addedByAndroidDeployQtPath + outputFilename); - Map> directoryContents = new TreeMap<>(); - - def dir = new File(assetsPath) - dir.eachFileRecurse (FileType.ANY) { file -> - - def name = file.path.substring(assetsPath.length()) - int slashIndex = name.lastIndexOf('/') - def pathName = slashIndex >= 0 ? name.substring(0, slashIndex) : "/" - def fileName = slashIndex >= 0 ? name.substring(pathName.length() + 1) : name - if (!fileName.isEmpty() && file.isDirectory() && !fileName.endsWith("/")) { - fileName += "/" - } - - if (!directoryContents.containsKey(pathName)) { - directoryContents[pathName] = new ArrayList() - } - if (!fileName.isEmpty()) { - directoryContents[pathName].add(fileName); - } - } - DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile)); - for (Map.Entry> e: directoryContents.entrySet()) { - def entryList = e.getValue() - fos.writeInt(e.key.length()*2); // 2 bytes per char - fos.writeChars(e.key); - fos.writeInt(entryList.size()); - for (String entry: entryList) { - fos.writeInt(entry.length()*2); - fos.writeChars(entry); - } - } - fos.close(); - } -} - -task copyInterfaceAssets() { - doLast { - def resourcesDir = new File("${appDir}/../../interface/resources") - def scriptsDir = new File("${appDir}/../../scripts") - def assetsDir = new File(appDir, 'src/main/assets') - - def assetsList = new File(assetsDir, 'cache_assets.txt'); - TimeZone.setDefault(TimeZone.getTimeZone('UTC')) - assetsList.withWriter { out -> - out.println(Long.toString(new Date().getTime())) - copy { - from resourcesDir - into new File(assetsDir, "resources") - eachFile { details-> out.println("resources/" + details.path) } - } - copy { - from scriptsDir - into new File(assetsDir, "scripts") - eachFile { details-> out.println("scripts/" + details.path) } - } - } - } -} // FIXME this code is prototyping the desired functionality for doing build time binary dependency resolution. // See the comment on the qtBundle task above