2024年安卓最新Android-第三方开源框架:Bugly让热修复变得如此简单,2024年最新android面试题目及答案

最后

答应大伙的备战金三银四,大厂面试真题来啦!

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960全网最全Android开发笔记》

《379页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

腾讯、字节跳动、阿里、百度等BAT大厂 2020-2021面试真题解析

资料收集不易,如果大家喜欢这篇文章,或者对你有帮助不妨多多点赞转发关注哦。文章会持续更新的。绝对干货!!!

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

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

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

Bugly要求baseApk(基准包)的tinkerId与补丁包的tinkerId要不一样。所以,在生成基准包时,请用如下tinkerId:

def myTinkerId = “base-” + rootProject.ext.android.versionName // 用于生成基准包(不用修改)

当生成补丁包时,请使用如下tinkerId:

def myTinkerId = “patch-” + rootProject.ext.android.versionName + “.0.0” // 用于生成补丁包(每次生成补丁包都要修改一次,最好是 patch-${versionName}.x.x)

对于同一个基准包,我们可能会多次生成补丁包上传到Bugly的热修复管理后台,这时,这些补丁包的tinkerId也要不一样,不然的话,当客户手机上的App在获取补丁时,会错乱(亲测,当同个基准包的补丁包的tinkerId一样时,App每次重启都会获取不同的补丁包,导致tinkerId相同的补丁包轮流下发)。所以,“patch-” + rootProject.ext.android.versionName + “.0.0"中的”.0.0"(称为计数)就是为了区分每次生成的补丁包,如.0.1,.0.2等等,建议versionName更新时计数重置。

因为Tinker的配置放在了tinker-support.gradle文件中,与app的build.gradle不在同一个文件中,所以没办法通过android.defaultConfig.versionName直接获取App的versionName,这里我使用了config.gradle来提取共同的属性,rootProject.ext.android.versionName获取的是config.gradle中的versionName属性,详情请百度。

4、补丁新旧判定


def myTinkerId = “patch-” + rootProject.ext.android.versionName + “.0.0” // 用于生成补丁包(每次生成补丁包都要修改一次,最好是 patch-${versionName}.x.x)

对于一个基准包,可以在Bugly上发布多个补丁包(切记tinkerid不同),这里或许会让你误以为计数越大,表明补丁越新,这是错误的,这个计数仅仅只是区分不同的补丁包而已,它没有标记补丁新旧的作用,补丁新旧由Bugly来判定,最后上传的补丁便是最新的补丁,举个例子,我在昨天上传了tinkerid为"patch-1.0.0.9"的补丁1,在今天上传了tinkerid为"patch-1.0.0.1"的补丁2,虽然补丁2的计数比补丁1小,但补丁2比补丁1晚上传,所以补丁2是最新的补丁,即补丁新旧与计数无关。Bugly会下发并应用最新的补丁(即补丁2),但还是建议计数从小到大计算,这里仅仅只是说明Bugly如何判定补丁新旧罢了。

五、初始化SDK

========

Bugly的初始化工作需要在Application中完成,但对原生Tinker来说,默认的Application是无法实现热修复的。看过Tinker官方Wiki的人应该知道,Tinker针对Application无法热修复的问题,给予开发者两个选择,分别是:

  • 使用「继承TinkerApplication + DefaultApplicationLike」。

  • 使用「DefaultLifeCycle注解 + DefaultApplicationLike」。

这2种选择都需要对自定义的Application进行改造,对于自定义Application代码不多的情况来说还可以接受,但有些情况还是比较"讨厌"这2种选择的,对此,Bugly给出了它的2种解决方法,分别如下:

  • 使用原来的自定义Application,Bugly通过反射为App动态生成新的Application。

  • 使用「继承TinkerApplication + DefaultApplicationLike」。

DefaultLifeCycle注解在Bugly中被阉割了。

分别对应tinker-support.gradle文件中enableProxyApplication的值:true或false。

1、enableProxyApplication = true


Bugly将通过反射的方式针对项目中自定义的Application动态生成新的Application,下图是源码中的AndroidManifest.xml和编译好的apk中的AndroidManifest.xml:

既然将enableProxyApplication的值设置为true,那接下来的重点就是完成Bugly的初始化工作了。需要在自定义的Application的onCreate()中进行Bugly的配置,在attachBaseContext()中进行Bugly的安装:

public class MyApplication extends Application {

private Context mContext;

@Override

public void onCreate() {

super.onCreate();

mContext = getApplicationContext();

// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId

// 调试时,将第三个参数改为true

configTinker();

}

@Override

protected void attachBaseContext(Context base) {

super.attachBaseContext(base);

// you must install multiDex whatever tinker is installed!

MultiDex.install(mContext);

// 安装tinker

// 此接口仅用于反射Application方式接入。

Beta.installTinker();

}

}

注意:

  1. Bugly的安装必须在attachBaseContext()方法中,否则将无法从Bugly服务器获取最新补丁。
  1. tinker需要你开启MultiDex,你需要在dependencies中进行配置compile "com.android.support:multidex:1.0.1"才可以使用MultiDex.install方法。

最后在清单文件中,声明使用我们自定义的Application即可:

<application

android:name=“com.lqr.MyApplication”

…>

2、enableProxyApplication = false


这是Bugly推荐的方式,稳定性有保障(因为第1种方式使用的是反射,可能会存在不稳定的因素),它需要对Application进行改造,首先就是继承TinkerApplication,然后在默认的构造函数中,将第2个参数修改为你项目中的ApplicationLike继承类的全限定名称:

public class SampleApplication extends TinkerApplication {

public SampleApplication() {

super(ShareConstants.TINKER_ENABLE_ALL, “com.lqr.SampleApplicationLike”,

“com.tencent.tinker.loader.TinkerLoader”, false);

}

}

注意:这个类集成TinkerApplication类,这里面不做任何操作,所有Application的代码都会放到ApplicationLike继承类当中

参数解析

参数1:tinkerFlags 表示Tinker支持的类型 dex only、library only or all suuport,default: TINKER_ENABLE_ALL

参数2:delegateClassName Application代理类 这里填写你自定义的ApplicationLike

参数3:loaderClassName Tinker的加载器,使用默认即可

参数4:tinkerLoadVerifyFlag 加载dex或者lib是否验证md5,默认为false

接着就是创建ApplicationLike继承类:

public class SampleApplicationLike extends DefaultApplicationLike {

public static final String TAG = “Tinker.SampleApplicationLike”;

private Application mContext;

public SampleApplicationLike(Application application, int tinkerFlags,

boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime,

long applicationStartMillisTime, Intent tinkerResultIntent) {

super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);

}

@Override

public void onCreate() {

super.onCreate();

mContext = getApplication();

configTinker();

}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)

@Override

public void onBaseContextAttached(Context base) {

super.onBaseContextAttached(base);

// you must install multiDex whatever tinker is installed!

MultiDex.install(base);

// 安装tinker

Beta.installTinker(this);

}

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)

public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {

getApplication().registerActivityLifecycleCallbacks(callbacks);

}

@Override

public void onTerminate() {

super.onTerminate();

Beta.unInit();

}

}

注意:

SampleApplicationLike这个类是Application的代理类,以前所有在Application的实现必须要全部拷贝到这里,在onCreate方法调用SDK的初始化方法,在onBaseContextAttached中调用Beta.installTinker(this)。

最后在清单文件中,声明改造好的Application(注意不是ApplicationLike):

<application

android:name=“com.lqr.SampleApplication”

…>

3、配置Bugly


这是Bugly官方给出的配置,应有尽有,注释也很nice,请仔细看看,对项目的功能拓展与用户体验有帮助:

private void configTinker() {

// 设置是否开启热更新能力,默认为true

Beta.enableHotfix = true;

// 设置是否自动下载补丁,默认为true

Beta.canAutoDownloadPatch = true;

// 设置是否自动合成补丁,默认为true

Beta.canAutoPatch = true;

// 设置是否提示用户重启,默认为false

Beta.canNotifyUserRestart = true;

// 补丁回调接口

Beta.betaPatchListener = new BetaPatchListener() {

@Override

public void onPatchReceived(String patchFile) {

Toast.makeText(mContext, “补丁下载地址” + patchFile, Toast.LENGTH_SHORT).show();

}

@Override

public void onDownloadReceived(long savedLength, long totalLength) {

Toast.makeText(mContext,

String.format(Locale.getDefault(), “%s %d%%”,

Beta.strNotificationDownloading,

(int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)),

Toast.LENGTH_SHORT).show();

}

@Override

public void onDownloadSuccess(String msg) {

Toast.makeText(mContext, “补丁下载成功”, Toast.LENGTH_SHORT).show();

}

@Override

public void onDownloadFailure(String msg) {

Toast.makeText(mContext, “补丁下载失败”, Toast.LENGTH_SHORT).show();

}

@Override

public void onApplySuccess(String msg) {

Toast.makeText(mContext, “补丁应用成功”, Toast.LENGTH_SHORT).show();

}

@Override

public void onApplyFailure(String msg) {

Toast.makeText(mContext, “补丁应用失败”, Toast.LENGTH_SHORT).show();

}

@Override

public void onPatchRollback() {

}

};

// 设置开发设备,默认为false,上传补丁如果下发范围指定为“开发设备”,需要调用此接口来标识开发设备

Bugly.setIsDevelopmentDevice(mContext, false);

// 多渠道需求塞入

// String channel = WalleChannelReader.getChannel(getApplication());

// Bugly.setAppChannel(getApplication(), channel);

// 这里实现SDK初始化,appId替换成你的在Bugly平台申请的appId

Bugly.init(mContext, “e9d0b7f57f”, true);

}

这里就用到了一开始获取到的App ID了,将其传入Bugly.init()方法的第二个参数,切记,用你自己的App ID。

其中如下两个方法很重要:

  • Bugly.setIsDevelopmentDevice()

设置当前设备是不是开发设备,这跟Bugly上传补丁包时所选的"下发范围"有关。

  • Bugly.init(context, appid, isDebug)

这个方法除了设置App ID外,还可以设置是否输出Log,可以观察到Bugly在App启动时做了哪些联网操作。

六、AndroidManifest.xml

=====================

1、 权限配置


2、Activity配置


<activity

android:name=“com.tencent.bugly.beta.ui.BetaActivity”

android:configChanges=“keyboardHidden|orientation|screenSize|locale”

android:theme=“@android:style/Theme.Translucent”/>

3、FileProvider配置


<provider

android:name=“android.support.v4.content.FileProvider”

android:authorities=“${applicationId}.fileProvider”

android:exported=“false”

android:grantUriPermissions=“true”>

<meta-data

android:name=“android.support.FILE_PROVIDER_PATHS”

android:resource=“@xml/provider_paths”/>

如果你使用的第三方库也配置了同样的FileProvider, 可以通过继承FileProvider类来解决合并冲突的问题,示例如下:

<provider

android:name=“.utils.BuglyFileProvider”

android:authorities=“${applicationId}.fileProvider”

android:exported=“false”

android:grantUriPermissions=“true”

tools:replace=“name,authorities,exported,grantUriPermissions”>

<meta-data

android:name=“android.support.FILE_PROVIDER_PATHS”

android:resource=“@xml/provider_paths”

tools:replace=“name,resource”/>

4、升级SDK下载路径配置


在res目录新建xml文件夹,创建provider_paths.xml文件如下:

<?xml version="1.0" encoding="utf-8"?>

注:1.3.1及以上版本,可以不用进行以上配置,aar已经在AndroidManifest配置了,并且包含了对应的资源文件。

七、混淆

====

Bugly混淆规则

-dontwarn com.tencent.bugly.**

-keep public class com.tencent.bugly.**{*;}

避免影响升级功能,需要keep住support包的类

-keep class android.support.**{*;}

好了,集成完毕,接下来就是制作基准包、补丁包和上传补丁包了。

八、制作基准包

=======

在app编码完成并测试完成后,就是打包上线了,上线前打的包就是基准包啦,下面我们就来制作基准包,分3步:

  1. 打开app下的tinker-support.gradle文件。

  2. 将带"base"的tinkerId注释解开,并注释掉带"patch"的tinkerId。

  3. 双击运行build下的assembleRelease。

通常主Module的名字是"app",但我这个Demo是"tinker-bugly",所以你执行第3步时,要根据具体项目找到要制作基准包的主Module。

AS在执行assembleRelease指令时,就是在编译基准包了,当编译完成时,app的build目录下会自动生成基准包文件夹,以时间戳来命名的(也就是说,每次执行assembleRelease指令都会在build目录创建不同的基准包文件夹)。

这3个文件对之后制作补丁包来说是相当重要的,你需要做的就是将这3个文件保存好,可以保存到云盘、Git服务器上等等,但就不要让它就这么放着,因为在你执行clean Project时,app的build目录会被删除,这样基准包及mapping与R文件都会丢失。

到这里,你就可以把它(基准包:tinker-bugly-release.apk)上架到应用市场了。试下Demo:

tip:加固与多渠道打包


本篇不涉及具体的加固与多渠道打包。

1、加固

如果你的app需要加固,那就需要在制作基准包之前,将tinker-support.gradle文件的isProtectedApp = true的注释去掉,然后加固,重新签名,最后上架,它对加固平台也有一定的要求。

详情见「Bugly热更新使用范例文档最后:加固打包」部分。

2、多渠道打包

分「gradle配置productFlavors方式」与「多渠道打包工具打多渠道包方式(推荐)」。

详情见「Bugly热更新使用范例文档:多渠道打包」部分。

九、补丁包

=====

现在要动态修复App了,对于代码修复、so库修复、资源文件修复,分别对应Demo中的"say something"、“get string from .so”、“我的头像”,修复过程无非是改代码,替换so文件,替换资源文件,这里就不演示了,直接开始制作补丁包,先将tinker-support.gradle文件打开。

1、基准包命名


确保基准包及相关文件的命名与配置文件中的一致:

2、修改baseApkDir与tinkerId


  1. 修改baseApkDir的值为基准包所有文件夹的名字。

  2. 注释掉带"base"的tinkerId,取消带"patch"的tinkerId的注释(多次生成补丁时,记得修改"计数",区分不同的补丁)。

3、执行编译,生成补丁


打开侧边的Gradle标签,找到项目的主Module,双击tinker-support下的buildTinkerPatchRelease指令,生成补丁包。

当编译完成后,在app的build/outputs/patch目录下会在"patch_singed_7zip.apk"文件,它就是补丁包,双击打开它,可以看到其中有一个YAPATCH.MF,里面记录了基准包与补丁包的tinkerId(两者是肯定不同,如果一样则说明配置有问题了)。

十、上传补丁包

=======

1、流程图解


首先,点击进入「Bugly产品页面」,或点击“我的产品 ”查看我的产品。

点击你要管理的产品后,依次点击"应用升级"、“热更新”,可以查看到该产品的补丁下发情况(这个产品我还没上传过补丁,故一片空白)。

按下图顺序操作即可上传补丁包:

2、上传失败分析


有可能你在上传完补丁包时,页面会提示"未匹配到可应用补丁包的App版本,请确认补丁包的基线版本是否已经发布"。

遇到这种情况请先冷静,首先来说明一件事:Bugly怎么知道基线版本是否已经发布?

尾声

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

  • 思维脑图
  • 性能优化学习笔记


  • 性能优化视频

    当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

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

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

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

版本,请确认补丁包的基线版本是否已经发布"。

遇到这种情况请先冷静,首先来说明一件事:Bugly怎么知道基线版本是否已经发布?

尾声

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

最后想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

  • 思维脑图
    [外链图片转存中…(img-mMuOp0D5-1715012210088)]
  • 性能优化学习笔记
    [外链图片转存中…(img-Kn2TOdLm-1715012210088)]
    [外链图片转存中…(img-6ahF8OIu-1715012210088)]

[外链图片转存中…(img-i2q9zPbt-1715012210089)]
[外链图片转存中…(img-5STZgpEy-1715012210089)]

  • 性能优化视频
    [外链图片转存中…(img-7b9ZODwf-1715012210089)]
    当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

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

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

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

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值