2024年Android-Gradle-自动化多渠道打包,高级安卓工程师面试题

最后

我的面试经验分享可能不会去罗列太多的具体题目,因为我依然认为面试经验中最宝贵的不是那一个个具体的题目或者具体的答案,而是结束面试时,那一刻你的感受以及多天之后你的回味~

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我整理了一些资料,需要的可以免费分享给大家

在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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’
}

敏感信息存取

我们都知道,签名需要签名文件,密码、别名等等文件,360加固需要配置账号与密码,这些都属于敏感信息,google官方不建议直接放在gradle中,它是以纯文本记录在gradle中的,建议存储在properties文件中。

// 把敏感信息存放到自定义的properties文件中
def propertiesFile = rootProject.file(“release.properties”)
def properties = new Properties()
properties.load(new FileInputStream(propertiesFile))

ext {
// 签名配置
signing = [keyAlias : properties[‘RELEASE_KEY_ALIAS’],
keyPassword : properties[‘RELEASE_KEY_PASSWORD’],
storeFile : properties[‘RELEASE_KEYSTORE_PATH’],
storePassword: properties[‘RELEASE_STORE_PASSWORD’]
]

// app相关的配置
app = [
//默认release apk的文件路径,因为加固是基于release包的
releasePath : “ p r o j e c t . b u i l d D i r / o u t p u t s / a p k / r e l e a s e " , / / 对 r e l e a s e a p k 加固后产生的加固 a p k 地址 p a c k e r s P a t h : " {project.buildDir}/outputs/apk/release", //对release apk 加固后产生的加固apk地址 packersPath : " project.buildDir/outputs/apk/release",//releaseapk加固后产生的加固apk地址packersPath:"{project.buildDir}/outputs/packers”,
//加固后进行腾讯多渠道打包的地址
channelPath : “${project.buildDir}/outputs/channels”,
//腾讯VasDolly多渠道打包jar包地址
vasDollyPath: “…/VasDolly.jar”
]

// 360加固配置
packers = [account : properties[‘ACCOUNT360’], //账号
password : properties[‘PASSWORD360’], //密码
zipPath : “ p r o j e c t . r o o t D i r / j i a g u / 360 j i a g u . z i p " , / / 加固压缩包路径 u n z i p P a t h : " {project.rootDir}/jiagu/360jiagu.zip", //加固压缩包路径 unzipPath : " project.rootDir/jiagu/360jiagu.zip",//加固压缩包路径unzipPath:"{project.rootDir}/jiagu/360jiagubao/”, //加固解压路径
jarPath : “ p r o j e c t . r o o t D i r / j i a g u / 360 j i a g u b a o / j i a g u / j i a g u . j a r " , / / 执行命令的 j a r 包路径 c h a n n e l C o n f i g P a t h : " {project.rootDir}/jiagu/360jiagubao/jiagu/jiagu.jar", //执行命令的jar包路径 channelConfigPath: " project.rootDir/jiagu/360jiagubao/jiagu/jiagu.jar",//执行命令的jar包路径channelConfigPath:"{project.rootDir}/jiagu/Channel.txt”, //加固多渠道
jiagubao_mac : “https://down.360safe.com/360Jiagu/360jiagubao_mac.zip”, //加固mac下载地址
jiagubao_windows : “https://down.360safe.com/360Jiagu/360jiagubao_windows_64.zip” //加固widnows下载地址
]

gradle相关基础

  • gradle脚本插件的引用

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

  • 局部变量

def dest = “A”

  • 扩展属性

使用ext扩展块,一次扩展多个属性
ext {
account = “XXXX”
password = “XXXXX”
}

  • 字符串相关

单引号不支持插值
def name = ‘张三’
双引号支持插值
def name = “我是${‘张三’}”
三个单引号支持换行
def name = “”"
张三
李四
“”"

  • 可有可无的圆括号

// 这两种写法等价
println(‘A’)
println ‘A’

  • 闭包作为方法的最后一个参数

repositories {
println “A”
}
repositories() { println “A” }
repositories({println “A” })

  • task依赖

task B {
// TaskB依赖TaskA,故会先执行TaskA
dependsOn A
//其次执行packersRelease
doLast {
println “B”
}
}

  • task排序

//taskB必须总是在 taskA 之后运行, 无论 taskA 和 taskB 是否将要运行
taskB.mustRunAfter(taskA)
//没有msut那么严格
taskB.shouldRunAfter (taskA)

  • 文件定位

// 使用一个相对路径
File configFile = file(‘src/config.xml’)
// 使用一个绝对路径
configFile = file(configFile.absolutePath)
// 使用一个项目路径的文件对象
configFile = file(new File(‘src/config.xml’))`

  • 文件遍历

// 对文件集合进行迭代
collection.each {File file ->
println file.name
}

  • 文件复制重命名

copy {
from 源文件地址
into 目标目录地址
rename(“原文件名”, “新文件名字”)
}

自动上传到服务器

这个功能准备在下篇文章更新,我们可以通过curl命令上传到自己的服务器,如果你在测试阶段可以上传到蒲公英或者fir.im托管平台,目前他们都提供了相关的操作方式,这样基本上整个自动化的目的就完成了,当然你也可以选择Jenknis自动化构建、打包及上传。

  • 发布应用到fir.im托管平台 入口

方式一:fir-CLI 命令行工具上传
$ fir p path/to/application -T YOUR_FIR_TOKEN
方式二:API 上传
通过curl命令调用相关的api
1.获取凭证
curl -X “POST” “http://api.bq04.com/apps”
-H “Content-Type: application/json”
-d “{“type”:“android”, “bundle_id”:“xx.x”, “api_token”:“aa”}”
2.上传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 使用
-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

整体效果

我们的需求是需要打两批包,用于老后台与新后台,老后台的包必须加上app-前缀,所以有三个任务packersNewRelease执行正常的加固打包用于新后台,packersOldRelease用于打包加前缀app-名称用于老后台,packersRelease这个任务用于一键同时打包成老后台与新后台。

同时可以在gradle控制台查看打包任务的输出日志,如下:

gradle自动化源码

为了能够让大家尝试自动化gradle脚本带来的便利之处,下面我贡献上自己的整个gradle源码,需要的可以拿走去研究,如存在问题也希望多多交流。

/**

  • @author hule
  • @date 2020/04/15 13:42
  • description:360自动加固+Vaslloy多渠道打包
    */

// 把敏感信息存放到自定义的properties文件中
def propertiesFile = rootProject.file(“release.properties”)
def properties = new Properties()
properties.load(new FileInputStream(propertiesFile))

ext {
// 签名配置
signing = [keyAlias : properties[‘RELEASE_KEY_ALIAS’],
keyPassword : properties[‘RELEASE_KEY_PASSWORD’],
storeFile : properties[‘RELEASE_KEYSTORE_PATH’],
storePassword: properties[‘RELEASE_STORE_PASSWORD’]
]

// app相关的配置
app = [
//默认release apk的文件路径,因为加固是基于release包的
releasePath : “ p r o j e c t . b u i l d D i r / o u t p u t s / a p k / r e l e a s e " , / / 对 r e l e a s e a p k 加固后产生的加固 a p k 地址 p a c k e r s P a t h : " {project.buildDir}/outputs/apk/release", //对release apk 加固后产生的加固apk地址 packersPath : " project.buildDir/outputs/apk/release",//releaseapk加固后产生的加固apk地址packersPath:"{project.buildDir}/outputs/packers”,
//加固后进行腾讯多渠道打包的地址
channelPath : “${project.buildDir}/outputs/channels”,
//腾讯VasDolly多渠道打包jar包地址
vasDollyPath: “…/VasDolly.jar”
]

// 360加固配置
packers = [account : properties[‘ACCOUNT360’], //账号
password : properties[‘PASSWORD360’], //密码
zipPath : “ p r o j e c t . r o o t D i r / j i a g u / 360 j i a g u . z i p " , / / 加固压缩包路径 u n z i p P a t h : " {project.rootDir}/jiagu/360jiagu.zip", //加固压缩包路径 unzipPath : " project.rootDir/jiagu/360jiagu.zip",//加固压缩包路径unzipPath:"{project.rootDir}/jiagu/360jiagubao/”, //加固解压路径
jarPath : “ p r o j e c t . r o o t D i r / j i a g u / 360 j i a g u b a o / j i a g u / j i a g u . j a r " , / / 执行命令的 j a r 包路径 c h a n n e l C o n f i g P a t h : " {project.rootDir}/jiagu/360jiagubao/jiagu/jiagu.jar", //执行命令的jar包路径 channelConfigPath: " project.rootDir/jiagu/360jiagubao/jiagu/jiagu.jar",//执行命令的jar包路径channelConfigPath:"{project.rootDir}/jiagu/Channel.txt”, //加固多渠道
jiagubao_mac : “https://down.360safe.com/360Jiagu/360jiagubao_mac.zip”, //加固mac下载地址
jiagubao_windows : “https://down.360safe.com/360Jiagu/360jiagubao_windows_64.zip” //加固widnows下载地址
]
}

/**

  • 360加固,适用于新后台打包
    */
    task packersNewRelease {
    group ‘packers’
    dependsOn ‘assembleRelease’
    doLast {
    //删除加固后的渠道包
    deleteFile()
    // 下载360加固文件
    download360jiagu()
    // 寻找打包文件release apk
    def releaseFile = findReleaseApk()
    if (releaseFile != null) {
    //执行加固签名
    packers360(releaseFile)
    //对加固后的apk重新用腾讯channel构建渠道包
    reBuildChannel()
    } else {
    println ‘packers===can’t find release apk and can’t excute 360 jiagu’
    }
    }
    }

/**

  • 适用于老后台,老后台需要在渠道apk的名称增加前缀 app-
    */
    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()
    }
    // 对文件集合进行迭代
    channelFile.listFiles().each { File file ->
    copy {
    from file.absolutePath
    into oldChannelFile.absolutePath
    rename(file.name, “app-${file.name}”)
    }
    }
    println ‘packers===packersOldRelease sucess’
    }
    }
    }

/**

  • 加固后,打新版本的渠道包时,同时生成老版本的渠道包
    */
    task packersRelease {
    group ‘packers’
    dependsOn packersNewRelease
    dependsOn packersOldRelease
    packersOldRelease.mustRunAfter(packersNewRelease)
    doLast {
    println “packers===packersRelease finished”
    }
    }

/**

  • 对于release apk 进行360加固
    */
    def packers360(File releaseApk) {
    println ‘packers=beginning 360 jiagu’
    def packersFile = file(app[“packersPath”])
    if (!packersFile.exists()) {
    packersFile.mkdir()
    }
    exec {
    // 登录360加固保
    executable = ‘java’
    args = [‘-jar’, packers[“jarPath”], ‘-login’, packers[“account”], packers[“password”]]
    println 'packers
    =import 360 login’
    }
    exec {
    // 导入签名信息
    executable = ‘java’
    args = [‘-jar’, packers[“jarPath”], ‘-importsign’, signing[“storeFile”],
    signing[“storePassword”], signing[“keyAlias”], signing[“keyPassword”]]
    println ‘packers=import 360 sign’
    }
    exec {
    // 查看360加固签名信息
    executable = ‘java’
    args = [‘-jar’, packers[“jarPath”], ‘-showsign’]
    println 'packers
    =show 360 sign’
    }
    exec {
    // 初始化加固服务配置,后面可不带参数
    executable = ‘java’
    args = [‘-jar’, packers[“jarPath”], ‘-config’]
    println ‘packers=init 360 services’
    }
    exec {
    // 执行加固
    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”]}"
    }

/**

  • 自动下载360加固保,也可以自己下载然后放到根目录
    */
    def download360jiagu() {
    // 下载360压缩包
    File zipFile = file(packers[“zipPath”])
    if (!zipFile.exists()) {
    if (!zipFile.parentFile.exists()) {
    zipFile.parentFile.mkdirs()
    println("packers=create parentFile jiagu ${zipFile.parentFile.absolutePath}")
    }
    // 加固保的下载地址
    def downloadUrl = isWindows() ? packers[“jiagubao_windows”] : packers[“jiagubao_mac”]
    // mac自带curl命令 windows需要下载curl安装
    def cmd = “curl -o ${packers[“zipPath”]} ${downloadUrl}”
    println cmd
    cmd.execute().waitForProcessOutput(System.out, System.err)
    }
    File unzipFile = file(packers[“unzipPath”])
    if (!unzipFile.exists()) {
    //解压 Zip 文件
    ant.unzip(src: packers[“zipPath”], dest: packers[“unzipPath”], encoding: “GBK”)
    println 'packers
    =unzip 360jiagu’
    //将解压后的文件开启读写权限,防止执行 Jar 文件没有权限执行,windows需要自己手动改
    if (!isWindows()) {
    def cmd = “chmod -R 777 ${packers[“unzipPath”]}”
    println cmd

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

当然我也为你们整理好了百度、阿里、腾讯、字节跳动等等互联网超级大厂的历年面试真题集锦。这也是我这些年来养成的习惯,一定要学会把好的东西,归纳整理,然后系统的消化吸收,这样才能极大的提高学习效率和成长进阶。碎片、零散化的东西,我觉得最没有价值的。就好比你给我一张扑克牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。这和我们收集资料就要收集那些系统化的,是一个道理。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。这和我们收集资料就要收集那些系统化的,是一个道理。

[外链图片转存中…(img-Mjjy5jXa-1714816677994)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 27
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值