[Qbs] building android aab package help

Jochen Ulrich jochen.ulrich at clausmark.com
Wed Apr 15 08:29:15 CEST 2020


Hi Raphael!

What doesn’t work as expected? Is there any error message or what output is missing?


> As a fall back solution I can create a new AndroidAab Product that will depend on the android application and implement all rules using inputsFromDependencies property.

And this works? You already tried this?


Best
Jochen

Von: Qbs <qbs-bounces at qt-project.org> im Auftrag von Raphael Cotty <raphael.cotty at gmail.com>
Datum: Dienstag, 14. April 2020 um 21:27
An: "qbs at qt-project.org" <qbs at qt-project.org>
Betreff: [Qbs] building android aab package help

Hi all, 
I am struggling to find a way to build the aab package (non runnable package required by google store) on the android platform.
For this platform the default qbs product type is changed from application to android.apk (runnable package).
What I am trying to achieve is allowing the user to just set a property in his project to enable the build of the aab package:
QtQuiApplication {
    name: "myApp"
    buildAab: true
    ...
}

Building an aab is similar to building apk. They both take the same inputs (including java files) and generate a java file (R.java) but in a different way.

I first tried to add the android.aab type to the product type property in order to build both types.
But I can't find a way to redirect all java files + the R.java apk to the next apk rule and all the java files + R.java aab to the next aab rule (without changing the java module).

It looks like I need to multiplex over the product type...
This simple project summaries the issue (assuming product type multiplexing exists):
Project {
    Product {
        multiplexByType: ["android.apk", "android.aab"]
        name: "android"

        files: [
            "a.java",
            "b.java"
        ]

        Group {
            files: "AndroidManifest.xml"
            fileTags: "android.manifest_final"
        }

        FileTagger {
            patterns: "*.java"
            fileTags: ["java.java"]
        }

        // Generate the R.java in a different way according to the product type
        Rule {
            inputs: "android.manifest_final"
            Artifact {
                filePath: FileInfo.joinPaths(product.buildDirectory, "R.java")
                fileTags: ["java.java"]
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "generating R.java";
                cmd.sourceCode = function() {
                    var readFile = TextFile(input.filePath, TextFile.ReadOnly);
                    var writeFile = TextFile(output.filePath, TextFile.WriteOnly)
                    writeFile.write(readFile.readAll());
                    if (product.type === "android.apk")
                        writeFile.write("This is the R.java for apk");
                    else
                        writeFile.write("This is the R.java for aab");
                    writeFile.close();
                };
                return [cmd];
            }
        }

        // This rule can't be changed as it comes from the java module
        Rule {
            multiplex: true
            inputs: ["java.java"]
            outputFileTags: ["java.class"]
            outputArtifacts: {
                var artifacts = [];
                for (var i = 0; i < inputs["java.java"].length; ++i) {
                    artifacts.push({
                                       fileTags: "java.class",
                                       filePath: FileInfo.joinPaths(product.buildDirectory,
                                                                    inputs["java.java"][i].baseName + ".class")});
                }
                return artifacts;
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "compiling java files";
                cmd.sourceCode = function() {
                    for (var i = 0; i < inputs["java.java"].length; ++i) {
                        File.copy(inputs["java.java"][i].filePath,
                                  outputs["java.class"][i].filePath);
                    }
                };
                return [cmd];
            }
        }

        // Let's gather all compiled java classes and generate the classes.dex
        // If running in the apk context then we have all project java classes and the
        // R.java generated in the apk context
        // If running in the aab context then we have all project java classes and the
        // R.java generated in the aab context
        Rule {
            multiplex: true
            inputs: ["java.class"]
            Artifact {
                filePath: "classes.dex"
                fileTags: ["android.dex"]
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "generating classes.dex";
                cmd.sourceCode = function() {
                    var writeFile = TextFile(output.filePath, TextFile.WriteOnly)
                    for (var i = 0; i < inputs["java.class"].length; ++i) {
                        var readFile = TextFile(inputs["java.class"][i].filePath, TextFile.ReadOnly);
                        writeFile.write(readFile.readAll());
                    }
                    writeFile.close();
                };
                return [cmd];
            }
        }

        // Generate the apk package
        Rule {
            multiplex: true
            inputs: ["android.dex"]
            Artifact {
                filePath: product.name + ".apk"
                fileTags: "android.apk"
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "generating apk";
                cmd.sourceCode = function() {
                    File.copy(inputs["android.dex"][0].filePath, output.filePath);
                };
                return [cmd];
            }
        }

        // Generate the aab package
        Rule {
            multiplex: true
            inputs: ["android.dex"]
            Artifact {
                filePath: product.name + ".aab"
                fileTags: "android.aab"
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "generating aab";
                cmd.sourceCode = function() {
                    File.copy(inputs["android.dex"][0].filePath, output.filePath);
                };
                return [cmd];
            }
        }
    }
}

As a fall back solution I can create a new AndroidAab Product that will depend on the android application and implement all rules using inputsFromDependencies property.

So let me know if you have any idea.
Thanks
Raph



More information about the Qbs mailing list