本文主要是介绍随笔:公司App升级第三方SDK踩坑两周小记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
/ 今日科技快讯 /
近日,亚马逊CEO安迪·贾西证实,该公司计划在去年11月宣布和今日媒体曝出的裁员中裁撤略多于1.8万个岗位,将从1月8日起与受裁员影响的员工沟通。贾西表示,有多个团队受到影响,但大部分裁员涉及亚马逊商店与人员、体验和技术(PXT)部门。
/ 作者简介 /
明天周六啦,天气越来越冷,大家注意做好防护!
本篇文章转自coder_pig的博客,文章主要分享了他在升级第三方SDK踩坑并解决的过程,相信会对大家有所帮助!
原文地址:
https://juejin.cn/post/7130532039870119973
/ 引言 /
如题,最近两周疲于折腾公司第三方SDK升级,掉坑里一直出不来,前天突发奇想,终于定位到问题原因。
问题很简单,却花费了这么长时间,终究还是我太菜了!
BUG虽然解了,但觉得还是有必要记录复盘下,以便下次遇到类似问题时,能找到更好的切入点,更快地把问题解决。
问题概述
现在哪个房产类APP不上VR全景图啊,所以我司也整了一个,经纪人录盘时,使用全景相机对盘源进行拍摄,在录盘填信息的同时,把全景图也上传到服务器。而他们录盘的过程是这样的:
使用全景相机官方APP,连接相机,对盘源进行拍摄,官方APP拼接生成全景图;
拍完打开公司APP,来到录盘页,填写录盘信息,然后打开手机相册,选择对应的全景图上传;
录一次盘得在两个APP间来回切换,可以是可以,但流程繁琐,效率也低,他们更希望:
直接就在公司APP上就可以完成相机连接、拍摄、拼接和上传。
任务传到客户端这边,所以我们需要:
集成官方SDK,参考官方Demo和文档,根据具体业务进行二次开发。
杰哥徒手封装的Library已经稳定跑了两年:
本以为可以一劳永逸,安享晚年,最近却出了幺蛾子:
有经纪人买了新款相机,然后用公司APP无法拍照。
em...硬件、固件升级,需要更新下SDK,可以理解,那就升吧,正当我以为这次升级,会像当初刚集成时那样丝滑流畅,却是磨人踩坑的开始...
/ 第一道坎:SDK自带预览组件黑屏 /
很快新的SDK到位,Library替换上新AAR,API有些变动,跟着Demo改改,算是跑起来了,但问题也来了:
拍摄预览页 → 关闭并跳转新页面 → 再次打开预览页 → 预览组件黑屏
看了下官方Demo有定义这个预览组件,但却没用到,再看一下文档:
难不成是销毁时还要手动去释放什么资源么?上个版本没这个问题啊,尝试寻求技术支持:
隔天早上,我又试着改了下官方Demo,加上预览组件部分的代码,也会黑屏,再次发问:
在等待回应的同时,我还对可能有关的方法调用都加上了日志打印,尝试找出问题原因:
对面说周一开早会,晚点看问题,结果等到了第二天中午:
按照他说的,在页面销毁时主动调用预览组件的releasePreview(),预览的确正常了,问题好像解决了?但这样的操作,却引起了第二个问题...
/ 第二道坎:小米机型闪退 /
页面销毁和创建多次会报异常崩溃,有时甚至发生在图片拼接时,再次发问,并提供机型和报错日志:
可能是我表达能力的问题,对面有点懵了:
重新组织了一下语言并附上更详细的奔溃日志,同时把demo中的改动文件发给他们测试:
得到的回复:
em...重复了30多次,看得出对面也很想帮我们解决问题,奈何鞭长莫及。
我甚至跟领导开玩笑说,要不把测试机寄过去那边给他们排查下吧,哈哈哈!另外,同事说他们这两款机型都是很老的机型了,会不会是CPU架构的问题,于是在build.gradle中指定了架构:
ndk {abiFilters 'armeabi-v7a', 'arm64-v8a'
}
运行后发现并没什么卵用,而网上搜了一圈这个异常:
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10 in tid 2261
发现一个唯一有用且这边能做的事情,删掉这个文件夹 → /data/local/tmp/perfd,删了可以,但治标不治本,删完下次又得删,麻烦且不说,公司APP也没有访问这个文件夹的权限啊 (root权限)。
唉,无解,关键代码都写在so库里,就一黑盒子,奈何笔者太菜,不会so库逆向调试,只能到这里了...
后面领导说先这样把,目前就一个经纪人用新相机,而且用的华为手机,打包给测试测下,没其它问题就先发包吧~
/ 第三道坎:打Release包无法拍摄 /
隔空艰难对接一周,最后妥协收场,正当我以为此事了解,可以回归摸鱼日常,结果测试一声惊雷平地起:
焯!跟进了一下发现:Debug包可以,Release就不行,旧相机可以,新相机不行,看下日志:
果断再次向技术支持请求援助,这次吸取教训, 把问题整理清楚再提问:
唉,大概是因为人类的悲欢并不相通吧,并没有得到有效帮助,但也给了我们一个思路,可能是混淆的问题。
但混淆代码没Keep住,调用时不是报ClassNotFound之类的Exception吗?难不成他们用try-catch包住不往外抛?半信半疑,不过眼下好像没有更好排查方向了,死马当活马医吧,这也是钻牛角尖的开始...
混淆排查
说到混淆,这不得打开:《补齐Android技能树 - 从害怕到玩转Android代码混淆》,边看边排查,首先混淆规则是叠加的:
在他们的AAR里,有看到混淆文件:
理论上来说,这里写了的话,app模块是不要再写一遍的,2333,但是为了保证一定生效,还是再写一遍吧。但重新打包后一样不行,可能这个 keep规则没有完全覆盖?于是写了匹配范围更广的规则:
-keep class com.hozo.** { *;}
-keep class com.hznovi.** { *; }
-keep interface com.hozo.** { *; }
-keep interface com.hznovi.** { *; }
一样不行,不应该啊?难道其他模块的混淆规则影响了?又或者Dex分包?会不会是AAR嵌套的原因?等等。
先看下是不是我们项目问题吧,于是尝试写一个Demo来引用这个库,Copy混淆规则,并打Release包,结果发现Demo能正常使用!!!焯,那就是我们项目有问题了,难道因为不知名原因,导致类丢失?于是我用AS打开两个Release的APK(公司APP和Demo)进行比对:
方法数啥的完全一样,难道真不是混淆的问题?那还可能是什么原因呢?一时有些找不着方向,同事放弃了,领导甚至在群里提出改方案的建议了(公司App只负责上传图片):
配置文件缺失/错误排查
而我还在 坚持,回归现象本身:
连接相机报错HZJsonResponse: Parse json payload failed。
等待很久后回调onNeedInitCamera(),然后跳转相机初始化页面。
点击后打印警告日志:Try to setup processor with invalid version,无法正常初始化。
对方的回复:
简单点说就是:没连上相机,就调用初始化接口
但明显和我们的代码逻辑相违背:只有连上了,才会进入初始化页面:
这时,我突发奇想,手机连接相机耗时,会不会是接收相机发过来的某些文件出错导致的?比对下是否有文件缺失不就好了?于是我打开Demo和公司APP的 data/data/包名目录进行比对,发现 shared_prefs 目录下没有这个文件:
copy一下,然后又看了下files目录,看到有个easy_panorama目录,里面明显是相机相关的东西,对比了下公司APP,有部分文件缺失:
同样copy覆盖一下,然后再次运行公司APP连相机,发现报错:没有文件操作权限,直接修改所有者和用户组为我司APP:
再次连相机,可以,不用初始化直接进入了拍摄页面,点击拍照,相机开始拍照,卧槽?难道真的是文件损坏或缺失引起的BUG吗?如果是的话可以往这个方面继续排查了,但事实打脸,拼接图片时卡住,然后提示照片下载失败,依旧是这个异常:
HZJsonResponse: Parse json payload failed。
又是空欢喜一场,唉,累了,毁灭了,就这样吧,改方案吧,什么垃圾SDK...
Xposed Hook调试AAR
度过了慵懒的周末,又到周一。
一到公司,看到桌面的相机就烦,焯!破玩意,浪费我两个星期时间...
表面上恨不得立马丢了,实际上又看起了源码,嘴上说着不要,身体却很诚实。
尝试定位到报错位置 (jd-gui反编译class.jar搜字符串常量):
报JSONException异常,才会走这里的代码,而这个异常的引发条件:
大概率是Json的问题,比如格式不正确,而这个方法是将byte数组转换成Json字符串:
如果可以把入参byte数组搞出来看看就好了,尝试在此下 断点,然后调试附加到 APP进程(手机Root了,并通过Magisk将APP都弄成Debug模式,所以能Debug Release APP)。
但是,并没有走进来,可能不能这样玩?得想下其他法子把参数打印出来。想到好久没玩的Xposed,立马打开专栏:Xposed从入门到入土「插件开发记录 x 框架源码解析」温故知新。到Github找到前几年写的玩具:CPWechatXposed,clone后Build一下。新建一个Hook类:
XposedInit.kt加上它:
运行模块后重启设备,然后连相机,日志断断续续打印出来了:
连接相机时,会报这个码,错误码么,文档上却没找着,再次发文:
噢,并不是错误码,后续Json数据也陆续打印出来了,复制到Json格式化工具,是正常的Json,这...
不过细心的我发现了,我在Xposed里try-catch这个JsonObject实例化的过程,并不会触发JsonException。但是Parse json playload failed. 还是打印出来了,说明是触发 JsonException???
好家伙,难不成你们家的 JsonObject 和 JsonException 是金做的还是银做的?
随手点进 JsonObject 的一定位,直接真相大白:
JsonObject 和 JsonException 指向不同的库!!!
卧槽,这谁埋的雷啊,虽然没定位到具体哪里抛异常,但绝壁是这个库的原因,问了下虾哥能否强制指定,被告知不行:
后面看了一下引入这个库,只是为了调用下xml转json的方法:
把 implementation files('jars/java-json.jar') 干掉,引入另一个xml转json的库:implementation 'com.github.smart-fun:XmlToJson:1.4.5',修改调用处相关代码,编译打Release包,安装运行,连接相机,拍照拼接,一气呵成,完美解决。就这样的小BUG磨了我两周,好一个前人挖坑,后人填坑啊...
/ 写在最后 /
事情的大概经过就这样,BUG说解了但又没有完全解,比如没有具体定位到哪里抛JsonException,也有一些让步,比如小米机型还能偶现奔溃问题,但这在我的能力边界外。可惜新相机寄回去了,不然我肯定趁机扩展这方面的姿势~
能用就行,在这个过程中也意识到自己的一些不足:
在与人对接描述问题时,并不能简要描述清楚自己的诉求,导致沟通效率并不高;
绝大部分时间都花在打包验证上了,每次一打就十来分钟,一直硬钢,没有想办法去提高编译效率;
容易钻牛角尖,明明自己认知里知道这样做是没问题的,还要去硬怼,而不是尝试换个方向;
Native Crash 的排查能力较弱,so库逆向调试也不会,有时间有机会可以了解下~
没有一个可以随时快速验证问题的项目,比如上面写Demo验证,我还得去新建项目,折腾kt版本等;
与之形成鲜明对比的就是我的Xposed插件玩具,改改就能用,当然如果能加上 注解简化调用就更棒了;
综上,还是自己太Vegetable了,得多多磨练和思考啊~
文中引用到的文章链接如下
补齐Android技能树 - 从害怕到玩转Android代码混淆:
https://juejin.cn/post/6966526844552085512
Xposed从入门到入土插件开发记录 x 框架源码解析:
https://juejin.cn/column/6961682067495059469
推荐阅读:
我的新书,《第一行代码 第3版》已出版!
2022年终总结,我的10年Android之旅
深入探究Kotlin的可见性控制,从internal入手
欢迎关注我的公众号
学习技术或投稿
长按上图,识别图中二维码即可关注
这篇关于随笔:公司App升级第三方SDK踩坑两周小记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!