How to create an OBB file using Gradle - android

How do I create an OBB file for my application using Gradle with the android plugin? As of now, I have to either zip or use the jobb tool to create my OBB file. If there were a means of creating the OBB file entirely through Gradle it would simplify my build process and my life.
MY current process involves creating a Gradle task that kicks of a shell script. Not totally desirable but it works. I am wondering however about zip support in Gradle.
task buildOBBOSX(type:Exec) {
workingDir '.'
//note: according to the docs, the version code used is that of the "first"
// apk with which the expansion is associated with
commandLine './buildOBB.sh'
//store the output instead of printing to the console:
standardOutput = new ByteArrayOutputStream()
ext.output = {
return standardOutput.toString()
}
}
Maybe this is the best solution? Possibly. If so, and nobody recommends better, I will add it as an answer.

Besides doing it the way you are trying to do it now, I found this:
Gradle:
all{currentFlavor ->
task ("create"+ currentFlavor.name.substring(0, 1).toUpperCase() + currentFlavor.name.substring(1)+"Obb", type:Zip){
archiveName = "main.${defaultConfig.versionCode}.${currentFlavor.applicationId}.obb"
ext.destDir = new File(buildDir, "obb/${currentFlavor.name}")
ext.destFile = new File(destDir, archiveName)
duplicatesStrategy DuplicatesStrategy.EXCLUDE
doFirst {
destDir.mkdirs()
}
description = "Creates expansion file for APK flavour ${currentFlavor.name}"
destinationDir = new File(buildDir, "obb/${currentFlavor.name}");
entryCompression = ZipEntryCompression.STORED
from "flavors/${currentFlavor.name}/obb", "obb"
tasks.createObb.dependsOn("create"+ currentFlavor.name.substring(0, 1).toUpperCase() + currentFlavor.name.substring(1)+"Obb")
}
}
Source: https://gitlab.labs.nic.cz/labs/tablexia/blob/devel/build.gradle#L154
Manually(you are doing this in your script):
Example, via command line:
jobb -d /temp/assets/ -o my-app-assets.obb -k secret-key -pn com.my.app.package -pv 11
Source: http://developer.android.com/tools/help/jobb.html
My Suggestions:
I'd recommend adding more to your task, similar to how this exec method works. This way, you can pass params or generate tasks using your packageName:
def createOBB(def assetsFolder, def obbFile, def secretKey, def packageName) {
def stdout = new ByteArrayOutputStream(), stderr = new ByteArrayOutputStream()
exec {
// jobb -d /temp/assets/ -o my-app-assets.obb -k secret-key -pn com.my.app.package -pv 11
commandLine 'jobb', '-d', assetsFolder, '-o', obbFile, '-k', secretKey, '-pn', packageName, '-pv', '11'
standardOutput = stdout
errorOutput = stderr
ignoreExitValue true // remove this if you want to crash if fail
}
}

Related

Run a command line with Gradle and Save the output result

I want to run a command line with Gradle that this command has an output.
I run this command in windows powershell:
./mybat.bat myArgs when I hit enter, it will print some digit, like this:
123456
I want to run this command with gradle and save this result(123456)
here is some code that I written in android build.gradle file:
task getSomeOutput(type: Exec) {
workingDir "${buildDir}/output"
commandLine 'powershell', './mybat.bat' , 'foo'//this is myArgs for example
}
this works and prints the value 123456, but I want to save it in a variable, how can I do that?
As you can see in the official doc HERE
This can be achieved with the following task
task executeCMD(type:Exec) {
workingDir '.'
commandLine 'mybat.bat', '>', 'log.txt'
doLast {
println "Executed!"
}
}
This will send the output of mybat.bat execution and set the results into a txt file called log .
the . is the directory where you have the script .
in my case its a project root directory .
the best approach I found is to add '/c' to commandLine arguments and use standardOutput, here some code that might help other people:
task getSomeOutput(type: Exec) {
workingDir "${buildDir}/output"
commandLine 'powershell', '/c', './mybat.bat' , 'foo'//this is myArgs for example
standardOutput = new ByteArrayOutputStream()
doLast {
def result = standardOutput.toString()
println "the result value is: $result"
}
}

Use `git describe --match` In Android build.gradle

Having trouble getting the latest git tag that matches a glob passed in to git describe within Gradle. It works fine when in terminal.
I have tried the following:
project.ext.releaseVersionName = "git describe --match \'[0-9]*.[0-9]*.[0-9]*\' --abbrev=0 --tags".execute().text.trim()
And
def getReleaseVersion = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'bash', '-c', 'git', 'describe', '--match "[0-9]*.[0-9]*.[0-9]*"', '--abbrev=0', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
return null
}
}
However both return empty strings. If I don't have the match then everything works correctly. I think it's the glob thats causing the issues.
By having the whole of '--match "[0-9]*.[0-9]*.[0-9]*"' in single quotes, you are basically passing an option with that whole string. What you really want is probably to pass the option --match with an argument of [0-9]*.[0-9]*.[0-9]*. You should therefore split that argument so that your commandLine becomes:
commandLine 'git', 'describe', '--match', '[0-9]*.[0-9]*.[0-9]*', '--abbrev=0', 'HEAD'
Alternatively you could switch the --match argument to the --arg=value syntax, i.e. use --match=[0-9]*.[0-9]*.[0-9]* like you do for --abbrev=0.
I've removed the 'bash', '-c' part as per the comments. If 'bash', '-c' was to be used, the whole rest should be a single string, as it would work as the value to the -c argument of bash.

How to launch .bat file after Gradle build. Sign and reinstall app from .bat

I was struggling with a problem where I wanted to use Gradle to execute .bat script after .apk build that signed the application with platform key, and reinstalled it on the device.
Folder structure
File instruction.bat content
java -jar "..\app\build\outputs\apk\signapk.jar"
"..\app\build\outputs\apk\platform.x509.pem"
"..\app\build\outputs\apk\platform.pk8"
"..\app\build\outputs\apk\app-debug.apk"
"..\app\build\outputs\apk\signed.apk"
adb install -r "..\app\build\outputs\apk\signed.apk"
adb shell am start -n
com.your.package/com.your.package.MainActivity
Add this to your build.gradle -
task signAndInstall(type: Exec) {
def finalPath = projectDir.toString() + '\build\outputs\apk\instruction.bat'
commandLine = [finalPath] }
android {
applicationVariants.all { variant ->
variant.assemble.doLast {
signAndInstall.execute()
}
} }

Run curl command in gradle at a specific point in time

I use bugsnag to monitor crashes in my Android app.
I also use ProGuard when I compile a release version.
I need to upload the mapping.txt file that is generated in build/outputs/mapping/prod/release folder of my project.
When I run this command in (Windows) command line:
curl https://upload.bugsnag.com -F proguard=#C:/mapping.txt -F apiKey=1111111111111111111111 -F versionCode=11111111 -F appId=com.my.package -F versionNumber=1.0.0
The file is uploaded and everything works.
All I need is to add a task to gradle so it uploads the file once its ready.
So once I compile the project for release, the mapping.txt file gets generated and once its ready, upload the file using this curl command (which is taken from bugsnag's web site by the way).
I tried many variations. The current one compiles but I do not think the file is being uploaded... I can't see any indication that it actually happened.
This is the code I currently use:
task uploadPro(type: Exec) {
logger.error("inside upload task")
commandLine 'cmd', '/c', 'curl', 'https://upload.bugsnag.com', '-F','proguard=#build/outputs/mapping/prod/release/mapping.txt', '-F', 'apiKey=1111111111111111111111', '-F', 'versionCode=111111', '-F', 'appId=com.my.package', '-F', 'versionNumber=1.0.0'
standardOutput = new ByteArrayOutputStream()
doLast {
String output = standardOutput.toString()
logger.info(output);
}
}
I also tried using this:
def p = ['cmd', '/c', 'curl', 'https://upload.bugsnag.com', '-F', 'proguard=#build/outputs/mapping/prod/release/mapping.txt', '-F', 'apiKey=11111111111111111111111', '-F', 'versionCode=1111111', '-F', 'appId=com.my.package', '-F', 'versionNumber=1.0.0'].execute()
The way I call this task is by using this command:
tasks.getByName("assembleRelease").finalizedBy(uploadPro)
Im really not sure how to do this. Any help is appreciated!! Thank you!
I found a solution to my own question... mostly. Here is the code I use to run the curl command at the end of the build process:
task uploadPro << {
logger.error("Uploading mapping.txt file to bugsnag")
def myCommand = "cmd /c curl https://upload.bugsnag.com -F proguard=#path\\to\mappingFile\\mapping.txt -F " +
"apiKey=111111111111111111111111 -F versionCode=" + versionCodeId + " -F " +
"appId=com.xxxx.yyy.zzz -F versionNumber=" + versionId
ProcessBuilder builder = new ProcessBuilder(myCommand.split(' '));
Process process = builder.start();
process.waitFor()
println process.err.text
println process.text
}
Then I use this to run it at the end of the build process:
gradle.buildFinished {
tasks.uploadPro.execute()
}
Cant be sure this is best practice but it works.
I would have liked to run the uploadPro task ONLY during a release buildType...but this proves to be difficult as well.

External dependencies on Gradle

I'm familiar with building large applications using make, but now I have begun using Android Studio and I want to understand how to do things I already do in a Makefile.
Here are a example that might help you frame an answer:
Makefile example: (minimalist)
INK=inkscape
INKFLAGS=--export-area-page
# Resolve *.png dependencies
drawable-mdpi/%.png: %.svg
$(INK) $< --export-png=$# -w 48 -h 48 $(INKFLAGS)
drawable-hdpi/%.png: %.svg
$(INK) $< --export-png=$# -w 72 -h 72 $(INKFLAGS)
drawable-xdpi/%.png: %.svg
$(INK) $< --export-png=$# -w 96 -h 96 $(INKFLAGS)
More simple example:
drawable-mdpi/ic_launcher.png: ic_launcher.svg
inkscape ic_launcher.svg --export-png=ic_launcher.png -w 48 -h 48 --export-area-page
drawable-hdpi/ic_launcher.png: ic_launcher.svg
inkscape ic_launcher.svg --export-png=ic_launcher.png -w 72 -h 72 --export-area-page
How to do that in Gradle?
I want to resolve external dependencies such as mentioned in the above example. Actually I'm doing it via 'make', but i want to completely remove this extra step.
It is possible to run external commands from Grandle and integrate those into your build process. My example runs inkscape.exe on Windows and defines its parameters in the build script, you can also just run a shell script this way.
The following code goes into the app\build.gradle file. Task convertDrawable is written in Groovy syntax and accomplishes the following (tl;dr it is an implementation of your "simple example"):
It looks through all the *.svg files in a custom folder art/drawable
Within each of those *.svg files, looks through all the drawable-* folders in your resources folder
Based on drawable-* folder name, determine the target resolution.
Then calls inkscape.exe to convert each *.svg to *.png with the required size.
Code:
task convertDrawables() {
def ink = 'C:\\Program Files (x86)\\Inkscape\\inkscape.exe'
// look for *.svg files in app/src/art/drawable folder
new File('app\\src\\art\\drawable').eachFileMatch(~/.*\.svg/) { file ->
// look for destination folders
new File('app\\src\\main\\res').eachFileMatch(~/drawable-.*/) { outputDir ->
// define size based on folder name
def size = ''
switch (outputDir.getAbsolutePath()) {
case ~/.*-ldpi/:
size = '36'
break
case ~/.*-mdpi/:
size = '48'
break
case ~/.*-hdpi/:
size = '72'
break
case ~/.*-xhdpi/:
size = '96'
break
case ~/.*-xxhdpi/:
size = '144'
break
case ~/.*-xxxhdpi/:
size = '192'
break
}
def cmd = ink + ' ' + file.getCanonicalPath() + ' --export-png=' + outputDir.getAbsolutePath() + '\\ic_launcher2.png -w ' + size + ' -h ' + size + ' --export-area-page'
def process = cmd.execute();
process.waitFor();
}
}
}
// make sure the convertDrawable task is executed somewhere in the make process
gradle.projectsEvaluated {
preBuild.dependsOn(convertDrawable)
}
Here are the resources I used:
Gradle Doc Chapter 15: More about Tasks
Gradle Doc Chapter 58. Writing Custom Task Classes
Gradle Doc Exec function
Groovy execute()
Stackoverflow Run task before compilation using Android Gradle plugin
Groovy Doc for File

Categories

Resources