} // 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.
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.
Here are some exclusive dry goods to share with you today:
[external chain picture transferring... (img-EP7G8EDu-1630558100032)]