本发明涉及计算机应用程序维护技术,更具体地,涉及对应用程序进行打点的方法和系统。
背景技术:
在android开发过程中,应用程序为了定位各个功能点的使用情况以及对用户的使用行为进行分析,一般需要在应用程序当中添加打点事件,比如用户点击了某个按钮的频率等等。
但是随着产品的更新迭代,需要添加的打点位置越来越多,同时打点的代码也越来越多,如果还是按照传统思路,代码在维护以及修改上会越来越困难,不仅增加了开发人员的工作量,还对代码的稳健性增加了隐患。因此,如何有效的解决这个问题,就成了迫在眉睫的事情。
技术实现要素:
本发明提供一种克服上述问题或者至少部分地解决上述问题的对应用程序进行打点的方法和系统。
根据本发明的一个方面,提供一种对应用程序进行打点的方法,包括:
s1、在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配;以及
s2、对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
根据本发明的另一个方面,提供一种对应用程序进行打点的系统,包括:
匹配模块,用于在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配;以及
打点模块,用于对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
本申请提出一种对应用程序进行打点的方法和系统,依靠预编译技术,在应用程序的编译期间修改字节码文件,能够动态批量添加打点函数,从而保证业务逻辑的开发人员无需在代码中手动添加打点函数,并且通过创建包含打点相关信息的打点文件,使得开发人员只需要维护一个打点文件,减少了开发人员的工作量以及程序的bug率,同时还减少后期的维护代码的风险。
附图说明
图1为根据本发明实施例的一种对应用程序进行打点的方法的流程示意图;
图2为根据本发明实施例的步骤s1的流程示意图;
图3为根据本发明实施例的步骤s1.2的流程示意图;
图4为根据本发明实施例的一种对应用程序进行打点的系统的结构框图;
图5为根据本发明实施例的另一种对应用程序进行打点的系统的结构框图。
具体实施方式
下面结合附图和实施例,对本发明的具体实施方式作进一步详细描述。以下实施例用于说明本发明,但不用来限制本发明的范围。
为了克服现有技术中,随着产品的更新迭代,需要添加的打点位置以及打点函数逐渐增多,带来的打点函数在维护以及修改上会越来越困难的问题,本发明提供了一种对应用程序进行打点的方法。
图1示出了本发明实施例的一种对应用程序进行打点的方法的流程示意图,本方法包括:
s1、在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配。在android平台,class文件会进一步优化成一个或者多个dex文件,dex即dalvikvmexecutes,是androiddalvik执行程序,由于生成dex文件后无法再对其进行代码级别的修改,所以需要在将class文件转换到dex文件这个时间段(即编译期)插入打点函数。
s2、对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
本申请提出一种对应用程序进行打点的方法和系统,依靠预编译技术,在应用程序的编译期间修改字节码文件,能够动态批量添加打点函数,从而保证业务逻辑的开发人员无需在代码中手动添加打点函数,并且通过创建包含打点相关信息的打点文件,使得开发人员只需要维护一个打点文件,减少了开发人员的工作量以及程序的bug率,同时还减少后期的维护代码的风险。
在一个可选实施例中,步骤s1之前还包括:
s0、创建打点文件,所述打点文件中包含一定数量的需要打点的打点类的信息、每个打点类中需要打点的函数的信息以及对每个需要打点的函数进行打点的打点函数的信息。
java语言中所有的java类,在编译时首先会生成字节码文件,即class文件,字节码文件主要为了实现特定软件运行,在本发明,特定软件指的就是打点程序。显然,为了在应用程序进行打点(也就是插入打点函数),应该在字节码文件中打点。
打点类即为字节码文件对应的java类,需要打点的函数指的是对该函数进行打点,即写入字节码,打点函数指的是需要写入的函数。例如,对dbhelper类的init()函数添加dotdbinit()函数,dbhelper类即为打点类,init()函数即需要打点的函数,加dotdbinit()函数即打点函数。
在一个可选实施例中,步骤s0和s1之间还包括:
获取所有字节码文件的路径以及所有字节码文件。只有获取字节码文件的路径才能够对字节码文件进行操作。
图2示出了根据本发明实施例的步骤s1的流程示意图,步骤s1包括:
s1.1、在应用程序编译期,遍历所有字节码文件,将字节码文件对应的类的信息与打点文件中所有打点类的信息进行第一次匹配。
选取一个字节码文件,根据字节码文件对应的类的信息与打点文件中打点类的信息进行第一次匹配,匹配成功,则说明该字节码文件需要进行打点操作,如果没有匹配成功,则说明该字节码文件不需要进行打点操作。
s1.2、若第一次匹配成功,则获取并遍历该字节码文件中所有的函数,将该字节码文件中函数的信息与打点文件中需要打点的函数的信息进行第二次匹配。
获取第一次匹配成功的字节码文件的所有函数,将这些函数的信息与打点文件中需要打点的函数的信息进行匹配,如果匹配成功,则说明该函数需要进行打点操作,如果没有匹配成功,则说明该函数不需要进行打点操作,随后寻找下一个函数与打点文件中需要打点的函数信息进行匹配,同理,直至该字节码文件中所有的函数都完成匹配操作。
在一个可选实施例中,步骤s1.2还包括:
若第一次匹配不成功,则选择未进行第一次匹配操作的字节码文件,将该未进行匹配操作的字节码文件对应的类的信息与打点文件中所有打点类的信息进行匹配。这里所说的未进行第一次匹配操作的字节码文件,指的是针对本次进行打点的操作中未进行第一次匹配操作的字节码文件。
在一个可选实施例中,步骤s1.2还包括:
若第二次匹配不成功,则将该字节码文件中未进行第二次匹配操作的函数的信息与打点文件中需要打点的函数的信息进行第二次匹配。这里所说的未进行第二次匹配操作的函数,指的是针对本次进行打点的操作中未进行第二次匹配操作的函数。
因为java中的函数有重载的可能性,同一个名字可能对应着多个函数,函数不止包括了函数名,还包括参数个数、参数类型和返回值,其中函数签名由参数个数和参数类型组成,函数在重载时,可以利用函数签名的不同(即参数个数与类型的不同)来区别调用者到底调用的是哪个函数,因此,在一个可选实施例中,需要打点的函数的信息包括该函数的名称和签名,打点函数的信息包括该打点函数的名称和签名。
图3示出了根据本发明实施例的步骤s1.2的流程示意图,步骤s1.2进一步包括:
s1.2.1、若第一次匹配成功,则获取并遍历该字节码文件中所有的函数,将该字节码文件中的每个函数的名称与打点文件中需要打点的函数的名称进行第二次匹配;以及
s1.2.2、若第二次匹配成功,则字节码中匹配成功的函数的签名与打点文件中匹配成功的需要打点的函数的签名进行第三次匹配。
java中常采用的预编译技术是通过注解处理器对应用程序进行预编译,但是在本发明中,如果通过注解处理器来实现,代码中需要加入相应的注解代码,其实还是对业务开发人员的代码有所改动,没有从本质上改变问题。
在一个可选实施例中,本发明基于java的字节码写入技术,将对应的打点函数写入至第二次匹配成功的函数的前面。
为了更清楚地阐述本发明的设计思路,下面结合具体实施例对本发明进行描述。
实现一个gradle脚本以hook住android系统应用程序的编译期,所谓的hook即为钩,是计算机领域的常用术语,hook住编译期需要创建androidgradle的transform抽象类,并创建transform抽象类中的transform方法,gradle脚本中提供directoryinput变量用来获取所有的class文件,通过类路径directoryinput.file.absolutepath获取所有的class文件的路径。
把应用程序中需要打点的位置都写到一个文件中,该文件命名为dot.txt,该文件的格式并不局限于txt文件,只需定义一个格式方便读取即可。dot.txt需要写入的信息是:需要打点的打点类的信息、每个打点类中需要打点的函数的信息以及对每个需要打点的函数进行打点的打点函数的信息,也就是说,后续的版本更新,开发人员只需要维护这个dot.txt文件的更新就能完成打点的功能。
在gradle的脚本中创建一个文件读取器,以读取该dot.txt文件,gradle中读取文件的类是file,通过file类将dot.txt文件加载,然后通过调用其read方法获取dot.txt文件的内容。
将获取dot.txt文件的内容保持至dotmodel类中,dotmodel类用来表示一个打点类的基本单元,dotmodel类包括:
字段clazz,用来存储打点类;
methods字段,methods字段是一个列表,用来存储所有需要打点的函数;以及
字段dotfuns,用来存储所有需要调用的打点函数。
比如对类dbhelper类的init()函数添加打点函数dotdbinit(),那么clazz对应就是dbhelper类的全称,methods是一个列表,其每一项存储一个函数的标识符,所以这里需要存储函数的名字和函数的签名,即对应存储的就是init这个函数名称和签名v(),同理,dotfuns是一个列表,其每一项存储的数据与methods类似,是需要调用的打点函数的名称和函数签名)这里就能很方便的是后续进行代码的判断与写入。
接下来我们利用java的字节码写入技术进行打点,字节码的注入可以使用java的javassist类库,javassist类库提供了大量字节码注入的方法具体包括:
通过类路径directoryinput.file.absolutepath对所有class文件进行遍历,与读取dot.txt文件获得的所有打点类进行匹配;
若匹配成功,调用javassist类库的getctclass方法将class文件对应的类通过javassist打开;
getctclass方法返回一个ctclass对象,ctclass对象用于调用其getmethods()方法获取该class文件所有的方法,getmethods()方法返回ctmethod对象的数组,然后遍历该数组获取所有的方法对象ctmethod;
调用ctmethod对象的getname方法,与获取的需要打点的函数的名称进行匹配,如果名称正确,再调用ctmethod对象的getsignature方法获取函数的签名,并与dot.txt文件中的需要打点的函数的签名进行匹配;
如果匹配成功,表明当前的函数需要添加打点,ctmethod对象具有insertbefore()语句以在一个函数前面添加代码,只需要将dot.txt文件读取到的打点函数添加进去就行,然后依次遍历,直到将所有的打点函数添加完成。
图4示出了本发明实施例提供的一种对应用程序进行打点的系统的结构框图,该系统包括:
匹配模块,用于在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配;以及
打点模块,用于对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
在一个实施例中,该系统还包括:打点文件模块,用于创建打点文件,所述打点文件中包含一定数量的需要打点的打点类的信息、每个打点类中需要打点的函数的信息以及对每个需要打点的函数进行打点的打点函数的信息。
图5示出了本发明实施例的另一个对应用程序进行打点的系统的结构框图,包括:
打点文件模块,用于创建打点文件,所述打点文件中包含一定数量的需要打点的打点类的信息、每个打点类中需要打点的函数的信息以及对每个需要打点的函数进行打点的打点函数的信息;
字节码文件获取模块,用于获取所有字节码文件的路径以及所有字节码文件;
匹配模块,用于在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配;以及
打点模块,用于对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
在一个可选实施例中,匹配模块进一步包括:
第一次匹配模块,用于在应用程序编译期,遍历所有字节码文件,将字节码文件对应的类的信息与打点文件中所有打点类的信息进行第一次匹配;以及
第二次匹配模块,用于在第一次匹配成功时,获取并遍历该字节码文件中所有的函数,将该字节码文件中函数的信息与打点文件中需要打点的函数的信息进行第二次匹配。
在一个可选实施例中,第二匹配模块还用于:在第一次匹配不成功时,选择未进行第一次匹配操作的字节码文件,将该未进行匹配操作的字节码文件对应的类的信息与打点文件中所有打点类的信息进行匹配。
在一个可选实施例中,第二匹配模块还用于:在第二次匹配不成功时,将该字节码文件中未进行第二次匹配操作的函数的信息与打点文件中需要打点的函数的信息进行第二次匹配。
在一个可选实施例中,需要打点的函数的信息包括该函数的名称和签名,所述打点函数的信息包括该打点函数的名称和签名。
在一个可选实施例中,第二匹配模块包括:
第一匹配单元,用于在第一次匹配成功时,获取并遍历该字节码文件中所有的函数,将该字节码文件中的每个函数的名称与打点文件中需要打点的函数的名称进行第二次匹配;以及
第二匹配单元,在第二次匹配成功时,则字节码中匹配成功的函数的签名与打点文件中匹配成功的需要打点的函数的签名进行第三次匹配。
在一个可选实施例中,本发明公开一种计算机程序产品,所述计算机程序产品包括存储在非暂态计算机可读存储介质上的计算机程序,所述计算机程序包括程序指令,当所述程序指令被计算机执行时,计算机能够执行上述各方法实施例所提供的方法,例如包括:
s1、在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配;以及
s2、对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
在一个可选实施例中,本发明公开了一种非暂态计算机可读存储介质,所述非暂态计算机可读存储介质存储计算机指令,所述计算机指令使所述计算机执行上述各方法实施例所提供的方法,例如包括:
s1、在应用程序编译期,遍历所有字节码文件,将字节码文件依次与打点文件中的打点类的信息和需要打点的函数的信息进行匹配;以及
s2、对匹配成功的字节码文件中的函数,调用对应的打点函数进行打点。
最后,本申请的函数仅为较佳的实施方案,并非用于限定本发明的保护范围。凡在本发明的精神和原则之内,所作的任何修改、等同替换、改进等,均应包含在本发明的保护范围之内。