Android gradle automated multi-channel packaging, introduction to Android development tutorial

Posted by FijiSmithy on Fri, 17 Dec 2021 00:49:19 +0100

     }
    // 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 In fact, it provides us with a series of related tasks, as shown in the figure below

![](https://upload-images.jianshu.io/upload_images/23319472-7ef5c42ec4a2e670.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


We need to get one before we carry out reinforcement release Package, so we can use it`assembleRelease`Before reinforcement`assembleRelease`this Task. 

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]( )

![](https://upload-images.jianshu.io/upload_images/23319472-8f2a656754f56405.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


> In particular, here are 360 configuration options for enhanced services bug,It has been communicated with the official that they need to fix it in the next version. It currently exists bug Version 3 of.2.2.3(2020-03-16),The command line cannot select piracy monitoring only at present

/**

  • 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. In this version, I adopt 360 automatic signature. If you want to sign manually, I give a set of scheme below, which mainly uses `zipalign` and `apksigner`Command them all to be located SDK In file build-tools In the directory, we need to perform automatic signature gradle Configure the path.

*   Align unsigned apk

zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk

*   Use your private key for apk autograph

apksigner sign --ks my-release-key.jks --out my-app-release.apk my-app-unsigned-aligned.apk

*   verification apk Has it been signed

apksigner verify my-app-release.apk

## Automatic implementation of multi-channel based on Apk

For multi-channel packaging, Tencent has been used in our previous projects VasDolly,So we are taking VasDolly Command, but you need to download it first[VasDolly.jar]( ),As for where to put it, there is no requirement, just gradle After configuring the path, I directly put it 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.

![](https://upload-images.jianshu.io/upload_images/23319472-b572a70857d8206b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



/**

  • 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 signature requires signature files, passwords, aliases and other files, and 360 reinforcement needs to configure accounts and passwords, which are sensitive information, google It is not recommended to put it directly in the gradle In, it is recorded in plain text gradle In, it is recommended to store in 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

*   gradle References to script plug-ins

apply from: "${project.rootDir}/packers.gradle"

*   local variable

def dest = "A"

*   Extended properties

Use the ext extension block to extend 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'm ${'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 rely on

task B {
//Task B depends on task a, so it will execute task a first
dependsOn A
//Secondly, execute packersRelease
doLast {
println "B"
}
}

*   task sort

//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 feature will be updated in the next article, which we can use curl The command is uploaded to your own server. 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, so basically the purpose of the whole automation is completed. Of course, you can also choose Jenknis Automated build, package and upload.

*   Publish apply to fir.im Hosting platform [entrance]( )

Method 1: fir cli command line tool upload
$ fir p path/to/application -T YOUR_FIR_TOKEN
Method 2: API upload
Call the relevant api through curl command
1. Obtain vouchers
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 = ad hoc" \ #type=ios use
-F "x:changelog=first"
https://up.qbox.me

*   Publish apply to Dandelion [entrance]( )

curl -F "file=@/tmp/example.ipa" -F "uKey=" -F "_api_key=" https://upload.pgyer.com/apiv1/app/upload

![](https://upload-images.jianshu.io/upload_images/23319472-e293fdcb57cbae8a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


## Overall effect

Our demand is to make two batches of packages for the old background and the new background. The packages of the old background must be added app-Prefix, so there are three tasks`packersNewRelease`Perform normal reinforcement packaging for the new background,`packersOldRelease`Prefixed for packaging app-The name is used for the old background,`packersRelease`This task is used to package the old background and the new background at the same time.

![](https://upload-images.jianshu.io/upload_images/23319472-180cba42d782c309.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


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

![](https://upload-images.jianshu.io/upload_images/23319472-653923c8930019c2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)


## gradle automation source code

In order to let everyone try automation gradle For the convenience of the script, I'll contribute my whole gradle Source code, you can take it away and study it. If there are problems, you also 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("KaTeX parse error: Expected '}', got 'EOF' at end of input: ...elFile = 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
    */
    task packersRelease {
    group 'packers'
    dependsOn packersNewRelease
    dependsOn packersOldRelease
    packersOldRelease.mustRunAfter(packersNewRelease)
    doLast {
    println "packers===packersRelease finished"
    }
    }

last

For programmers, there are too many knowledge contents and technologies to learn. If they want not to be eliminated by the environment, they have to constantly improve themselves. It is always us to adapt to the environment, not the environment to adapt to us!

Finally, I repeat, if you want to be a good Android Developer, please focus on doing in-depth research on the basics and important things.

For many junior and intermediate Android engineers, if they want to improve their skills, they often grope and grow by themselves. The learning effect of fragmentation is inefficient, long and helpless. These architecture technologies hope to be a reference for Android development friends and avoid detours. The focus of this article is whether you have gained and grown, and the rest are not important. I hope readers can keep this in mind.

In order for you to successfully advance to middle and senior architects, I have specially prepared a set of high-quality Android architect tutorials such as source code and framework video for you to learn, so as to ensure that your salary will rise to a higher level after you learn.

CodeChina open source project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code

Here are some exclusive dry goods to share with you today:

We**

Finally, I repeat, if you want to be a good Android Developer, please focus on doing in-depth research on the basics and important things.

For many junior and intermediate Android engineers, if they want to improve their skills, they often grope and grow by themselves. The learning effect of fragmentation is inefficient, long and helpless. These architecture technologies hope to be a reference for Android development friends and avoid detours. The focus of this article is whether you have gained and grown, and the rest are not important. I hope readers can keep this in mind.

In order for you to successfully advance to middle and senior architects, I have specially prepared a set of high-quality Android architect tutorials such as source code and framework video for you to learn, so as to ensure that your salary will rise to a higher level after you learn.

CodeChina open source project: Android learning notes summary + mobile architecture Video + big factory interview real questions + project actual combat source code

Here are some exclusive dry goods to share with you today:

[external chain picture transferring... (img-EP7G8EDu-1630558100032)]

Topics: Java Android Design Pattern