App开发中高级技巧
2.1 crash 异常收集与统计,作者在书中介绍了如何收集crash 到数据库,如何对大量crash信息进行去重,如何生成crash报表,如何将crash 自动分配给开发人员提供一整套解决方案。
2.2 作者花了大量时间,列举出100多个crash实例,且分析出出现原因,并给出解决方案,而且这些crash也多是项目中可能出现的,有了这些crash信息库,可以帮助我们快速定位处理crash,我们在项目中就可能遇到过
比如除数为0,textView.settext(count) count为int型(会报找不到资源id)、is your activity running(dialog,popwindow show时,activity未启动完或actiivty已关闭)、rmeabi 和armeabi-v7a中so包数量不一致,会导致UnsatisfiedLinkError、不要相信api 返回数据,必须做非空判断,类型异常等容错处理、遍历集合时不能删除集合中数据,否则发生崩溃、多个线程同时操作同一集合数据也可能会发生崩溃、网络请求时,实体类被混淆、系统碎片化,高版本api在低版本崩溃、SQLite 支持单线程、多线程、串行三种模式,但是多线程中使用单个数据库连接不是安全的,当一个线程写数据,一个在删数据会抛I/O 异常,当一个操作完关闭数据库,另外一个还在操作也会导致Crash等,作者将100多个carsh分为以下几类:
1 java语法相关的异常
2 acitivty相关的异常
3 序列化相关的异常
4 列表相关的异常
5 窗体相关的异常
6 资源相关的异常
7 系统碎片化的异常
8 sql相关异常
9 其他异常
限于篇幅问题,就不一一列举了,有兴趣的朋友可以去详细阅读下,对快速处理crash是有很大帮助的。
2.3 混淆
有时我们会遇到直接AS 运行项目,没问题,但打release包时某些功能模块就有bug, 花上大半天也不知问题所在,这种情况下就要考虑下是不是混淆所致了。
针对app 量身定制一套混淆规则:
1 保留实体类和成员不被混淆,作者是建议将keep 实体类所在的包下所有类,本人之前在项目中也用过另外一种方式
定义一个接口类:
public interface NonProguard { }
不想被混淆的类 实现这个接口
public class ErrorResponeBean implements NonProguard{ private String errorCode; private String errorMessage;
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
在混淆文件中添加:
-keep interface com.example.NonProguard
2 内部类不被混淆
-keep class tv.danmaku.ijk.media.player$* {*;}
$符用来分割内部类与其母体的标志
3 对webview的处理
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
public boolean *(android.webkit.WebView, java.lang.String)
}
-keepclassmembers class * extends android.webkit.webViewClient {
public void *(android.webkit.webView, java.lang.String)
}
4 对javaScript的处理
app供h5调用的原生方法不能被混淆
-keepclassmembers class com.example.youngheart.MainActivity$JSInterface1 {
<methods>;
}
5 保留自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View {
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
6 第三方jar包
有些第三方sdk已经是混淆了,所以要在混淆规则 keep ,不过一般第三方都会提供混淆规则,直接复制到自己的项目中的混淆规则文件中即可。
2.4 竞品分析
对于竞品,从技术上讲,有以下几个点是重点研究方向:
为什么他们的App体积比我们小?
为什么他们App访问速度比我们快?
为什么他们App基本上不咋崩溃?
通过竞品分析,作者提供一些优化方案,
1 知己知彼,百战不殆。通过分析竞品app安装包结构,了解竞品可能用到的技术点,获取竞品app资源,如动画,xml等, 但直接解压的xml 文件,我们看到的是乱码,作者提供了一款神器AXMLPrinter2.jar,执行
java -jar AXMLPrinter2 AndroidManifest.xml
此外我们还可以通过app 反编译工具如apktool 对dex 包进行反编译,查看dex包中的源码
apktool使用 可参考:http://blog.csdn.net/vipzjyno1/article/details/21039349/
2 提升Splash 广告速度,书中提到的方法和目前我们项目中用到的差不多,首次异步调接口api,获取广告信息及缓存广告图片到本地,下次启动直接展示已缓存的图片,同时异步调用接口检查有无新广告,有则缓存,此时要针对 用户网络情况 如是wifi,还是使用流量采取不同的策略。
3 H5页面提速:
将常用的h5页面、css ,js打成zip包,app每次启动,启用一个线程,异步将zip包解压到本地,每次从本本地读取H5页面,就不用每次从服务器获取。为了保证H5页面是最新的,我们需要对zip包进行版本化管理,每次加载H5页面都向服务器询问当前版本号,如过期重新下载zip包,同时为避免app自带zip版本过旧,导致新用户下载的包比较大,每次发版前都要将最近的zip包内嵌到app内。
制作增量zip包,为了提升zip包下载速度及节省流量,引入增量更新概念,每次只将新增及修改的文件放入zip包,同时控制图片资源数量,即使是增量更新也要控制增量包的大小在100K内。
4 png/jpg使用:png是无损的,jpg是有损的,同样尺度的图片,png会大些,但手机偏偏对png情有独钟,会对其进行硬加速,虽然png体积大些,但加载速度快。所以APP内的图片优先使用png格式。但尺度大的图片,如splash图、引导图、大的背景图及需要网络下载的图片,为了减小App体积,可以考虑采用jpg.
google提供了一种新的图片格式 webP,压缩率比jpg更好,android是支持的,ios如个使用需要引入WebP解码器。
5 自动选取最佳服务器策略:项目可能有多台服务器,分别接入电信、移动或者联通专线,可以考虑让app尝试从哪个服务器连接速度快些,同时要处理好服务器的负载平衡。
6 热修复, 热修复可以解决一下紧急bug,而不需要发版本,但目前ios禁止了热修复使用。
android 热修复技术可参考:http://blog.csdn.net/yangxi\_pekin/article/details/54929809