使用Maven构建Android项目
http://www.ikoding.com/build-android-project-with-maven/
之前一直在做WEB前端项目,前段时间接手第一个Android项目,拿到代码之后,先试着run起来再说,导入eclipse,一堆错误,设置classpath依赖,折腾半天,还是编译错误,于是联系项目接口人,得知他有一个Android库项目没有提交到SVN,晕。。。
对于习惯使用Maven管理Java项目的我来说,自然想到能否用Maven构建Android项目呢?于是开始Google、百度,发现已经有前人做过这样的实践了,不过在使用过程中还是遇到不少问题,后面经过各种努力终于能比较顺地使用了,这篇文章对如何使用Maven构建Android项目作了简要总结。如果你和我一样饱受项目依赖管理的折磨,和我一样讨厌项目打包发布时的繁琐,希望能通过Maven让这一切自动化完成。那么,这篇文章或许对你有用。
1. 环境搭建
- JDK与Android SDK安装
做Android开发,这里无需多说,但安装完成后需要正确设置JAVA_HOME、CLASSPATH、ANDROID_HOME等环境变量。其中ANDROID_HOME为Android SDK安装的根目录。并将%ANDROID_HOME%\tools和%ANDROID_HOME%\platform-tools值添加到Path变量中。
- Maven安装
这里无需多说,下载安装Maven并正确设置环境变量即可。
- IDE支持
- Eclipse
大多数人都在使用Eclipse开发Android应用,如果你用Eclipse做Android开发,推荐下载eclipse-with-m2e-and-adt,该版本已经安装了ADT、m2e、m2e-android等重要插件,支持在Eclipse中使用Maven进行Android应用开发。当时为了安装这些插件费了好大劲,所以,如果你看到这里,可以直接下载它,不用像我一样去做那些没有意义又浪费时间的事情。
- IntelliJ IDEA
做Java开发,你不能不知道的神器,完美支持使用Maven构建Android应用,强烈推荐。即使是装了插件的Eclipse对使用Maven构建Android应用仍然支持不好。如果你是Eclipse的信徒,你也可以试试它,如果你能习惯它,你一定会被它的强大所吸引。
- NetBeans IDE
NetBeans也支持Android开发,但没怎么了解,用的人应该也比较少。
2. 项目构建
以下是我的项目中使用的pom文件,因为涉及保密,部分地方做过修改,但整体结构没有改变,可以清楚地说明问题。
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ikoding.android</groupId>
<artifactId>android-app-quickstart</artifactId>
<version>1.0.0</version>
<packaging>apk</packaging>
<name>Android Application Quick Satrt</name>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>support-v4</artifactId>
<version>r7</version>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j</artifactId>
<version>0.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>com.ikoding.android</groupId>
<artifactId>android-base</artifactId>
<version>2.0.0</version>
<type>apklib</type>
</dependency>
</dependencies>
<properties>
<keystore.filename>app-quickstart.keystore</keystore.filename>
<keystore.storepass>2013@ikoding</keystore.storepass>
<keystore.keypass>2013@ikoding</keystore.keypass>
<keystore.alias>ikoding-android-app</keystore.alias>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<finalName>${project.artifactId}-${project.version}-${manifest.metadata.id}</finalName>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>.</directory>
<filtering>true</filtering>
<targetPath>../filtered-resources</targetPath>
<includes>
<include>AndroidManifest.xml</include>
</includes>
</resource>
<resource>
<directory>resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>**/env-*.properties</exclude>
</excludes>
</resource>
</resources>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>3.5.0</version>
<extensions>true</extensions>
<executions>
<execution>
<id>run</id>
<goals>
<goal>deploy</goal>
<goal>run</goal>
</goals>
<phase>install</phase>
</execution>
</executions>
<configuration>
<proguardConfig>proguard.cfg</proguardConfig>
<proguardSkip>${project.build.proguardSkip}</proguardSkip>
<manifestDebuggable>${manifest.debuggable}</manifestDebuggable>
<androidManifestFile>target/filtered-resources/AndroidManifest.xml</androidManifestFile>
<release>${project.build.release}</release>
<run>
<debug>${project.build.debug}</debug>
</run>
<runDebug>${project.build.runDebug}</runDebug>
<sign>
<debug>${project.build.sign.debug}</debug>
</sign>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<configuration>
<sdk>
<platform>15</platform>
</sdk>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>keytool-maven-plugin</artifactId>
<version>1.2</version>
<!--<executions>-->
<!--<execution>-->
<!--<goals>-->
<!--<goal>clean</goal>-->
<!--<goal>generateKeyPair</goal>-->
<!--</goals>-->
<!--<phase>generate-resources</phase>-->
<!--</execution>-->
<!--</executions>-->
<configuration>
<keystore>${keystore.filename}</keystore>
<storepass>${keystore.storepass}</storepass>
<keypass>${keystore.keypass}</keypass>
<alias>${keystore.alias}</alias>
<dname>CN=iKoding, OU=iKoding, O=iKoding, C=CN</dname>
<sigalg>SHA1withDSA</sigalg>
<validity>10000</validity>
<keyalg>DSA</keyalg>
<keysize>1024</keysize>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<projectnatures>
<projectnature>org.eclipse.m2e.core.maven2Nature</projectnature>
<projectnature>com.android.ide.eclipse.adt.AndroidNature</projectnature>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
</projectnatures>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>debug</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<filters>
<filter>resources/env-debug.properties</filter>
</filters>
</build>
<properties>
<project.build.debug>true</project.build.debug>
<project.build.runDebug>false</project.build.runDebug>
<project.build.proguardSkip>true</project.build.proguardSkip>
<project.build.release>false</project.build.release>
<project.build.sign.debug>true</project.build.sign.debug>
<manifest.debuggable>true</manifest.debuggable>
</properties>
</profile>
<profile>
<id>release</id>
<properties>
<project.build.debug>false</project.build.debug>
<project.build.runDebug>false</project.build.runDebug>
<project.build.proguardSkip>false</project.build.proguardSkip>
<project.build.release>true</project.build.release>
<project.build.sign.debug>false</project.build.sign.debug>
<manifest.debuggable>false</manifest.debuggable>
</properties>
<build>
<filters>
<filter>resources/env-release.properties</filter>
</filters>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>sign</id>
<goals>
<goal>sign</goal>
</goals>
<phase>package</phase>
<inherited>true</inherited>
<configuration>
<includes>
<include>${project.build.outputDirectory}/*.apk</include>
</includes>
<keystore>${keystore.filename}</keystore>
<storepass>${keystore.storepass}</storepass>
<keypass>${keystore.keypass}</keypass>
<alias>${keystore.alias}</alias>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- 渠道profiles -->
<profile>
<id>channel-test</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<manifest.metadata.id>test</manifest.metadata.id>
<manifest.metadata.channel>test</manifest.metadata.channel>
</properties>
</profile>
<profile>
<id>channel-91</id>
<properties>
<manifest.metadata.id>91-market</manifest.metadata.id>
<manifest.metadata.channel>91 market</manifest.metadata.channel>
</properties>
</profile>
<profile>
<id>channel-yingyonghui</id>
<properties>
<manifest.metadata.id>yingyonghui-market</manifest.metadata.id>
<manifest.metadata.channel>yingyonghui market</manifest.metadata.channel>
</properties>
</profile>
<profile>
<id>channel-tongbutui</id>
<properties>
<manifest.metadata.id>tongbutui-market</manifest.metadata.id>
<manifest.metadata.channel>tongbutui market</manifest.metadata.channel>
</properties>
</profile>
<profile>
<id>channel-tengxun</id>
<properties>
<manifest.metadata.id>tengxun-market</manifest.metadata.id>
<manifest.metadata.channel>tengxun market</manifest.metadata.channel>
</properties>
</profile>
<profile>
<id>channel-anzhi</id>
<properties>
<manifest.metadata.id>anzhi-market</manifest.metadata.id>
<manifest.metadata.channel>anzhi market</manifest.metadata.channel>
</properties>
</profile>
<profile>
<id>channel-gfan</id>
<properties>
<manifest.metadata.id>gfan</manifest.metadata.id>
<manifest.metadata.channel>gfan</manifest.metadata.channel>
</properties>
</profile>
</profiles>
</project>
以上的pom文件基本上涉及到了一个Android应用构建过程中的各个方面,以下针对其中比较重要的一些点作简要说明。
- 依赖管理
这也是我们使用Maven构建Android项目的重要原因之一,值得注意的是以下部分:
<groupId>com.ikoding.android</groupId>
<artifactId>android-base</artifactId>
<version>2.0.0</version>
<type>apklib</type>
</dependency>
以上依赖的type为apklib,这就是我们项目中的Library Project,此外,我们还可以使用Maven管理Native库,亦即我们项目中所依赖的那些so库文件。
- 资源过滤
项目中总会有一些和环境相关的配置,比如线下测试环境和线上环境的配置可能不一样,为此我们在pom中分别定义了id为debug和release两个profile,并使用不同的filter进行资源过滤。
- 生成keystore
我们使用了keytool-maven-plugin来生成签名时所需的keystore文件,我在properties中定义了生成keystore文件所需的信息,如下所示:
<keystore.filename>app-quickstart.keystore</keystore.filename>
<keystore.storepass>2013@ikoding</keystore.storepass>
<keystore.keypass>2013@ikoding</keystore.keypass>
<keystore.alias>ikoding-android-app</keystore.alias>
</properties>
可以运行mvn keytool:generateKeyPair命令来生成keystore文件,之后在应用正式打包发布时候就会使用该keystore文件进行签名。
- 生成渠道包
项目最终发布时需要根据渠道号生成不同的渠道包,我们可以利用Maven的资源过滤对AndroidManifest.xml文件中的渠道信息进行替换,例如我们上面的pom文件对Manifest文件中${manifest.metadata.channel}的渠道信息进行了替换,还有一些其他信息如Manifest文件的debuggable属性也可以针对不同配置进行替换,比如我们在日常开发中需要将该值设为true,而在项目正式发布时需要将该值设为false,我们以上的pom文件中就定义了多个针对不同渠道的profile。
- 代码混淆
项目正式发布时需要对代码进行混淆处理,我们只需在android-maven-plugin配置中指定proguardConfig文件,比如我们在上面的pom中指定proguard文件为proguard.cfg,项目构建过程中会自动运行代码混淆,并且可以通过proguardSkip属性指定是否运行代码混淆任务,这样我们就可以在日常开发调试过程中关闭混淆,而在项目发布时开启混淆。
- 签名
我们使用了maven-jarsigner-plugin对apk文件进行签名,签名使用的证书就是之前生成的keystore文件。
- 调试
我在使用Maven构建Android项目之初遇到的问题就是无法进行断点调试,这显然会降低开发效率,后来发现可以通过android-maven-plugin的runDebug属性开启调试,这样可以在应用程序启动时连接debugger进行调试。
- IDE支持
再次回到这个话题上,在导入eclipse之前,你需要先运行mvn eclipse:eclipse命令,生成eclipse项目文件,因为eclipse对android-maven-plugin支持不好。
3. 常用命令
以下是使用Maven构建Android项目中常用的一些命令,你可以根据需要选择合适的命令。
- mvn clean package
打包,但不部署。
- mvn clean install
打包,部署并运行。
- mvn clean package android:redeploy android:run
这个命令通常用于手机上已经安装了要部署的应用,但签名不同,所以我们打包的同时使用redeploy命令将现有应用删除并重新部署,最后使用run命令运行应用。
- mvn android:redeploy android:run
不打包,将已生成的包重新部署并运行。
- mvn android:deploy android:run
部署并运行已生成的包,与redeploy不同的是,deploy不会删除已有部署和应用数据。
4. 总结
使用Maven构建Android应用很好地解决了依赖管理的问题,而且我们也可以将很多繁琐的任务自动化完成。在使用过程中主要的问题是Eclipse的m2e-android插件支持不够理想,而IntelliJ IDEA在这方便显得非常强大,让我得以将Maven和IDE的优势结合在一起。你可以在此基础上开发出一些常用类型项目的maven archetype,这样你就可以更快的开始一个新的项目。
5. 坚持?改变?
事实上我所在的团队成员最初都在使用Eclipse进行开发,后来在我的一再“忽悠”下,大家都接受了这种新的开发方式,并逐渐转向IntelliJ IDEA。这需要你有做出改变的勇气,毕竟改变是痛苦的,没有充分的理由就很难说服别人改变,但当你适应后就会有新的收获。
附件
下面是Android Library Project的pom文件,它比文中的Application Project的pom文件看起来要简单很多:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ikoding.android</groupId>
<artifactId>android-lib-quickstart</artifactId>
<version>1.0.0</version>
<packaging>apklib</packaging>
<name>Android Library Project Quick Start</name>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<sourceDirectory>src</sourceDirectory>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>3.5.0</version>
<extensions>true</extensions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<configuration>
<sdk>
<platform>15</platform>
</sdk>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<projectnatures>
<projectnature>org.eclipse.m2e.core.maven2Nature</projectnature>
<projectnature>com.android.ide.eclipse.adt.AndroidNature</projectnature>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
</projectnatures>
</configuration>
</plugin>
</plugins>
</build>
</project>
使用Maven构建Android项目的更多相关文章
- gradle学习系列之eclipse中简单构建android项目
看不到图片能够去訪问这个网址看看:http://pan.baidu.com/s/1o6FrFkA 一.什么是Gradle 官网www.gradle.org上介绍Gradle是升级版(evolved)的 ...
- 使用Gradle构建Android项目
阅读目录 Gradle是什么? 环境需求 Gradle基本结构 任务task的执行 基本的构建定制 目录配置 签名配置 代码混淆设置 依赖配置 输出不同配置的应用 生成多个渠道包(以Umeng为例) ...
- 转】用Maven构建Mahout项目
原博文出自于: http://blog.fens.me/hadoop-mahout-maven-eclipse/ 感谢! 用Maven构建Mahout项目 Hadoop家族系列文章,主要介绍Hadoo ...
- 转】用Maven构建Hadoop项目
原博文出自于: http://blog.fens.me/hadoop-maven-eclipse/ 感谢! 用Maven构建Hadoop项目 Hadoop家族系列文章,主要介绍Hadoop家族产品 ...
- 使用Eclipse maven构建springmvc项目
Eclipse maven构建springmvc项目 Listener 监听器 架构 使用Log4J监控系统日志邮件警报 2014-12-16 13:09:16 控制器在完成逻辑处理后,通常会产生一些 ...
- Maven学习:Eclipse使用maven构建web项目(转)
Maven学习:Eclipse使用maven构建web项目(转) 8.更改class路径:右键项目,Java Build Path -> Source 下面应该有4个文件夹.src/main/j ...
- Maven管理Android项目1
maven-android-plugin网站:https://code.google.com/p/maven-android-plugin/wiki/GettingStarted android ...
- 利用Eclipse中的Maven构建Web项目(三)
利用Eclipse中的Maven构建Web项目 1.将Maven Project转换成动态Web项目,鼠标右键项目,输入"Project Facets" 2.依据Dynamic W ...
- Eclipse Maven构建WebApp项目资源目录显示不全的原因与解决方式
一.问题展示 1.Eclipse在使用Maven构建WebApp项目的时候,首先Maven的安装和配置都没有问题的,但是构建项目之后,Maven项目要求的几个必须要有的资源目录显示不了: 问题如下图: ...
随机推荐
- OSG快速生成一个带有纹理的四边形Geometry
可以使用Geometry头文件中的 Geometry* createTexturedQuadGeometry osg::ref_ptr<osg::Texture2D> texture = ...
- FTL标签
<#if blockObject ??> <#else> </if>判断对象是否存在 <#if componentid ?? &&compon ...
- [Android Pro] Gradle Tips#1-tasks
reference to : http://trickyandroid.com/gradle-tip-1-tasks/ http://blog.csdn.net/lzyzsd/article/deta ...
- [Ubuntu] ubuntu10.04系统维护之Wine的安装
在介绍安装wine之前,我想是有必要先介绍一下Wine的.当然,如果是Liunx的高手,我想是没必要看的,但是对于笔者这样的菜鸟级人物还是需要看一下的. Wine是一款Liunx下的模拟器软件,但是W ...
- PHP之MVC项目实战
本文主要包括以下内容 类文件自动加载 路径管理 页面跳转 注册自动加载方法 配置文件系统 cookie session 类文件自动加载 在PHP中使用别的类时,需要载入类文件,如果类很多的话,需要重复 ...
- hdu 1005
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1005 思路:找规律题 #include<stdio.h> main() { ]; int ...
- java 接口与继承
一.继承条件下的构造方法调用 运行 TestInherits.java 示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent的另一个构 ...
- ListView + PopupWindow实现滑动删除
原文:ListView滑动删除 ,仿腾讯QQ(鸿洋_) 文章实现的功能是:在ListView的Item上从右向左滑时,出现删除按钮,点击删除按钮把Item删除. 看过文章后,感觉没有必要把dispat ...
- md5sum
[root@NB index]# ls index()().html index()().html index()().html index()().html index()().html [root ...
- probe函数何时调用的
转自:http://blog.csdn.net/xiafeng1113/article/details/8030248 Linux中 probe函数何时调用的 所以的驱动教程上都说:只有设备和驱动的名 ...