Tencent Shadow—零反射全动态Android插件框架正式开源

2024-03-23 22:48

本文主要是介绍Tencent Shadow—零反射全动态Android插件框架正式开源,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Shadow是一个腾讯自主研发的Android插件框架,主要有以下特点:


  • Shadow所指的插件是插件的代码完全是一个正常可安装的App代码,无需引用任何Shadow的库。这样的App代码应用了Shadow之后可以免安装运行在另一个App中。

  • Shadow是一个完全无Hack,甚至零反射实现的Android插件框架。

  • Shadow是一个全动态实现的插件框架,就是说插件框架的代码跟插件的代码一样都是动态发布的。

  • Shadow是目前业内唯一的真正能开detectNonSdkApiUsage严格检查模式运行的插件框架。

Shadow主要解决了两个大问题


问题一:Android 9.0开始限制非公开SDK接口访问


Android 9.0出现限制非公开SDK接口访问之后,可以说当时我们已知的所有插件框架实现都或多或少的出现了适配问题。大家的应对方式基本上都是一种对抗的思想,有的去破解限制,有的通过和Google沟通浅灰名单有效期暂时续命。


我们也遇到了这个问题,但是我们没有选择和这个策略进行对抗,我们非常理解Google为什么限制使用非公开SDK接口。所以我们重新Review了插件框架的本质原理和设计缺陷,进而设计了全新的插件框架Shadow。Shadow没有使用任何非公开SDK接口,实现了和原本在用的使用了大量非公开SDK接口的实现一样的功能。

 

在Shadow的Sample中可以添加这样的代码开启严格检查模式运行,而其他插件框架并不能做到。

 
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();	
builder.penaltyDeath();	
builder.detectNonSdkApiUsage();	
StrictMode.setVmPolicy(builder.build());

比如,我们看到的一款也宣传未使用非公开SDK接口,支持Android 9.0的插件框架,在它的Sample中开启严格模式运行后,出现了如下Crash信息:

 
W/.xxx.sampl: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)	
W/System.err: StrictMode VmPolicy violation with POLICY_DEATH; shutting down.

可见,即使它的实现代码中没有出现任何非公开SDK的引用,实际上它依赖的第三方组件内部也使用了非公开SDK接口。

Shadow所支持的功能类型是十分丰富的,Shadow支撑了QQ群视频、Now直播、腾讯即玩等业务比较复杂、访问量巨大的业务,并没有对这些业务的功能做出任何限制。功能细节欢迎持续关注Github上的更新。

问题二:插件框架不完善,其本身的代码需要更新、修复


这是一个在我们长期接触插件框架技术后就意识到的问题。也是我们发现所有已知的插件框架没有解决的问题。我们将它称为全动态插件框架。全动态指的就是除了插件代码之外,插件框架本身的所有逻辑代码也都是动态的。实际上插件框架的代码我们是和插件打包在一起发布的。

 

这个特性有多重要呢?实际上它比无Hack、零反射实现还要重要!因为有了这个特性之后,就算是我们用了Hack的方案,需要兼容各种手机厂商的系统。我们也不需要等宿主App更新才能解决问题。

 

实际上,Shadow的这个特性是更早实现的。我们早在2015年就开始大量使用插件技术了。在2016年就实现了这个特性。凭借这个特性不断的动态发布插件框架的代码,去适配各种兼容性问题。在今年更是应用这个特性,在完全不跟宿主版本的前提下,将原本的具有上百个反射Hack调用的旧实现更新为了ShadowHack实现。新的Shadow自然也具备这个特性。

 

这个特性对于新研发的Shadow来说也尤为重要,因为新研发的东西肯定有很多不完善的地方。如果是要打包在宿主里发布的话,那必然要测试的非常小心,还要写大量过设计以满足未来的插件需求。但是,现在Shadow是不需要这样的,Shadow只实现业务眼前所需的功能就可以发布了。

 

这个特性还有一个好处就是对宿主的增量特别的小。我们的宿主对于业务接入在增量上有极其苛刻的要求。Shadow接入时只使用了15.1KB,160个方法。

而我们已知的其他插件框架对宿主的增量一般在110KB,900个方法到370KB,2300个方法之间。


640?wx_fmt=png



Shadow为解决所有插件框架问题铺平了道路


我们总结对插件框架发布的版本更新其实只有两种原因:

1.    业务需要新功能

2.    兼容不同的手机系统

640?wx_fmt=png

Shadow的两大特性正好针对这两类问题,并且一次性的解决了87%的问题。


实现原理


其实实现原理属于一层窗户纸,一捅就破了。重要的在于思路上的转变。以前的插件框架总是想用一些Hack手段去修改系统行为,找到系统的漏洞达到目的。Shadow的原则是不去跟系统对抗。既然只是限制非公开SDK接口访问,而没有限制动态加载代码。那么肯定有办法在不使用非公开SDK接口的前提下实现原来的目的。因为我们插件技术的目的本质上来说还是动态加载代码。

那么一个重要的原则就是,如果一个组件需要安装才能使用,那么就别在没安装的情况下把它交给系统。我们已知的插件框架中,做的最好的也不符合这个原则,所以尽管它的Hook点少,但就是由于它将没有安装的Activity交给系统了,所以后面就不得不做一些Hack的事修补。

所以套一个壳子的方案就非常好。这种思路其他框架很早就有了,但是它们一直想把一个插件Activity套在一个宿主Activity之中,然后想办法实现一个转调关系。如果插件Activity是一个真的Activity,那这个插件就可以正常编译安装运行,对开发插件或者直接上架插件App非常有利。但是由于它是个系统的Activity子类,它就有很多方法不能直接调用,甚至还可能需要避免它的super方法被调用。如果插件Activity不是一个真的Activity,只是一个跟Activity有差不多方法的普通类,这件事就简单多了,只需要让壳子Activity持有它,转调它就行了。但这种插件的代码正常编译成独立App安装运行会比较麻烦,代码中可能会出现很多插件相关的if-else,也不好。

Shadow做了一个非常简单事,通过运用AOP思想,利用字节码编辑工具,在编译期把插件中的所有Activity的父类都改成一个普通类,然后让壳子持有这个普通类型的父类去转调它就不用Hack任何系统实现了。虽然说是非常简单的事,实际上这样修改后还带来一些额外的问题需要解决,比如getActivity()方法返回的也不是Activity了。不过Shadow的实现中都解决了这些问题。

总的来说,Shadow实践的是一个非常著名的理论:

任何软件工程遇到的问题都可以通过增加一个中间层来解决——佚名


640?wx_fmt=png

具体到每个问题,细节上的原理各不相同,请关注Shadow相关的后续技术分享文章。如果想探究某个功能Shadow能否支持,可以fork项目,然后在Sample里自己写一个用例测试一下。Shadow的工程中的Sample可以直接安装运行,也可以直接以插件方式运行,用来对比插件实现和正常安装时行为是否一致非常方便。如果你的用例Shadow不支持,也欢迎把不支持的用例提一个Pull Request过来,我们可以探讨一下如何实现。

真诚期待开源贡献


Shadow开源的思路是将我们已经实现的功能,最有借鉴价值的代码,分享给大家。我们没有试图实现一个覆盖所有功能的SDK直接给大家用。因为我们自身业务没有在使用的功能,我们实现了也是不可靠的。反过来说,Shadow开源的代码绝大部分代码都是经过了亿级用户线上检验的,是可靠的。由于精力有限,我们的自动化测试用例也还比较少。这些都需要大家共同完善。


Tencent Shadow 正式开源

Github 开源地址:
https://github.com/Tencent/Shadow

(点击文末阅读原文直接访问)

请给 Shadow 一个 Star !

欢迎提出你的 issue 和 PR!

Shadow国内镜像地址:

https://git.code.tencent.com/Tencent_Open_Source/Shadow

640?wx_fmt=png

腾讯工蜂源码系统为开源开发者提供完整、最新的腾讯开源项目国内镜像

 


640?wx_fmt=jpeg




这篇关于Tencent Shadow—零反射全动态Android插件框架正式开源的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/839740

相关文章

maven中的maven-antrun-plugin插件示例详解

《maven中的maven-antrun-plugin插件示例详解》maven-antrun-plugin是Maven生态中一个强大的工具,尤其适合需要复用Ant脚本或实现复杂构建逻辑的场景... 目录1. 核心功能2. 典型使用场景3. 配置示例4. 关键配置项5. 优缺点分析6. 最佳实践7. 常见问题

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

Java使用MethodHandle来替代反射,提高性能问题

《Java使用MethodHandle来替代反射,提高性能问题》:本文主要介绍Java使用MethodHandle来替代反射,提高性能问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录一、认识MethodHandle1、简介2、使用方式3、与反射的区别二、示例1、基本使用2、(重要)

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

C++ HTTP框架推荐(特点及优势)

《C++HTTP框架推荐(特点及优势)》:本文主要介绍C++HTTP框架推荐的相关资料,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Crow2. Drogon3. Pistache4. cpp-httplib5. Beast (Boos

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1

SpringBoot基础框架详解

《SpringBoot基础框架详解》SpringBoot开发目的是为了简化Spring应用的创建、运行、调试和部署等,使用SpringBoot可以不用或者只需要很少的Spring配置就可以让企业项目快... 目录SpringBoot基础 – 框架介绍1.SpringBoot介绍1.1 概述1.2 核心功能2

MyBatis分页插件PageHelper深度解析与实践指南

《MyBatis分页插件PageHelper深度解析与实践指南》在数据库操作中,分页查询是最常见的需求之一,传统的分页方式通常有两种内存分页和SQL分页,MyBatis作为优秀的ORM框架,本身并未提... 目录1. 为什么需要分页插件?2. PageHelper简介3. PageHelper集成与配置3.

C#特性(Attributes)和反射(Reflection)详解

《C#特性(Attributes)和反射(Reflection)详解》:本文主要介绍C#特性(Attributes)和反射(Reflection),具有很好的参考价值,希望对大家有所帮助,如有错误... 目录特性特性的定义概念目的反射定义概念目的反射的主要功能包括使用反射的基本步骤特性和反射的关系总结特性

Maven 插件配置分层架构深度解析

《Maven插件配置分层架构深度解析》:本文主要介绍Maven插件配置分层架构深度解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Maven 插件配置分层架构深度解析引言:当构建逻辑遇上复杂配置第一章 Maven插件配置的三重境界1.1 插件配置的拓扑