blogjava-凯发k8网页登录

blogjava-凯发k8网页登录http://www.blogjava.net/qileilove/category/52522.htmlblog已经转移至github,大家请访问qileizhaokan.github.iozh-cnwed, 18 mar 2015 14:38:58 gmtwed, 18 mar 2015 14:38:58 gmt60利用drozer进行android渗透测试http://www.blogjava.net/qileilove/archive/2015/03/18/423597.html顺其自然evo顺其自然evowed, 18 mar 2015 14:06:00 gmthttp://www.blogjava.net/qileilove/archive/2015/03/18/423597.htmlhttp://www.blogjava.net/qileilove/comments/423597.htmlhttp://www.blogjava.net/qileilove/archive/2015/03/18/423597.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/423597.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/423597.html 一、安装与启动
  1. 安装
  第一步:从http://mwr.to/drozer下载drozer ( installer)
  第二步:在设备中安装agent.apk
  adb install agent.apk
  2. 启动
  第一步:在pc上使用adb进行端口转发,转发到drozer使用的端口31415
  adb forward tcp:31415 tcp:31415
  第二步:在android设备上开启drozer agent
  选择embedded server-enable
  第三步:在pc上开启drozer console
  drozer console connect
  二、步骤
  1.获取包名
  dz> run app.package.list -f sieve
  com.mwr.example.sieve
  2.获取应用的基本信息
  run app.package.info -a com.mwr.example.sieve
  3.确定攻击面
  run app.package.attacksurface com.mwr.example.sieve
  4.activity
  (1)获取activity信息
  run app.activity.info -a com.mwr.example.sieve
  (2)启动activity
  run app.activity.start --component com.mwr.example.sieve
  dz> help app.activity.start
  usage: run app.activity.start [-h] [--action action] [--category category]
  [--component package component] [--data-uri data_uri]
  [--extra type key value] [--flags flags [flags ...]]
  [--mimetype mimetype]
  5.content provider
  (1)获取content provider信息
  run app.provider.info -a com.mwr.example.sieve
  (2)content providers(数据泄露)
  先获取所有可以访问的uri:
  run scanner.provider.finduris -a com.mwr.example.sieve
  获取各个uri的数据:
  run app.provider.query
  content://com.mwr.example.sieve.dbcontentprovider/passwords/ --vertical
  查询到数据说明存在漏洞
  (3)content providers(注入)
  run app.provider.query content://com.mwr.example.sieve.dbcontentprovider/passwords/ --projection "'"
  run app.provider.query content://com.mwr.example.sieve.dbcontentprovider/passwords/ --selection "'"
  报错则说明存在sql注入。
  列出所有表:
  run app.provider.query content://com.mwr.example.sieve.dbcontentprovider/passwords/ --projection "* from sqlite_master where type='table';--"
  获取某个表(如key)中的数据:
  run app.provider.query content://com.mwr.example.sieve.dbcontentprovider/passwords/ --projection "* from key;--"
  (4)同时检测sql注入和目录遍历
  run scanner.provider.injection -a com.mwr.example.sieve
  run scanner.provider.traversal -a com.mwr.example.sieve
  6 intent组件触发(拒绝服务、权限提升)
  利用intent对组件的触发一般有两类漏洞,一类是拒绝服务,一类的权限提升。拒绝服务危害性比较低,更多的只是影响应用服务质量;而权限提升将使得没有该权限的应用可以通过intent触发拥有该权限的应用,从而帮助其完成越权行为。
  1.查看暴露的广播组件信息:
  run app.broadcast.info -a com.package.name  获取broadcast receivers信息
  run app.broadcast.send --component 包名 --action android.intent.action.xxx
  2.尝试拒绝服务攻击检测,向广播组件发送不完整intent(空action或空extras):
  run app.broadcast.send 通过intent发送broadcast receiver
  (1)   空action
  run app.broadcast.send --component 包名 receivername
  run app.broadcast.send --component 包名 receivername
  (2)   空extras
  run app.broadcast.send --action android.intent.action.xxx
  3.尝试权限提升
  权限提升其实和拒绝服务很类似,只不过目的变成构造更为完整、更能满足程序逻辑的intent。由于activity一般多于用户交互有关,所以基 于intent的权限提升更多针对broadcast receiver和service。与drozer相关的权限提升工具,可以参考intentfuzzer,其结合了drozer以及hook技术,采用 feedback策略进行fuzzing。以下仅仅列举drozer发送intent的命令:
  (1)获取service详情
  run app.service.info -a com.mwr.example.sieve
  不使用drozer启动service
  am startservice –n 包名/service名
  (2)权限提升
  run app.service.start --action com.test.vulnerability.send_sms --extra string dest 11111 --extra string text 1111 --extra string op send_sms
  7.文件操作
  列出指定文件路径里全局可写/可读的文件
  run scanner.misc.writablefiles --privileged /data/data/com.sina.weibo
  run scanner.misc.readablefiles --privileged /data/data/com.sina.weibo
  run app.broadcast.send --component 包名 --action android.intent.action.xxx
  8.其它模块
  shell.start 在设备上开启一个交互shell
  tools.file.upload / tools.file.download 上传/下载文件到设备
  tools.setup.busybox / tools.setup.minimalsu 安装可用的二进制文件


顺其自然evo 2015-03-18 22:06 发表评论
]]>
appium android bootstrap之控件androidelementhttp://www.blogjava.net/qileilove/archive/2014/12/23/421669.html顺其自然evo顺其自然evomon, 22 dec 2014 16:26:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421669.htmlhttp://www.blogjava.net/qileilove/comments/421669.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421669.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421669.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421669.htmlandroidelementhash的这个getelement命令要做的事情就是针对这两点来根据不同情况获得目标控件
/**
* return an elements child given the key (context id), or uses the selector
* to get the element.
*
* @param sel
* @param key
*          element id.
* @return {@link androidelement}
* @throws elementnotfoundexception
*/
public androidelement getelement(final uiselector sel, final string key)
throws elementnotfoundexception {
androidelement baseel;
baseel = elements.get(key);
uiobject el;
if (baseel == null) {
el = new uiobject(sel);
} else {
try {
el = baseel.getchild(sel);
} catch (final uiobjectnotfoundexception e) {
throw new elementnotfoundexception();
}
}
if (el.exists()) {
return addelement(el);
} else {
throw new elementnotfoundexception();
}
}
  如果是第1种情况就直接通过选择子构建uiobject对象,然后通过addelement把uiobject对象转换成androidelement对象保存到控件哈希表
  如果是第2种情况就先根据appium传过来的控件哈希表键值获得父控件,再通过子控件的选择子在父控件的基础上查找到目标uiobject控件,最后跟上面一样把该控件通过上面的addelement把uiobject控件转换成androidelement控件对象保存到控件哈希表
  4. 求证
  上面有提过,如果pc端的脚本执行对同一个控件的两次findelement会创建两个不同id的androidelement并存放到控件哈希表中,那么为什么appium的团队没有做一个增强,增加一个keymap的方法(算法)和一些额外的信息来让同一个控件使用不同的key的时候对应的还是同一个androidelement控件呢?毕竟这才是哈希表实用的特性之一了,不然你直接用一个dictionary不就完事了?网上说了几点hashtable和dictionary的差别,如多线程环境最好使用哈希表而非字典等,但在bootstrap这个控件哈希表的情况下我不是很信服这些说法,有谁清楚的还劳烦指点一二了
  这里至于为什么appium不去提供额外的key信息并且实现keymap算法,我个人倒是认为有如下原因:
  有谁这么无聊在同一个测试方法中对同一个控件查找两次?
  如果同一个控件运用不同的选择子查找两次的话,因为最终底层的uiobject的成员变量uiselector mselector不一样,所以确实可以认为是不同的控件
  但以下两个如果用同样的uiselector选择子来查找控件的情况我就解析不了了,毕竟在我看来bootstrap这边应该把它们看成是同一个对象的:
  同一个脚本不同的方法中分别对同一控件用同样的uiselelctor选择子进行查找呢?
  不同脚本中呢?
  这些也许在今后深入了解中得到解决,但看家如果知道的,还望不吝赐教
  5. 小结
  最后我们对bootstrap的控件相关知识点做一个总结
  androidelement的一个实例代表了一个bootstrap的控件
  androidelement控件的成员变量uiobject el代表了uiautomator框架中的一个真实窗口控件,通过它就可以直接透过uiautomator框架对控件进行实质性操作
  pc端的webelement元素和bootstrap的androidelement控件是通过androidelement控件的string id进行映射关联的
  androidelementhash类维护了一个以androidelement的id为键值,以androidelement的实例为value的全局唯一哈希表,pc端想要获得一个控件的时候会先从这个哈希表查找,如果没有了再创建新的androidelement控件并加入到该哈希表中,所以该哈希表中维护的是一个当前已经使用过的控件
相关文章:
appium android bootstrap源码分析之简介
 通过上一篇《  源码分析之简介》我们对bootstrap的定义以及其在appium和uiautomator处于一个什么样的位置有了一个初步的了解,那么按照正常的写书的思路,下一个章节应该就要去看bootstrap是如何建立socket来获取数据然后怎样进行处理的了。但本人觉得这样子做并不会太好,因为到时整篇文章会变得非常的冗长,因为你在编写的过程中碰到不认识的类又要跳入进去进行说明分析。这里我觉得应该尝试吸取著名的《重构》这本书的建议:一个方法的代码不要写得太长,不然可读性会很差,尽量把其分解成不同的函数。那我们这里就是用类似的思想,不要尝试在一个文章中把所有的事情都做完,而是尝试先把关键的类给描述清楚,最后才去把这些类通过一个实例分析给串起来呈现给读者,这样大家就不会因为一个文章太长影响可读性而放弃往下了。
  那么我们这里为什么先说bootstrap对控件的处理,而非刚才提到的socket相关的socket服务器的建立呢?我是这样子看待的,大家看到本人这篇文章的时候,很有可能之前已经了解过本人针对uiautomator源码分析那个系列的文章了,或者已经有uiautomator的相关知识,所以脑袋里会比较迫切的想知道究竟appium是怎么运用了uiautomator的,那么在appium中于这个问题最贴切的就是appium在服务器端是怎么使用了uiautomator的控件的。
  这里我们主要会分析两个类:
  :代表了bootstrap持有的一个ui界面的控件的类,它拥有一个uiobject成员对象和一个代表其在下面的哈希表的键值的string类型成员变量id
  androidelementshash:持有了一个包含所有bootstrap(也就是appium)曾经见到过的(也就是脚本代码中findelement方法找到过的)控件的哈希表,它的key就是androidelement中的id,每当appium通过findelement找到一个新控件这个id就会+1,appium的pc端和bootstrap端都会持有这个控件的id键值,当需要调用一个控件的方法时就需要把代表这个控件的id键值传过来让bootstrap可以从这个哈希表找到对应的控件
  1. androidelement和uiobject的组合关系
  从上面的描述我们可以知道,androidelement这个类里面拥有一个uiobject这个变量:
  public class androidelement {
  private final uiobject el;
  private string         id;
  ...
  }
  大家都知道uiobject其实就是uiautomator里面代表一个控件的类,通过它就能够对控件进行操作(当然最终还是通过uiautomation框架). anroidelement就是通过它来跟uiautomator发生关系的。我们可以看到下面的androidelement的点击click方法其实就是很干脆的调用了uiobject的click方法:
  public boolean click() throws uiobjectnotfoundexception {
  return el.click();
  }
  当然这里除了click还有很多控件相关的操作,比如dragto,gettext,longclick等,但无一例外,都是通过uiobject来实现的,这里就不一一列举了。
  2. 脚本的webelement和bootstrap的androidelement的映射关系
  我们在脚本上对控件的认识就是一个webelement:
  webelement addnote =  driver.findelementbyandroiduiautomator("new uiselector().text(\"add note\")");
  而在bootstrap中一个对象就是一个androidelement. 那么它们是怎么映射到一起的呢?我们其实可以先看如下的代码:
  webelement addnote = driver.findelementbyandroiduiautomator("new uiselector().text(\"add note\")");
  addnote.gettext();
  addnote.click();
  做的事情就是获得notes这个app的菜单,然后调用控件的gettext来获得‘add note'控件的文本信息,以及通过控件的click方法来点击该控件。那么我们看下调试信息是怎样的:


顺其自然evo 2014-12-23 00:26 发表评论
]]>
appium android bootstrap源码分析之命令解析执行http://www.blogjava.net/qileilove/archive/2014/12/23/421668.html顺其自然evo顺其自然evomon, 22 dec 2014 16:25:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421668.htmlhttp://www.blogjava.net/qileilove/comments/421668.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421668.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421668.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421668.html通过上一篇《  源码分析之控件androidelement》我们知道了appium从pc端发送过来的命令如果是控件相关的话,最终目标控件在bootstrap中是以androidelement对象的方式呈现出来的,并且该控件对象会在androidelementhash维护的控件哈希表中保存起来。但是appium触发一个命令除了需要提供是否与控件相关这个信息外,还需要其他的一些信息,比如,这个是什么命令?这个就是我们这篇文章需要讨论的话题了。
  下面我们还是先看一下从pc端发过来的json的格式是怎么样的:
  可以看到里面除了params指定的是哪一个控件之外,还指定了另外两个信息:
  cmd: 这是一个action还是一个shutdown
  action:如果是一个action的话,那么是什么action
  开始前我们先简要描述下我们需要涉及到几个关键类:


顺其自然evo 2014-12-23 00:25 发表评论
]]>
fliptest—ios 的应用a/b测试框架http://www.blogjava.net/qileilove/archive/2014/12/23/421666.html顺其自然evo顺其自然evomon, 22 dec 2014 16:22:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421666.htmlhttp://www.blogjava.net/qileilove/comments/421666.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421666.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421666.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421666.html
 fliptest是专为ios设计的应用a/b测试框架,通过它,开发者可以无需重新向app store提交应用或重构代码,只需添加一行代码,即可直接在ios应用上进行a/b测试。对移动应用做 a/b 是非常难的,而 fliptest 可以帮你简化这个过程。
  对于想要追求ui极致的开发者而言,fliptest绝对是最合适的。fliptest会为应用选择最恰当的用户界面,还会基于外观、可用性等众多因素返还测试结果,从而帮助开发者彻底解决ui问题。


顺其自然evo 2014-12-23 00:22 发表评论
]]>
ios功能测试工具 frankhttp://www.blogjava.net/qileilove/archive/2014/12/23/421667.html顺其自然evo顺其自然evomon, 22 dec 2014 16:22:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421667.htmlhttp://www.blogjava.net/qileilove/comments/421667.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421667.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421667.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421667.html  也是一款深受开发者喜爱的应用框架,该框架可以模拟用户操作对应用程序进行,并使用cucumber作为自然语言来编写。此外,frank还会对应用测试操作进行记录,以帮助开发者进行测试回顾。
  一、基本介绍
  frank是ios开发环境下一款实现自动测试的工具。
  xcode环境下开发完成后,通过frank实现结构化的测试用例,其底层语言为。作为一款开源的ios测试工具,在国外已经有广泛的应用。但是国内相关资料却比较少。其最大的优点是允许我们用熟悉的自然语言实现实际的操作逻辑。
  一般而言,测试文件由一个.feature文件和一个.rb文件组成。.feature文件包含的是测试操作的自然语言描述部分,内部可以包含多个测试用例,以标签(@tagname)的形式唯一标识,每个用例的首行必须有scenario: some description;.rb文件则是ruby实现逻辑,通过正则表达式匹配.feature文件中的每一句自然语言,然后执行相应的逻辑操作,最终实现自动测试的目的。
  二、安装
  1.       terminal 输入sudo gem install frank-cucumber,下载并安装frank
  2.       terminal 进入工程所在路径,工程根目录
  3.       输入:frank-skeleton,会在工程根目录新建frank文件夹
  4.       返回xcode界面,右键targets下的app,选择复制,duplicate only
  5.       双击appname copy,更改副本名,例如 appname frankified
  6.       右击app,add files to appname……
  7.       勾选副本,其余取消选定。选择新建的frank文件夹,add.
  8.       选择app,中间部分build phases选项卡,link binary with librariesàcfnetwork.framework,add.
  9.       依旧中间部分,选择build settings选项卡,other linker flags,双击,添加“-all_load”和“objc”
  10.   左上角,scheme selector,在run和stop按钮的右边,选择appname copy-iphone
  11.   浏览器中打开http://localhost:37265,可以在浏览器中看到植入frank的应用
  我在添加了两个flag之后老是报错,尝试了n种方法之后索性全部删掉,结果就可以了,无语
  三、基本步骤
  1.       terminal 切换到frank文件夹所在目录
  2.       frank launch, 打开simulator,开始运行(默认是用iphone simulator,要用ipad simulator时,需要如下命令行,添加参数:frank launch --idiom ipad)
  3.       cucumber frank/features/my_first.feature --tags @tagname (注意tags前面两个‘-’)ps:如果没有tag则自动运行文件中所有case


顺其自然evo 2014-12-23 00:22 发表评论
]]>
移动应用测试框架—appgrader(android)http://www.blogjava.net/qileilove/archive/2014/12/23/421664.html顺其自然evo顺其自然evomon, 22 dec 2014 16:20:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421664.htmlhttp://www.blogjava.net/qileilove/comments/421664.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421664.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421664.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421664.html  是来自以色列的应用服务商utest推出的一款测试产品。相比其他主流框架,appgrader可能并不太为开发者所熟知,但它却能够为众多的开发者提供非常专业的意见参考。
  通过appgrader,开发者可以将自己所开发的应用与其他同类应用就图形、功能及其他方面进行比较,从而对应用进行改善。据悉,继appgrader for android之后,utest还将推出appgrader for ios。


顺其自然evo 2014-12-23 00:20
]]>
移动应用测试框架—cedar(ios)http://www.blogjava.net/qileilove/archive/2014/12/23/421663.html顺其自然evo顺其自然evomon, 22 dec 2014 16:19:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421663.htmlhttp://www.blogjava.net/qileilove/comments/421663.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421663.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421663.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421663.html 和kiwi一样,cedar也是一款bdd风格的objective-c测试框架。它不仅适用于ios和os x代码库,而且在其他环境下也可以使用。
  kiwi、specta、expecta以及cedar都可以通过cocoapods添加到你的项目中。


顺其自然evo 2014-12-23 00:19
]]>
ios应用功能测试框架 kif概述http://www.blogjava.net/qileilove/archive/2014/12/23/421661.html顺其自然evo顺其自然evomon, 22 dec 2014 16:17:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421661.htmlhttp://www.blogjava.net/qileilove/comments/421661.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421661.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421661.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421661.html的全称是keep it functional,来自square,是一款专为ios设计的应用框架。由于kif是使用objective-c语言编写的,因此,对于ios开发者而言,用起来要更得心应手,可以称得上是一款非常值得收藏的ios测试利器。
  kif最酷的地方是它是一个开源的项目,且有许多新功能还在不断开发中。例如下一个版本将会提供截屏的功能并且能够保存下来。这意味着当你跑完测试之后,可以在你空闲时通过截图来查看整个过程中的关键点。难道这不是比鼠标移动上去并用肉眼观察kif点击和拖动整个过程好上千倍万倍么?kif变得越来越好了,所以如何使用它,对于自己来说是一个很好的投资。
  由于kif测试用例是继承了ocunit,并使用了标准的xcode5测试框架,你可以使用持续集成来跑这个测试。当你在忙着别的事情的时候,就拥有了一个能够像人的手指一样准点触控的机器人去测试你的应用程序。太棒了!


顺其自然evo 2014-12-23 00:17
]]>
android单元测试框架 robolectrichttp://www.blogjava.net/qileilove/archive/2014/12/23/421657.html顺其自然evo顺其自然evomon, 22 dec 2014 16:08:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/23/421657.htmlhttp://www.blogjava.net/qileilove/comments/421657.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/23/421657.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421657.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421657.html 开发者们注意了,这款框架一定会让你们兴奋不已,因为它是一款已基本上摆脱了模拟器测试的老套路的速率。可以解压android sdk,还能直接对应用进行测试,从而帮你轻而易举地解决所遇到的任何问题。
  robolectric 是一款android单元测试框架,示例代码:
@runwith(robolectrictestrunner.class)
public class myactivitytest {
@test
public void clickingbutton_shouldchangeresultsviewtext() throws exception {
activity activity = robolectric.buildactivity(myactivity.class).create().get();
button pressmebutton = (button) activity.findviewbyid(r.id.press_me_button);
textview results = (textview) activity.findviewbyid(r.id.results_text_view);
pressmebutton.performclick();
string resultstext = results.gettext().tostring();
assertthat(resultstext, equalto("testing android rocks!"));
}
}


顺其自然evo 2014-12-23 00:08
]]>
如何设计android app测试用例http://www.blogjava.net/qileilove/archive/2014/12/22/421640.html顺其自然evo顺其自然evomon, 22 dec 2014 15:23:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/22/421640.htmlhttp://www.blogjava.net/qileilove/comments/421640.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/22/421640.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421640.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421640.html 在当今竞争激烈的市场上一个app的成功离不开一个可靠的用户界面(ui)。因此,对功能和用户体验有一些特殊关注和照顾的ui的全面是必不可少的。当涉及到安卓平台及其提出的独特问题的数量(安卓就ui提出显著挑战)时,挑战变得更加复杂。关键字“碎片化”象征着应用全面测试的最大障碍,还表明了发布到市场上的所有形态、大小、配置类型的安卓设备所引起的困难。本文将介绍安卓模拟器如何能通过使用一些技巧和简单的实践提供覆盖大量设备类型的广泛测试。
  简介—分散装置里的测试
  一般安卓开发者在其日常中面临的最大挑战之一是:终端设备和版本的范围太广。opensignal进行的一项研究表明,2013年7月市场上有超过11,828的不同安卓终端设备,所有设备在类型/大小/屏幕分辨率以及特定配置方面有所不同。考虑到前一年的调查仅记录有3,997款不同设备,这实在是一个越来越大的挑战障碍。
 
 图1.11,828 款安卓设备类型( opensignal研究, 2013年7月[ 1 ] )分布
  从一个移动app开发角度出发,定义终端设备有四个基本特征:
  1.操作系统:由“api指标”( 1 ?18 )专业定义的安卓操作系统版本( 1.1? 4.3 ),。
  2.显示器:屏幕主要是由屏幕分辨率(以像素为单位),屏幕像素密度( 以dpi为单位),和/或屏幕尺寸(以英寸为单位)定义的。
  3.cpu:该“应用程序二进制接口” (abi )定义cpu的指令集。这里的主要区别是arm和基于intel的cpu。
  4.内存:一个设备包括内存储器( ram)和dalvik 虚拟存储器( vm堆)的预定义的堆内存。
  这是前两个特点,操作系统和显示器,都需要特别注意,因为他们是直接由最终用户明显感受,且应该不断严格地被测试覆盖。至于安卓的版本, 2013年7月市场上有八个同时运行导致不可避免的碎片的不同版本。七月,近90%这些设备中的34.1 %正在运行gingerbread版本( 2.3.3-2.3.7 ),32.3 %正在运行jelly bean( 4.1.x版),23.3 %正在运行ice cream sandwich( 4.0.3 - 4.0.4 )。
  
图2.16款安卓版本分布(opensignal研究,2013年7月[1])
  考虑设备显示器,一项techcrunch从2013年4月进行的研究显示,绝大多数(79.9%)有效设备正在使用尺寸为3和4.5英寸的“正常”屏幕。这些设备的屏幕密度在“mdpi”(160 dpi),“hdpi”(240 dpi)和“xhdpi”(320 dpi)之间变化。也有例外, 一种只占9.5%的设备屏幕密度低“hdpi”(120 dpi)且屏幕小。
  
图3. 常见的屏幕尺寸和密度的分布(研究,2013年4月)[2]
  如果这种多样性在质量保证过程中被忽略了,那么绝对可以预见:bugs会潜入应用程序,然后是bug报告的风暴,最后 play store中出现负面用户评论。因此,目前的问题是:你怎么使用合理水平的测试工作切实解决这一挑战?定义及一个伴随测试过程是一个应付这一挑战的有效武器。
  用例—“在哪测试”、“测试什么”、“怎么测试”、“何时测试”?
  “在哪测试”
  为了节省你测试工作上所花的昂贵时间,我们建议首先要减少之前所提到的32个安卓版本组合及代表市场上在用的领先设备屏的5-10个版本的显示屏。选择参考设备时,你应该确保覆盖了足够广范围的版本和屏幕类型。作为参考,您可以使用opensignal的调查或使用检测的信息图[3],来帮助选择使用最广的设备。

  为了满足好奇心,可以从安卓文件[5]将屏幕的尺寸和分辨率映射到上面数据的密度(“ldpi”,“mdpi”等)及分辨率(“小的”,“标准的”,等等)上。
  
图4.多样性及分布很高的安卓终端设备的六个例子(手机检测研究,2013年2月)[3]
  有了2013手机检测研究的帮助,很容易就找到了代表性的一系列设备。有一件有趣的琐事:30%印度安卓用户的设备分辨率很低只有240×320像素,如上面列表中看到的,三星galaxy y s5360也在其中。另外,480×800分辨率像素现在最常用(上表中三星galaxy s ii中可见)。
  “测试什么”
  移动app必须提供最佳用户体验,以及在不同尺寸和分辨率(关键字“响应式设计”)的各种智能手机和平板电脑上被正确显示(ui测试)。与此同时,apps必须是功能性的和兼容的(兼容性测试),有尽可能多的设备规格(内存,cpu,传感器等)。加上先前获得的“直接”碎片化问题(关于安卓的版本和屏幕的特性), “环境相关的”碎片化有着举足轻重的作用。这种作用涉及到多种不同的情况或环境,其中用户正在自己的环境中使用的终端设备。作为一个例子,如果网络连接不稳定,来电中断,屏幕锁定等情况出现,你应该慎重考虑压力测试[4]和探索性测试以确保完美无错。
  
图5. 测试安卓设备的各个方面
  有必要提前准备覆盖app最常用功能的所有可能的测试场景。早期bug检测和源代码中的简单修改,只能通过不断的测试才能实现。
  “怎么测试”
  将这种广泛的多样性考虑在内的一种务实方法是, 安卓模拟器 - 提供了一个可调节的工具,该工具几乎可以模仿标准pc上安卓的终端用户设备。简而言之,安卓模拟器是qa流程中用各种设备配置(兼容性测试)进行连续回归测试(用户界面,单元和集成测试)的理想工具。探索性测试中,模拟器可以被配置到一个范围广泛的不同场景中。例如,模拟器可以用一种能模拟连接速度或质量中变化的方式来设定。然而,真实设备上的qa是不可缺少的。实践中,用作参考的虚拟设备依然可以在一些小的(但对于某些应用程序来说非常重要)方面有所不同,比如安卓操作系统中没有提供程序特定的调整或不支持耳机和蓝牙。真实硬件上的性能在评价过程中发挥了自身的显著作用,它还应该在考虑了触摸硬件支持和设备物理形式等方面的所有可能终端设备上进行测试(可用性测试)。
  “何时测试”
  既然我们已经定义了在哪里(参考设备)测试 ,测试什么(测试场景),以及如何( 安卓模拟器和真实设备)测试,简述一个过程并确定何时执行哪一个测试场景就至关重要了。因此,我们建议下面的两级流程:
  1 .用虚拟设备进行的回归测试。
  这包括虚拟参考设备上用来在早期识别出基本错误的连续自动化回归测试。这里的理念是快速地、成本高效地识别bugs。
  2 .用真实设备进行的验收测试。
  这涉及到:“策划推广”期间将之发布到google play store前在真实设备上的密集测试(主要是手动测试),(例如,google play[ 5 ]中的 alpha和beta测试组) 。
  在第一阶段,测试自动化极大地有助于以经济实惠的方式实现这一策略。在这一阶段,只有能轻易被自动化(即可以每日执行)的测试用例才能包含在内。
  在一个app的持续开发过程中,这种自动化测试为开发人员和测试人员提供了一个安全网。日常测试运行确保了核心功能正常工作,app的整体稳定性和质量由测试数据透明地反映出来,认证回归可以轻易地与最近的变化关联。这种测试可以很轻易地被设计并使用saas凯发天生赢家一触即发官网的解决方案(如云中的testobject的ui移动app测试)从测试人员电脑上被记录下来。
  当且仅当这个阶段已被成功执行了,这个过程才会在第二阶段继续劳动密集测试。这里的想法是:如果核心功能通过自动测试就只投入测试资源,使测试人员能够专注于先进场景。这个阶段可能包括测试用例,例如性能测试,可用性测试,或兼容性测试。这两种方法相结合产生了一个强大的移动apps质量保证策略[ 7 ] 。
  结论 - 做对测试
  用正确的方式使用,测试可以在对抗零散的安卓的斗争中成为一个有力的工具。一个有效的测试策略的关键之处在于定义手头app的定制测试用例,并定义一个简化测试的工作流程或过程。测试一个移动app是一个重大的挑战,但它可以用一个结构化的方法和正确的工具集合以及专业知识被有效解决掉。


顺其自然evo 2014-12-22 23:23
]]>
关于安卓通过webservice访问数据库问题http://www.blogjava.net/qileilove/archive/2014/12/11/421321.html顺其自然evo顺其自然evothu, 11 dec 2014 15:42:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421321.htmlhttp://www.blogjava.net/qileilove/comments/421321.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421321.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421321.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421321.html ============问题描述============
  访问时,能增删数据库的数据就是显示不了数据库的里的数据不知道是哪里的问题,用的http
  这是我中的产看所有信息的方法:
public list selectallcargoinfor()
{
list list = new list();
try
{
string sql = "select * from c";
sqlcommand cmd = new sqlcommand(sql,sqlcon);
sqldatareader reader = cmd.executereader();
while (reader.read())
{
//将结果集信息添加到返回向量中
list.add(reader[0].tostring());
list.add(reader[1].tostring());
list.add(reader[2].tostring());
}
reader.close();
cmd.dispose();
}
catch(exception)
{
}
return list;
}
  接下来是安卓端的:
  这个是mainactivity中的设置listview的方法
private void setlistview() {
listview.setvisibility(view.visible);
list> list = new arraylist>();
list = dbutil.getallinfo();
adapter = new simpleadapter(mainactivity.this, list, r.layout.adapter_item,
new string[] { "cno", "cname", "cnum" },
new int[] { r.id.txt_cno, r.id.txt_cname, r.id.txt_cnum });
listview.setadapter(adapter);
}
  这个是操作类:
public list> getallinfo() {
list> list = new arraylist>();
arraylist.clear();
brraylist.clear();
crraylist.clear();
new thread(new runnable() {
@override
public void run() {
// todo auto-generated method stub
crraylist = soap.getwebservre("selectallcargoinfor", arraylist, brraylist);
}
}).start();
hashmap temphash = new hashmap();
temphash.put("cno", "cno");
temphash.put("cname", "cname");
temphash.put("cnum", "cnum");
list.add(temphash);
for (int j = 0; j < crraylist.size(); j = 3) {
hashmap hashmap = new hashmap();
hashmap.put("cno", crraylist.get(j));
hashmap.put("cname", crraylist.get(j 1));
hashmap.put("cnum", crraylist.get(j 2));
list.add(hashmap);
}
return list;
}
连接webservice的那个方法httpconnsoap应该是没问题的因为数据库的增删都是可以的,就是无法实现这个显示所有信息到listview中的这个功能不知道为什么,logcat中也是一片绿没什么问题
  logcat中的信息:
05-02 15:51:40.642: i/system.out(3678): 1rice1002dog503白痴25
05-02 15:51:40.647: i/system.out(3678):
05-02 15:51:40.647: i/system.out(3678): soap:envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:xsd="http://www.w3.org/2001/xmlschema"
05-02 15:51:40.647: i/system.out(3678): soap:body
05-02 15:51:40.647: i/system.out(3678): selectallcargoinforresponse xmlns="http://tempuri.org/"
05-02 15:51:40.647: i/system.out(3678): selectallcargoinforresult
05-02 15:51:40.647: i/system.out(3678): 0
05-02 15:51:40.647: i/system.out(3678): string>1
05-02 15:51:40.647: i/system.out(3678): string>rice
05-02 15:51:40.647: i/system.out(3678): string>100
05-02 15:51:40.647: i/system.out(3678): string>2
05-02 15:51:40.652: i/system.out(3678): string>dog
05-02 15:51:40.652: i/system.out(3678): string>50
05-02 15:51:40.652: i/system.out(3678): string>3
05-02 15:51:40.652: i/system.out(3678): string>白痴
05-02 15:51:40.652: i/system.out(3678): string>25
05-02 15:51:40.652: i/system.out(3678): /selectallcargoinforresult
05-02 15:51:40.652: i/system.out(3678): 1
  ============凯发天生赢家一触即发官网的解决方案1============
  分析原因就是在线程还没有执行完时候,getallinfo早已执行完毕以后,,所以在执行for (int j = 0; j < crraylist.size(); j = 3)时候, crraylist为零行。你取出的logcat是执行请求以后的返回数据,这时候setlistview方法早已经走完,所以只有一行数据。截图中的一行数据来自
  hashmap temphash = new hashmap();
  temphash.put("cno", "cno");
  temphash.put("cname", "cname");
  temphash.put("cnum", "cnum");
  list.add(temphash);
  使用thread应该配合handler来使用。
  我把代码修改一下
private final static int   request_success = 1;
private final static int   request_false = 0;
private void requestdata()
{
arraylist.clear();
brraylist.clear();
crraylist.clear();
new thread(new runnable() {
@override
public void run() {
// todo auto-generated method stub
crraylist = soap.getwebservre("selectallcargoinfor", arraylist, brraylist);
message msg = new message();
if(crraylist.size()>0)
{
msg.what = request_success;
}
else
{
msg.what = request_false;
}
// 发送消息
mhandler.sendmessage(msg);
}
}).start();
}
public handler mhandler = new handler(){
// 接收消息
@override
public void handlemessage(message msg) {
// todo auto-generated method stub
super.handlemessage(msg);
switch (msg.what)
{
case request_success:
setlistview();
break;
case request_false:
// 做错误处理
break;
default:
break;
}
}
};
private void setlistview() {
listview.setvisibility(view.visible);
list> list = new arraylist>();
list = dbutil.getallinfo();
adapter = new simpleadapter(mainactivity.this, list, r.layout.adapter_item,
new string[] { "cno", "cname", "cnum" },
new int[] { r.id.txt_cno, r.id.txt_cname, r.id.txt_cnum });
listview.setadapter(adapter);
}
public list> getallinfo() {
list> list = new arraylist>();
hashmap temphash = new hashmap();
temphash.put("cno", "cno");
temphash.put("cname", "cname");
temphash.put("cnum", "cnum");
list.add(temphash);
for (int j = 0; j < crraylist.size(); j = 3) {
hashmap hashmap = new hashmap();
hashmap.put("cno", crraylist.get(j));
hashmap.put("cname", crraylist.get(j 1));
hashmap.put("cnum", crraylist.get(j 2));
list.add(hashmap);
}
return list;
}
  执行requestdata就可以,我没法编译,细节自己再调整看一下,应该能解决问题了。
  你给的分数太少了,大牛们都不给你解答。如果解决问题就给分哈。
  另外,java多线程的操作可以系统学习一下。工作中使用极为频繁


顺其自然evo 2014-12-11 23:42
]]>
appium inspector 真机定位元素http://www.blogjava.net/qileilove/archive/2014/12/11/421314.html顺其自然evo顺其自然evothu, 11 dec 2014 15:36:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421314.htmlhttp://www.blogjava.net/qileilove/comments/421314.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421314.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421314.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421314.html对环境的需求:
  ios
  mac osx 10.7
  xcode 4.5 和 command line tools
  npm 0.8 or greater
  mac os x 10.7 or higher, 10.8.4 recommended
  xcode >= 4.6.3
  检查一下:
  发现两个网址的说法不同,安全第一,弄个高版本的吧。
  我弄了一个xcode5.0.2,安装好了以后,继续安装command line tools:
  好了,环境基本上弄好了,看看别人的帖子说法:
  1、安装node.js
  2、安装appium
  $ npm install -g appium@0.12.3
  注意appium的版本和os的兼容。
  3、启动appium
  $appium &
  真机上,启动时指定设备的uuid
  $appium -u xxxxxxxxxxxxxxxxxxxxxxxxxx
  appium启动服务的参数详细:
  https://github.com/appium/appium/blob/master/docs/server-args.md
 4、真机上运行,被测app必须是developer版本。
  再看看官方网页的说法:
  npm install -g appium
  npm install wd
  appium &
  node your-appium-test.js
  哇,好简单呀!想得美,会者不难而已。
  开始吧:
  需要先安装一个node,不过我的机器上没有brew所以还得先安装一下brew,brew类似于ubuntu下面的apt-get,就是用做联网搜软件然后帮你安装上的一个管理工具,哎呀,这种描述好粗糙,能明白我的意思就行了 ^_^,先搜了一个方法:
  cd /usr/local
  mkdir homebrew
  cd homebrew
  curl -lssf http://github.com/mxcl/homebrew/tarball/master | tar xvz -c/usr/local --strip 1
  cd bin
  ./brew -v
  file brew
  sudo ./brew update
  more brew
  自己做了一遍,大致是这个步骤,顺利安装上了:
  admins-mac:local admin$ cd bin
  admins-mac:bin admin$ ./brew -v
  homebrew 0.9.5
  admins-mac:bin admin$ file brew
  brew: posix shell script text executable
  cd
  vi .bash_profile
  export path=/usr/local/homebrew/bin:$path
  关闭后重新打开terminal,使.bash_profile被执行,使得path环境变量生效,当然你也可以source ./.bash_profile
  在这个安装的过程中,唯一需要注意的是权限,我的作法是在所有步骤之前直接把/usr/local目录都改为了admin所有,就不用每次安装都用sudo来搞了
  sudo chown -rf admin:staff /usr/local
  这下安装node.js就简单了,一行命令:
  brew install node
  然后就是看看node安装的对不对,先vi hello_world.js,输入以下内容(假定你会用vi,vim一类的编辑器)
  var sys = require('sys'),
  http = require('http');
  http.createserver(function(req, res) {
  settimeout(function() {
  res.writehead(200, {'content-type': 'text/plain'});
  res.write('hello world');
  res.end();//截至最新版 res.close(); 以替换为 res.end();
  }, 2000);
  }).listen(8000);
  执行命令:
  node hello_world.js
  下面这样浏览器返回了hello world字样就是成功了。
  最后检查一下:
  node -v
  v0.10.15
  npm -v
  1.4.6
  好了,全齐了。这下该正事了:
  npm install -g appium
  npm install wd
  运行appium-doctor来检查一下appium是不是都彻底ok了:
  admins-mac:bin admin$ pwd
  /usr/local/bin
  admins-mac:bin admin$ ls -l
  total 39064
  lrwxr-xr-x  1 admin  staff        40 apr 14 16:33 appium -> ../lib/node_modules/appium/bin/appium.js
  lrwxr-xr-x  1 admin  staff        47 apr 14 16:33 appium-doctor -> ../lib/node_modules/appium/bin/appium-doctor.js
  lrwxr-xr-x  1 admin  staff        47 apr 14 16:33 authorize_ios -> ../lib/node_modules/appium/bin/authorize-ios.js
  -rwxrwxr-x  1 admin  staff       813 apr 14 08:53 brew
  -rwxr-xr-x  1 admin  staff  19975968 jul 26  2013 node
  lrwxr-xr-x  1 admin  staff        38 jul 31  2013 npm -> ../lib/node_modules/npm/bin/npm-cli.js
  lrwxr-xr-x  1 admin  staff        33 jul 31  2013 weinre -> ../lib/node_modules/weinre/weinre
  因为这台mac上没有android环境,所以报错,我也没打算在这台mac上测试android程序,所以不用搭理。appium已经ok了。
  启动appium(&的意思是后台执行,不占用窗口):
  admins-mac:appium admin$ appium &
  [1] 1886
  admins-mac:appium admin$ info: welcome to appium v0.18.1 (rev d242ebcfd92046a974347ccc3a28f0e898595198)
  info: appium rest http interface listener started on 0.0.0.0:4723
  info: socket.io started
  info: non-default server args: {"merciful":true}
  检查进程,顺带删除掉这个后台进程:
  admins-mac:appium admin$ ps -ef|grep appium
  501  1886  1274   0  4:47pm ttys000    0:00.73 node /usr/local/bin/appium
  501  1892  1274   0  4:48pm ttys000    0:00.00 grep appium
  admins-mac:appium admin$ kill 1886
  好了,环境部分差不多就这样了。


顺其自然evo 2014-12-11 23:36
]]>
appium inspector 真机定位元素http://www.blogjava.net/qileilove/archive/2014/12/11/421316.html顺其自然evo顺其自然evothu, 11 dec 2014 15:36:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421316.htmlhttp://www.blogjava.net/qileilove/comments/421316.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421316.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421316.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421316.html  过程中,对被测试元素的定位是相当重要的。前面中也讲到了一些儿定位方法。今天讲解,如何用真机运行程序,用 inspector,ui automation viewer来定位app的元素。
  一、inspector定位
  平时我们定位元素的时候,通常是按下面的方式设置的。
  device name填写的是模拟器的名称,启动模拟器,appium后,再启动inspector就能reflesh启动app,来进行操作。可是这存在一个问题:模拟器比较慢,而且多少和真机不一样,比如说模拟器不能调出键盘等;所以如果我们要做自动化测试的时候,最好还是用真机来运行app,然后进行定位。
  真机运行inspector的时候也非常简单,首先将手机连接到电脑上。如果有91手机助手或是类似的软件的时候,就会提示是否连接成功!一定要确保连接成功,然后将device name替换成手型号,如下所示:
  然后运行appium,启动inspector,就可以在真机上安装并启动app,此时刷新就可以获取最新的screenshot,左边就能展开对应的分支,你就可以大展拳脚,进行定位了。
  注:用appium inspector在真机上运行并定位元素的时候,不管你现在有没有安装这个app,它都会给你重新安装一下,然后再打开,这个是很不爽的。不过运行的时候,如果有安装,则直接打开,没有安装时才会安装。
  二、ui automation viewer定位
  只要你用真机连接上电脑,并运行了要测试的app,打开ui automation viewer后,单击“device screenshot”按钮,就能刷新出手机上的界面,并能展示定位,如果有任何变动。再次刷新即可。


顺其自然evo 2014-12-11 23:36
]]>
appium框架中android下edittext内容清除http://www.blogjava.net/qileilove/archive/2014/12/11/421312.html顺其自然evo顺其自然evothu, 11 dec 2014 15:33:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/11/421312.htmlhttp://www.blogjava.net/qileilove/comments/421312.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/11/421312.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421312.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421312.html在做过程中 ,难免会对edittext的内容进行修改,通常我们对edittext输入 内容的时候,用的是send_key()函数。可是这个函数不会先清除原来的内容,只会在光标当前位置上输入函数参数中的数据。如果我们需要修改,必须清除原来的内容,查看了一下clear()参数不好使用,只好去网上搜索了。
  找到了如下方法:
  “首先 clear(), send_keys(), set_text(),在android上不太好用是个已知的bug (在ios上不清楚,没有测试环境),会在 1.2.3上修复。请参见github的issue:https://github.com/appium/python-client/issues/53
  在这之前我们可以用 press_keycode的方式实现删除,删除速度比忽略 clear()抛出的异常要快很多。
  大概思路是:
  1. 点击要清除的edit field
  2. 全选
  3. 删除
  element.click()
  sleep(1)   #waiting for 1 second is important, otherwise 'select all' doesn't work. however, it perform this from my view
  self.driver.press_keycode(29,28672)   # 29 is the keycode of 'a', 28672 is the keycode of meta_ctrl_mask
  self.driver.press_keycode(112)   # 112 is the keycode of forward_del, of course you can also use 67“
  我试了一下上面的方法,没有什么效果,只好继续寻找了。搜了好多网页,在一个网页上看到了一个不错的办法,不过可以打开的网页太多了,一忙忘记是哪儿个网页了。具体的方案就是:
  先将光标移到文本框最后,然后取一下edittext中文本的长度,最后一个一个地删除文本。
  具体示例如下:
  def edittextclear(self,text):
  '''
  请除edittext文本框里的内容
  @param:text 要清除的内容
  '''
  driver.keyevent(123)
  for i in range(0,len(text)):
  driver.keyevent(67)
  使用实例:
  adr=driver.find_element_by_id('com.subject.zhongchou:id/edit_person_detailaddress') #找到要删除文本的edittext元素
  adr.click()#激活该文本框
  context2=adr.get_attribute('text')#获取文本框里的内容
  self.edittextclear(context2)#删除文本框中是内容


顺其自然evo 2014-12-11 23:33
]]>
如何设计android app测试用例http://www.blogjava.net/qileilove/archive/2014/12/08/421177.html顺其自然evo顺其自然evomon, 08 dec 2014 12:35:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/08/421177.htmlhttp://www.blogjava.net/qileilove/comments/421177.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/08/421177.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/421177.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/421177.html在当今竞争激烈的市场上一个app的成功离不开一个可靠的用户界面(ui)。因此,对功能和用户体验有一些特殊关注和照顾的ui的全面是必不可少的。当涉及到安卓平台及其提出的独特问题的数量(安卓就ui提出显著挑战)时,挑战变得更加复杂。关键字“碎片化”象征着应用全面测试的最大障碍,还表明了发布到市场上的所有形态、大小、配置类型的安卓设备所引起的困难。本文将介绍安卓模拟器如何能通过使用一些技巧和简单的实践提供覆盖大量设备类型的广泛测试。
  简介—分散装置里的测试
  一般安卓开发者在其日常中面临的最大挑战之一是:终端设备和版本的范围太广。opensignal进行的一项研究表明,2013年7月市场上有超过11,828的不同安卓终端设备,所有设备在类型/大小/屏幕分辨率以及特定配置方面有所不同。考虑到前一年的调查仅记录有3,997款不同设备,这实在是一个越来越大的挑战障碍。
 
 图1.11,828 款安卓设备类型( opensignal研究, 2013年7月[ 1 ] )分布
  从一个移动app开发角度出发,定义终端设备有四个基本特征:
  1.操作系统:由“api指标”( 1 ?18 )专业定义的安卓操作系统版本( 1.1? 4.3 ),。
  2.显示器:屏幕主要是由屏幕分辨率(以像素为单位),屏幕像素密度( 以dpi为单位),和/或屏幕尺寸(以英寸为单位)定义的。
  3.cpu:该“应用程序二进制接口” (abi )定义cpu的指令集。这里的主要区别是arm和基于intel的cpu。
  4.内存:一个设备包括内存储器( ram)和dalvik 虚拟存储器( vm堆)的预定义的堆内存。
  这是前两个特点,操作系统和显示器,都需要特别注意,因为他们是直接由最终用户明显感受,且应该不断严格地被测试覆盖。至于安卓的版本, 2013年7月市场上有八个同时运行导致不可避免的碎片的不同版本。七月,近90%这些设备中的34.1 %正在运行gingerbread版本( 2.3.3-2.3.7 ),32.3 %正在运行jelly bean( 4.1.x版),23.3 %正在运行ice cream sandwich( 4.0.3 - 4.0.4 )。
  
图2.16款安卓版本分布(opensignal研究,2013年7月[1])
  考虑设备显示器,一项techcrunch从2013年4月进行的研究显示,绝大多数(79.9%)有效设备正在使用尺寸为3和4.5英寸的“正常”屏幕。这些设备的屏幕密度在“mdpi”(160 dpi),“hdpi”(240 dpi)和“xhdpi”(320 dpi)之间变化。也有例外, 一种只占9.5%的设备屏幕密度低“hdpi”(120 dpi)且屏幕小。
  
图3. 常见的屏幕尺寸和密度的分布(研究,2013年4月)[2]
  如果这种多样性在质量保证过程中被忽略了,那么绝对可以预见:bugs会潜入应用程序,然后是bug报告的风暴,最后 play store中出现负面用户评论。因此,目前的问题是:你怎么使用合理水平的测试工作切实解决这一挑战?定义及一个伴随测试过程是一个应付这一挑战的有效武器。
  用例—“在哪测试”、“测试什么”、“怎么测试”、“何时测试”?
  “在哪测试”
  为了节省你测试工作上所花的昂贵时间,我们建议首先要减少之前所提到的32个安卓版本组合及代表市场上在用的领先设备屏的5-10个版本的显示屏。选择参考设备时,你应该确保覆盖了足够广范围的版本和屏幕类型。作为参考,您可以使用opensignal的调查或使用检测的信息图[3],来帮助选择使用最广的设备。


为了满足好奇心,可以从安卓文件[5]将屏幕的尺寸和分辨率映射到上面数据的密度(“ldpi”,“mdpi”等)及分辨率(“小的”,“标准的”,等等)上。
  
图4.多样性及分布很高的安卓终端设备的六个例子(手机检测研究,2013年2月)[3]
  有了2013手机检测研究的帮助,很容易就找到了代表性的一系列设备。有一件有趣的琐事:30%印度安卓用户的设备分辨率很低只有240×320像素,如上面列表中看到的,三星galaxy y s5360也在其中。另外,480×800分辨率像素现在最常用(上表中三星galaxy s ii中可见)。
  “测试什么”
  移动app必须提供最佳用户体验,以及在不同尺寸和分辨率(关键字“响应式设计”)的各种智能手机和平板电脑上被正确显示(ui测试)。与此同时,apps必须是功能性的和兼容的(兼容性测试),有尽可能多的设备规格(内存,cpu,传感器等)。加上先前获得的“直接”碎片化问题(关于安卓的版本和屏幕的特性), “环境相关的”碎片化有着举足轻重的作用。这种作用涉及到多种不同的情况或环境,其中用户正在自己的环境中使用的终端设备。作为一个例子,如果网络连接不稳定,来电中断,屏幕锁定等情况出现,你应该慎重考虑压力测试[4]和探索性测试以确保完美无错。
  
图5. 测试安卓设备的各个方面
  有必要提前准备覆盖app最常用功能的所有可能的测试场景。早期bug检测和源代码中的简单修改,只能通过不断的测试才能实现。
  “怎么测试”
  将这种广泛的多样性考虑在内的一种务实方法是, 安卓模拟器 - 提供了一个可调节的工具,该工具几乎可以模仿标准pc上安卓的终端用户设备。简而言之,安卓模拟器是qa流程中用各种设备配置(兼容性测试)进行连续回归测试(用户界面,单元和集成测试)的理想工具。探索性测试中,模拟器可以被配置到一个范围广泛的不同场景中。例如,模拟器可以用一种能模拟连接速度或质量中变化的方式来设定。然而,真实设备上的qa是不可缺少的。实践中,用作参考的虚拟设备依然可以在一些小的(但对于某些应用程序来说非常重要)方面有所不同,比如安卓操作系统中没有提供程序特定的调整或不支持耳机和蓝牙。真实硬件上的性能在评价过程中发挥了自身的显著作用,它还应该在考虑了触摸硬件支持和设备物理形式等方面的所有可能终端设备上进行测试(可用性测试)。
  “何时测试”
  既然我们已经定义了在哪里(参考设备)测试 ,测试什么(测试场景),以及如何( 安卓模拟器和真实设备)测试,简述一个过程并确定何时执行哪一个测试场景就至关重要了。因此,我们建议下面的两级流程:
  1 .用虚拟设备进行的回归测试。
  这包括虚拟参考设备上用来在早期识别出基本错误的连续自动化回归测试。这里的理念是快速地、成本高效地识别bugs。
  2 .用真实设备进行的验收测试。
  这涉及到:“策划推广”期间将之发布到google play store前在真实设备上的密集测试(主要是手动测试),(例如,google play[ 5 ]中的 alpha和beta测试组) 。
  在第一阶段,测试自动化极大地有助于以经济实惠的方式实现这一策略。在这一阶段,只有能轻易被自动化(即可以每日执行)的测试用例才能包含在内。
  在一个app的持续开发过程中,这种自动化测试为开发人员和测试人员提供了一个安全网。日常测试运行确保了核心功能正常工作,app的整体稳定性和质量由测试数据透明地反映出来,认证回归可以轻易地与最近的变化关联。这种测试可以很轻易地被设计并使用saas凯发天生赢家一触即发官网的解决方案(如云中的testobject的ui移动app测试)从测试人员电脑上被记录下来。
  当且仅当这个阶段已被成功执行了,这个过程才会在第二阶段继续劳动密集测试。这里的想法是:如果核心功能通过自动测试就只投入测试资源,使测试人员能够专注于先进场景。这个阶段可能包括测试用例,例如性能测试,可用性测试,或兼容性测试。这两种方法相结合产生了一个强大的移动apps质量保证策略[ 7 ] 。
  结论 - 做对测试
  用正确的方式使用,测试可以在对抗零散的安卓的斗争中成为一个有力的工具。一个有效的测试策略的关键之处在于定义手头app的定制测试用例,并定义一个简化测试的工作流程或过程。测试一个移动app是一个重大的挑战,但它可以用一个结构化的方法和正确的工具集合以及专业知识被有效解决掉。


顺其自然evo 2014-12-08 20:35
]]>
ios中使用reachability 检测网络http://www.blogjava.net/qileilove/archive/2014/12/03/420959.html顺其自然evo顺其自然evowed, 03 dec 2014 05:31:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/03/420959.htmlhttp://www.blogjava.net/qileilove/comments/420959.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/03/420959.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420959.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420959.html如果你想在ios程序中提供一仅在wifi网络下使用(reeder),或者在没有网络状态下提供离线模式(evernote)。那么你会使用到reachability来实现网络检测。
  写本文的目的
  了解reachability都能做什么
  检测3中网络环境
  2g/3g
  wifi
  无网络
  如何使用通知
  单个controller
  多个controller
  简单的功能:
  仅在wifi下使用
  reachability简介
  reachablity 是一个ios下检测,ios设备网络环境用的库。
  监视目标网络是否可用
  监视当前网络的连接方式
  监测连接方式的变更
  安装
  创建 network 工程(network是我创建的demo工程,附件中可以下载到)
  使用cocoaspod安装依赖
  在项目中添加 systemconfiguration.framework 库
  由于reachability非常常用。直接将其加入到supporting files/networ-prefix.pch中:
  #import
  #import
  如果你还不知道cocoaspod是什么,看这里:
  http://witcheryne.iteye.com/blog/1873221
  使用
  stackoverflow上有一篇回答,很好的解释了reachability的用法
  http://stackoverflow.com/questions/11177066/how-to-use-ios-reachability
  一般情况一个reachability实例就ok了。
  一个controller只需要一个reachability
  block方式使用
- (void)viewdidload
{
[super viewdidload];
dlog(@"开启 www.apple.com 的网络检测");
reachability* reach = [reachability reachabilitywithhostname:@"www.apple.com"];
dlog(@"-- current status: %@", reach.currentreachabilitystring);
// start the notifier which will cause the reachability object to retain itself!
[[nsnotificationcenter defaultcenter] addobserver:self
selector:@selector(reachabilitychanged:)
name:kreachabilitychangednotification
object:nil];
reach.reachableblock = ^(reachability * reachability)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.blocklabel.text = @"网络可用";
self.blocklabel.backgroundcolor = [uicolor greencolor];
});
};
reach.unreachableblock = ^(reachability * reachability)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.blocklabel.text = @"网络不可用";
self.blocklabel.backgroundcolor = [uicolor redcolor];
});
};
[reach startnotifier];
}
- (void)viewdidload
{
[super viewdidload];
dlog(@"开启 www.apple.com 的网络检测");
reachability* reach = [reachability reachabilitywithhostname:@"www.apple.com"];
dlog(@"-- current status: %@", reach.currentreachabilitystring);
// start the notifier which will cause the reachability object to retain itself!
[[nsnotificationcenter defaultcenter] addobserver:self
selector:@selector(reachabilitychanged:)
name:kreachabilitychangednotification
object:nil];
reach.reachableblock = ^(reachability * reachability)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.blocklabel.text = @"网络可用";
self.blocklabel.backgroundcolor = [uicolor greencolor];
});
};
reach.unreachableblock = ^(reachability * reachability)
{
dispatch_async(dispatch_get_main_queue(), ^{
self.blocklabel.text = @"网络不可用";
self.blocklabel.backgroundcolor = [uicolor redcolor];
});
};
[reach startnotifier];
}
 使用notification的方式
- (void)viewdidload
{
[super viewdidload];
dlog(@"开启 www.apple.com 的网络检测");
reachability* reach = [reachability reachabilitywithhostname:@"www.apple.com"];
dlog(@"-- current status: %@", reach.currentreachabilitystring);
// start the notifier which will cause the reachability object to retain itself!
[[nsnotificationcenter defaultcenter] addobserver:self
selector:@selector(reachabilitychanged:)
name:kreachabilitychangednotification
object:nil];
[reach startnotifier];
}
- (void) reachabilitychanged: (nsnotification*)note {
reachability * reach = [note object];
if(![reach isreachable])
{
self.notificationlabel.text = @"网络不可用";
self.notificationlabel.backgroundcolor = [uicolor redcolor];
self.wifionlylabel.backgroundcolor = [uicolor redcolor];
self.wwanonlylabel.backgroundcolor = [uicolor redcolor];
return;
}
self.notificationlabel.text = @"网络可用";
self.notificationlabel.backgroundcolor = [uicolor greencolor];
if (reach.isreachableviawifi) {
self.wifionlylabel.backgroundcolor = [uicolor greencolor];
self.wifionlylabel.text = @"当前通过wifi连接";
} else {
self.wifionlylabel.backgroundcolor = [uicolor redcolor];
self.wifionlylabel.text = @"wifi未开启,不能用";
}
if (reach.isreachableviawwan) {
self.wwanonlylabel.backgroundcolor = [uicolor greencolor];
self.wwanonlylabel.text = @"当前通过2g or 3g连接";
} else {
self.wwanonlylabel.backgroundcolor = [uicolor redcolor];
self.wwanonlylabel.text = @"2g or 3g网络未使用";
}
}
- (void)viewdidload
{
[super viewdidload];
dlog(@"开启 www.apple.com 的网络检测");
reachability* reach = [reachability reachabilitywithhostname:@"www.apple.com"];
dlog(@"-- current status: %@", reach.currentreachabilitystring);
// start the notifier which will cause the reachability object to retain itself!
[[nsnotificationcenter defaultcenter] addobserver:self
selector:@selector(reachabilitychanged:)
name:kreachabilitychangednotification
object:nil];
[reach startnotifier];
}
- (void) reachabilitychanged: (nsnotification*)note {
reachability * reach = [note object];
if(![reach isreachable])
{
self.notificationlabel.text = @"网络不可用";
self.notificationlabel.backgroundcolor = [uicolor redcolor];
self.wifionlylabel.backgroundcolor = [uicolor redcolor];
self.wwanonlylabel.backgroundcolor = [uicolor redcolor];
return;
}
self.notificationlabel.text = @"网络可用";
self.notificationlabel.backgroundcolor = [uicolor greencolor];
if (reach.isreachableviawifi) {
self.wifionlylabel.backgroundcolor = [uicolor greencolor];
self.wifionlylabel.text = @"当前通过wifi连接";
} else {
self.wifionlylabel.backgroundcolor = [uicolor redcolor];
self.wifionlylabel.text = @"wifi未开启,不能用";
}
if (reach.isreachableviawwan) {
self.wwanonlylabel.backgroundcolor = [uicolor greencolor];
self.wwanonlylabel.text = @"当前通过2g or 3g连接";
} else {
self.wwanonlylabel.backgroundcolor = [uicolor redcolor];
self.wwanonlylabel.text = @"2g or 3g网络未使用";
}
}
  附件demo说明
  开启wifi状态
  关闭wifi的状态
  遗留问题
  如何在多个controller之前共用一个reachability(附件demo中是一个controller一个reachability实例)
  应该在什么使用停止reachability的检测.


顺其自然evo 2014-12-03 13:31
]]>
ios开发之山寨版新浪微博小结http://www.blogjava.net/qileilove/archive/2014/12/03/420957.html顺其自然evo顺其自然evowed, 03 dec 2014 05:30:00 gmthttp://www.blogjava.net/qileilove/archive/2014/12/03/420957.htmlhttp://www.blogjava.net/qileilove/comments/420957.htmlhttp://www.blogjava.net/qileilove/archive/2014/12/03/420957.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420957.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420957.html之前的博客ios开发之新浪围脖中获取微博的内容是使用我自己的access_token来请求的数据,那么如何让其他用户也能登陆并获取自己的微博内容呢?接下来就是oauth和sso出场的时候啦。oauth的全称为open authorization 开发授权,sso--单点登陆(single sign on)。至于其原理是什么,更具体的介绍网上的资料是一抓一大把,在这就不做过多的原理性的概述。当然啦,oauth和sso在web和其他终端上应用还是蛮多的,所有这方面的资料也是多的很。
  简单的说就是可以通过新浪的oauth把之前access_token换成用户自己的access_token,从而请求自己微博的内容(因为之前做的的关于新浪微博的东西,所以用到是新浪提供的oauth)。更详细的内容请参考新浪对oauth2.0授权认证,ios版sdk的github下载后,其中有详细的使用说明并附有使用demo.所以sdk的使用在这就不做过多的赘述。可能有的小伙伴会问哪本篇博客要介绍什么东西呢?本篇博客就是被之前的新浪微博加上oauth授权认证,给之前的博客做一个善后。
  1.还是在博客的开头先来几张截图(第一张是没有登录时的启动图,第二张是获取授权的页面,第三张是授权后的页面,第四张是把之前写的ios开发之自定义表情键盘(组件封装与自动布局)整合了进来)这样的话一个app的基本功能算是有啦。
  2.在今天的博客中没有大量的代码,只是对之前博客中的内容的一个应用,如何用新浪的oauth的sdk,新浪给提供的开发文档中说明的很详细了,笔者也是按上面一步步做的,没有太大问题。上面给出了sdk的下载地址,有兴趣小伙伴可以下载一个研究研究。
  3.在用户授权以后,新浪接口或返回一些用户的信息,其中就有该授权用户所对应的access_token, 下面是响应代码,把返回的用户access_token存入到了nsuserdefaults中,关于nsuserdefault的具体内容请参考之前的博客ios开发之记录用户登陆状态,在这就不做赘述了。
1 - (void)didreceiveweiboresponse:(wbbaseresponse *)response
2 {
3     if ([response iskindofclass:wbsendmessagetoweiboresponse.class])
4     {
5         nsstring *title = @"发送结果";
6         nsstring *message = [nsstring stringwithformat:@"响应状态: %d\n响应userinfo数据: %@\n原请求userinfo数据: %@",
7                              response.statuscode, response.userinfo, response.requestuserinfo];
8        nslog(@"%@", message);
9     }
10     else if ([response iskindofclass:wbauthorizeresponse.class])
11     {
12
13         self.wbtoken = [(wbauthorizeresponse *)response accesstoken];
14
15         if (self.wbtoken != nil) {
16             //获取userdefault单例
17             nsuserdefaults *token = [nsuserdefaults standarduserdefaults];
18             [token setobject:self.wbtoken forkey:@"token"];
19         }
20     }
21 }
  4.添加我们的自定义键盘也挺简单的,因为之前是用纯代码封装的自定义键盘并留有响应的接口,所有移植到我们的新浪微博上就是一个拷贝粘贴的体力活,关于自定义键盘的东西请参考之前的博客ios开发之自定义表情键盘(组件封装与自动布局),在这就不做赘述。


顺其自然evo 2014-12-03 13:30
]]>
安装运行appium初体验http://www.blogjava.net/qileilove/archive/2014/11/27/420696.html顺其自然evo顺其自然evothu, 27 nov 2014 03:57:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/27/420696.htmlhttp://www.blogjava.net/qileilove/comments/420696.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/27/420696.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420696.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420696.html 最近有空玩了一下,记录一下
  1.下载appium for windows,现在是0.12.3版本
  解压后如下图
  双击appium.exe就能启动appium界面
  点击launch开启服务
  2. 下载 sdk
  解压后
  3. 配置系统环境变量
  android_home: c:\adt-bundle-windows-x86_64-20131030\sdk
  path添加: %android_home%\tools;%android_home%\platform-tools
 4. 启动avd,耗资源啊,这时候我t400的cpu已经100%了
  5. 编写test,使用adt安装好maven插件,创建一个maven项目,添加一个文件夹apps用来存放被测的app,这里测试的是contactmanager.apk
  pom.xml添加如下依赖
1  
2    
3             junit
4             junit
5             4.11
6             test
7        
8        
9             org.seleniumhq.selenium
10             selenium-java
11             latest
12             test
13        
14  
 编写androidcontactstest
1 package com.guowen.appiumdemo;
2
3 import org.junit.after;
4 import org.junit.before;
5 import org.junit.test;
6 import org.openqa.selenium.*;
7 import org.openqa.selenium.interactions.hastouchscreen;
8 import org.openqa.selenium.interactions.touchscreen;
9 import org.openqa.selenium.remote.capabilitytype;
10 import org.openqa.selenium.remote.desiredcapabilities;
11 import org.openqa.selenium.remote.remotetouchscreen;
12 import org.openqa.selenium.remote.remotewebdriver;
13 import java.io.file;
14 import java.net.url;
15 import java.util.list;
16
17 public class androidcontactstest {
18     private webdriver driver;
19
20     @before
21     public void setup() throws exception {
22         // set up appium
23         file classpathroot = new file(system.getproperty("user.dir"));
24         file appdir = new file(classpathroot, "apps/contactmanager");
25         file app = new file(appdir, "contactmanager.apk");
26         desiredcapabilities capabilities = new desiredcapabilities();
27         capabilities.setcapability("device","android");
28         capabilities.setcapability(capabilitytype.browser_name, "");
29         capabilities.setcapability(capabilitytype.version, "4.4");
30         capabilities.setcapability(capabilitytype.platform, "windows");
31         capabilities.setcapability("app", app.getabsolutepath());
32         capabilities.setcapability("app-package", "com.example.android.contactmanager");
33         capabilities.setcapability("app-activity", ".contactmanager");
34         driver = new swipeablewebdriver(new , capabilities);
35     }
36
37     @after
38     public void teardown() throws exception {
39         driver.quit();
40     }
41
42     @test
43     public void addcontact(){
44         webelement el = driver.findelement(by.name("add contact"));
45         el.click();
46         list textfieldslist = driver.findelements(by.tagname("textfield"));
47         textfieldslist.get(0).sendkeys("some name");
48         textfieldslist.get(2).sendkeys("some@example.com");
49         driver.findelement(by.name("save")).click();
50     }
51
52     public class swipeablewebdriver extends remotewebdriver implements hastouchscreen {
53         private remotetouchscreen touch;
54
55         public swipeablewebdriver(url remoteaddress, capabilities desiredcapabilities) {
56             super(remoteaddress, desiredcapabilities);
57             touch = new remotetouchscreen(getexecutemethod());
58         }
59
60         public touchscreen gettouch() {
61             return touch;
62         }
63     }
64 }
  6. 运行test,注意avd里的android如果没有解锁需要先解锁
  这时候我们可以看到avd在运行了,
  同时appium的命令行有对应的输出
  7. 更多信息请参考appium的github


顺其自然evo 2014-11-27 11:57
]]>
ios为移动中的uiview(uibutton )添加点击事件http://www.blogjava.net/qileilove/archive/2014/11/26/420637.html顺其自然evo顺其自然evowed, 26 nov 2014 07:08:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/26/420637.htmlhttp://www.blogjava.net/qileilove/comments/420637.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/26/420637.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420637.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420637.html 高高兴兴迎接新的产品新需求,满心欢喜的开始,结果研究了一下午才发现,是自己想的太简单了,是我太单纯呀。
  需求是这样的类似下雪的效果,随机产生一些小雪花,然后每个雪花可以点击到下个页面。
  接到需求之后我的首先想法就是用button实现不久可以了,多简单点事情,结果实践之后就知道自己多么的无知了,在中的button根本没有办法接收点击事件。
  然后同事给出了一种解决办法,通过手势获取点击的位置,然后遍历页面上的控件,如果在这个范围内就点击成功。通过这个想法我尝试用frame来实现需求,然后发现自己又白痴了,页面上所有的“雪花”的frame,都是动画结束的位置,并不是实时的位置。
  但是我感到用手势,然后通过位置,遍历,这个思路应该是对的,于是继续,发现了一个好东西
  - (calayer *)hittest:(cgpoint)p;
  通过这个可以得到这个页面时候覆盖了这个点,这样就可以解决我的问题了,把手势加在“雪花”的父页面上,然后点击事件里进行处理(当然 用这个方法就没有必要一定用button)
-(void)tapclick:(uitapgesturerecognizer *)tap
{
cgpoint clickpoint =  [tap locationinview:self];
for (uiimageview *imageview in [self subviews])
{
if ([imageview.layer.presentationlayer hittest:clickpoint])
{
// this button was hit whilst moving - do something with it here
break;
}
}
}
}
  这样就可以解决问题,当然应该还有其他的方法,欢迎补充。


顺其自然evo 2014-11-26 15:08
]]>
ios开发ui篇—app主流ui框架结构http://www.blogjava.net/qileilove/archive/2014/11/18/420224.html顺其自然evo顺其自然evotue, 18 nov 2014 02:07:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/18/420224.htmlhttp://www.blogjava.net/qileilove/comments/420224.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/18/420224.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420224.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420224.html 一、简单示例
  说明:使用app主流ui框架结构完成简单的界面搭建
  搭建页面效果:
  二、搭建过程和注意点
  1.新建一个项目,把原有的控制器删除,添加uitabbarcontroller控制器作为管理控制器
  2.对照界面完成搭建
  3.注意点:
  (1)隐藏工具条:配置一个属性,hideabotton bar在push的时候隐藏底部的bar在那个界面隐藏,就在哪个界面设置。
  (2).cell可以设置行高
  (4)说明:在上面的页面搭建中直接使用了静态单元格,但在实际开发中,通常不这么做。
  (5)在tableview中添加headerview(显示一根蓝线)
  三、 app主流ui框架结构
  请问:uitabbarcontroller和导航控制器的在结构中的位置能否互调?(一个导航条)
  设置控制器关联或出现问题,tableviewcontroller默认实现了数据源的方法,两个控制器把它反过来管理。关于导航条。导航条上显示什么内容由栈顶控制器来确定,下面的导航条只有一个(栈顶控制器就是tabbar控制器)。
  补充说明:ios7全屏化的设计
  打印ios7中控制器的层次结构:
  打印ios6中控制器的层次结构:


顺其自然evo 2014-11-18 10:07
]]>
android数据库升级实例http://www.blogjava.net/qileilove/archive/2014/11/14/420060.html顺其自然evo顺其自然evofri, 14 nov 2014 02:03:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/14/420060.htmlhttp://www.blogjava.net/qileilove/comments/420060.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/14/420060.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/420060.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/420060.html  第一部分
  andoird的sqliteopenhelper类中有一个onupgrade方法。帮助文档中只是说当升级时该方法被触发。经过实践,解决了我一连串的疑问:
  1. 帮助文档里说的“数据库升级”是指什么?
  你开发了一个程序,当前是1.0版本。该程序用到了数据库。到1.1版本时,你在数据库的某个表中增加了一个字段。那么软件1.0版本用的数据库在软件1.1版本就要被升级了。
  2. 数据库升级应该注意什么?
  软件的1.0版本升级到1.1版本时,老的数据不能丢。那么在1.1版本的程序中就要有地方能够检测出来新的软件版本与老的数据库不兼容,并且能够有办法 把1.0软件的数据库升级到1.1软件能够使用的数据库。换句话说,要在1.0软件的数据库的那个表中增加那个字段,并赋予这个字段默认值。
  3. 程序如何知道数据库需要升级?
  sqliteopenhelper类的构造函数有一个参数是int version,它的意思就是指数据库版本号。比如在软件1.0版本中,我们使用sqliteopenhelper访问数据库时,该参数为1,那么数据库版本号1就会写在我们的数据库中。
  到了1.1版本,我们的数据库需要发生变化,那么我们1.1版本的程序中就要使用一个大于1的整数来构造sqliteopenhelper类,用于访问新的数据库,比如2。
  当我们的1.1新程序读取1.0版本的老数据库时,就发现老数据库里存储的数据库版本是1,而我们新程序访问它时填的版本号为2,系统就知道数据库需要升级。
  4. 何时触发数据库升级?如何升级?
  当系统在构造sqliteopenhelper类的对象时,如果发现版本号不一样,就会自动调用onupgrade函数,让你在这里对数据库进行升级。根据上述场景,在这个函数中把老版本数据库的相应表中增加字段,并给每条记录增加默认值即可。
  新版本号和老版本号都会作为onupgrade函数的参数传进来,便于开发者知道数据库应该从哪个版本升级到哪个版本。
  升级完成后,数据库会自动存储最新的版本号为当前数据库版本号。
  参考:stackoverflow对“数据库版本在数据库中的存储位置”的问答。
  第二部分做应用,不可避免的会与sqlite打交道。随着应用的不断升级,原有的数据库结构可能已经不再适应新的功能,这时候,就需要对 sqlite数据库的结构进行升级了。 sqlite提供了alter table命令,允许用户重命名或添加新的字段到已有表中,但是不能从表中删除字段。
  并且只能在表的末尾添加字段,比如,为 subscription添加两个字段:
  1 alter table subscription add column activation blob;
  2 alter table subscription add column key blob;
  另外,如果遇到复杂的修改操作,比如在修改的同时,需要进行数据的转移,那么可以采取在一个事务中执行如下语句来实现修改表的需求。
  1. 将表名改为临时表
  alter table subscription rename to __temp__subscription;
  2. 创建新表
  create table subscription (orderid varchar(32) primary key ,username varchar(32) notnull ,productid varchar(16) not null);
  3. 导入数据
  insert into subscription select orderid, “”, productid from __temp__subscription;
  或者
  insert into subscription() select orderid, “”, productid from __temp__subscription;
  * 注意 双引号”” 是用来补充原来不存在的数据的
  4. 删除临时表
  drop table __temp__subscription;
  通过以上四个步骤,就可以完成旧数据库结构向新数据库结构的迁移,并且其中还可以保证数据不会应为升级而流失。
  当然,如果遇到减少字段的情况,也可以通过创建临时表的方式来实现。


顺其自然evo 2014-11-14 10:03
]]>
appium知识技巧收集http://www.blogjava.net/qileilove/archive/2014/11/11/419906.html顺其自然evo顺其自然evotue, 11 nov 2014 02:10:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/11/419906.htmlhttp://www.blogjava.net/qileilove/comments/419906.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/11/419906.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419906.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419906.html1、真机调试打开usb调试模式
  2、启动脚本提示apk包could not make a string,是释放string.json出错,由于apk损坏导致,验证是安装到真机上开启app
  3、activity要写对,否则提示不存在activity,建议写完整名称,完整包名类似com.xxx.xxx.activity;启动activity要写对,否则提示xxx never xxx。包名参数与activity参数可以在androidmanifest.xml(获取方法http://code.google.com/p/android-apktool/)中查看,包名:android:versioncode="12" android:versionname="2.6.0.0.0" package="com.xxx.xxx",一般位于xml定义的下一行,启动activity在这里看,带有launcher关键字
  android:name="com.xxx.xxx.splashactivity" android:launchmode="singletop" android:screenorientation="portrait" ,本例中是com.xxx.xxx.splashactivity
  4、支持一个webdriver元素定位方法的子集
  find by "tag name" (i.e., 通过ui的控件类型)
  find by "name" (i.e., 通过元素的文本, 标签, 或者开发同学添加的id标示, 比如accessibilityidentifier)
  find by "xpath" (i.e., 具有一定约束的路径抽象标示, 基于xpath方式)
  5、appium 在 mac os x 上安装使用文档,参考:http://testerhome.com/topics/166,平台,参考:http://testerhome.com/topics/155,平台,参考:http://testerhome.com/topics/160,android平台,参考:http://testerhome.com/topics/153
  6、ios模拟器—>硬件—>设备—>iphone
  7、【坑】appium在macos10.9以及ios7上面的问题:启动appium脚本没有问题。安装好应用之后log中会报出500,同时instruments会显示simulator session timeout。
  8、生成build/test.appa的方法,进入到目录下面编译
  xcodebuild -sdk iphonesimulator6.0
  9、安装路径问题
  全局路径,也就是带上参数 -g 的安装模式。这个命令会把模块安装在 $prefix/lib/node_modules 下,可通过命令 npm root -g 查看全局模块的安装目录。 package.json 里定义的bin会安装到 $prefix/bin 目录下,如果模块带有 man page 会安装到 $prefix/share/man 目录下。
  本地路径,不带 -g 参数的。从当前目录一直查找到根目录/下有没有 node_modules 目录,有模块安装到这个目录下的 node_modules 目录里,如果没有找到则把模块安装到当前目录 node_modules 目录下。package.josn 定义的 bin 会安装到 node_modules/.bin 目录下,man page 则不会安装。


顺其自然evo 2014-11-11 10:10
]]>appium for mac环境准备篇http://www.blogjava.net/qileilove/archive/2014/11/06/419574.html顺其自然evo顺其自然evothu, 06 nov 2014 02:34:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/06/419574.htmlhttp://www.blogjava.net/qileilove/comments/419574.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/06/419574.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419574.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419574.html 之前写过一篇 for windows的,因为是09年的t400,启动模拟器的时候死机三次,那就公司申请台macbook air吧,15寸的macbook pro实在太重了,也就mac才能真正发挥appium的功能,支持android和ios。好了,废话不多,开始。
  1. 爬墙
  因为后续安装过程中可能会碰到墙的问题,所以首先得解决爬墙的问题。
  我的方便,公司提供代理。
  2. 
  guowenxie-macbookair:~ guowenxie$ java -version
  java version "1.8.0_05"
  java(tm) se runtime environment (build 1.8.0_05-b13)
  java hotspot(tm) 64-bit server vm (build 25.5-b02, mixed mode)
  3. git
  guowenxie-macbookair:~ guowenxie$ git --version
  git version 1.8.5.2 (apple git-48)
  4. ruby
  guowenxie-macbookair:~ guowenxie$ ruby -v
  ruby 2.0.0p451 (2014-02-24 revision 45167) [universal.x86_64-darwin13]
  5. brew
  guowenxie-macbookair:~ guowenxie$ brew -v
  homebrew 0.9.5
  这边提下brew的安装,brew是mac os不可或缺的套件管理器
  执行下面命令
  ruby -e "$(curl -fssl https://raw.github.com/homebrew/homebrew/go/install)"
  6. node
  有了brew安装node就方便了
  brew install node
  7. npm
  guowenxie-macbookair:~ guowenxie$ npm -v
  2.0.0-alpha-5
 8. appium
  现在可以开始安装appium
  guowenxie-macbookair:~ guowenxie$ appium -v
  1.2.0
  9. wd
  npm install wd
  10. xcode和android sdk
  这个不说了
  11. 检查环境
  appium提供了一个doctor,运行appium-doctor
guowenxie-macbookair:~ guowenxie$ appium-doctor
running ios checks
xcode is installed at /applications/xcode.app/contents/developer
xcode command line tools are not installed: error: command failed: no receipt for 'com.apple.pkg.cltools_executables' found at '/'.
fix it  (y/n) y
press any key to continue:
xcode command line tools are installed.
devtoolssecurity is enabled.
the authorization db is set up properly.
node binary found at /usr/local/bin/node
ios checks were successful.
running android checks
android_home is set but does not exist on the file system at "users/guowenxie/documents/adt-bundle_mac-x86_64-20140702/sdk"
appium-doctor detected problems. please fix and rerun appium-doctor.
  这里可以看到我xcode command line tools没有安装,这个方便,fix it 的时候输入y,就能自动导向安装了。
  另一个是android_home的环境变量没配置好,那么我们要配置下。
  12. bash_profile文件
  mac 默认是没有这个文件的,我们自己建一个
  touch .bash_profile
  vi .bash_profile
  打开bash_profile文件配置android_home和java_home
  export android_home="/users/guowenxie/documents/adt-bundle-mac-x86_64-20140702/sdk"
  export java_home=$(/usr/libexec/java_home)
  source .bash_profile
  好了,再次运行appium-doctor
guowenxie-macbookair:~ guowenxie$ appium-doctor
running ios checks
xcode is installed at /applications/xcode.app/contents/developer
xcode command line tools are installed.
devtoolssecurity is enabled.
the authorization db is set up properly.
node binary found at /usr/local/bin/node
ios checks were successful.
running android checks
android_home is set to "/users/guowenxie/documents/adt-bundle-mac-x86_64-20140702/sdk"
java_home is set to "/usr/libexec/java_home."
adb exists at /users/guowenxie/documents/adt-bundle-mac-x86_64-20140702/sdk/platform-tools/adb
android exists at /users/guowenxie/documents/adt-bundle-mac-x86_64-20140702/sdk/tools/android
emulator exists at /users/guowenxie/documents/adt-bundle-mac-x86_64-20140702/sdk/tools/emulator
android checks were successful.
all checks were successful
  到此,环境基本准备好了。
  最后,如果不想通过命令行安装appium,也可以安装dmg


顺其自然evo 2014-11-06 10:34
]]>
appium环境抢建(for web browser test)http://www.blogjava.net/qileilove/archive/2014/11/03/419418.html顺其自然evo顺其自然evomon, 03 nov 2014 01:16:00 gmthttp://www.blogjava.net/qileilove/archive/2014/11/03/419418.htmlhttp://www.blogjava.net/qileilove/comments/419418.htmlhttp://www.blogjava.net/qileilove/archive/2014/11/03/419418.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419418.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419418.html  sdk
  
  安装 nodejs
  安装 appium
  配置
  下载&运行项目
  appium是android平台上一个测试框架。
  本文简单地介绍如何在机器上安装并运行该框架。
  应用环境:
  ubuntu 12.04 lts
  htc one x (endeavoru, s720e)
  android sdk
  请参考sdk环境,这里就不多说了。
  appium
  安装 nodejs
  apt-get install nodejs
  # 或者通过nodejs源码编译,这样可以使用最新的代码
  cd ~/downloads
  wget http://nodejs.org/dist/v0.10.25/node-v0.10.25.tar.gz
  tar -zxf node-v0.10.25.tar.gz
  cd ode-v0.10.25
  ./configure --prefix=/usr/local/node
  make && make install
  # edit ~/.bashrc and add node to your path env
  安装 appium
  npm install -g appium # install appium as a global app
  配置手机
  手机需要是已经root过的!
  adb 
  su
  chmod 777 /data/local
  另外,也要确保你手机上安装了最新的chrome浏览器!
  note:
  这步是必需的,否则后面会发生无法启动浏览器的异常。
  下载&运行测试项目
  # 下载项目
  git clone git@github.com:ytfei/appium_chrome_demo.git
  cd appium_chrome_demo
  npm install # 安装依赖包
  # 启动appium
  appium -g appium.log &
  # 开始测试
  node .js


顺其自然evo 2014-11-03 09:16
]]>
appium环境抢建(for web browser test)http://www.blogjava.net/qileilove/archive/2014/10/30/419235.html顺其自然evo顺其自然evothu, 30 oct 2014 03:24:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/30/419235.htmlhttp://www.blogjava.net/qileilove/comments/419235.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/30/419235.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/419235.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/419235.html  sdk
  
  安装 nodejs
  安装 appium
  配置
  下载&运行项目
  appium是android平台上一个测试框架。
  本文简单地介绍如何在机器上安装并运行该框架。
  应用环境:
  ubuntu 12.04 lts
  htc one x (endeavoru, s720e)
  android sdk
  请参考sdk环境,这里就不多说了。
  appium
  安装 nodejs
  apt-get install nodejs
  # 或者通过nodejs源码编译,这样可以使用最新的代码
  cd ~/downloads
  wget http://nodejs.org/dist/v0.10.25/node-v0.10.25.tar.gz
  tar -zxf node-v0.10.25.tar.gz
  cd ode-v0.10.25
  ./configure --prefix=/usr/local/node
  make && make install
  # edit ~/.bashrc and add node to your path env
  安装 appium
  npm install -g appium # install appium as a global app
  配置手机
  手机需要是已经root过的!
  adb 
  su
  chmod 777 /data/local
  另外,也要确保你手机上安装了最新的chrome浏览器!
  note:
  这步是必需的,否则后面会发生无法启动浏览器的异常。
  下载&运行测试项目
  # 下载项目
  git clone git@github.com:ytfei/appium_chrome_demo.git
  cd appium_chrome_demo
  npm install # 安装依赖包
  # 启动appium
  appium -g appium.log &
  # 开始测试
  node .js


顺其自然evo 2014-10-30 11:24
]]>
2014非常好用的开源android测试工具http://www.blogjava.net/qileilove/archive/2014/10/17/418844.html顺其自然evo顺其自然evofri, 17 oct 2014 07:34:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/17/418844.htmlhttp://www.blogjava.net/qileilove/comments/418844.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/17/418844.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/418844.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/418844.html当前有很大的趋势是转向应用平台, 是最广泛使用的移动,2014 年大约占 80% 以上的市场。在开发 android 应用的时候要进行,现在市场上有大量的测试工具。
  本文主要是展示一系列的开源 android 测试工具。每个工具都会有相应的简短介绍,还有一些相关的资源。android 测试工具列表是按照字母来排序的,最后还会介绍几个不是特别活跃的 android 测试相关的开源项目。
  本文提到的开源 android 工具包括:android  kit, androidjunit4, appium, calabash-android, monkey, monkeytalk, nativedriver, robolectric, robospock, robotium, uiautomator, selendroid。
  android test kit
  android test kit 是一组  ,用于 android 平台,包含 espresso api 可用于编写简洁可靠的 android ui 测试。
  androidjunit4
  androidjunit4 是一个让  4 可以直接运行在 android 设备上的开源命令行工具。
  oschina url: http://www.oschina.net/p/androidjunit4
  appium
  appium 是一个开源、跨平台的工具,用于测试原生和轻量移动应用,支持 ios, android 和 firefoxos 平台。appium 驱动的 uiautomation 库和 android 的 uiautomator 框架,使用  的 webdriver json 协议。appinm 的 ios 支持是基于 dan cuellar's 的 ios auto. appium 同时绑定了 selendroid 用于老的 android 平台测试。
  oschina url: http://www.oschina.net/p/appium
  相关资源
  * appium tutorial
  * android ui testing with appium
  calabash-android
  calabash-android 是一个基于 cucumber 的 android 的功能自动化测试框架。calabash 允许你写和执行,是开源的自动化移动应用测试工具,支持 android 和 ios 原生应用。calabash 的库允许原生和混合应用的交互测试,交互包括大量的终端用户活动。calabash 可以媲美 selenium webdriver。但是, 需要注意的是  应用和桌面环境的交互跟触摸屏应用的交互是不同的。calabash 专为触摸屏设备的原生应用提供 apis。
  oschina url: http://www.oschina.net/p/calabash-android
  相关资源
  * a better way to test android applications using calabash
  * calabash android: query language basics
  monkey
  monkey 是 google 开发的 ui/应用测试工具,也是命令行工具,主要针对。你可以在任意的模拟器示例或者设备上运行。monkey 发送一个用户事件的 pseudo-random 流给系统,作为你开发应用的压力测试。
  oschina url: http://developer.android.com/tools/help/monkey.html
  monkeytalk
  monkeytalk 是世界上最强大的移动应用测试工具。monkeytalk 自动为 ios 和 android 应用进行真实的,功能性交互测试。monkeytalk 提供简单的 "smoke tests",复杂数据驱动的测试套件。monkeytalk 支持原生,移动和混合应用,真实设备或者模拟器。monkeytalk 使得场景捕获非常容易,可以记录高级别,可读的测试脚本。同样的命令可以用在 ios 和 android 应用上。你可以记录一个平台的一个测试,并且可以在另外一个平台回放。monkeytalk 支持移动触摸和基于手势交互为主的移动体验。点击,拖拽,移动,甚至是手指绘制也可以被记录和回放。
  oschina url: http://www.oschina.net/p/monkeytalk
  相关资源
  * using monkeytalk in androidstudio
  nativedriver
  nativedriver 是 webdriver api 的实现,是原生应用 ui 驱动,而不是 web 应用。
  oschina url: http://www.oschina.net/p/nativedriver
 robolectric
  robolectric 是一款android单元测试框架,使用 android sdk jar,所以你可以使用测试驱动开发 android 应用。测试只需几秒就可以在工作站的 jvm 运行。robolectric 处理视图缩放,资源加载和大量 android 设备原生的 c 代码实现。robolectric 允许你做大部分真实设备上可以做的事情,可以在工作站中运行,也可以在常规的 jvm 持续集成环境运行,不需要通过模拟器。
  oschina url: http://www.oschina.net/p/robolectric
  additional resources
  * better android testing with robolectric 2.0
  using robolectric for android testing – tutorial
  robospock
  robospock 是一个开源的 android 测试框架。提供简单的编写 bdd 行为驱动开发规范的方法,使用groovy 语音,支持 google guice 库。robospock 合并了 robolectric 和 spock 的功能。
  oschina url: http://www.oschina.net/p/robospock
  相关资源
  * robospock – behavior driven development (bdd) for android
  robotium
  robotium 是一款国外的android自动化测试框架,主要针对android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击、长 按、滑动等)、查找和断言机制的api,能够对各种控件进行操作。robotium结合android官方提供的测试框架达到对应用程序进行自动化的测 试。另外,robotium 4.0版本已经支持对webview的操作。robotium 对activity,dialog,toast,menu 都是支持的。
  oschina url: http://www.oschina.net/p/robotium
  相关资源
  * robotium – testing android user interface
  * android user interface testing with robotium – tutorial
  uiautomator
  uiautomator 测试框架提高用户界面(ui)的测试效率,通过自动创建功能 ui 测试示例,可以在一个或者多个设备上运行你的应用。
  oschina url: http://www.oschina.net/p/uiautomator
  相关资源
  * automatic android testing with uiautomator
  selendroid
  selendroid 是一个 android 原生应用的 ui 自动化测试框架。测试使用 selenium 2 客户端 api 编写。selendroid 可以在模拟器和实际设备上使用,也可以集成网格节点作为缩放和并行测试。
  oschina url: http://www.oschina.net/p/selendroid
  相关资源
  * mobile test automation with selendroid
  * road to setup selendroid and create first test script of android application
  * up and running with: selendroid
  一些停止维护的 android 测试工具
  一些几乎没有继续维护的开源 android 测试工具项目(至少是最近几个月都没有更新的项目)。
  emmagee
  emmagee 是监控指定被测应用在使用过程中占用机器的cpu、内存、流量资源的性能测试小工具。emmagee 同时还提供非常酷的一些特性,比如定制间隔来收集数据,使用浮动窗口呈现实时进程状态等。
  oschina url: http://www.oschina.net/p/emmagee
  sirocco
  scirocco(scirocco-webdriver) 是开源的应用自动化测试工具,可以从 eclipse 访问必要的测试设备。scirocco 提供自动化的 android 应用测试功能,代替手工测试。scirocco 支持谷歌的 nativedriver,把 androiddriver 作为主要的测试库。scirocco 包括三个部分:nativedriver,androiddriver,scirocco 插件(一个 eclipse 插件;可以自动执行 scenario 测试和制作测试报告截图)。


顺其自然evo 2014-10-17 15:34
]]>
android如何进行单元测试http://www.blogjava.net/qileilove/archive/2014/10/16/418770.html顺其自然evo顺其自然evothu, 16 oct 2014 01:50:00 gmthttp://www.blogjava.net/qileilove/archive/2014/10/16/418770.htmlhttp://www.blogjava.net/qileilove/comments/418770.htmlhttp://www.blogjava.net/qileilove/archive/2014/10/16/418770.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/418770.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/418770.html menifest.xml中加入:
中加入:
android:name="android.test.runner" />
外面加入:
android:label=" for my app"/>
  编写代码:必须继承自androidtestcase类
package name.feisky.android.test;
import android.test.androidtestcase;
import junit.framework.assert;
public class mytest extends androidtestcase {
private static final string tag="mytest";
}


顺其自然evo 2014-10-16 09:50
]]>
android中数据库升级onupgrade方法说明http://www.blogjava.net/qileilove/archive/2014/09/28/418349.html顺其自然evo顺其自然evosun, 28 sep 2014 02:44:00 gmthttp://www.blogjava.net/qileilove/archive/2014/09/28/418349.htmlhttp://www.blogjava.net/qileilove/comments/418349.htmlhttp://www.blogjava.net/qileilove/archive/2014/09/28/418349.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/418349.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/418349.htmlandoird的sqliteopenhelper类中有一个onupgrade方法。帮助文档中只是说当升级时该方法被触发。经过实践,解决了我一连串的疑问:
  1. 帮助文档里说的“数据库升级”是指什么?
  你开发了一个程序,当前是1.0版本。该程序用到了数据库。到1.1版本时,你在数据库的某个表中增加了一个字段。那么软件1.0版本用的数据库在软件1.1版本就要被升级了。
  2. 数据库升级应该注意什么?
  软件的1.0版本升级到1.1版本时,老的数据不能丢。那么在1.1版本的程序中就要有地方能够检测出来新的软件版本与老的数据库不兼容,并且能够 有办法把1.0软件的数据库升级到1.1软件能够使用的数据库。换句话说,要在1.0软件的数据库的那个表中增加那个字段,并赋予这个字段默认值。
  3. 程序如何知道数据库需要升级?
  sqliteopenhelper类的构造函数有一个参数是int version,它的意思就是指数据库版本号。比如在软件1.0版本中,我们使用sqliteopenhelper访问数据库时,该参数为1,那么数据库版本号1就会写在我们的数据库中。
  到了1.1版本,我们的数据库需要发生变化,那么我们1.1版本的程序中就要使用一个大于1的整数来构造sqliteopenhelper类,用于访问新的数据库,比如2。
  当我们的1.1新程序读取1.0版本的老数据库时,就发现老数据库里存储的数据库版本是1,而我们新程序访问它时填的版本号为2,系统就知道数据库需要升级。
  4. 何时触发数据库升级?如何升级?
  当系统在构造sqliteopenhelper类的对象时,如果发现版本号不一样,就会自动调用onupgrade函数,让你在这里对数据库进行升级。根据上述场景,在这个函数中把老版本数据库的相应表中增加字段,并给每条记录增加默认值即可。
  新版本号和老版本号都会作为onupgrade函数的参数传进来,便于开发者知道数据库应该从哪个版本升级到哪个版本。
  升级完成后,数据库会自动存储最新的版本号为当前数据库版本号。


顺其自然evo 2014-09-28 10:44
]]>
android、ios和windows phone中的推送技术http://www.blogjava.net/qileilove/archive/2014/08/27/417397.html顺其自然evo顺其自然evowed, 27 aug 2014 02:43:00 gmthttp://www.blogjava.net/qileilove/archive/2014/08/27/417397.htmlhttp://www.blogjava.net/qileilove/comments/417397.htmlhttp://www.blogjava.net/qileilove/archive/2014/08/27/417397.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/417397.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/417397.html  推送并不是什么新技术,这种技术在时代就已经很流行了。只是随着进入互联网时代,推送技术显得更加重要。因为在智能中,推送从某种程度上,可以取代使用多年的短信,而且与短信相比,还可以向用户展示更多的信息(如图像、表格、声音等)。
  推送技术的实现通常会使用服务端向客户端推送消息的方式。也就是说客户端通过用户名、key等id注册到服务端后,在服务端就可以将消息向所有活动的客户端发送。
  实际上,在很多移动中,官方都为其提供了推送方案,例如,的云推送、ios、 phone7/8也都提供了类似的推送方案。不过这些推送方案的服务器都在国外,有一些推送服务(如google的云推送)在国内由于某些原因不太稳定,所以国内近几年涌现出了很多专门为国人打造的推送服务。
  本文将从各种流行移动操作系统入手介绍推送技术的各种实现方式。当然,我们的主要目的是讨论的推送技术。
  一、ios的推送技术
  apple为ios提供了很完美的推送方案,其基本原理是apple提供了自己的推送服务器,叫apns(apple push notification service,推送通知服务器)。而客户端设备(iphone、ipad等)直接与apns建立长连接。不过向客户端设备发送的消息并不是由apns产生的,而是在需要发送消息的用户自己提供的服务器(称为provider)中产生的,然后provider将消息传送给apns,最后由apns将消息传送给客户端设备。也就是说,消息最开始由provider产生,然后provider将消息传送给apns,最后再由apns传送给客户端设备。消息传递的过程如图1所示。
  
  在发送消息到客户端设备接收到消息的过程中,始终伴随这一个令牌的传送(device token)。要想使用apns提供消息服务,应用程序需要先向ios注册需要提供的一个必要的信息就是与当前设备有关的device token,ios在接收到devicetoken后,会向apns查询这个device token是否在apns上注册了(所有的ios设备在第一次使用时都需要向苹果服务器注册一个账号,否则无法从applestore下载应用,当然更无法使用推送服务了),如果已经注册,apns会直接向应用程序返回这个devicetoken。应用程序获得这个devicetoken后,表示apns已经允许向自己推送消息了,接着还需要将该device token发送给推送服务器(provider)。到这里应用程序已经成功将自己注册到apns中了。现在就可以通过provider产生要推送的消息,然后provider会将消息发送给apns服务器,最后apns服务器会直接向应用程序发送消息。这个过程比较复杂,不过看一下图2的描述就会对这一过程更加了解了。每一个流程描述前面的数字表示发送的时间先后顺序。
  
  二、windows phone的推送技术
  为window phone提供的推送方案与ios类似,也需要自己准备推送服务器(可以称为cloud service)。只是表示设备的id变成了uri。在window phone中有一个push client service(pcs)。所有需要推送服务的应用程序都需要与push client service通信。下面是window phone推送的基本步骤,读者可以与图3对照来看这一过程。
  第1步:应用程序会向push client service请求一个push notification uri(①)。
  第2步:如果当前window phone设备已经在微软服务器注册了,push client service会从mpns(microsoft push notification service ,微软推送通知服务)获取push notification uri,并返回给应用程序,表示推送服务可用(②和③)。
  第3步:应用程序需要将push notification uri发送给自己的推送服务器(cloud service)(④)。
  第4步:如果需要推送消息,cloud service会将消息发送到mpns,然后mpns会将消息发送给push client service,最后由push client service将消息传送给应用程序(⑤、⑥和③)。
  
  除了使用官方的推送方案外,现在国内涌现出多个第三方的推送方案,例如,极光推送(jpush)、百度推送等。读者也可以用一下,这些同时通常是免费的(可能推送多媒体数据需要收费)。


顺其自然evo 2014-08-27 10:43
]]>
android robotium搭建环境测试微信http://www.blogjava.net/qileilove/archive/2014/08/20/417137.html顺其自然evo顺其自然evowed, 20 aug 2014 01:36:00 gmthttp://www.blogjava.net/qileilove/archive/2014/08/20/417137.htmlhttp://www.blogjava.net/qileilove/comments/417137.htmlhttp://www.blogjava.net/qileilove/archive/2014/08/20/417137.html#feedback0http://www.blogjava.net/qileilove/comments/commentrss/417137.htmlhttp://www.blogjava.net/qileilove/services/trackbacks/417137.html因为要在命令行下运行一些的工具,所以配置一些环境变量会比较方便:
  遇到问题:  -jar re-sign.jar 出现提示android路径没有配置好:
  需要配置如下:
  配置android_home为android sdk的安卓目录,例如:d:\android-sdk
  在path下添加这两个:
  %android_home%\tools;%android_home%\platform-tools;
  重新开关一次命令窗口
  在真机中安装apk(以微信作为的apk)
  因为要求被测应用和测试代码要有一致的key,所以我们需要把下载到的apk,通过re-sign.jar来产生debug key的apk,这个重新生成的apk就会跟测试项目签名一致了
  re-sign.jar可以从这里下载到:
  http://www.troido.de/re-sign.jar
  下载完后,在命令行下 通过 java -jar re-sign.jar就会出现一个节目,然后将apk拖到这个节目,就会自动生成一个debug key的apk
  产生新apk的过程中会弹出一个信息框,记得截下图,因为里面有两个信息我们等会的代码中需要用到
  然后打开模拟器(模拟器器一定要打开才能安装成功),然后打开命令行
  adb install mitalk_debug.apk(新生成apk的名称)
  安装成功就可以再模拟器里看到该应用的图标了
  注意:
  一、删除之前 apk 文件的签名
  1、解压apk 文件
  2、删除解压出来文件夹中的 meta-inf 目录:meta-inf 存放签名后的cert 和manifest 文件,用于识别软件的
  签名及凯发k8网页登录的版权。
  3、删除文件夹后重新把解压出来的其它文件夹压缩为zip 文件,然后直接把文件后缀改为apk
  二、为 apk 重新生成签名
  1、将证书复制到与需要重新签名的apk 文件相同的目录下
  2、jarsigner -keystore debug.keystore -storepass android -keypass android d:\robotium\robotium\robotium\weixin_delet_rsa_sf.apk androiddebugkey
  创建项目
  打开eclipse,点击file->new一个android  project,然后点击下一步的时候选择this project(因为我们没有米聊应用的源码),然后选择要在哪个android版本上测试
  在该项目下创建一个包,com.tencent.test,在该包下创建logintest类,如下
package com.mitalk.test;
import android.app.activity;
import android.test.activityinstrumentationtestcase2;
import com.jayway.android.robotium.solo.solo;
@suppresswarnings("rawtypes")
public class logintest extends activityinstrumentationtestcase2 {
public solo solo;
public activity activity;
private static class launchactivityclass;
// 对应re-sign.jar生成出来的信息框里的两个值
private static string mainactiviy = "com.tencent.mm.ui.launcherui";
private static string packagename = "com.tencent.mm";
static {
try {
launchactivityclass = class.forname(mainactiviy);
} catch (classnotfoundexception e) {
throw new runtimeexception(e);
}
}
@suppresswarnings("unchecked")
public logintest() {
super(packagename, launchactivityclass);
}
@override
protected void setup() throws exception {
super.setup();
this.activity = this.getactivity();
// this.solo = new solo(getinstrumentation(), getactivity());
}
public void testloginwithincorrentusernameandpassword() throws exception {
wait(5000);
//待完成
}
@override
public void teardown() throws exception {
try {
this.solo.finishopenedactivities();
} catch (throwable e) {
e.printstacktrace();
}
this.activity.finish();
super.teardown();
}
}


顺其自然evo 2014-08-20 09:36
]]>
网站地图