Android项目管理之配置管理

在Android开发中难免会遇到一系列的配置管理,例如版本配置、数据库版本号配置、预置数据配置、网络接口配置、加密信息配置、日志配置、异常捕获配置等。本文将对这些内容给出一个较为合理的解决方案。

首先:为什么需要这些配置信息呢?
1.版本配置:发布版本的时候毋庸置疑,需要在每次发布的时候修改版本号和版本名称,提醒用户升级也是根据版本号来判断的,所以版本配置是必须的
2. 数据库版本配置:每次对用户版本的升级,如果涉及到数据库变更,必须要升级数据库,而数据库的升级是由SQLiteHelper根据数据库版本号来判断 的,即数据库自身保存了上一版本的数据库版本号,如果此次传入的版本号大余自身的版本号,则对数据库upgread,并将新的版本号存储为自身版本号。
3.预置数据配置:对于一个需要联网获取内容显示给用户的应用,如果首次用户打开你的应用是在没有网络的环境下进行的,你的应用会呈现出什么样子呢?提供些预制数据吧,当然预置数据还可以包含更多信息,如设置信息等
4.网络接口配置:为了灵活地应对网络接口的变更,对网络接口进行配置应该是比较好的方法,当然,还可以配置多套网络接口,例如调试地址、正式地址、测试地址等
5.加密信息处理:如果你在项目中需要对某些预制内容加密或者压缩、而又希望开发的时候能够以源码的方式进行
6.日志配置:你在不同的环境下希望日志有不同的表现,例如在正式发布后希望不要显示日志、调试时显示debug日志、测试时显示warning日志等
7.异常配置:是否希望开启异常捕获,并将异常信息反馈到你的服务器
二:如何配置?
1.对于1版本配置对于Android开发而言,需要在Manifest中进行
2.对于2数据库版本配置、6日志配置、7异常配置在/res/raw/system.properties(位置和文件名可以是任意的,个人推荐位置是这里)中配置
3.对于3预置数据配置,可以建立一个单独的文件,用于配置预置数据
4.对于4网络接口配置,可以2方法和3方法配合使用,2中配置环境,3中配置接口详细信息
5. 对于5加密信息处理,首先要保证发布时信息被加密货压缩,其次要保证开发时不受影响,我们可以在项目的根目录下建立一个文件夹,名称随便叫什么,然后需要 加密或压缩的文件放在这里,如果压缩或者加密工具比较小的话也可以放在这里,执行压缩或加密脚本,将内容结果拷贝到需要的位置
三:最佳实践
对二中给出的配置做实际性的处理
1.版本配置
Manifest.xml
 
             
  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     package="xxx.xxx.xxx" 
  3.     android:versionCode="xxx" 
  4.     android:versionName="xxx" > 
2.数据库版本,日志及异常配置
/res/raw/system.properties
 
             
  1. #the output versioin 
  2. version:9 
  3. #appName 
  4. appName:xxx 
  5. #log open or close 
  6. log:true 
  7. #carch exception ;true catch , false not carch 
  8. exception:false 
  9. #database version,when database is modified  ,plus 1 
  10. dbversion:9 
 
在系统初始化的时候初始化基本配置信息
 
              
  1. /** 
  2.      * 系统参数初始化 
  3.      * 
  4.      * @param appllicationContext 
  5.      */ 
  6.     public static void initSystemProperties(Context appllicationContext) { 
  7.         InputStream is = appllicationContext.getResources().openRawResource( 
  8.                 R.raw.system); 
  9.         Properties properties = new Properties(); 
  10.         try { 
  11.             properties.load(is); 
  12.             Variable.versionCode = Integer.parseInt(properties.getProperty( 
  13.                     Common.VERSION, "1")); 
  14.             Variable.isLogOpened = Boolean.parseBoolean(properties.getProperty( 
  15.                     Common.LOG, "false")); 
  16.             Variable.dbVersion = Integer.parseInt(properties.getProperty( 
  17.                     Common.DBVERSION, "1")); 
  18.             Variable.appName = properties.getProperty(Common.APPNAME); 
  19.             Variable.dbchange = properties.getProperty(Common.DBCHANGE, ""); 
  20.             Variable.isExceptionOpened = Boolean.parseBoolean(properties.getProperty( 
  21.                     Common.EXCEPTION, "false")); 
  22.         } catch (IOException e) { 
  23.             Util.error(e.getMessage()); 
  24.         } finally { 
  25.             Util.closeStream(is); 
  26.         } 
  27.     } 
 
2.1DBHelper作为单例,实例化时将数据库版本号传入
 
                
  1. public static DBHelper getInstance() { 
  2.         if (helper == null) { 
  3.             helper = new DBHelper(Variable.appllicationContext, DB_NAME, null
  4.                     Variable.dbVersion); 
  5.         } 
  6.         return helper; 
  7.     } 

2.2日志
 
                   
  1. /** 
  2.      * Common log 
  3.      * 
  4.      * @param tag 
  5.      * @param msg 
  6.      * @param level 
  7.      */ 
  8.     public static void log(String tag, String msg, int level) { 
  9.         if (Variable.isLogOpened) { 
  10.             String msgs = msg; 
  11.             String tags = tag; 
  12.             Exception e = new Exception(); 
  13.             StackTraceElement[] els = e.getStackTrace(); 
  14.             String logDetails = Common.PACKAGENAME; 
  15.             for (int i = 0, l = els.length; i < l; i++) { 
  16.                 if (els[i].getClassName().startsWith(Common.PACKAGENAME) 
  17.                         && !els[i].getClassName().equals(Util.class.getName())) { 
  18.                     logDetails = els[i].getFileName() + "->" 
  19.                             + els[i].getMethodName() + ":" 
  20.                             + els[i].getLineNumber() + " "
  21.                     msgs = logDetails + msgs; 
  22.                     if ("".equals(tags)) { 
  23.                         tags = els[i].getFileName().substring(0
  24.                                 els[i].getFileName().indexOf(".")); 
  25.                     } 
  26.                     break
  27.                 } 
  28.             } 
  29.             switch (level) { 
  30.             case Log.DEBUG: 
  31.                 Log.d(tags, msgs); 
  32.                 break
  33.             case Log.INFO: 
  34.                 Log.i(tags, msgs); 
  35.                 break
  36.             case Log.WARN: 
  37.                 Log.w(tags, msgs); 
  38.                 break
  39.             case Log.ERROR: 
  40.                 Log.e(tags, msgs); 
  41.                 break
  42.             default
  43.                 Log.d(tag, msgs); 
  44.                 break
  45.             } 
  46.         } 
  47.     } 
  48.  
  49.     /** 
  50.      * Simple log 
  51.      * 
  52.      * @param tag 
  53.      * @param msg 
  54.      */ 
  55.     public static void log(String tag, String msg) { 
  56.         log(tag, msg, Log.WARN); 
  57.     } 
  58.  
  59.     public static void log(String msg) { 
  60.         log("", msg); 
  61.     } 
  62.  
  63.     public static void info(String msg) { 
  64.         log("", msg, Log.INFO); 
  65.     } 
  66.  
  67.     public static void error(String msg) { 
  68.         log("", msg, Log.ERROR); 
  69.     } 
  70.  
  71.     public static void debug(String msg) { 
  72.         log("", msg, Log.DEBUG); 
  73.     } 

2.3异常
BaseActivity的onCreate方法中添加

 

 
                       
  1. if(Variable.isExceptionOpened){ 
  2.             CrashHandler handler = CrashHandler.getInstance(); 
  3.             handler.init(getApplicationContext()); 
  4.             Thread.setDefaultUncaughtExceptionHandler(handler); 
  5.         } 
3.预置数据
/home/chenze/workspace/trunk/assets/init.json
推荐使用json格式,占用小,易解析,这里主要就是解析特定格式的数据,然后存不存储看项目了,可以入库等
 
4.网络接口:
由上面的2和3看,思路基本就是这样了,2.中配环境,3中配地址

5.加密和压缩信息处理
须 知在Android项目打包过程中,Android的根目录中除了创建项目时的文件夹,其他的内容都不会被打包进去,这样我们就可以在根目录中随意存储内 容了(当然不建议太多)。我这里建立了一个general目录,存放压缩和加密的工具及需要压缩和加密内容的源码。为了管理方便,建议写一个脚本,执行后 自动将目标内容拷贝到目标地址。例如,在该目录下新建一个数据库变更脚本,执行加密命令后,将该脚本的加密后副本拷贝到/res/raw目录下,当需要执 行数据库升级脚本时,解密该内容并执行

总结:
本文主要讨论了笔者自身在项目配置方面的管理经验,当然这些内容有的是借鉴了同事的经验,无论怎样,主要提供一些为了简便开发和管理的思路。