1 为什么想调用这个?
目的是想要为一个APP UI自动遍历加一个小的优化,将遍历可视化并记录下便利的路径。
2 怎么做?
首先想到的是画图,类似于流程图一样,从一个页面通过点击哪个按钮到达另一个页面
网上找了下有什么工具可以绘制图片的,然后就找到了graphviz
网上有很多教程的,写这个是为了给自己看看的,记录自己做的事
3 达成的效果如何?
效果图如下:
循环图全景(没有循环完毕)
- 方块 为页面信息:里面展示的事安卓Activity名
- 椭圆 为按钮信息 :里面包括按钮文本内容 和 按钮点击坐标,这里有局限性,APP中有些按钮是没有文本的,单从坐标也是很难看出按钮位置
- 本页面 ->按钮 的连线 表示的是按钮从属于页面。
- 按钮 -> 本页面 的连线 表示 点击该按钮还在本页面,未进行页面跳转
- 按钮 -> 另一个页面 的连线 表示 点击该按钮跳转到另一个页面
- 每一次点击都会有一个表示顺序的数字在该指向线中标出
4 缺陷以及优化点
1)很明显的一点就是,不太美观,遍历一旦复杂就会图片就会臃肿,光看这些图片感觉看不出啥来,但是比起没有总好点
2)不好看的话,就用想办法好看点,就是用颜色来弥补,画面太杂,用颜色好区分,个人感觉
5 怎么实现这个图片绘制的呢?
很简单呀,网上查就好。
啊不,我写这个是为了方便自己的,省得以后要用到了还要从头查起
首先,我查到的是 :
--使用DOT来绘图
思路:写绘制脚本 -> 利用dot,绘制成图
脚本形如:
digraph G { main -> parse -> execute; main -> init; main -> cleanup; execute -> make_string; execute -> printf; init -> make_string; main -> printf; execute -> compare; }
效果图:
:
然后在.dot所在路进行执行:
dot -Tpng G.dot -o g.png
现在发现,其实还没有装graphviz呢,哈哈哈哈
我是Mac,所以来一句安装命令吧
sudo brew install graphviz
简单用法,知道下面几点基本上就够用了:
- 有向图(digraph)用a->b,无向图(graph)用a--b;
- 节点、边通过中括号中的key=value来设置,比如main[shape=box];将main节点设置为矩形;
- 连接点的方向可以通过b->c:se;进行指定;
- 使用subgraph定义子流程图;
但是,我是要把这个写到便利工具中的,一开始的想法,是自己根据这个来封装几个类,然后将运行得到的一连串字符串保存成.dot文件,然后调用
dot -Tpng G.dot -o g.png
就可以绘制成图了,这个想法其实可以的,这样就相当于你能用脚本写出来的,我用代码也能写出来。
不过后来发现其实有相关函数可以调用的:
下面是我自己封装的几个函数
class graphviz_handler(): # _digraph_str_start="digraph pic { " # _digraph_str_context="" # _digraph_str_end="}" dot = Digraph(comment='Test---') #将dot文件转换成png图片 def generate_PNG(self,test_mark): print(self.dot.source) self.dot.render('test-output/'+test_mark+'_result.gv', view=True) #创建当前页面所有元素,对按钮元素进行初始化 def element_init(self,sqlite_base,list): nameList=self.element_handle(self,sqlite_base,list) for elementName in nameList: # self._digraph_str_context += elementName+"[shape=circle,lable="+elementName+"] "; self.dot.node(elementName,elementName) # *实时查看 self.dot.view() # print("%%->"+self._digraph_str_context) #处理下元素,获取元素的名字 def element_handle(self,sqlite_base,list): tmp_list = [] for element in list: e = {'location': element.location, 'size': element.size} tmp_list.append(e) dictList = sqlite_base.get_click_position(tmp_list) strList = [] nameList = [] for d in dictList: strList.append(sqlite_base.position_dict2string(d)) count=0 while(count<len(list)): nameList.append(list[count].text + "(" + strList[count] + ")") count+=1 # return nameList #通过id获取元素的所需要的标志name def get_elementNmaeByID(sqlite_base,id): return sqlite_base.get_elementPositionAndTextByID(sqlite_base,id) #创建当前页面 def cur_page_init(self,pagename): self._digraph_str_context += pagename+"[shape=box,lable = "+pagename+"] " # print("%%->" + self._digraph_str_context) self.dot.node(pagename,pagename,shape="box") # *实时查看 self.dot.view() #创建 页面从属关系 def page_element_connection(self,sqlite_base,page_name,list): self.cur_page_init(self,page_name) self.element_init(self,sqlite_base,list) nameList = self.element_handle(self,sqlite_base,list) for element in nameList: # self._digraph_str_context+= page_name+"--"+element+"[lable='属于'] " # print("%%->**********************" + self._digraph_str_context) self.dot.edge(page_name,element) #*实时查看 self.dot.view() print(page_name + "--" + element) def element_to_page(self,sqlite_base,pagename,elementID,runtimes): # self._digraph_str_context+=pagename+"->"+self.get_elementNmaeByID(sqlite_base,elementID)+" " # print("%%----->" + self._digraph_str_context) self.dot.edge(self.get_elementNmaeByID(sqlite_base,elementID),pagename,label=str(runtimes)) # *实时查看 self.dot.view() print(pagename+"->"+self.get_elementNmaeByID(sqlite_base,elementID)+" 第"+str(runtimes)+"次")
关键几个是:
from graphviz import Digraph
dot = Digraph(comment='Test---')
self.dot.node(pagename,pagename,shape="box")//节点连接
self.dot.render('test-output/'+test_mark+'_result.gv', view=True)//生成图片具体可以看此链接https://blog.csdn.net/a1368783069/article/details/52067404
然后只要把相关函数放到工具里的合适地方就好了
----------------------------------------------------------
那么问题来了,之前一直运行的好好的,后来我不知道搞了什么,就~就~
graphviz.backend.ExecutableNotFound: failed to execute ['dot', '-Tpdf', '-O', 'test-output/Android_1529386737_result.gv'], make sure the Graphviz executables are on your systems' PATH
哇,伤心!
然后这个问题还没解决。