面向触控类安卓支持库的应用代码替换技术
2020-11-12沈立炜赵文耘
王 超 沈立炜 赵文耘
1(复旦大学软件学院 上海 201203) 2(复旦大学计算机科学技术学院 上海 201203) 3(上海市数据科学重点实验室 上海 201203)
0 引 言
屏幕触摸是移动设备上最主要的人机交互渠道,它能提供例如下拉刷新、左右滑动等应用特性,这些特性丰富了界面的展示效果。为了实现这些特性,安卓应用开发者需要基于最基本的onTouchEvent等事件机制集成应用响应逻辑,但依旧需要编写相应代码以识别触控的事件类型,如手指的下拉、释放等。
谷歌从2011年开始提供安卓支持库来辅助开发者,这些支持库对开发者经常需要的功能进行了封装,其中包括了对特定类型界面触控事件的封装,例如SwipRefreshLayout控件集成了下拉刷新的功能、DrawerLayout控件集成了左右滑动的功能。使用这些支持库不仅提高了开发者的开发效率,而且能够在低版本的安卓平台上使用高版本的功能。但许多开发者对安卓支持库提供的功能缺乏了解,因此将已有代码替换成支持库需要花费很多的精力去学习,比如开发者需要对安卓支持库中下拉刷新、左右侧滑等控件的代码结构和实现机制有深入的了解。此外,对于维护采用基本事件处理机制编写的安卓应用程序,没有相应的技术来提醒安卓应用维护者进行支持库的替换,因此维护人员需要花费额外的精力在应用程序的源码中寻找可替换的功能代码。
目前已经有的代码替换工作主要集中在API和Library库的迁移。例如将项目中涉及的弃用API(Deprecated API) 用新的API进行迁移[1]。再比如随着软件系统生命周期的变化,对于系统中已有的依赖库需要用更相关的库来进行迁移[2]。而对于将已有功能代码替换成安卓支持库中相应控件实现的代码,目前还没有很好的方法来支持。
针对上述目标,本文提出了一种面向安卓触控类支持库的应用代码替换技术,其利用android.support.v4.widget支持库下的触摸控件并以自动化的方式寻找目标应用中的可替换点,最终为应用开发者和维护者生成替换建议。具体而言,本文首先提出用以描述安卓事件回调方法代码特征的元模型,以此为基础将目标代码特征模型与安卓支持库各控件的特征模型进行匹配。当匹配的结果能够进行替换时,分别从功能的实现代码、监听器的绑定、layout资源文件这三个方面生成替换建议。实验结果表明本文所提技术能够为支持库控件相应的,且用基本触控逻辑来实现的事件回调方法及其资源布局给出正确的替换建议。安卓开发者利用本文方法,可以分析出应用程序中的哪些代码可以进行替换,以及用安卓支持库中的哪一个触摸控件进行替换。
1 相关工作
与本文相关的研究工作主要包括安卓应用分析、代码相似度检测、代码迁移技术这三个方面。
安卓应用分析方法主要分为动态分析和静态分析两大类。动态分析是指当应用程序在运行时对应用程序的各种行为进行分析,以获取程序的动态行为特征。静态分析则是分析应用程序的源码或者字节码,构造应用程序的整体结构。对于安卓静态分析,目前一些研究工具利用不同类型的图来描绘程序的特征,如控制流图、数据流图等[3-4]。为了获取安卓应用程序的源码或字节码,需要对APK安装包反编译,常用的反编译工具有Dexpler[5]、Smail[6]和AndroGuard[7]。本文方法也依赖于安卓静态分析技术,在安卓应用程序的源码层面上利用抽象语法树分析结果来进一步描绘程序的特征。
针对代码的相似问题目前已有很多分析方法,如基于文本识别、基于度量值、基于代码结构和基于图结构的代码相似分析。基于文本识别的代码相似分析方法是将代码表示成文本或token序列的方式,进而采用模式匹配技术来检测代码间是否相似。代码克隆[8]就是基于文本识别的方法来检测待分析代码中的重复部分。基于度量值的代码相似分析方法,不直接比较程序代码,而是提取选定的度量值信息,形成一组包含这些信息的特征向量,通过比较这些特征向量来比较代码的相似程度[9]。衡量代码的度量值有很多,如圈复杂度、类耦合度和继承深度等。基于代码结构的代码相似分析方法是将待分析的代码转化成抽象语法树,进而在语法树上使用匹配或搜索技术寻找相似的子树[10-11]。基于图结构的代码相似分析是将程序代码表示成程序依赖图来进行分析[12-13]。从两个特定的起始点开始,寻找两幅图中的最大相似子图。本文方法也利用了基于代码结构相似的分析方法,将安卓应用程序代码构造成抽象语法树,进而在抽象语法树的基础上利用树匹配算法进行相似分析。
代码迁移目前主要分为API迁移和Library库的迁移。对于API的迁移,可以通过比较两个版本API在库中的声明变化以及两个版本API在代码中的使用方式来进行迁移[14]。对于Library库的迁移,通过对大量开源软件项目的分析来识别相似库之间的迁移变化,进而根据大量的分析数据来为Library库的迁移提供建议[2]。与上述工作不同,本文方法关注控件支持库层面的迁移,涉及一组代码语句与控制结构,其中的核心要素是识别目标代码与安卓支持库中特定控件在功能和结构上的相似性。
2 动机案例
图1为开发者使用基础回调方法onTouch实现的下拉刷新功能:当手指下拉并松开后,在屏幕上发送一条通知。该代码在基础回调方法的UP分支下实现发送通知的业务逻辑。
图1 下拉刷新案例功能代码
图2为该应用程序相应的资源文件,其中子视图由两个文本框TextView构成,这两个文本框在LinearLayout布局的内部。
图2 下拉刷新案例资源文件
图1的功能代码和图2的资源文件都可以用安卓支持库中已经封装好的控件进行替换。当安卓应用软件开发者需要用安卓支持库中已有的控件进行替换时,先要判断是否能够替换以及用什么控件进行替换,然后还要分别从功能代码和资源文件两块进行替换。
对于开发者来说这将会面临很多困难。首先许多安卓开发者对安卓支持库下提供的功能并不了解,因此将已有代码替换成支持库需要一定的学习代价。虽然拥有了一定的安卓支持库的储备知识,但没有相应的技术提醒开发者该应用程序中的某些功能能够用安卓支持库中的控件进行替换。此外,一些开发者知道该项目的有些功能可以使用支持库的控件进行替换,但是他们不知道如何在项目中进行替换。
当开发者使用基于本文方法所开发的工具时,就可以根据工具生成的建议快速地在项目中进行支持库的替换。该工具将会从功能实现代码、监听器的绑定和布局文件这三个方面给出替换建议。
图3为根据替换建议用SwipeRefreshLayout这个支持库控件进行替换后的功能代码。该代码中,迁移的代码被放置在SwipeRefreshLayout的onRefresh回调方法中,同时为SwipeRefreshLayout绑定OnRefresh-Listener监听器,用来监听事件。
图3 用支持库控件替换后的功能代码
资源文件的替换如图4所示。根据替换建议,使用SwipeRefreshLayout控件节点来替换原先的LinearLayout节点。
图4 用支持库替换后的资源文件
3 支持库代码特征模型及其构造
3.1 安卓事件回调方法的代码特征元模型
图5所示的元模型用来描绘安卓事件回调方法的代码特征信息。该元模型既可以表示支持库中的回调方法,又可以用来描述目标替换代码的方法代码结构。
图5 安卓事件回调方法的代码特征元模型
Widget表示安卓支持库中的一个触摸控件,在该元模型中,控件包含了一组监听器。每一个监听器负责监听一个或多个事件并触发相应的回调方法(Callback)。我们使用一棵特征树(FeatureTree)来表示Callback的具体代码及其应用逻辑,并以FeatureTreeRoot来表示该特征树的根节点。根节点一般命名为基础回调的方法名,例如onTouch、onTouchEvent等。
特征树是由一系列表示代码元素的节点构成,即CodeElement。节点之间存在Order信息与Include关系。Order关系表示同层次代码元素与同层次代码元素之间的次序关系,Include关系表示外部代码元素与内部代码元素之间的包含关系。另外,每一个节点包含KeyWordSet属性,用以代表代码元素中的关键字集合。该集合可包括方法名以及部分静态常量名。这些关键字从SDK中提取得来,用以反映代码的实现功能。
元模型中列举了三种特定类型的代码元素,即代码控制结构(ControlStructure)、代码语句(Statement)和插桩点(Instrumentation)。
ControlStructure用来描述代码的骨架结构,表示程序执行的动作顺序。本文将控制结构分成两类,循环结构(Loop)和分支结构(Branch)。循环结构包括For、While、Do等,分支结构包括If、Switch等。
Statement用来记录代码结构中的基本语句信息,例如方法调用信息,Statement就记录了该方法调用是在代码控制结构中的哪个分支下进行调用的。
Instrumentation记录控件回调方法在代码中的哪个位置被间接触发。例如SwipeRefreshLayout控件中的onRefresh回调方法是在onTouchEvent这个基础回调方法中的UP分支下被间接触发的。在进行代码替换时,用户实现业务功能的代码就放在该插桩点所记录的回调方法的内部。
3.2 目标代码特征模型的构造方法
算法1是目标代码特征模型的构造方法。该算法的输入是一个Callback方法,对Callback方法中的每一个结构块进行迭代分析。算法的输出是FeatureTree,即一个以树状结构表示回调方法的特征模型。
算法1目标代码特征模型的构造方法
Function: BuildFeatureTree
输入: Callback。
输出: FeatureTree。
begin
For each ControlBlock in Callback
begin
CNode=CreateNode(Loop/Branch)
CreateOrder(PreCNode, CNode)
SNode=CreateNode(Condition)
AddIncludeNode(CNode, SNode)
BNode=CreateNode(Statement)
AddIncludeNode(SNode, BNode)
PreCNode=CNode
end
return FeatureTree
end
在迭代过程中,对于每一个结构块,创建一个ControlStructure类型的节点,节点记录该控制结构的类型是Loop还是Branch,并将此控制结构节点与父控制结构节点关联起来。为了记录控制结构之间的Order关系,在关联两个控制结构节点时以Order属性的边来连接这两个节点。控制结构中的条件信息,用Statement类型的节点来保存,并将该节点以Include关系关联到所属的控制结构节点上。对于某一个条件下的代码语句,仍然用Statement类型节点来保存,并将该节点以Include关系关联到所对应的分支条件节点上。如果该控制结构是分支结构,则需要对分支结构下的每一个分支条件进行分析。
3.3 支持库控件的特征模型构建
首先需要为支持库每一个触摸控件中每一个监听器下的每一个回调方法构造特征模型。为了获取支持库控件中的回调方法,可以通过参阅文档或检索支持库中具有Listener的类来找到相应的回调方法。为了找到触发回调方法的调用语句,需要对回调方法进行回溯,由于回调方法有时候并不能在某一个方法中找到对其的调用,因此回溯过程将分为以下两种情形:
(1) 如果在某一个方法中找到触发该回调方法的调用语句,则以该方法继续向上回溯。
(2) 如果没有找到触发该回调方法的调用语句,则利用事先对安卓内部回调方法的总结,找到触发该回调方法的方法,然后以该方法继续向上回溯。
算法2描述了回调函数调用链的回溯过程,该算法的输入是一个支持库控件中的回调方法,输出是控件中的基础回调方法。通过算法2,可以将控件中以回调方法为终点,以基础回调方法为起点的方法调用链构建完成。接着采用算法1,对基础回调方法进行特征模型树的构造。此时的特征模型树需要加上插桩类型节点,该节点存储了控件中的某个回调方法,并且将该节点连接到基础回调方法对应的代码块下。
算法2回调函数调用链的回溯算法
Function: SearchBaseMethod
输入: Callback。
输出: BaseMethod。
begin
if Callback是基础回调方法 then
begin
BaseMethod=Caller
return BaseMethod
end
if 找到该回调方法的Caller then
begin
SearchBaseMethod(Caller)
end
else then
begin
通过整理的回调方法总结中找到Caller
SearchBaseMethod(Caller)
end
end
图6给出了一个控件特征模型的例子。onTouchEvent是SwipeRefreshLayout控件内部的一个基础回调函数。
图6 特征模型树示例
可以看出,其内部是一个分支类型的控制结构,用ControlStructure类型的节点来表示,节点存储了该控制结构类型为Branch类型。该结构有三个分支,分别用三个Statement类型的节点保存分支条件的信息。每一个分支条件下用Statement类型节点保存该分支下的代码语句片段信息。由于UP分支下间接调用了onRefresh这个回调方法,因此用一个插桩类型的节点来存储该回调方法信息。
4 目标应用的支持库控件替换
4.1 代码替换技术的方法流程
代码替换技术的方法流程如图7所示,该方法流程主要分成两个阶段,第一阶段是安卓支持库特征模型的准备,第二阶段是基于第一阶段支持库特征模型的代码替换技术。
图7 代码替换技术的方法流程
安卓支持库特征模型的准备分成两个部分:一是回调方法调用链的构建,二是回调方法特征模型的构建。回调方法调用链的构建是对于安卓支持库控件中的每一个回调方法,找到该方法是在哪个基础回调方法中被触发的。回调方法特征模型的构建是对控件中的每一个回调方法构建特征模型树。
支持库特征模型的代码替换分成三个部分,分别是基于支持库特征模型的待替换代码的定位、匹配和替换。首先需要对待分析的安卓应用进行扫描,对应用中每一个Activity中的每一个回调方法进行定位。如果该回调方法名与支持库特征模型中的某个基础回调方法名一致,则该回调方法是一个潜在待替换代码。如果方法名不一致,则继续定位应用中的下一个回调方法。对于定位到的一个潜在待替换代码,采用树匹配的算法将潜在待替换代码特征模型树与控件中相对应的特征模型树进行匹配,根据匹配结果判断能否进行替换。当可以替换时,生成相应的替换建议。
4.2 基于支持库特征模型的代码匹配
为了对目标代码特征模型树和安卓支持库控件的特征模型树进行匹配比较,本文采用一种树匹配算法(TM)来寻找两棵特征模型树间的最大匹配。S(SA,S1,S2,…,Si)和T(TB、T1,T2,…,Tj)分别是目标代码特征模型树和安卓支持库控件特征模型树。其中:Si为树S的第一层子树的第i个节点;Tj为树T的第一层子树的第j个节点;SA和SB分别为树的根节点。M为两个特征模型树的匹配,最大匹配M就是拥有最多节点对间的匹配,其最大匹配节点个数为M+1,加1是因为根节点也是匹配的节点对。为了求出M(
1) 当两个子树中有一个为空是,匹配数M为0。
2) 当两个子树都不为空时,可分为以下几个情形:
(1) 匹配Si和Tj,这时M(
(2) 匹配Si,这时M(
(3) 匹配Tj,这时M(
最后根据树匹配算法的结果,计算出两个特征模型之间的相似度:
式中:Node(S)和Node(T)分别表示树S和树T节点的个数;TM(S,T)表示通过树匹配算法计算后返回的两棵树间的最大匹配的节点个数。
图8所示为两个特征模型树S和T,节点中的标号表示该节点的类型,具有相同标号的节点看成是相同节点。利用TM算法可以求出S和T之间的最大匹配为9,因此它们之间的相似度为0.9。
图8 两棵特征模型树
因此两棵特征模型树的最大匹配节点个数越多,则两棵树的相似度就越大,也就越相似。对于本文的场景,需要在目标代码的特征模型树中匹配到一棵子树,该子树即控件基础回调方法的特征模型树。所以最大匹配树TM(S,T)满足以下关系时,目标代码可以用安卓支持库里的控件进行替换:
TM(S,T)=Node(T)
式中:T表示的是安卓支持库控件代码的特征模型树;S表示的是目标代码的特征模型树;Node(T)表示树T节点的个数;TM(S,T)表示通过树匹配算法计算后返回的两棵树间的最大匹配的节点个数。
4.3 基于支持库特征模型的替换
1) 功能实现代码和监听器的替换。算法3描述了功能实现代码和监听器的替换方法。该算法的输入是两个特征模型树,分别是目标代码的特征模型树CallbackFeatureTree和能够用来替换该目标代码的支持库控件中的基础回调方法的特征模型树BaseMethodFeatureTree。该算法用CodeSegmentMap来保存能够被迁移的代码片段,用NotReplaceSet来保存未被迁移的代码片段。
算法3功能实现代码和监听器的替换算法
Function: CallbackReplace
输入: CallbackFeatureTree, BaseMethodFeatureTree。
输出: CodeSegmentMap, NotReplaceCodeSet。
begin
for each Statement in CallbackFeatureTree
begin
if Statement 对应到BaseMethodFeatureTree中的一个插桩点 then
begin
for each widget in WidgetSet
begin
for each FeatureTreeRoot in widget
begin
if FeatureTreeRoot==BaseMethodFeatureTree.root then
begin
find Listener where Listener.contain(FeatureTreeRoot)
CodeSegmentMap.put(控件+监听器+插桩点, Statement)
end
end
end
end
if Statement 对应不到BaseMethodFeatureTree中的一个节点 then
begin
NotRepalceCodeSet.put(Statement)
end
end
return CodeSegmentMap, NotReplaceCodeSet
end
在算法3中,以CallbackFeatureTree为基准,遍历该特征模型树上的Statement类型节点,如果该节点直接对应到BaseMethodFeatureTree中的一个非插桩节点,那么说明新控件已经包含这些语句。如果对应的是一个插桩类型的节点,说明该代码语句是可以进行迁移的。如果没有对应到任何一个节点,则将该代码语句记录到NotReplaceCodeSet中,该代码语句无法被迁移。对于监听器的搜索,首先找到BaseMethodFeatureTree是在哪个widget下的,然后在该Widget下找到哪一个listener的孩子节点中有一个孩子节点是该BaseMethod的,则该listener就是需要用来替换的监听器。最后以插桩点、监听器和该控件作为key键,Statement作为值,记录到CodeSegmentMap中。
2) layout资源文件的替换。layout资源文件的替换分成两步:第一步需要找到待替换的控件是什么;第二步需要找到资源文件是哪一个。在Callback所处的Activity中,可以找到该回调的监听器,然后向上回溯找到是哪一个对象set了这个监听器,则该对象就是需要找的待替换控件。一个Activity的资源文件是在该Activity中的onCreate方法内部的setContentView方法中被加载的,该方法中的参数就是layout资源文件的名字。例如方法参数是R.layout.activity_main,则需要的资源文件名称就是activity_main.xml。
接着需要在该资源文件中搜索到用户控件的节点,当找到该节点后,将该节点用支持库控件进行替换。算法4描述了节点搜索的方法。
算法4搜索节点的算法
Function: depthSearch
输入: root//xml文件的根节点。
输出: child//待替换的控件节点。
begin
nodeStack.add(root)
while(!node.isEmpty)
begin
node=nodeStack.pop()
list=node.getChildren()
for child ∈ list
begin
nodeStack.add(child)
if child.name==layout.name then
begin
return child
end
end
end
end
算法4的实质是树的深度优先搜索算法,由于Activity是由一组ViewGroup组成,所以从根节点出发,依次遍历每一组ViewGroup。对于每一组ViewGroup,依次搜索其每一个孩子节点分支,然后再以该孩子节点为起点,照此方法直到搜索到某一分支的叶子节点时返回上一层继续搜索。当搜索到节点的名字属性与待替换控件的名字属性一致时就停止搜索,那么该位置的节点就是需要用新的控件去替换的位置。
4.4 替换建议的生成
本文给用户提供的生成建议包含以下几个部分:
1) 对于安卓应用中可以进行迁移的代码,需要将支持库控件、监听器、回调方法、可迁移代码组合成完整的代码片段。为了方便用户的理解,该建议还增加了一些文字描述,将这些描述与组合后的代码片段作为完整的可迁移代码的替换建议。图9给出了可迁移代码建议的模板。
图9 可迁移代码的建议模板
在替换建议中,图9模板先给出了替换前的代码,并用文字指明了该代码片段位于哪个Activity的哪个基础回调方法,然后给出了迁移后的代码示例,也用文字介绍了使用安卓支持库中的哪个控件进行替换,以及绑定的监听器和回调方法的信息。
2) 对于安卓应用中未被迁移的代码,本文同样将未被迁移代码和一些文字描述作为替换建议展示给用户。图10给出了未被迁移代码建议的模板,其既给出了未被迁移的代码片段,又给出了该代码片段是位于该应用中的哪个Activity里的哪个基础回调方法下的。
图10 未被迁移代码的建议模板
3) 对于资源文件的替换,本文依旧给出原资源文件和替换后的资源文件,同时也通过文字描述进行解释,方便用户的定位和替换。图11给出了资源文件替换建议的模板,文字描述告诉用户资源文件的名称,以及是用支持库中的哪个控件进行替换。
图11 资源文件替换的建议模板
5 实验分析
图12为基于本文方法所设计的工具界面,该工具的界面分成上下两个部分。上半部分是用户的输入部分,用户需要提供待分析的安卓项目的地址。下半部分是替换建议生成部分,分别从可迁移代码、资源文件替换和未被迁移代码三个方面给出替换建议。界面中的三个文本框分别用来展示这三个方面的替换信息。
图12 工具界面
本文主要通过两组实验来对本文方法在实际开发中的实用性进行分析,这两组实验分别是针对用户开发应用的支持库替换实验和针对开源应用的支持库替换实验。
1) 针对用户开发应用的支持库替换实验。本实验邀请了三位具有初级安卓开发经验的同学,让这三位同学基于基础回调方法实现例如下拉操作、侧滑操作等功能的安卓应用程序。表1列举了给这三位同学安排的开发任务和提供的开发建议。
表1 实验的开发任务与开发建议
当三位同学完成应用开发后,利用本文方法对这三个应用进行替换分析。最终的分析结果如表2所示。
表2 实验结果
其中有两个应用有替换建议,有一个应用没有替换建议。本节将选取实验1和实验3,即一个有替换建议的例子和一个没有替换建议的例子来对该实验进行分析。
(1) 有替换建议的例子分析。该例子用onTouchEvent这个基础回调方法实现下拉刷新的功能。图13是该功能实现代码的片段。该例子在onTouchEvent的Up分支下写了一段更新子视图的逻辑,该逻辑是当手指下拉松开后,在子视图的ListView中添加一行List。
图13 功能实现代码片段
通过本文方法分析后,安卓支持库里的下拉刷新控件SwipeRefreshLayout可以对例子中用基础回调方法onTouchEvent实现的下拉刷新代码进行替换。图14是可迁移代码的替换建议,可待迁移代码放置在SwipeRefreshLayout的onRefresh回调方法中,该回调方法是在手指下拉手松后被间接触发的。同时为Swipe-RefreshLayout绑定一个setOnRefreshListener监听器,用来监听事件。
图14 可迁移代码的替换建议
该例子的资源文件如图15中替换前的代码所示,该资源文件有两个视图,分别是子视图ListView和父视图LinearLayout,子视图ListView在父视图LinearLayout的内部。对于替换后的资源文件如图15中替换后的代码所示, ListView这个子视图在SwipeRefreshLayout控件节点的内部。
图15 资源文件的替换建议
(2) 无替换建议的例子分析。该例子没有替换建议是因为该例子将下拉刷新的逻辑用一个类封装好,所以在Activity中只保留了更新子视图的逻辑,对于下拉刷新的逻辑则在那个类中进行实现。图16展示了Activity中处理业务逻辑的代码片段。PullRefreshLayout是封装好的类,在Activity中直接创建该类的一个对象,然后绑定相应的监听器来监听动作,在该例子中使用的是setRefreshListener。
图16 无替换建议的实现代码
2) 针对开源应用的支持库替换实验。本部分实验从开源社区上找了五个与安卓支持库触摸控件功能相似的开源安卓应用项目,然后利用本文的方法对这五个安卓应用项目进行替换分析。本实验所选取的开源应用的来源信息如表3所示,最终分析结果如表4所示。
表3 开源项目来源
表4 开源项目实验结果
可以看出,这五个案例中有2个案例有替换建议输出,有3个案例没有替换建议输出。其中能够进行替换的项目均包含与支持库控件相应的,且用基本触控逻辑来实现的事件回调方法。相对地,在三个没有替换建议输出的应用中,有一个是使用了封装好的功能类来实现对应的功能,有两个是直接使用了安卓支持库中的控件。对于将功能封装成一个类的情形,本文给出的方法同样也可以进行分析替换,但这样做的意义不大。由于用户已经将一个功能封装好了,那就没有必要再去用安卓支持库里的控件进行替换,因此本文设计的方法对封装好的功能类是不进行分析的。
6 结 语
本文提出了一种面向安卓触控类支持库的应用代码替换技术。首先设计了一种用于描述安卓事件回调方法中代码特征的元模型,其不仅能够表示支持库中的回调函数,也可以用来描述目标替换代码中的方法代码结构;接着基于安卓支持库的特征模型和目标替换代码的特征模型进行匹配;最后对于可以进行替换的目标代码,设计了一种涵盖功能实现、页面布局的代码替换建议生成方法。
本文方法仍然有一些不足的地方,需要在后续工作中不断完善。第一,目前只是针对安卓触摸类控件进行替换分析,对于支持库中的其他功能目前还无法做到替换分析;第二,本文方法的实现与用户交互的功能还不够完善,后续将对该方法实现进行扩展,增加与用户交互的功能。