发布程序时移除Android 调试Log

在Android开发中,我们使用android.util.Log来打印日志,方便我们的开发调试。但是对于正式发布的程序,我们并不希望这些Log信息显示,一方面对于用户来说影响机器性能,另一方面,其他开发者看到这些信息的时候,对我们应用程序的安全是有威胁的。所以,我们需要在正式发布时不让Log执行,或者将其移除。这里,我提供三种方法。

自己写一个Log的帮助类,在类中设置显示级别

示例代码如下,通过一个静态变量设置Log的显示级别。

public class Log {
  public static int logLevel = Log.VERBOSE;

  public static void i(String tag, String msg) {
      if (logLevel <= Log.INFO)
          android.util.Log.i(tag, msg);
  }

  public static void e(String tag, String msg) {
      if (logLevel <= Log.ERROR)
          android.util.Log.e(tag, msg);
  }

  public static void d(String tag, String msg) {
      if (logLevel <= Log.DEBUG)
          android.util.Log.d(tag, msg);
  }

  public static void v(String tag, String msg) {
      if (logLevel <= Log.VERBOSE)
          android.util.Log.v(tag, msg);
  }

  public static void w(String tag, String msg) {
      if (logLevel <= Log.WARN)
          android.util.Log.w(tag, msg);
  }
}

使用Proguard移除代码中的Log代码

修改Proguard的配置文件,添加以下配置:

-assumenosideeffects class android.util.Log {

public static int v(...);

public static int i(...);

public static int w(...);

public static int d(...);

public static int e(...);

}

可以根据需要在发布时候显示的级别来决定移除哪些级别的Log(需要移除的就放到配置中),同时Proguard的配置中还要注意不要有-dontoptimize这个配置。

比较

以上两种方法都可以达到开发阶段不显示Log,正式发布移除Log。但是使用Proguard的方式,可能不是所有程序都会进行Proguard的。这个呢,大家根据自己的项目需求,来选择合适的方法。

在Ubuntu下配置Android开发环境

主要包括:jdk idea android sdk

安装JDK

sudo add-apt-repository ppa:webupd8team/java   #添加源
sudo apt-get update                             #更新仓库
sudo apt-get install oracle-java7-installer     #安装java7

执行

java -version

检查java版本,确保已经正确安装jdk
最后执行

sudo apt-get install oracle-java7-set-default

将设置java7到系统的环境变量中(这样就不需要自己配置了)

安装JetBrains IntelliJIDEA

打开这个页面http://www.jetbrains.com/idea/download/ 下载Community Edition。
下载回来后,解压即可。

安装Android SDK

到这个页面https://developer.android.com/sdk/index.html,下载SDK Tools,选择最后一个Download For Other Platforms,下面的SDK Tools Only,选择对应平台,linux的是http://dl.google.com/android/android-sdk_r22.6.2-linux.tgz

下载回来后,解压即可。

第一次启动

启动IDEA,创建一个Android 项目,会提示你设置JDK和Android SDK。这就OK了。

原文地址:http://isming.me/2014/06/28/install-android-in-ubuntu,转载请注明出处。

一个程序员的Ubuntu安装的那些软件

鄙人程序猿一枚,Android开发,常年使用Ubuntu(主要是买不起Mac,O(∩_∩)O哈哈~)。分享一下自己使用的那些软件,如果你有什么好的软件。欢迎与我交流。

输入法:开始的时候是用的fcitx,后来搜狗出了linux版本,选择之。下载链接

办公软件:WPS Linux,真心很好用,比libreOffice好用不止一点.下载链接 注意:下载alpah版本.

浏览器:chrome 和 FireFox,不解释,一个浏览器不够用的。这两个,开发调试都够了。关于支付宝的话,可以安装支付宝官方给的一个脚本就可以了。

邮件客户端: ThunderBird Mail 火狐家的,算比较好用的了。

笔记:为知笔记 ,为知真是业界良心,唯一一家提供linux版本的,做的还挺不错的,虽然有一些不好,但是相信以后会越做越好的。安装方法:

\( sudo add-apt-repository ppa:wiznote-team
\) sudo apt-get update

$ sudo apt-get install wiznote

常用编辑器:普通的编辑器就是用Vim,或者用sublime text,sb在ubuntu下中文输入会有问题,看这篇文章。http://blog.isming.me/blog/2014/03/15/jie-jue-ubuntuxia-sublime-text-3zhong-wen-shu-ru-de-wen-ti/.markdown 编辑器,我用retext,ubuntu仓库中有,直接下载就可以了。

开发工具:工欲善其事,必先利其器,作为android开发者,一个好用的工具也很重要,我用IntelliJ IDEA CE,同时配合Android SDK,推荐你们也用这个。

仓库:git,不解释。

抓包工具: windows 下面有很好用的工具Fiddler,在linux 下面我也找到一款好用的工具,Charles下载地址.

先写这么多了,以后有新发现,继续分享。

使用Intent启动组件

android应用程序的三大组件——Activities、Services、Broadcast Receiver,通过消息触发,这个消息就是Intent,中文又翻译为"意图"(我感觉读着不顺畅,还是读英文)。我们可以通过Intent去启动三大组件,并且通过Intent携带数据到其他组件中。本文来看一下怎么使用Intent启动组件,以及Intent的过滤规则。

Intent对象

首先来看Intent对象中包含的成员。

private String mAction;   //动作
private Uri mData;        //数据
private String mType;
private String mPackage;   //包名
private ComponentName mComponent;  //组件名 包含程序包名+类名,以及应用包名
private int mFlags;         //标志
private HashSet<String> mCategories;   //种类
private Bundle mExtras;    //附加信息
private Rect mSourceBounds;
private Intent mSelector;
private ClipData mClipData;

看Intent的源码,主要包含以上成员。

Intent解析

Intent解析有两种方式:显式解析和隐式解析。

显式解析,我们直接传组件进入,打开这个指定的组件,比较简单,通常应用程序内使用。

比如我们创建一个显式的Intent:

Intent intent = new Intent(context, OtherActivity.class);

隐式解析,没有指定具体的组件,通过规则去匹配组件。通常用于多个程序之间的互相调用比较多。我们使用隐式解析式,action、data(包括URI和数据类型)、category都必须有。比如我们启动浏览器去打开一个网址,intent可以这样创建:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://blog.isming.me"));

上面没有填写category,创建Intent的时候会自动填写为default。

等待补充吧。

乱扯

好吧,本来像,会写的很长的,但是真正想写的时候,发现就这么简单,也没什么好写的。下次多看看源码,再看有没有要补充的。就酱紫了!

android中JSON的解析

android中网络数据传输是经常被用到的,通常我们使用xml或者json,而json更加轻量,便捷,我们使用的更多。我自己在项目中使用很多,今天就说说android中怎么去解析JSON,帮助自己总结内容,同时帮助别人少走弯路。

JSON语法

首先看JSON的语法和结构,这样我们才知道怎么去解析它。JSON语法时JavaScript对象表示语法的子集。

JSON的值可以是:

  • 数字(整数或者浮点数)

  • 字符串(在双引号内)

  • 逻辑值(true 或 false)

  • 数组(使用方括号[]包围)

  • 对象( 使用花括号{}包围)

  • null

JSON中有且只有两种结构:对象和数组。

1、对象:对象在js中表示为“{}”括起来的内容,数据结构为 {key:value,key:value,…}的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是 数字、字符串、数组、对象几种。

2、数组:数组在js中是中括号“[]”括起来的内容,数据结构为 ["java","javascript","vb",…],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种。

andoroid解析JSON

android sdk中为我们提供了org.json,可以用来解析json,在android3.0又为在android.util包JsonReader和JsonWriter来进行json的解析和生成。

使用org.json包JSONObject和JSONArray进行解析

我们知道json中就两种结构array和object,因此就有这个两个类进行解析。

如我们有下面几个json字符串:

{"name":"sam","age":18,"weight":60} //json1 一个json对象
[12,13,15]                    //json2 一个数字数组
[{"name":"sam","age":18},{"name":"leo","age":19},{"name":"sky", "age":20}] //json3 json array中有object

第一个json对象json1的解析

JSONObject jsonObj = new JSONObject(json1);
String name = jsonObj.optString("name");
int age = jsonObj.optInt("age");
int weight = jsonObj.optInt("weight");

另外还有

Object opt(String name)
boolean optBoolean(String name)
double optDouble(String name)
JSONArray optJSONArray(String name)
JSONObject optJSONObject(String name)

等方法,我推荐用这些方法,这些方法在解析时,如果对应字段不存在会返回空值或者0,不会报错。

当然如果你使用以下方法
java
Object get(String name)
boolean getBoolean(String name)
int getInt(String name)

等方法时,代码不会去判断是否存在该字段,需要你自己去判断,否则的话会报错。自己判断的话使用has(String name)来判断。

<

p>再来看解析数组,简单的数组。第二个json2
“`java
JSONArray jsonArray = new JSONArray(json2);<br/>
for (int = 0; i < jsonArray.length();i++) {<br/>
int age = jsonArray.optInt(i); <br/>
}

<pre><code>
解析复杂数组,包含对象,json3
“`java
JSONArray jsonArray = new JSONArray(json3);
for (int = 0; i < jsonArray.length();i++) {
JSONObject jsonObject = jsonArray.optJSONObject(i);
String name = jsonObject.optString("name");
int age = jsonObject.optInt("age");
}

从上面可以看到数组的话解析方法和对象差不多,只是将键值替换为在数组中的下标。另外也是有optXXX(int index)和getXXX(int index)方法的,opt也是安全的,即对应index无值的时候,不会报错,返回空,推荐使用。

使用JsonReader进行解析

JsonReader的使用其实和xml解析中的pull是有一点类似的,我们来看示例。

前面的JSONObject和JSONArray创建时传的是String,而JsonReader需要传入的时候是Reader,网络访问中,我们可以直接拿输入流传进来,转成Reader。我们这里假设我们上面的String已经转成InputStream了,分别为jsonIs1,jsonIs2,jsonIs3。

上面的json1解析:

JsonReader reader = new JsonReader(new InputStreamReader(jsonIs1));
try {积分:49排名:第1495693名上传资源:1
    reader.beginObject();
    while (reader.hasNext()) {
        String keyName = reader.nextName();
        if (keyName.equals("name")) { 
            String name = reader.nextString();
        } else if (keyName.equals("age")) {
            int age = reader.nextInt();
        } else if (keyName.equals("weight")) {
            int weight = reader.nextInt();
        }
    }
    reader.endObject();
} finally {
    reader.close();
}

上面json2的解析:

JsonReader reader = new JsonReader(new InputStreamReader(jsonIs2));
try {
    List<Integer> ages = new ArrayList<Integer>();
    reader.beginArray();
    while (reader.hasNext()) {
        ages.add(reader.nextInt());
    }
    reader.endArray();
} finally {
    reader.close();
}

第三个我就不写示例了。

看到这个的话是通过去遍历我们的json,去取得我们的内容,我觉得在效率上面会比第一种效率高一些。具体使用的话就按照我这两个例子可以写出来的。

使用GSON解析JSON

GSON是谷歌出品,很好用。同时呢还有一些其他的第三方的比如fastjson等,都和Gson差不多,传一个string和要转换的对象,帮你直接直接解析出来,不再需要我们自己一个字段一段字段的解析。这里就以Gson为例吧,因为我只用过Gson,对其最熟悉。_^

使用Gson,我们需要导入Gson的包,下载地址https://code.google.com/p/google-gson/downloads/list

现在开始看看,怎么解析上面的三个json字符串例子。

第一个对象json1

首先我们需要一个实体类
“`java
public class People{</p>

<p>public String name;</p>

<p>@SerializedName(age)<br/>
pubic int mAge; //如果我们类中成员的名称和json对象中的键名不同,可以通过注解来设置名字</p>

<p>public int weight;<br/>
}<br/>
“`

然后就可以解析了

Gson gson = new Gson();
Poeple people = gson.fromJson(json1, People.class);

对于第二个json2,我们可以解析成int数组,也可以解析成Integer的List。
解析成数组:
java
Gson gson = new Gson();
int[] ages = gson.fromJson(json2, int[].class);

解析成List:

Gson gson = new Gson();
List<Integer> ages = gson.fromJson(json2, new TypeToken<List<Integer>>(){}.getType);

第三个同样可以解析成List或者数组,我们就直接解析成List.
java
Gson gson = new Gson();
List<People> peoples = gson.fromJson(json3, new TypeToke<List<People>>(){}.getType);

从上面的代码看到,使用Gson解析的话就非常简单了。需要注意的是如果对应的键值和成员名称不同的话可以使用注解来标记。

闲扯

上面就说清了主流的一些解析,可以看到使用Gson之后解析是十分简单,这可以为我们的开发节约很多的时间。同时呢android本身为我们提供的也挺够用的,并且3.0后增加的JsonReader操作更加流畅,和其他如Pull解析xml的方式有些类似。

本文中仅仅介绍了使用,还有一些api以及高级用法没有提到,毕竟一篇文章能描写的有限,请自行查看官方文档。

上面说的只是解析,其实还有json的生成,JSONObject,JSONArray,都可以直接生成json的,3.0也提供了JsonWriter来生成json。而Gson中,直接gson.toJson(),就可以生成json了,一切都是这么的美妙。不过我们平时,生成json使用比较少,我这里就不写了(或者单独写一篇生成)_

参考资料地址:

使用proguard混淆android代码

当前是有些工具比如apktool,dextojar等是可以对我们android安装包进行反编译,获得源码的。为了减少被别人破解,导致源码泄露,程序被别人盗取代码,等等。我们需要对代码进行混淆,android的sdk中为我们提供了ProGrard这个工具,可以对代码进行混淆(一般是用无意义的名字来重命名),以及去除没有使用到的代码,对程序进行优化和压缩,这样可以增加你想的难度。最近我做的项目,是我去配置的混淆配置,因此研究了一下,这里分享一下。

如何启用ProGuard

ant项目和eclipse项目启用方法

在项目的project.properties文件中添加一下代码

proguard.config=proguard.cfg //proguard.cfg为proguard的配置文件

proguard.config=/path/to/proguard.cfg //路径不在项目根目录时,填写实际路径

填写这句配置后,在release打包时就会按照我们的配置进行混淆,注意,在我们平时的debug时是不会进行混淆的。

Gradle项目(以及Android Studio)

在build.gradle中进行配置

android {
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),'some-other-rules.txt'
//proguardFile 'some-other-rules.txt' 配置单个文件这样
}
}
}

如上面代码所示,我们可以使用runProguard true开启,并且对其配置混淆配置,可以配置多个文件或单个文件。

android的sdk中已经为我们提供了两个默认的配置文件,我们可以拿过来进行使用,proguard-android.txt和proguard-android-optimize.txt。

ProGuard配置

上面说到android为我们提供了两个默认的配置文件,在其中,我们可以看到他的一些语法。本节进行描述。

保留选项(配置不进行处理的内容)

-keep {Modifier} {class_specification} 保护指定的类文件和类的成员

-keepclassmembers {modifier} {class_specification} 保护指定类的成员,如果此类受到保护他们会保护的更好

-keepclasseswithmembers {class_specification} 保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。

-keepnames {class_specification} 保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)

-keepclassmembernames {class_specification} 保护指定的类的成员的名称(如果他们不会压缩步骤中删除)

-keepclasseswithmembernames {class_specification} 保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)

-printseeds {filename} 列出类和类的成员-keep选项的清单,标准输出到给定的文件

压缩

-dontshrink 不压缩输入的类文件

-printusage {filename}

-whyareyoukeeping {class_specification}

优化

-dontoptimize 不优化输入的类文件

-assumenosideeffects {class_specification} 优化时假设指定的方法,没有任何副作用

-allowaccessmodification 优化时允许访问并修改有修饰符的类和类的成员

混淆

-dontobfuscate 不混淆输入的类文件

-obfuscationdictionary {filename} 使用给定文件中的关键字作为要混淆方法的名称

-overloadaggressively 混淆时应用侵入式重载

-useuniqueclassmembernames 确定统一的混淆类的成员名称来增加混淆

-flattenpackagehierarchy {package_name} 重新包装所有重命名的包并放在给定的单一包中

-repackageclass {package_name} 重新包装所有重命名的类文件中放在给定的单一包中

-dontusemixedcaseclassnames 混淆时不会产生形形色色的类名

-keepattributes {attribute_name,…} 保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.

-renamesourcefileattribute {string} 设置源文件中给定的字符串常量

后面的文件名,类名,或者包名等可以使用占位符代替

?表示一个字符
* 可以匹配多个字符,但是如果是一个类,不会匹配其前面的包名
** 可以匹配多个字符,会匹配前面的包名。

在android中在android Manifest文件中的activity,service,provider, receviter,等都不能进行混淆。一些在xml中配置的view也不能进行混淆,android提供的默认配置中都有。

ProGuard的输出文件及用处

混淆之后,会给我们输出一些文件,在gradle方式下是在/build/proguard/目录下,ant是在/bin/proguard目录,eclipse构建在/proguard目录像。

分别有以下文件:

+ dump.txt 描述apk文件中所有类文件间的内部结构。

+ mapping.txt 列出了原始的类,方法,和字段名与混淆后代码之间的映射。
+ seeds.txt 列出了未被混淆的类和成员
+ usage.txt 列出了从apk中删除的代码

当我们发布的release版本的程序出现bug时,可以通过以上文件(特别时mapping.txt)文件找到错误原始的位置,进行bug修改。同时,可能一开始的proguard配置有错误,也可以通过错误日志,根据这些文件,找到哪些文件不应该混淆,从而修改proguard的配置。

注意:重新release编译后,这些文件会被覆盖,所以每次发布程序,最好都保存一份配置文件。

调试Proguard混淆后的程序

上面说了输出的几个文件,我们在改bug时可以使用,通过mapping.txt,通过映射关系找到对应的类,方法,字段等。

另外Proguard文件中包含retrace脚本,可以将一个被混淆过的堆栈跟踪信息还原成一个可读的信息,window下时retrace.bat,linux和mac是retrace.sh,在/tools/proguard/文件夹下。语法为:

retrace.bat|retrace.sh [-verbose] mapping.txt []

例如:

retrace.bat -verbose mapping.txt obfuscated_trace.txt

如果你没有指定,retrace工具会从标准输入读取。

一些常用包的Proguard配置

下面再写一些我在项目中使用到的一些第三方包需要单独配置的混淆配置

sharesdk混淆注意

-keep class android.net.http.SslError
-keep class android.webkit.**{*;}
-keep class cn.sharesdk.**{*;}
-keep class com.sina.**{*;}
-keep class m.framework.**{*;}

Gson混淆配置

-keepattributes *Annotation*
-keep class sun.misc.Unsafe { *; }
-keep class com.idea.fifaalarmclock.entity.***
-keep class com.google.gson.stream.** { *; } 

Umeng sdk混淆配置

-keepclassmembers class * {
   public <init>(org.json.JSONObject);
}

-keep class com.umeng.**

-keep public class com.idea.fifaalarmclock.app.R$*{
    public static final int *;
}

-keep public class com.umeng.fb.ui.ThreadView {
}

-dontwarn com.umeng.**

-dontwarn org.apache.commons.**

-keep public class * extends com.umeng.**

-keep class com.umeng.** {*; }

关于配置方面,我写的不够详细,可以去看参考资料第二条,proguard官方文档。也欢迎大家交流使用遇到的问题和心得。

资料参考:

1.http://proguard.sourceforge.net/

2.http://developer.android.com/tools/help/proguard.html

使用Gradle构建Android项目

新项目中,使用了Google I/O 2013发布的新工具,使用Gradle构建android项目,并且在新版的Intellig IDEA以及google的Android Studio对其支持。本文就介绍一下怎么使用gradle构建android项目,进行多个版本编译。

Gradle是什么?

Gradle是以Groovy为基础,面向java应用,基于DSL语法的自动化构建工具。是google引入,替换ant和maven的新工具,其依赖兼容maven和ivy。

使用gradle的目的:

  • 更容易重用资源和代码;
  • 可以更容易创建不同的版本的程序,多个类型的apk包;
  • 更容易配置,扩展;
  • 更好的IDE集成;

环境需求

Gradle1.10或者更高版本,grale插件0.9或者更高版本.

android SDK需要有Build Tools 19.0.0以及更高版本

Gradle基本结构

使用ide创建的gradle构建的项目,会自动创建一个build.gradle,如下:
“`
buildscript {<br/>
repositories {<br/>
mavenCentral()<br/>
}</p>

<pre><code>dependencies {
classpath 'com.android.tools.build:gradle:0.9.0'
}
</code></pre>

<p>}</p>

<p>apply plugin: 'android'</p>

<p>android {<br/>
compileSdkVersion 19<br/>
buildToolsVersion "19.0.0"<br/>
}<br/>

<pre><code><br />可以看到,构建文件主要有三个区域:

buildscript{…}

<blockquote>
Configures the build script classpath for this project. 设置脚本的运行环境
</blockquote>

apply plugin: 'android'

<blockquote>
设置使用android插件构建项目
</blockquote>

android{…}

<blockquote>
设置编译android项目的参数
</blockquote>

<h3 id="toc_3">任务task的执行</h3>

通常会有以下任务:

<ul>
<li>assemble The task to assemble the output(s) of the project(输出一个项目文件,android就是打包apk)</li>
<li>check The task to run all the checks.(运行检查,检查程序的错误,语法,等等)</li>
<li>build This task does both assemble and check (执行assemble和check)</li>
<li>clean This task cleans the output of the project(清理项目输出文件)</li>
</ul>

<blockquote>
上面的任务assemble,check,build实际上什么都不做,他们其实都是其他任务的集合。
</blockquote>

执行一个任务的方式为<code>gradle 任务名</code>, 如<code>gradle assemble</code>

在android项目中还有connectedCheck(检查连接的设备或模拟器),deviceCheck(检查设备使用的api版本)

通常我们的项目会有至少生成两个版本,debug和release,我们可以用两个任务assembleDebug和assembleRelease去分别生成两个版本,也可以使用assemble一下子生成两个版本。

gradle支持任务名缩写,在我们执行<em>gradle assembleRelease</em>的时候,可以用<em>gradle aR</em>代替。

<h3 id="toc_4">基本的构建定制</h3>

我们可以在build.gradle文件中配置我们的程序版本等信息,从而可以生成多个版本的程序。<br /><br />
支持的配置有:

<ul>
<li>minSdkVersion 最小支持sdk版本 </li>
<li>targetSdkVersion 编译时的目标sdk版本</li>
<li>versionCode 程序版本号</li>
<li>versionName 程序版本名称</li>
<li>packageName 程序包名</li>
<li>Package Name for the test application 测试用的程序包名</li>
<li>Instrumentation test runner 测试用的instrumentation实例</li>
</ul>

例如:<br />
“`<br />
android {<br/>
compileSdkVersion 19<br/>
buildToolsVersion “19.0.0”</p>

<pre><code>defaultConfig {
versionCode 12
versionName “2.0”
minSdkVersion 16
targetSdkVersion 16
}
</code></pre>

<p>}<br/>

目录配置

默认情况下项目目录是这样的
有两个组件source sets,一个main,一个test,对应下面两个文件夹。
src/main/
src/androidTest/

然后对于每个组件目录都有两个目录,分别存储java代码和资源文件
java/
resources/

对于android项目中呢,对应的目录和文件是
AndroidManifest.xml //该文件src/androidTest/目录下不需要,程序执行时会自动构建
res/
assets/
aidl/
rs/
jni/

如果需要上面这些文件,但是不是在上面所说的目录,则需要设置。

sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}

可以给main或者test设置根目录,如

sourceSets {
androidTest.setRoot('tests')
}

可以指定每种文件的存储路径

sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}

特别是我们的ndk生成的.so文件,通常我们不是放到jni目录中的,我们需要设置一下

sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}

签名配置

可以给不同类型进行不同的配置,先看示例:

“`
android {<br/>
signingConfigs {<br/>
debug {<br/>
storeFile file("debug.keystore")<br/>
}</p>

<pre><code> myConfig {
storeFile file("other.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}

buildTypes {
foo {
debuggable true
jniDebugBuild true
signingConfig signingConfigs.myConfig
}
}
</code></pre>

<p>}<br/>

<pre><code><br />上面的配置文件配置两个类型,一个时debug类型,一个时自己的自定义类型。两个分别使用了不同的签名,同时对于生成密钥,要填写设置的密码。

<h3 id="toc_7">代码混淆设置</h3>

直接看代码:<br /><br />
<code><br />
android {<br />
buildTypes {<br />
release {<br />
runProguard true<br />
proguardFile getDefaultProguardFile('proguard-android.txt')<br />
}<br />
}<br />
}<br />
</code>

以上是使用默认的proguard文件去进行混淆,也可以使用自己编写的规则进行混淆,<code>proguardFile 'some-other-rules.txt'</code>

<h3 id="toc_8">依赖配置</h3>

程序中会依赖别的包,或者程序,需要引入别的类库。前面也说到了,支持maven。<br />
对于本地的类库,可以这样引入:<br />
“`<br />
dependencies {<br/>
compile files(‘libs/foo.jar’) //单个文件<br/>
compile fileTree(dir: ‘libs’, include: [‘*.jar’]) //多个文件<br/>
}</p>

<p>android {<br/>
…<br/>
}<br/>

对于maven仓库文件:
“`
repositories {<br/>
mavenCentral()<br/>
}</p>

<p>dependencies {<br/>
compile 'com.google.guava:guava:11.0.2'<br/>
}</p>

<p>android {<br/>
…<br/>
}<br/>
“`

输出不同配置的应用

看代码:

“`
android {<br/>
…</p>

<pre><code>defaultConfig {
minSdkVersion 8
versionCode 10
}

productFlavors {
flavor1 {
packageName "com.example.flavor1"
versionCode 20
}

flavor2 {
packageName "com.example.flavor2"
minSdkVersion 14
}
}
</code></pre>

}<br/>
“`
通过以上设置,我们可以输出不同的保命不同的版本号,以及最小sdk的程序包。当然我们可以根据自己的需求去做其他的不同

生成多个渠道包(以Umeng为例)

我的完整配置文件

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}
apply plugin: 'android'

repositories {
        mavenCentral()
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.3"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

    lintOptions {
        abortOnError false
    }


//签名
    signingConfigs {
        //你自己的keystore信息
        release {
            storeFile file("×.keystore")
            storePassword "×××"
            keyAlias "××××"
            keyPassword "×××"
        }
    }

    buildTypes {

        debug {
            signingConfig signingConfigs.release
        }

        release {
            signingConfig signingConfigs.release
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }

    //渠道Flavors,我这里写了一些常用的,你们自己改
    productFlavors {
        //GooglePlay{}
        //Store360{}
        //QQ{}
        //Taobao{}
        //WanDouJia{}
        //AnZhuo{}
        //AnZhi{}
        //BaiDu{}
        //Store163{}
        //GFeng{}
        //AppChina{}
        //EoeMarket{}
        //Store91{}
        //NDuo{}
        xiaomi{}
        umeng{}
    }

}


//替换AndroidManifest.xml的UMENG_CHANNEL_VALUE字符串为渠道名称
android.applicationVariants.all{ variant ->
    variant.processManifest.doLast{

        //之前这里用的copy{},我换成了文件操作,这样可以在v1.11版本正常运行,并保持文件夹整洁
        //${buildDir}是指./build文件夹
        //${variant.dirName}是flavor/buildtype,例如GooglePlay/release,运行时会自动生成
        //下面的路径是类似这样:./build/manifests/GooglePlay/release/AndroidManifest.xml
        def manifestFile = "${buildDir}/manifests/${variant.dirName}/AndroidManifest.xml"

        //将字符串UMENG_CHANNEL_VALUE替换成flavor的名字
        def updatedContent = new File(manifestFile).getText('UTF-8').replaceAll("UMENG_CHANNEL_VALUE", "${variant.productFlavors[0].name}")
        new File(manifestFile).write(updatedContent, 'UTF-8')

        //将此次flavor的AndroidManifest.xml文件指定为我们修改过的这个文件
        variant.processResources.manifestFile = file("${buildDir}/manifests/${variant.dirName}/AndroidManifest.xml")
    }
}

以上的功能就是替换我的Manifest中的umeng渠道标示,同时去生成不同的apk包。

最后说明

程序在buid的时候,会执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。

lintOptions {
abortOnError false
}

最后PS一下

本人使用gradle确实方便很多,虽然电脑配置低,build的时候比较慢。

内容呢,主要时参考谷歌官方的文档。

关于怎么安装,没有讲到,可以参考这篇文章:http://stormzhang.github.io/android/2014/02/28/android-gradle/

附上我参考的文档,没看懂的可以去看看。http://tools.android.com/tech-docs/new-build-system/user-guide

gradle升级了,我又写了一篇,地址这里:http://blog.isming.me/2014/11/21/use-gradle-new/

使用Intellij IDEA阅读android源码

一直使用Ubuntu+Intellig IDEA进行android开发,并且android源码已经花了两三个星期下载回来了,但是linux平台,没有好用的source insight,所以一直阅读都是需要看哪个了才去搜索那一个。原来发现,原来android提供了eclipse,idea等工具进行阅读的方法。

在android源码目录有一个目录development/tools/idegen,这个就是用来生成idea的project文件的。

那么就开始生成吧!

首先在源码根目录执行这个文件
bash
sh ./development/tools/idegen/idegen.sh

发现需要idegen.jar文件,我这里贡献给大家,把这个文件复制到out/host/linux-x86/framework/目录下,然后重新执行刚才的命令即可。文件下载地址

给我的提示是:

Read excludes: 25ms
Traversed tree: 592981ms

即,总共花费这么多时间,当然电脑快的话,可能也会更快一点。

在我的源码目录生成了android.imlandroid.ipr两个文件。

然后在idea中点击file>open,选择刚刚生成的android.ipr文件即可。

android中网络操作使用总结(http)

Android是作为智能手机的操作系统,我们开发的应用,大多数也都需要连接网络,通过网络发送数据、获取数据,因此作为一个应用开发者必须熟悉怎么进行网络访问与连接。通常android中进行网络连接一般是使用scoket或者http,http是最多的情况,这里,我来总结下,怎么进行http网络访问操作。

android是采用java语言进行开发的,android的包中包含java的URLConnection和apache 的httpclient,因此我们可以使用这两个工具进行网络连接和操作。同时,为了控制是否允许程序连接网络,我们开发应用时,需要在Manifest文件中配置申请网络连接的权限,代码如下。
xml
<uses-permission android:name="android.permission.INTERNET"/>

使用URLConnection连接网络

URLConnection为java.net包中提供的网络访问,支持http,https,ftp等,进行http连接时,使用HttpURLConnection即可,示例代码如下:

URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    readStream(in);   //该方法是我们自己写的,从流中取数据保存到本地,实现从网络获取数据。
finally {
    urlConnection.disconnect();
}

向服务器提交数据时,需要采用POST传输
“`java
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();<br/>
try {<br/>
urlConnection.setDoOutput(true); //设置可以上传数据<br/>
urlConnection.setChunkedStreamingMode(0);</p>

<pre><code>OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
writeStream(out); //该方法时我们自己写的,向输出流中写数据,实现数据上传。

InputStream in = new BufferedInputStream(urlConnection.getInputStream());
readStream(in);
</code></pre>

<p>finally {<br/>
urlConnection.disconnect();<br/>
}<br/>
“`
更多使用方法和函数请查看:http://developer.android.com/reference/java/net/HttpURLConnection.html

同时HttpsURLConnection的使用方法请查看:http://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html

使用HttpClient

这个呢,我们也可以使用AndroidHttpClient页可以使用apache默认的DeafultHttpClient,两者之间仅仅常见Client不同,其他都一样

创建AndroidHttpClient
java
AndroidHttpClient httpClient = AndroidHttpClient.newInstance("user-agent");
java
创建DefaultHttpClient
java
HttpClient client = new DefaultHttpClient();

GET请求
“`java
HttpGet getRequest = new HttpGet("<a href="http://blog.isming.me%22">http://blog.isming.me"</a>);<br/>
try {<br/><br/>
HttpResponse response = httpClient.execute(getMethod); //发起GET请求 </p>

<pre><code>Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //获取响应码<br />
Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8"));//获取服务器响应内容<br />
</code></pre>

<p>} catch (ClientProtocolException e) {<br/><br/>
// TODO Auto-generated catch block<br/><br/>
e.printStackTrace();<br/><br/>
} catch (IOException e) {<br/><br/>
// TODO Auto-generated catch block<br/><br/>
e.printStackTrace();<br/><br/>
}<br/><br/>

<pre><code><br />发起POST请求:<br />
“`java<br />
//先将要传的数据放入List<br/><br/>
params = new LinkedList<BasicNameValuePair>();<br/><br/>
params.add(new BasicNameValuePair(“param1”, “Post方法”));<br/><br/>
params.add(new BasicNameValuePair(“param2”, “第二个参数”)); </p>

<p>try {<br/><br/>
HttpPost postMethod = new HttpPost(baseUrl);<br/><br/>
postMethod.setEntity(new UrlEncodedFormEntity(params, “utf-8”)); //将参数填入POST Entity中 </p>

<pre><code>HttpResponse response = httpClient.execute(postMethod); //执行POST方法
Log.i(TAG, “resCode = ” + response.getStatusLine().getStatusCode()); //获取响应码
Log.i(TAG, “result = ” + EntityUtils.toString(response.getEntity(), “utf-8”)); //获取响应内容
</code></pre>

<p>} catch (UnsupportedEncodingException e) {<br/><br/>
// TODO Auto-generated catch block<br/><br/>
e.printStackTrace();<br/><br/>
} catch (ClientProtocolException e) {<br/><br/>
// TODO Auto-generated catch block<br/><br/>
e.printStackTrace();<br/><br/>
} catch (IOException e) {<br/><br/>
// TODO Auto-generated catch block<br/><br/>
e.printStackTrace();<br/><br/>
}<br/><br/>

说明

从上面看到,使用HttpClient更加方便,明了。不过Android官方给我们的文档说明是建议android2.2及以下版本建议使用HttpClient,android2.3及以上版本建议使用HttpURLConnection。

原因是HttpURLConnection时一个轻量级的Http客户端,提供的API比较简单,方便扩展,但是在2.2及以前版本中,这个API存在一些bug,在2.3的版本中,给修改了。

而HttpClient虽然稳定,bug少,但是其提供的API很多,进行升级和扩展不方便,android团队在提升和优化其方面的积极性不高。

因此,在Android2.2版本以前,使用HttpClient时最好的选择。

Android2.3版本及以后,使用HttpURLConnection时最佳选择。

框架

网络连接是耗时的操作,通常我们不会将其放在UI线程操作,会编写异步线程,将其放在后台线程执行(异步线程操作看这里)。

而网上有一些线程的网络操作框架,可以减少我们的工作量,同时我们自己写的好,可能很多异常处理之类的,没有其向的更加全面。

有轻量的android-async-http

谷歌官方的volley

Square提供的Retrofit

这个可以根据自己项目的需要选择不同的框架,有空我来写写volley的使用(PS:网上已经有使用方法了,自己百度去),另外两个我的连接中已经有使用方法了。

ok,完成!

写的东西不少,但是介绍的不够详细。如果不清楚的,欢迎与我交流

ubuntu快速变装mac

其实,我喜欢Mac的,想要有个MacBook,喜欢其婀娜多姿的身材,妩媚的脸庞,最终要的是有一个UNIX的心。可惜,屌丝买不起啊,只好用Ubuntu来装装Mac了,有什么办法变装呢,那就是安装主题,哈哈。

之前的时候,还是Ubuntu13.04的时候,用过一个主题,让我的桌面变得真的很像Mac,但是升级到14.04之后,发现那个主题安装不了了。今天偶然发现,原来是作者对其升级了,针对不同版本安装不同的主题包,然后我又恢复原来的那个界面了。遂分享之。

先来晒晒我的界面,(__) 嘻嘻……

佛说,万物皆有源!首先,我们要先将该软件的源加到我们的源列表中。


sudo add-apt-repository ppa:noobslab/themes
sudo apt-get update

然后针对不同版本,安装不同的主题

Ubuntu13.04(更低版本,可以用这个试一下,不保证可以用)


sudo apt-get install mac-icons-noobslab
sudo apt-get install mac-ithemes-noobslab

Ubuntu13.10

sudo apt-get install mac-icons-v2-noobslab
sudo apt-get install mac-ithemes-v2-noobslab

Ubuntu14.04

sudo apt-get install mac-icons-v3
sudo apt-get install mac-ithemes-v3

执行完之后,需要安装Ubuntu Tweak ,在theme中进行更多的设置,我的配置如下图所示。