app出现剖析您们好有语法错误吗一回事

移动应用性能问题决定用户去留——国内首份移动App性能数据深度解析报告
发表于 15:19|
来源新闻资讯|
作者云知秋
摘要:据听云 ()研究统计:74%以上的用户在性能问题面前会选择沉默、忍受、或离开,而在移动应用出现性能问题导致延时响应10秒后,有近5%的真实用户会放弃使用该应用。
据听云 ()研究统计:74%以上的用户在性能问题面前会选择沉默、忍受、或离开,而在移动应用出现性能问题导致延时响应10秒后,有近5%的真实用户会放弃使用该应用。一般情况下,应用性能问题出现的频率与错误种类超乎人想象,由于网络环境、设备机型、开发环境等多样元素的存在,应用性能问题组合超1亿零700万种(对5079个不同机型、1172种操作系统以及18家运营商进行整合分析得出),你永远都不知道下一个导致用户流失的性能问题是什么。
听云研发人员称:&比起用户流失来说,移动应用性能问题还会给用户带来更多的损失,比如像当应用出现崩溃、错误时,便会引起关键业务中断、收入下降等情况,进一步便会影响到产品生命周期价值;如果应用请求响应时间长,那么便会导致终端用户体验缓慢、用户留存率下降的情况发生;如果是应用交互性能慢的话,那么页面元素加载就会缓慢进而造成卡顿或是不完整造成的布局错乱。&
关于崩溃:2014移动应用性能数据不尽如人意
2014年是移动互联网快速发展的一年,据听云对3.5亿活跃设备进行性能监控发现,当iOS崩溃率超过8&、Android的崩溃率超过4&时,活跃用户有明显下降态势,并且全年平均崩溃率均超出标准值,普遍存在轻微隐患。
2014年9月苹果公司推出了iOS8系统,而该操作系统成为目前崩溃发生最高的操作系统,崩溃率超25&;相较于其他系统,iOS7X整体整体崩溃表现稳定,崩溃率均低于10&。
相较于iOS系统,Android整体崩溃率较低,其中只有Android2X系统崩溃率高于10&,在Android4.X版本后,崩溃率稳定在2&-4&。
据分析,Android系统整体崩溃率较低的原因在于:Android4.X版本稳定性较之前版本有显著提升,而iOS8版本较不稳定;其二,在更新策略上,iOS更新推送周期较长,Android则会进行即时推送更新;其三,由于语言/系统架构的特殊性,OC需直接面对底层API,出错可能性较高,而受OS版本影响,硬件差异影响较java更大;最后,iOS系统受限更多,如内存、后台、API限制等。
关于错误:多体现在建联失败、请求超时、500
移动应用错误顾名思义为应用在生产环境下所出现的网络错误和HTTP(HTTP状态码)汇总,会造成应用页面无法显示,影响用户体验。据统计,连接超时在网络错误中占比最高,占29%;建立连接失败居第二,占23%;占比较高的还有非法主机(19%)和非法URL(13%)。在Http错误中,&500&以46%占比居首。
对于整体错误来说,连接超时、建立连接失败、500及未知主机在移动应用错误排行靠前,整体错误率占比6.3&。当面对HTTP错误时,听云认为应该根据错误代码对错误含义对症下药,而网络错误则需要从网络层面剖析问题发生的原因。
关于应用请求响应时间:会直接影响用户留存
用户留存率是移动互联网和互联网均最重视的关键业务指标之一,留存用户和留存率直接体现了应用的质量和保留用户的能力。当应用请求响应时间处在不同数值时,应用反应的状态会有所不同。经听云对超过5万的移动应用的主机请求响应时间监控发现,当请求响应时间超过2000ms后,用户开始流失。
关于应用交互性能:会直接导致用户丧失耐心
用户与移动应用的界面元素和内容交互的体验耗时为交互性能时间,应用的页面元素加载时间过长所引起的用户体验下降被称为交互缓慢。当页面加载缓慢时,便会造成应用卡顿的现象,这其中造成加载缓慢的原因有很多,像界面布局、视图加载、存储过程、查询数据库、程序运算等。那么如何找出交互性能的瓶颈?听云认为可通过查询前段UI线程或后台工作线程的方法用时来进行判断。数据统计,当应用交互执行性能时间达400ms时,该应用则进入性能轻微隐患阶段。
关于运营商网络性能:不同地域差异较大
随着2G到4G网络的发展,用户对运营商的网络性能提出了越来越高的需求。据听云数据统计,当2G网络响应时间达4600ms时,该网络则被判定为轻微隐患。然而相同运营商的3G、4G网络性能在进入轻微隐患状态时,相对应的网络响应时间则缩短至1200ms和600ms。
同样可以看到的是,同一运营商在不同网络下,各省份网络响应时间也大不相同。移动各网段在黑龙江、西藏网络性能较好,而在香港、福建等南方城市性能较差;联通2G网络在广东、福建性能较差,而3G、4G网络却在如甘肃、北京、河北等北方城市性能较好;电信各网段性能分布较不均衡,2G、3G性能较好省份不如移动、联通明显,分布于西藏、台湾,而4G较好区域集中在贵州、湖北等中部省份。
从响应时长本身可分析出,2G、3G、4G网络性能最优依次为电信、联通、电信,同为3G网络下,联通与电信不相上下,4G网络下电信网络性能远优于联通与移动。
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章看我来找茬|京东到家APP用户体验分析
一、视觉设计
搜索框问题
【体验问题】搜索输入框默认文案和背景色对比度不够,导致文字看不清楚;
【优化方案】输入框内的底色跟首页一直,但是底色背景调整为浅灰或白色。比如:微信、百度外卖、爱鲜蜂的搜索框默认底色均为纯白(255,255,255);
【设计原则】一款APP应以同色配色做辅助,中间无色或灰色做协调,对比色做点缀。
首页图标配色
【体验问题】图标颜色太淡、整体偏小,视觉上压不住标题,需要用户花时间去反应底部的文案;
【优化方案】首页图标风格整体以纯色为主,颜色搭配可以选择少量冲突色做点缀(见下图);
【设计原则】“Don’t make me think”图标形状固化,特殊节日(比如:双十一)换下样式,但整体布局保持统一。
图片拉伸/模糊
【体验问题】图片存在被拉伸、模糊的情况,促销活动的视觉设计比较粗糙;
【优化方案】一般产品/活动上线前产品经理、QA、运营等各角色需要确认后才能上线的,如果这是确认后的效果,本人只能“呵呵”了。比如:
1)领取优惠劵页“京东到家”的背景图片是拉伸的;
2)首页默认弹窗的推广促销图片是模糊的,且设计粗糙;
【设计原则】C端产品全是细节堆砌起来的,非常考验产品经理产品细节的把控能力,建议产品经理每天花10分钟把用户反馈过一遍,每周去客服部门轮岗一次,坚持三个月用户感觉会有一次很大的提升(本人坚持了8年)。
入口和标示不分
1)“满59减12”文案意思和视觉设计都是状态,但实际情况是可点击的,为一个入口;
2)“加入购物车”文案意思是一个动作,竟然又是不可点;
3)“点击领取优惠劵”文案意思同样为动作,但是我点,我点,我点点点,真的没反应的哦~
4)“鲁海”点击后打开的是一个店铺,大家是不是也觉得应该是个状态呢?
【设计规则】
“加入购物车”“点击领取优惠劵”为“动作引导型文案”,一般点击后是有后续行为的;
“满59减12““2小时内送达”为“转态型文案”,一般是告诉用户一个结果,无后续行为;
以上规则在视觉设计、交互设计时都应该特别注意。
二、交互设计
低频操作放在一级入口,且容易误操作
【体验问题1】“删除”为低频操作,用户需要的时候能找到就行,没必要做成一级按钮;
【体验问题2】删除放在编辑右侧,单手操作手机很容易误操作的,这道理大家都懂;
【优化方案】“删除”按钮放在“编辑”入口里面,用户使用的时候能找到即可。
默认未定位当前城市(数据经验)
【体验问题】新增收货地址页,需要用户手动选择城市;
【优化方案】根据小编的经验,LBS产品91%以上的用户会选择当前所在城市,新建地址时默认显示当前地址就能满足绝大部分用户的需求。
商品详情页右上角的“…”,不符合APP交互设计规则
【体验问题1】“消息中心”收在二级目录,新消息提醒(比如:小红点)无法展示;
【体验问题2】该页面返回首页,有两种途径:
1)连续点击两次左上角的”返回“按钮;
2)点击右上角的“…”选择“回到首页”;
两种方式基本无区别,以本人多年经验来分析,该页面通过“…”返回首页的用户应该不超过5%,消息中心的点击肯定小于1%;
【优化方案】根据“步骤最简原则”,商品详情页右上角直接放一个“Home”标示,点击后一键回到首页。
弹窗尽量少使用(干扰用户)
【体验问题1】优惠劵顶部的“i”用户不容易注意到;
【体验问题2】优惠劵的使用规则需要点击图标后,才展示优惠劵“仅限在线订单”;
【设计规则】能直接给用户结果时,不要让用户操作,尽量少使用弹窗(干扰用户)。
文案少使用负面词语
【体验问题1】优惠劵已领完,直接告诉用户就行了,没必要点击后出弹窗;
【体验问题2】“领取失败”的文案也不合适;
【优化方案】负面的词语(比如:失败/超时/崩溃等),技术术语(比如:服务器/系统异常/繁忙/任务出错等)应该尽量少用或不用。
交互最简原则
【体验问题】在线客服层级太深,步骤过于繁琐;
【优化方案】依据仍然是“步骤最简”原则,中间的两步操作可以合并,具体请见下图。
三、细节体验
交互不一致
同层级页面,同样的位置,部分轮播图是入口(打开新页面),部分仅是信息展示(无法点击)。
用户引导不明确
点击“小红心”进行评价,真心没有找到哪儿有红心啊。
系统适配bug
系统时间显示不全的问题,这个应该算是适配bug。
商品评价太假
商品的评价确实是有点假,咱们至少也人工审核一下吧。
文案语法错误
“部分商品8折起”有语法错误,应是“促销商品8折起”“部分商品低至8折”。
商品折扣价混乱
“部分商品8折起”“超市商品7折起”“实际是4.5折”,小编已经迷茫了。作为电商类APP,不都是展示最优惠的价格么,京东真土豪啊,做好事不留名的哦。
中英文文字混用
作为一个细节强迫症,小编是绝对忍不了“中英文符号混用”“中英文混用”的,而在京东到家对这种细节完全不关注。
活动图片缺失
此处后台没有配图,作为一家上市公司,咱是不是稍微专业一点点呢。
时间关系,就先写这么多了。这个文章算是吐槽,因为作为一名细节控产品经理,实在是忍不了这么多的问题。同时也是交流,如果大家认识京东到家的产品经理,也欢迎帮忙转达。
看过本文的人还看过
最新图文推荐
最新专栏文章
大家感兴趣的内容
&&<a rel="nofollow" class="red" href="" target="_blank" color="red新版网站排行榜
===全新上线===
网友热评的文章app出现剖析语法错误一回事_百度知道
app出现剖析语法错误一回事
app出现剖析语法错误一回事
我有更好的答案
出现错误很正常 科技只能帮助人类 人脑才是最重要的
其他类似问题
为您推荐:
app的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Android无需权限显示悬浮窗, 兼谈逆向分析app - 简书
下载简书移动应用
写了32839字,被293人关注,获得了174个喜欢
Android无需权限显示悬浮窗, 兼谈逆向分析app
最近UC浏览器中文版出了一个快速搜索的功能, 在使用其他app的时候, 如果复制了一些内容, 屏幕顶部会弹一个窗口, 提示一些操作, 点击后跳转到UC, 显示这个悬浮窗不需要申请android.permission.SYSTEM_ALERT_WINDOW权限.
如下图, 截图是在使用Chrome时截的, 但是屏幕顶部却有UC的view浮在屏幕上. 我使用的是小米, 我并没有给UC授悬浮窗权限, 所以我看到这个悬浮窗时是很震惊的.
悬浮窗原理
做过悬浮窗功能的人都知道, 要想显示悬浮窗, 要有一个服务运行在后台, 通过getSystemService(Context.WINDOW_SERVICE)拿到WindowManager, 然后向其中addView, addView第二个参数是一个WindowManager.LayoutParams, WindowManager.LayoutParams中有一个成员type, 有各种值, 一般设置成TYPE_PHONE就可以悬浮在很多view的上方了, 但是调用这个方法需要申请android.permission.SYSTEM_ALERT_WINDOW权限, 在很多机型上, 这个权限的名字叫悬浮窗, 比如小米手机上默认是禁用这个权限的, 有些恶意app会用这个权限弹广告, 而且很难追查是哪个应用弹的. 如果这个权限被禁用, 那么结果就是悬浮窗无法展示, 比如有道词典的复制查词功能, 在小米手机上经常没用, 其实是用户没有授权, 而且应用也没有引导用户给它打开授权.
现在UC能突破这个限制, 我很好奇它是怎么做到的.
Android开发有点蛋疼的地方就是太容易被反编译, 但有时这也成为我们研究别人app的一种手段.
使用apktool可以很轻松的反编译UC.
逆向别人的app, 比较关键的地方是怎么找代码, 因为代码基本上都是混淆的, 直接看肯定是看不懂的, 只能去找, 突破口一般在字符资源上, 比如我们看到上图中的快速搜索是UC的字符, 那么我们到res/values/strings.xml去找快速搜索, 就可以找到下面的内容
&string name="dark_search_banner_search"&快速搜索&/string&
这里我们拿到了快速搜索对应的名字dark_search_banner_search, Android在编译时会给每个资源分配一个id, 我们grep一下这个字符资源的名字就能知道id是多少, 一般在R.java, res/values/public.xml中有定义, 我直接到public.xml中找到了它的id
&public type="string" name="dark_search_banner_search" id="0x7f070049" /&
有了字符资源的id 0x7f070049, 我们再在代码里面grep一下这个id, 就能知道哪几个文件使用了这个字符资源.
之所以这么确定是在代码里, 是因为UC在我们复制的内容不同时, 悬浮窗标题会不一样, 一定是在代码里控制的, 结果如下
./com/uc/browser/b/f.smali
结果可能和大家不一样, 但是一定会找到一个被混淆的smali文件
这一部应该是最恶心的. smali代码和java代码的关系, 就像汇编代码和C++代码, 但是smali比汇编代码要容易理解的多, 不然也不会有那么多公司故意将代码写在C++层了.
虽然代码都被混淆了, 而且以我们不熟悉的方式出现, 但我们可以根据一些蛛丝马迹来判断代码的执行, 比如Framework的类和API是不能被混淆的, 这也是我们能看懂smali的原因之一, 我们可以结合这些面包屑来还原整个app代码, 当然这需要我们对smali很熟悉, 如果不熟悉smali, 至少要对Android的API熟悉. 因为有时实在看不懂, 我们要靠猜来还原一段代码的逻辑.
首先在代码里面找到0x7f070049, 发现了如下代码
const v3, 0x7f070049
invoke-virtual {v1, v3}, Landroid/content/res/R-&getString(I)Ljava/lang/S
move-result-object v1
iput-object v1, v0, Lcom/uc/browser/b/a;-&dpC:Ljava/lang/S
invoke-virtual {v0, v1}, Lcom/uc/browser/b/a;-&o(Landroid/graphics/drawable/D)V
:try_end_2
.catch Ljava/lang/E {:try_start_2 .. :try_end_2} :catch_0
goto/16 :goto_0
这是0x7f070049出现之后的一部分代码, 一路看下来, 其实都是在取值赋值, 就拿0x7f070049来说:
#使v3寄存器的值为0x7f070049
const v3, 0x7f070049
#v1是Resources实例, 调用它的getString方法, 方法的参数是v3中的值
invoke-virtual {v1, v3}, Landroid/content/res/R-&getString(I)Ljava/lang/S
#将结果存入v1寄存器
move-result-object v1
其实就是我们常用的getResources().getString其实如果一直这么看下去, 会发现毫无头绪, 剩下的代码一直在干差不多的事情, 所以我只截取了这部分, 注意最后一行
goto/16 :goto_0
也就是说, 有可能代码转到goto_0那儿去了, 那么看看goto_0那里又写了些什么
const-string v1, "window"
invoke-virtual {v0, v1}, Landroid/content/C-&getSystemService(Ljava/lang/S)Ljava/lang/O
move-result-object v0
check-cast v0, Landroid/view/WindowM
invoke-interface {v0}, Landroid/view/WindowM-&getDefaultDisplay()Landroid/view/D
move-result-object v0
invoke-virtual {v0}, Landroid/view/D-&getWidth()I
move-result v0
iget-object v1, v10, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
iput v0, v1, Landroid/view/WindowManager$LayoutP-&width:I
iget-object v0, v10, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
invoke-virtual {v10}, Lcom/uc/browser/b/a;-&getContext()Landroid/content/C
move-result-object v1
invoke-virtual {v1}, Landroid/content/C-&getResources()Landroid/content/res/R
move-result-object v1
const v2, 0x7f0d0022
invoke-virtual {v1, v2}, Landroid/content/res/R-&getDimension(I)F
move-result v1
float-to-int v1, v1
iput v1, v0, Landroid/view/WindowManager$LayoutP-&height:I
iget-object v0, v10, Lcom/uc/browser/b/a;-&mWindowManager:Landroid/view/WindowM
iget-object v1, v10, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
invoke-interface {v0, v10, v1}, Landroid/view/WindowM-&addView(Landroid/view/VLandroid/view/ViewGroup$LayoutP)V
其实看到const-string v1, "window", 我们就应该有所警惕了, 这可能是关键代码了. 为什么这么说? 因为悬浮窗的实现里面, 需要获取WindowManager, 从而需要调用Context.getSystemService(Context.WINDOW_SERVICE), 而官方文档写了Context.WINDOW_SERVICE就是常量window. 而后我们看到代码中构造了WindowManager.LayoutParams, 最终在addView时传入.
看到这里, 我也觉得很奇怪, 我在悬浮窗原理中写的是我知道的实现悬浮窗的方法, UC的实现好像跟我调用的是相同的API, 也没看到反射之类可能展示奇技淫巧的代码, 为什么UC就可以不需要权限直接显示悬浮窗呢?
我认为addView的第二个参数WindowManager.LayoutParams可能是关键, 所以我需要知道UC是如何构造这个WindowManager.LayoutParams的.
由于是系统的类, 无法混淆, 直接搜索LayoutParams就找到了下面的代码
iget-object v1, v10, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
这句话就是把v10的值赋给v1, v10是com/uc/browser/b/a的成员dpx, 那么打开com/uc/browser/b/a.smali看看dpx到底是怎么构造的.
.field dpx:Landroid/view/WindowManager$LayoutP
new-instance v0, Landroid/view/WindowManager$LayoutP
invoke-direct {v0}, Landroid/view/WindowManager$LayoutP-&&init&()V
iput-object v0, p0, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
if-eqz p2, :cond_0
iget-object v0, p0, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
const/16 v1, 0x7d5
iput v1, v0, Landroid/view/WindowManager$LayoutP-&type:I
iget-object v0, p0, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
const/4 v1, 0x1
iput v1, v0, Landroid/view/WindowManager$LayoutP-&format:I
这里的代码就很简单的, 我最先看的是下面这段
const/16 v1, 0x7d5
iput v1, v0, Landroid/view/WindowManager$LayoutP-&type:I
这两句代码就是把WindowManager.LayoutParams.type字段设成0x7d5, 官网上写了0x是WindowManager.LayoutParams.TYPE_TOAST的值.
实际测试了一下, 将type设置成TYPE_TOAST果然有奇效, 不需要android.permission.SYSTEM_ALERT_WINDOW权限就能显示一个悬浮窗.
之前我一直以为调用了系统WindowManager.addView需要android.permission.SYSTEM_ALERT_WINDOW权限, 但实际上调用这个方法是不需要权限的, 在Android源码中有这么一段
public int checkAddPermission(WindowManager.LayoutParams attrs) {
int type = attrs.
if (type & WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
|| type & WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
return WindowManagerImpl.ADD_OKAY;
String permission =
switch (type) {
case TYPE_TOAST:
// XXX right now the app process has complete control over
// this...
should introduce a token to let the system
// monitor/control what they are doing.
case TYPE_INPUT_METHOD:
case TYPE_WALLPAPER:
// The window manager will check these.
case TYPE_PHONE:
case TYPE_PRIORITY_PHONE:
case TYPE_SYSTEM_ALERT:
case TYPE_SYSTEM_ERROR:
case TYPE_SYSTEM_OVERLAY:
permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
if (permission != null) {
if (mContext.checkCallingOrSelfPermission(permission)
!= PackageManager.PERMISSION_GRANTED) {
return WindowManagerImpl.ADD_PERMISSION_DENIED;
return WindowManagerImpl.ADD_OKAY;
可以猜到这个方法是往系统的WindowManager里addView的时候做权限检查用的, 那个type就是我们在构造WindowManager.LayoutParams时赋值的type, 可以看到, 除了TYPE_TOAST, 其他都是要权限的, 而且非常喜感的是, 代码中的注释还说他们现在对这种type毫无限制, 应该引入标记来限制开发者.
处理兼容性
在这篇文章刚刚公布的时候, 就有同学反馈悬浮窗无法接收事件, 刚开始我并没有特别在意, 在廖祜秋大神做了一个demo之后, 这篇文章阅读量又涨了不少, 随即收到更多反馈事件的问题, 我今天晚上借了台MIUI V5 4.2.2实测了一下, 这台机器上UC的快速搜索功能也无法正常使用.
在这个ROM上表现为:使用TYPE_PHONE这类需要权限的type时, 只有在app处于前台时能显示悬浮窗, 且能正常接受触摸事件. 如果在应用详情里面授悬浮窗权限, 则工作完全正常.(这里是MIUI V5对悬浮窗的特殊处理, 现在的ROM, 包括MIUI V6上, 如果不授权, 无法显示任何悬浮窗)使用TYPE_TOAST这个不需要权限的type时, 悬浮窗正常显示, 但不能接受触摸事件.
我重新检查了一下smali代码, 发现UC是有分版本处理的, 不过因为smali代码的规则问题, 很难直接看出来, 我把分析过程写出来, 顺便解释一下smali的语法, 供大家以后逆向时拿来参考.
这次我是在OS X上反编译的, 所以变量名可能略有区别.
接着上面com/uc/browser/b/a.smali中查看dpx的构造过程, 代码如下:
.field dpx:Landroid/view/WindowManager$LayoutP
# direct methods
.method public constructor &init&(Landroid/content/CZ)V
new-instance v0, Landroid/view/WindowManager$LayoutP
invoke-direct {v0}, Landroid/view/WindowManager$LayoutP-&&init&()V
iput-object v0, p0, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
if-eqz p2, :cond_0
iget-object v0, p0, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
const/16 v1, 0x7d5
iput v1, v0, Landroid/view/WindowManager$LayoutP-&type:I
为了方便说明, 我遵循smali的规则, 它用.line XX, 我们就说这是第XX行的代码.
上面是我之前分析得到UC使用的是TYPE_TOAST的地方, 证据就是第70行的const/16 v1, 0x7d5, 但是要知道, smali代码没有跳转的话, 就是从上往下执行, 我们看第69行的代码如下:
if-eqz p2, :cond_0
这句话的意思是如果p2等于0, 控制流跳转到cond_0, 否则就是继续顺序往下执行. 也就是说UC只有在p2 != 0条件满足的时候才会使用TYPE_TOAST, 我们看看cond_0对应的代码.
iget-object v0, p0, Lcom/uc/browser/b/a;-&dpx:Landroid/view/WindowManager$LayoutP
const/16 v1, 0x7d2
iput v1, v0, Landroid/view/WindowManager$LayoutP-&type:I
这里很简单, 就是将0x7d2赋给了type, 官网写了0x是TYPE_PHONE, 也就是说UC在某种情况下还是会用需要权限的老方法展示悬浮窗.
现在问题是条件是什么, 关键在p2, 在smali里面, 有两种寄存器命名规则, 一种叫v命名规则, 另一种是p命名规则, 当然只是命名规则而已, 在使用apktool时是可以选的. 这里是p命名规则.
我刚才分析的赋值过程, 所在的方法是下面这个, 我在刚才的代码片段中也保留了这个部分.
# direct methods
.method public constructor &init&(Landroid/content/CZ)V
这就是com/uc/browser/b/a的构造方法, dpx就是在构造方法里初始化的, .locals 7告诉我们这个方法中将出现7个局部寄存器(local register), 名字是v0, v1...v6, 而这个方法的参数有3个, 隐式告诉我们这个方法中将出现3个参数寄存器(parameter register), 名字分别是p0, p1, p2.
我是怎么知道这个方法有3个参数的呢. smali中非静态方法, 都隐含一个参数p0, 指向自身, 和Java中的this是一个意思, 而方法的参数写在括号里, 也就是Landroid/content/CZ, 其中Landroid/content/C很明显就是Android中的Context, 值存储在p1里, 而Z对应的是Android中的boolean, p2就是他了.
也就是说, type是用TYPE_TOAST还是用TYPE_PHONE, 取决于这个构造方法的第二个参数, 那到底谁构造了com/uc/browser/b/a呢? 可以去代码里面搜形如new-instance ***, Lcom/uc/browser/b/a;的代码. 更保险的做法是搜Lcom/uc/browser/b/a然后一个一个的看.
我在com/uc/browser/b/f.smali里面找到了下面的代码:
const/4 v0, 0x0
const/4 v1, 0x1
new-instance v3, Lcom/uc/browser/b/a;
iget-object v4, v9, Lcom/uc/browser/b/e;-&mContext:Landroid/content/C
sget v5, Landroid/os/Build$VERSION;-&SDK_INT:I
const/16 v6, 0x13
if-lt v5, v6, :cond_0
move v0, v1
invoke-direct {v3, v4, v0}, Lcom/uc/browser/b/a;-&&init&(Landroid/content/CZ)V
这段代码首先是创建了com/uc/browser/b/a的实例, 存储在v3中, 从另一处拿到了一个Context存储在v4中, 然后拿到了当前系统的android.os.Build.VERSION.SDK_INT存储在v5中, 此时将v6的值设为0x13, 千万别粗心看成13了, 我好几次都觉得这是13, 其实是十进制的19, 接下来是一个条件分支, 如果v5的值小于v6, 也就是说android.os.Build.VERSION.SDK_INT & 19, 直接跳转到cond_0, 否则先将v1的值赋给v0, 再顺序执行.
invoke-direct {v3, v4, v0}, Lcom/uc/browser/b/a;-&&init&(Landroid/content/CZ)V
就是调用v3的构造方法, 参数是v4和v0, 分析一下上面这段代码的逻辑就是:如果当前系统API level小于19, 那么第二个参数就是0, 否则就是1.
而这第二个参数的值就是之前我们分析的p2的值, UC只有在p2 != 0条件满足的时候才会使用TYPE_TOAST, 把整个逻辑串起来就是:
UC在API level &= 19的时候, 使用TYPE_TOAST, 其他情况使用TYPE_PHONE(需要权限).
可能是为了规避在低版本TYPE_TOAST不能接受事件的问题.
关于针对源代码的分析, 请看
我之前写的一个app有悬浮窗播放功能, 支持拖动窗口和点击暂停, 关闭窗口等等, 在4.4.4上实测功能正常.
无权限悬浮窗演示gif
感谢微博上关注的大神, 他做了个, 虽然交互和UC不同, 可以参考一下实现.
廖祜秋大神的demo
关于这个, 他也写了一篇
评论区的浮海大虾同学有更多补充如下:
TYPE_TOAST一直都可以显示, 但是用TYPE_TOAST显示出来的在2.3上无法接收点击事件, 因此还是无法随意使用.下面是我之前研究后台线程显示对话框的时候记得笔记, 大家可以看看我们项目中有需求需要在后台任务中显示Dialog, 项目最初的做法是用Activity模拟Dialog, 一个Activity已经承载了近20种Dialog, 代码混乱至极. 后来我发现Dialog可以通过改变Window Type实现不依赖Activity显示, 然后就很兴奋的要在使用这种方式来作为新的实现方式.最初WindowType是WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 可是这是悬浮窗了, MIUI会默认禁止(真他妈操蛋,也没有任何提示)最终放弃. 后来试着换成了WindowManager.LayoutParams.TYPE_TOAST, 起初效果很好,MIUI也不禁止了, 哪里都能显示, 这下开心了. 可是后来又发现在2.3上不能接收点击事件, 也就是说Dialog上的按钮不能点击, 这他妈就很操蛋了, 又放弃了. 又试了试其他的Type都不能满足需求, 结果如下:TYPE_SEARCH_BAR: 未知TYPE_ACCESSIBILITY_OVERLAY: 拒绝使用TYPE_APPLICATION: 只能配合Activity在当前APP使用TYPE_APPLICATION_ATTACHED_DIALOG: 只能配合Activity在当前APP使用TYPE_APPLICATION_MEDIA: 无法使用(什么也不显示)TYPE_APPLICATION_PANEL: 只能配合Activity在当前APP使用(PopupWindow默认就是这个Type)TYPE_APPLICATION_STARTING: 无法使用(什么也不显示)TYPE_APPLICATION_SUB_PANEL: 只能配合Activity在当前APP使用TYPE_BASE_APPLICATION: 无法使用(什么也不显示)TYPE_CHANGED: 只能配合Activity在当前APP使用TYPE_INPUT_METHOD: 无法使用(直接崩溃)TYPE_INPUT_METHOD_DIALOG: 无法使用(直接崩溃)TYPE_KEYGUARD_DIALOG: 拒绝使用TYPE_PHONE: 属于悬浮窗(并且给一个Activity的话按下HOME键会出现看不到桌面上的图标异常情况)TYPE_TOAST: 不属于悬浮窗, 但有悬浮窗的功能, 缺点是在Android2.3上无法接收点击事件TYPE_SYSTEM_ALERT: 属于悬浮窗, 但是会被禁止
现在我们都知道了如何在不申请权限的情况下显示悬浮窗, 我相信以中国Android开发者的脑洞, 一定会有很多有趣或恶心的功能被开发出来, 一方面我自己觉得这个东西很有用, 可以实现一些很神奇的功能, 另一方面又担心这个API被滥用, 最终不得不限制权限.
还有就是, 逆向分析仅用于学习, 不要干违法的事情.
本人技术有限, 如果文中有错误的欢迎指正, 以免误导他人
利益声明: 虽然我目前在UC实习, 但我并没有UC浏览器中文版的代码权限, 也不会将公司的代码分享给外人. 本文完全是靠我自己开发经验+逆向分析经验+Google完成, 在此之前没有看过UC浏览器的任何代码.
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
玩转简书的第一步,从这个专题开始。
想上首页热门榜么?好内容想被更多人看到么?来投稿吧!如果被拒也不要灰心哦~入选文章会进一个队...
· 77177人关注
简书程序员大本营
投稿须知:
1.本专题仅收录与程序有关的文章。
2.请在代码框里写代码,尽量保证可看性。
· 60509人关注
简书上的IT大社群。
管理员由 简书@IT社群 不定期轮换当班。
入选本专题的文章,且通过首页投稿审核,则会进入简书首页 ...
· 20916人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:

我要回帖

更多关于 语法错误 的文章

 

随机推荐