Android中可以作为Log开关的一些操作及安全性详解
前言
本文主要给大家介绍了关于Android中能够作为Log开关的一些操作及安全性的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
自定义常量
开发阶段利用Log日志方便代码调试是再常见不过的事情。出于安全考虑,这种做法仅限于Debug模式,Release模式下打包发布时一定要关掉。所以在我们的项目中,一定会有一个工具类或者方法来控制Log日志的使用,比如:
publicclassLogUtils{ publicstaticfinalBooleanDEBUG_MODE=true; publicstaticvoidd(Stringmessage){ if(DEBUG_MODE){ Log.d("TAG",message); } } }
常见的做法便是像上面这样,自定义一个布尔类型的常量作为开关来控制是否打印日志。但是这种做法有一个弊端,那就是每次发布Release包时都需要手动修改这个常量的值为false,然后下一次开发阶段再手动修改为true。
虽然是很简单的手动修改操作,但是也很容易忘记。那么有没有一种办法实现自动化管理呢?答案当然是有的,使用BuildConfig类。
BuildConfig
类似R资源文件,BuildConfig也是在编译阶段,Gradle插件自动生成的一个class文件。该文件包含一些帮助开发人员辨别当前build类型的常量信息。当然你也可以通过Gradle提供的定制功能向该文件里面添加其他辅助内容。这里我们看一下默认情况下,BuildConfig文件都包含有哪些内容:
publicfinalclassBuildConfig{ publicstaticfinalbooleanDEBUG=Boolean.parseBoolean("true"); publicstaticfinalStringAPPLICATION_ID="com.yifeng.sample"; publicstaticfinalStringBUILD_TYPE="debug"; publicstaticfinalStringFLAVOR=""; publicstaticfinalintVERSION_CODE=1; publicstaticfinalStringVERSION_NAME="1.0"; }
能够看出,都是一些大家很熟悉的信息。其中包括一个DEBUG常量,其值便可用于判断当前build类型。debug模式下为true,release模式下为false。所以,使用BuildConfig.DEBUG可以替代前面我们自定义的常量,实现自动管理Log日志的打印:
publicstaticvoidd(Stringmessage){ if(BuildConfig.DEBUG){ Log.d("TAG",message); } }
看上去貌似已经很完美了,但其实还是有瑕疵的。BuildConfig类文件的生成依据于Module,也就是说每一个Module编译时都会产生自己的这个文件。如果你的主appmodule使用其他依赖module中BuildConfig文件里面的DEBUG值,就需要多加注意。
默认情况下,Library的构建永远是以Release模式执行的,所以其BuildConfig.DEBUG值一定是false!即使主Module使用Debug模式构建,也是如此。
那么,有没有办法修改LibraryModule的默认构建方式呢?答案也是肯定的。打开对应Library的build.gradle文件,添加这样一行配置代码:
android{ //这里省略其他内容 publishNonDefaulttrue }
即表示不使用默认构建方式,编译时也会自动生成其他build类型的BuildConfig类文件。你可以在相应Library路径下查看配置该命令前后BuildConfig文件的生成情况,目录地址为:
libraryName/build/generated/source/buildConfig/+debug/release
然后在我们的主Module依赖的时候同时引入debug和release两种配置,这里以extras/PullToRefresh作为Library为例,看下依赖代码:
dependencies{ releaseCompileproject(path:':extras:PullToRefresh',configuration:'release') debugCompileproject(path:':extras:PullToRefresh',configuration:'debug') }
如此这般,便可以解决前面提到的依赖Module问题。当然,如果你的项目比较简单,只是单一Module,也就不存在这个问题。
但是如果项目中的依赖Module比较多的话,这种处理方式还是略显麻烦。你需要在用到的地方针对每个Module逐一处理。其实还有一种更好的解决方案,那就是使用Manifest清单文件中application标签里的debuggable属性。
ApplicationInfo
application标签里有个android:debuggable属性,表示当前应用是否可以被调试(一般不建议手动设置这个属性)。这个属性也会随着build类型自动改变。所以,利用这个特性也能判定应用是否处于Debug模式,比如:
publicstaticbooleanisDebug(Contextcontext){ return(context.getApplicationInfo().flags&ApplicationInfo.FLAG_DEBUGGABLE)!=0; }
控制Log日志打印的开关,除了上面讲到的这些方式,其实还有别的方式。比如利用Gradle的灵活性在build.gradle文件中自定义一个Boolean变量,根据build类型动态赋值,也能达到我们的目的。
Android自定义Log开关
有时Log太多会影响速度,需要根据需要开关Log,而AndroidIDE环境没有这个功能,起码Eclipse没有,那么我们可以写一个类将Log封装,通过调用这个类设置boolean变量,控制Log是否有效。
publicclassMLog { publicstaticfinalbooleanDEBUG=true;//开关控制 publicstaticvoidi(Stringtag,Stringmsg) { if(DEBUG) { Log.i(tag,msg); } publicstaticvoide(Stringtag,Stringmsg) { if(DEBUG) { Log.e(tag,msg); } //其它级别的同上... }
使用的时候直接调用MLog替换Log即可。
更安全的Log用法
前面所有这些做法都只是使release包不去显示Log日志,从而提高安全性。但是,有没有想过,如果apk被反编译的话,这些Log相关的代码还是能够别识别出来,别人只需要稍作修改,重新打包,依旧能够使Log重现。
当然,使用常量作为LogUtils中的判断条件的话,根据proguard的优化规则,在Release包中是不包含条件体中的Log.d等操作代码的。关于这一点,可以自己反编译apk尝试看下。
然而,在其他调用LogUtils工具类的地方依旧暴露了我们的意图。所以,定义一个LogUtils类虽然提高了使用Log的效率,依旧解决不了Log安全的问题。相比而言,我们做了这么多努力只是稍微提高了一些安全的门槛而已。
所以,最好的办法就是,Release包中不包含任何用于调试的Log代码(如果使用LogUtils的话,也包括该类的调用)。也就是说,不使用LogUtils工具类封装,在任何需要的地方,不嫌麻烦的逐一添加判断条件:(可以使用LiveTemplate提高效率)
if(BuildConfig.DEBUG){ Log.d("TAG",message); }
这样,打包时,开启proguard后,Release包会自动删除上面的代码,彻底根绝Log引发的安全问题。关于这一部分的细节操作,可以参考这两篇文章:
- AndroidApk文件反编译和重新打包的过程分析
- 如何安全地打印日志
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。