Android gradle automated multi-channel packaging and analysis of underlying principles

/**
* Automatically download 360 reinforcement protection, or you can download it yourself and put it in the root directory
*/
def download360jiagu() {
   // Download 360 compressed package
   File zipFile = file(packers["zipPath"])
   if (!zipFile.exists()) {
       if (!zipFile.parentFile.exists()) {
           zipFile.parentFile.mkdirs()
           println("packers===create parentFile jiagu ${zipFile.parentFile.absolutePath}")
       }
       // Download address of reinforcement protection
       def downloadUrl = isWindows() ? packers["jiagubao_windows"] : packers["jiagubao_mac"]
       // mac comes with curl command. windows needs to download curl installation
       def cmd = "curl -o ${packers["zipPath"]} ${downloadUrl}"
       println cmd
       cmd.execute().waitForProcessOutput(System.out, System.err)
   }
   File unzipFile = file(packers["unzipPath"])
   if (!unzipFile.exists()) {
       //Unzip Zip the Zip file
       ant.unzip(src: packers["zipPath"], dest: packers["unzipPath"], encoding: "GBK")
       println 'packers===unzip 360jiagu'
       //Open the read-write permission of the extracted file to prevent the execution of Jar file without permission. If windows does not have permission, it needs to change it manually
       if (!isWindows()) {
           def cmd = "chmod -R 777 ${packers["unzipPath"]}"
           println cmd
           cmd.execute().waitForProcessOutput(System.out, System.err)
       }
   }
}

Make a release package

gradle actually provides us with a series of related tasks, as shown in the figure below

We need to get a release package before strengthening, so we can use assemblyrelease to execute the Task of assemblyrelease before strengthening.

task packersNewRelease {
    group 'packers'
    //You can use the dependency of task to perform packaging first
    dependsOn 'assembleRelease'
    }

Automatic reinforcement

The so-called automatic reinforcement is nothing more than a few lines of commands. 360 reinforcement insurance provides a set of Command line reinforcement

In particular, there is a bug in the optional enhanced service configured by 360 here, which has been communicated with the official. They need to fix it in the next version. The current version 3.2 2.3 (March 16, 2020). Currently, the command line cannot only select piracy monitoring

/**
 *  360 reinforcement for release apk
 */
def packers360(File releaseApk) {
    println 'packers===beginning 360 jiagu'
    def packersFile = file(app["packersPath"])
    if (!packersFile.exists()) {
        packersFile.mkdir()
    }
    exec {
        // Login 360 reinforcement insurance
        executable = 'java'
        args = ['-jar', packers["jarPath"], '-login', packers["account"], packers["password"]]
        println 'packers===import 360 login'
    }
    exec {
        // Import signature information
        executable = 'java'
        args = ['-jar', packers["jarPath"], '-importsign', signing["storeFile"],
                signing["storePassword"], signing["keyAlias"], signing["keyPassword"]]
        println 'packers===import 360 sign'
    }
    exec {
        // View 360 signature information
        executable = 'java'
        args = ['-jar', packers["jarPath"], '-showsign']
        println 'packers===show 360 sign'
    }
    exec {
        // Initialize the reinforcement service configuration without parameters
        executable = 'java'
        args = ['-jar', packers["jarPath"], '-config']
        println 'packers===init 360 services'
    }
    exec {
        // Execute reinforcement, and then automatically sign. If automatic signature is not adopted, you need to sign by yourself through build tools command
        executable = 'java'
        args = ['-jar', packers["jarPath"], '-jiagu', releaseApk.absolutePath, app["packersPath"], '-autosign']
        println 'packers===excute 360 jiagu'
    }
    println 'packers===360 jiagu finished'
    println "packers===360 jiagu path ${app["packersPath"]}"
}

Automatic signature

As for automatic signature, in fact, 360 provides the configuration option of automatic signature during reinforcement. If you don't want to upload the signature file to 360, you can choose to sign manually after reinforcement, because it involves security issues. I adopt 360 automatic signature in this version. If you want to sign manually, I'll give you a set of scheme below, We mainly use ziphalign and apksigner commands, which are located in the build tools directory in the SDK file. We need gradle to configure the path to execute automatic signature.

  • Align unsigned apk s
zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
  • Sign apk with your private key
apksigner sign --ks my-release-key.jks --out my-app-release.apk my-app-unsigned-aligned.apk
  • Verify that the apk has been signed
apksigner verify my-app-release.apk

Automatic implementation of multi-channel based on Apk

As for multi-channel packaging, we have always used Tencent's VasDolly in our previous projects, so we take the VasDolly command this time, but we need to download it first VasDolly.jar , there is no requirement on where to put it. Just configure the path in gradle. I put it directly in the project root directory. You can also use 360 multi-channel reinforcement. In fact, the whole set can use the commands provided by 360 reinforcement.

/**
 * Rebuild channel package for Tencent channel
 */
def reBuildChannel() {
    File channelFile = file("${app["channelPath"]}/new")
    if (!channelFile.exists()) {
        channelFile.mkdirs()
    }
    def cmd = "java -jar ${app["vasDollyPath"]} put -c ${"../channel.txt"} ${outputpackersApk()} ${channelFile.absolutePath}"
    println cmd
    cmd.execute().waitForProcessOutput(System.out, System.err)
    println 'packers===excute VasDolly reBuildChannel'
}

Sensitive information access

We all know that signing requires signature files, passwords, aliases and other files, and 360 reinforcement needs to configure accounts and passwords. These are sensitive information. google officials do not recommend directly putting them in gradle. It is recorded in gradle in plain text, and it is recommended to store them in the properties file.

// Store the sensitive information in the custom properties file
def propertiesFile = rootProject.file("release.properties")
def properties = new Properties()
properties.load(new FileInputStream(propertiesFile))

ext {
    // Signature configuration
    signing = [keyAlias     : properties['RELEASE_KEY_ALIAS'],
               keyPassword  : properties['RELEASE_KEY_PASSWORD'],
               storeFile    : properties['RELEASE_KEYSTORE_PATH'],
               storePassword: properties['RELEASE_STORE_PASSWORD']
    ]

    // app related configuration
    app = [
            //The default is the file path of release apk, because reinforcement is based on the release package
            releasePath : "${project.buildDir}/outputs/apk/release",
            //Reinforcement APK address generated after reinforcement of release apk
            packersPath : "${project.buildDir}/outputs/packers",
            //Address for Tencent multi-channel packaging after reinforcement
            channelPath : "${project.buildDir}/outputs/channels",
            //Tencent VasDolly multi-channel packaging jar package address
            vasDollyPath: "../VasDolly.jar"
    ]

    // 360 reinforced configuration
    packers = [account          : properties['ACCOUNT360'], //account number
               password         : properties['PASSWORD360'],  //password
               zipPath          : "${project.rootDir}/jiagu/360jiagu.zip",  //Reinforced package path
               unzipPath        : "${project.rootDir}/jiagu/360jiagubao/",  //Reinforcement decompression path
               jarPath          : "${project.rootDir}/jiagu/360jiagubao/jiagu/jiagu.jar",  //jar package path to execute the command
               channelConfigPath: "${project.rootDir}/jiagu/Channel.txt",  //Reinforced multi-channel
               jiagubao_mac     : "https://down.360safe.com/360Jiagu/360jiagubao_mac.zip ", / / Mac download address
               jiagubao_windows : "https://down.360safe.com/360Jiagu/360jiagubao_windows_64.zip "/ download address of widnows
    ]

gradle related Foundation

  • Reference to the gradle script plug-in
apply from: "${project.rootDir}/packers.gradle"
  • local variable
 def dest = "A"
  • Extended properties
use ext An extension block that extends multiple attributes at a time
ext {
    account = "XXXX"
    password = "XXXXX"
}
  • String correlation
Single quotation marks do not support interpolation
def name = 'Zhang San'
Double quotes support interpolation
def name = "I am ${'Zhang San'}"
Three single quotes support line breaks
def name = """
Zhang San
 Li Si
"""
  • Optional parentheses
// The two expressions are equivalent
println('A')
println 'A'
  • Closure as the last parameter of the method
repositories {
    println "A"
}
repositories() { println "A" }
repositories({println "A" })
  • task dependency
task B {
    // Task B depends on task a, so it will execute task a first
    dependsOn A
    //Secondly, execute packersRelease
    doLast {
        println "B"
    }
}
  • task sorting
//taskB must always run after taskA, regardless of whether taskA and taskB will run
taskB.mustRunAfter(taskA)
//Not as strict as msut
taskB.shouldRunAfter (taskA)
  • File location
// Use a relative path
File configFile = file('src/config.xml')
// Use an absolute path
configFile = file(configFile.absolutePath)
// A file object that uses a project path 
configFile = file(new File('src/config.xml'))`
  • File traversal
// Iterate over a collection of files
collection.each {File file ->
    println file.name
}
  • File copy rename
 copy {
        from Source file address
        into Destination directory address
        rename(""Original file name", "New file name")  
    }

Auto upload to server

This function will be updated in the next article. We can upload it to our server through curl command. If you are in the test phase, you can upload it to dandelion or fir Im hosting platform. At present, they all provide relevant operation methods, which basically completes the purpose of the whole automation. Of course, you can also choose Jenknis to automatically build, package and upload.

  • Publish and apply to fir Im hosting platform entrance
Mode 1: fir-CLI Command line tool upload  
$ fir p path/to/application -T YOUR_FIR_TOKEN
 Mode 2: API upload
 adopt curl Command call related api
1.Get voucher
curl -X "POST" "http://api.bq04.com/apps" \
     -H "Content-Type: application/json" \
     -d "{\"type\":\"android\", \"bundle_id\":\"xx.x\", \"api_token\":\"aa\"}"
2.upload apk
curl   -F "key=xxxxxx"              \
       -F "token=xxxxx"             \
       -F "file=@aa.apk"            \
       -F "x:name=aaaa"             \
       -F "x:version=a.b.c"         \
       -F "x:build=1"               \
       -F "x:release_type=Adhoc"   \  #type=ios usage
       -F "x:changelog=first"       \
       https://up.qbox.me
curl -F "file=@/tmp/example.ipa" -F "uKey=" -F "_api_key=" https://upload.pgyer.com/apiv1/app/upload

Overall effect

Our requirement is to make two batches of packages for the old background and the new background. The packages of the old background must be prefixed with app. Therefore, there are three tasks: packersNewRelease performs normal reinforcement packaging for the new background, packersOldRelease for packaging prefixed app name for the old background, and packersRelease for packaging the old background and the new background at the same time.

At the same time, you can view the output log of the packaging task on the gradle console, as follows:

gradle automation source code

In order to let you try the convenience brought by automated gradle script, I'll contribute my whole gradle source code. You can take it away and study it if necessary. If there are problems, I hope to communicate more.

/**
 * @author hule
 * @date 2020/04/15 13:42
 * description:360 Automatic reinforcement + Vaslloy multi-channel packaging
 */

// Store the sensitive information in the custom properties file
def propertiesFile = rootProject.file("release.properties")
def properties = new Properties()
properties.load(new FileInputStream(propertiesFile))

ext {
    // Signature configuration
    signing = [keyAlias     : properties['RELEASE_KEY_ALIAS'],
               keyPassword  : properties['RELEASE_KEY_PASSWORD'],
               storeFile    : properties['RELEASE_KEYSTORE_PATH'],
               storePassword: properties['RELEASE_STORE_PASSWORD']
    ]

    // app related configuration
    app = [
            //The default is the file path of release apk, because reinforcement is based on the release package
            releasePath : "${project.buildDir}/outputs/apk/release",
            //Reinforcement APK address generated after reinforcement of release apk
            packersPath : "${project.buildDir}/outputs/packers",
            //Address for Tencent multi-channel packaging after reinforcement
            channelPath : "${project.buildDir}/outputs/channels",
            //Tencent VasDolly multi-channel packaging jar package address
            vasDollyPath: "../VasDolly.jar"
    ]

    // 360 reinforced configuration
    packers = [account          : properties['ACCOUNT360'], //account number
               password         : properties['PASSWORD360'],  //password
               zipPath          : "${project.rootDir}/jiagu/360jiagu.zip",  //Reinforced package path
               unzipPath        : "${project.rootDir}/jiagu/360jiagubao/",  //Reinforcement decompression path
               jarPath          : "${project.rootDir}/jiagu/360jiagubao/jiagu/jiagu.jar",  //jar package path to execute the command
               channelConfigPath: "${project.rootDir}/jiagu/Channel.txt",  //Reinforced multi-channel
               jiagubao_mac     : "https://down.360safe.com/360Jiagu/360jiagubao_mac.zip ", / / Mac download address
               jiagubao_windows : "https://down.360safe.com/360Jiagu/360jiagubao_windows_64.zip "/ download address of widnows
    ]
}

/**
 *  360 Reinforced, suitable for new background packaging
 */
task packersNewRelease {
    group 'packers'
    dependsOn 'assembleRelease'
    doLast {
        //Delete the reinforced channel package
        deleteFile()
        // Download 360 reinforcement files
        download360jiagu()
        // Find the package file release apk
        def releaseFile = findReleaseApk()
        if (releaseFile != null) {
            //Execute hardening signature
            packers360(releaseFile)
            //For the strengthened apk, build the channel package with Tencent channel again
            reBuildChannel()
        } else {
            println 'packers===can\'t find release apk and can\'t excute 360 jiagu'
        }
    }
}

/**
 * It is applicable to the old background. The old background needs to add the prefix app to the name of the channel apk-
 */
task packersOldRelease {
    group 'packers'
    doLast {
        File channelFile = file("${app["channelPath"]}/new")
        if (!channelFile.exists() || !channelFile.listFiles()) {
            println 'packers==== please excute pakcersNewRelease first!'
        } else {
            File oldChannelFile = file("${app["channelPath"]}/old")
            if (!oldChannelFile.exists()) {
                oldChannelFile.mkdirs()
            }
            // Iterate over a collection of files
            channelFile.listFiles().each { File file ->
                copy {
                    from file.absolutePath
                    into oldChannelFile.absolutePath
                    rename(file.name, "app-${file.name}")
                }
            }
            println 'packers===packersOldRelease sucess'
        }
    }
}

/**
 *  After reinforcement, when playing the new version of channel package, the old version of channel package is generated at the same time
### Full preparation for the interview

Some basic knowledge and theories must be memorized and understood. Summarize them in your own language and memorize them.

although Android It's not as hot as it was a few years ago. It's past the era when the four components can find high paying jobs. This only shows Android Positions below the intermediate level are saturated,**There is still a shortage of senior engineers**,I can obviously feel that there are many senior positions after the national day, so it is the most important to strive to become a senior engineer.

Well, I hope it will help you.

The next step is to sort out some Android Learning materials,**Interested friends can pay attention to my free collection method**. 

**①Android Notes on developing core knowledge points**

**②Benchmarking "Ali" P7" 40W+Annual salary enterprise senior architect growth and learning Roadmap**

![](https://img-blog.csdnimg.cn/img_convert/2ad271593a0763a9a3744a3ea0b70e92.png)

**③Interview highlights summary**

![](https://img-blog.csdnimg.cn/img_convert/f7c05c10c074b5894afcfeab36ce915d.png)

**④Full set of systematic advanced architecture video**

**Android After learning, it is even more powerful!**March BATJ Big factories, etc. (prepare for war)! Now it is said that the cold winter of the Internet is nothing more than that you get on the wrong car and wear less (skills). If you get on the right car, your own technical ability is strong enough and the cost of replacing the company is high, how can you be laid off? It is all to eliminate the end business Curd nothing more! Nowadays, the market is flooded with junior programmers. This tutorial is aimed at Android Development Engineer 1-6 The staff in is in a bottleneck period and wants to break through their salary increase and advance in the next year Android Middle and senior architects are like fish in water for you. Get it quickly!

![](https://img-blog.csdnimg.cn/img_convert/29643721be267e1382b28f61152f7233.png)

**[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://codechina.csdn.net/m0_60958482/android_p7)**

G1wWMJ-1630557998519)]

**③Interview highlights summary**

[External chain picture transfer...(img-Nn3Lijds-1630557998520)]

**④Full set of systematic advanced architecture video**

**Android After learning, it is even more powerful!**March BATJ Big factories, etc. (prepare for war)! Now it is said that the cold winter of the Internet is nothing more than that you get on the wrong car and wear less (skills). If you get on the right car, your own technical ability is strong enough and the cost of replacing the company is high, how can you be laid off? It is all to eliminate the end business Curd nothing more! Nowadays, the market is flooded with junior programmers. This tutorial is aimed at Android Development Engineer 1-6 The staff in is in a bottleneck period and wants to break through their salary increase and advance in the next year Android Middle and senior architects are like fish in water for you. Get it quickly!

[External chain picture transfer...(img-x8kcVyxG-1630557998521)]

**[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://codechina.csdn.net/m0_60958482/android_p7)**

Keywords: Java Android Design Pattern

Added by coffeeguy on Fri, 17 Dec 2021 09:10:12 +0200