基于Eclipse ADT和Maven的Android开发
Android Studio目前作为Android官方的IDE,它使用Gradle作为构建工具,对Android平台引入的新特性都能够很快的支持。相比之下,Eclipse ADT则更新缓慢,与最常用的构建工具——Maven的集成主要依靠开源界的个人开发者的力量,因而问题较多。
使用Android Studio进行Android开发的确是理想的选择,但是,对于长期习惯于Eclipse + Maven的开发团队来说,Android Studio + Gradle的组合有不小的学习、转换成本。况且很多团队同时负责Android和传统的JavaEE开发,难以摆脱对大量Eclipse、Maven插件的依赖,使用Android Studio后团队需要同时熟悉两套开发工具。
我们团队采用了Eclipse ADT + Maven的组合,本文记录开发环境的搭建过程,开发过程中遇到的问题及其解决方案,备忘并供各位参考。
安装Eclipse ADT或者Android Studio之一,都会自动安装Android SDK管理工具。亦可下载独立安装包。
安装完毕后,设置如下环境变量:
- ANDROID_HOME 设置为Android SDK安装位置,例如D:\Android\sdk
- PATH 中添加 %ANDROID_HOME%\tools 、 %ANDROID_HOME%\platform-tools
%ANDROID_HOME%目录下的AVD Manager.exe、SDK Manager.exe分别是Android模拟器管理工具、SDK管理器。打开SDK管理器,根据需要安装SDK版本和工具。通常需要安装:最新的、以及项目需要的Android版本的SDK Platform、ARM/Intel的System Image、Google APIS、Sources for Android SDK。以及Extra下的全部项目。
如果使用模拟器开发调试,并且你的机器是基于Intel的Windows,则应该在下载完毕后,安装位于extras\intel\Hardware_Accelerated_Execution_Manager目录下的HAXM,可以在很大程度上提高模拟器的性能。
插件 | 说明 |
Android Development Tools |
即ADT,提供Android应用的集成开发环境 Eclipse Marketplace搜索ADT安装 |
Android for Maven Eclipse |
即m2e-android,一个M2E Connector,是Maven插件与ADT、Andmore之间的桥梁。可以依据POM中的配置生成ADT工程结构、维护Android和Maven依赖。 插件Update site:http://rgladwell.github.io/m2e-android/updates/,或者Eclipse Marketplace搜索m2e-android安装 |
Android Maven Plugin |
一个Maven插件。通过Maven构建Android应用程序或者库(aar或者apklib格式),该插件支持:
该插件需要Maven运行时版本不小于3.1.1。通过m2e-android,该插件的大部分功能可以很好的在Eclipse下使用 该插件当前版本为4.3.0,和3.8比起来变动较大,插件的groupId已经改为:com.simpligility.maven.plugins |
maven-jarsigner-plugin |
一个Maven插件,提供对APK进行数字签名的能力,该插件也可以对jar等其它构件进行数字签名 |
Maven中心仓库中,更新Android SDK构件的速度非常慢,这可能是因为Android官方不使用Maven作为构建工具的原因。
我们可以使用Maven Android SDK Deployer补充Android的Maven构件,该工具可以批量的安装Android SDK组件到Maven仓库,其本质上是一个Maven工程,运行时需要Maven 3.1.1+支持。
使用该工具前,设置好ANDROID_HOME,打开%ANDROID_HOME%\SDK Manager.exe:
- 下载所需版本的SDK Platform。检查对应的%ANDROID_HOME%\platforms\android-N目录存在(N为SDK数字版本号)
- 下载所需版本的Addon Google APIs。检查对应的%ANDROID_HOME%\add-ons\addon-google_apis-google-N目录存在
下载完毕后,执行下面的命令安装SDK组件到Maven仓库:
1 2 3 4 5 6 7 8 |
cd D:\Android\tools rem 从GitHub下载maven-android-sdk-deployer git clone https://github.com/simpligility/maven-android-sdk-deployer.git maven-android-sdk-deployer cd maven-android-sdk-deployer rem 安装4.1版本的SDK组件到Maven仓库 set M2_HOME=D:\JavaEE\maven\3.3 rem 如果要安装所有SDK版本的构件到Maven仓库,你需要预先下载所有版本的Android SDK,并执行mvn install mvn install -P 4.1 |
Maven Android SDK Deployer依照下面的规则命名SDK组件对应的Maven构件
构件 | groupId | artifactId | 中心仓库等价构件 |
核心Android API | android | android | com.google.android:android |
Google地图API | com.google.android.maps | maps | |
USB Addon | com.android.future | usb |
ADT相关的全局设置位于Window ⇨ Preferences ⇨ Android下:
选项路径 | 说明 | ||
Android | SDK Location:设置为Android SDK的安装位置。点击Apply会更新可用SDK列表 | ||
Android/Launch | Default emulator options:设置模拟器默认启动选项:
|
在Eclipse中,打开Window ⇨ Android Virtual Devices Manager,看到如下界面:
点击右侧按钮Start,可以启动既有的模拟器。
点击右侧按钮Create,创建一个模拟器,参数设置如下:
点击OK,即可完成模拟器创建。
模拟器按钮 | 对应开发机按键 |
返回设备主界面 | HOME |
后退到上一界面 | ESC |
电源按钮 | F7 |
横屏切换 | Ctrl-F12 |
本节介绍两种创建ADT工程的方法,推荐使用第二种方式,以便获得Maven工程的诸多优势。
在不使用Maven的情况下,可以直接创建Android应用工程。点击Eclipse菜单:File ⇨ New ⇨ Android Application Project,弹出如下对话框:
各字段说明如下:
- Application Name:应用程序的名称,会显示在应用商店、设置(Settings)程序中
- Project Name:即Eclipse工程的名称
- Package Name:作为一个应用程序(不管版本如何变迁)的唯一标识符,同时也作为Java的包名
- Minimum Required SDK:运行时需要的SDK最低版本,版本越低则可用特性越少
- Target SDK:此应用可支持的最高SDK版本,用于提示低于/等于此版本的运行时系统,不去执行兼容性行为
- Compile With:使用哪个已安装的SDK版本来编译程序。通常使用最近的SDK,或者支持所有你想直接使用(不通过反射)的API的某个SDK
- Theme:应用程序的基本主题风格
填写好上述字段后,点击 Next,显示如下对话框:
如果取消勾选Create custom launcher icon、Create activity,则可以结束向导,完成工程创建。否则,后面两个步骤分别用来定制应用图标、选择一个指定布局方式的Activity。
勾选Mark this project as a library,则当前工程被作为Android库看待。
目录/文件 | 说明 | ||
gen | ADT自动生成的Java文件 | ||
src | 源代码文件,如果使用Maven,默认Java源码放在src/main/java | ||
assets | 资产文件,使用原始的流方式使用该目录中的各种文件 | ||
res |
资源文件,例如图片、图标、音频格式、XML文件等等 每个资源文件都会在R.java中自动分配一个唯一的预编译ID(unique precompiled ID) |
||
bin | 二进制文件,存放apk文件。使用Maven时,apk默认生成到target而不是bin目录 | ||
project.properties | Android工程属性设置:
|
||
AndroidManifest.xml |
包含Android应用程序最基本的信息,系统在运行应用之前,必须知道这些信息。该文件包含以下方面的内容:
|
可以直接创建Maven Project,由m2e-android负责生成ADT工程结构:
- 点击Eclipse菜单:File ⇨ New ⇨ Maven Project,在第二步选择groupId为de.akquinet.android.archetypes、artifactId为android-quickstart的Maven原型。如果搜索不到此原型,点击Add Archetype添加
- 点击Next,输入Group Id、Artiface Id等信息,并填写原型属性:
- platform为目标Android SDK版本
- android-plugin-version为android-maven-plugin的版本
- 点击Finish,完成工程创建
注意:原型android-quickstart是基于android-maven-plugin 3.x的,android-maven-plugin 4.x工程目录结构变化较大,需要手工调整。调整步骤可以参考迁移到4.x版本。也参考下面的完整POM手工创建工程。
为便于表述,本节后续内容称此Maven工程为apk工程。
需要注意的地方:
- 如果使用3.8.x版本的android-maven-plugin,Eclipse可能提示错误:“Plugin execution not covered by lifecycle configuration: com.jayway.maven.plugins.android.generation2:android-maven-plugin:3.8.2:consume-aar (execution: default-consume-aar, phase: compile)”。consume-aar是android-maven-plugin添加的用来支持Android新的库归档格式(AAR)的Goal,但是m2e-android、ADT暂时均不支持AAR,这是出现错误的原因。修改工程的POM可以屏蔽此错误
12345678910111213141516171819202122232425262728<pluginManagement><plugins><plugin><groupId>org.eclipse.m2e</groupId><artifactId>lifecycle-mapping</artifactId><version>1.0.0</version><configuration><lifecycleMappingMetadata><pluginExecutions><pluginExecution><pluginExecutionFilter><groupId>com.jayway.maven.plugins.android.generation2</groupId><artifactId>android-maven-plugin</artifactId><versionRange>${android.plugin.version}</versionRange><goals><goal>consume-aar</goal></goals></pluginExecutionFilter><action><ignore /></action></pluginExecution></pluginExecutions></lifecycleMappingMetadata></configuration></plugin></plugins></pluginManagement>修改POM完毕后,工程右键 ⇨ Maven ⇨ Update Project,工程不再报错。
- 广泛使用的3.8版本的android-maven-plugin对高版本的Android SDK支持存在问题,如果在POM中修改了
<sdk><platform>16</platform></sdk> 元素中的版本号,例如修改为22,会无法正常生成/更新ADT工程元数据和AndroidManifest.xml,需要手工介入:
- 修改project.properties: target=android-22
- 修改AndroidManifest.xml中的SDK版本声明:
1<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="22" />
下面是apk工程完整的pom.xml(使用 4.3.0版本的android-maven-plugin):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
<?xml version="1.0" encoding="UTF-8"?> <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>cc.gmem.study</groupId> <artifactId>cordova-study</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>apk</packaging> <name>cordova-study</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <android.plugin.version>4.3.0</android.plugin.version> </properties> <dependencies> <!-- 安卓SDK依赖,原型默认生成的是groupId为com.google.android的依赖项,但是5.0+以上的构件始终没有加入到中心仓库 --> <!-- 因此这里手工修改为Maven Android SDK Deployer生成的构件 --> <dependency> <groupId>android</groupId> <artifactId>android</artifactId> <version>5.1.1_r2</version> <scope>provided</scope> </dependency> <!-- 添加一个apklib/aar依赖,依赖项必须位于当前Workspace中 --> <dependency> <groupId>org.apache.cordova</groupId> <artifactId>cordova-android</artifactId> <version>5.4.1-SNAPSHOT</version> <type>apklib</type> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <!-- 如果不指定,默认执行的生命周期阶段或者目标 --> <defaultGoal>package android:deploy android:run</defaultGoal> <pluginManagement> <plugins> <plugin> <groupId>com.simpligility.maven.plugins</groupId> <artifactId>android-maven-plugin</artifactId> <version>${android.plugin.version}</version> <extensions>true</extensions> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>com.simpligility.maven.plugins</groupId> <artifactId>android-maven-plugin</artifactId> <configuration> <sdk> <!-- 指定Android SDK版本,Update Project可能无效,需要手工修改AndroidManifest.xml、project.properties文件 --> <platform>22</platform> </sdk> <!-- 控制dex命令的执行 --> <dex> <jvmArguments> <jvmArgument>-Xms256m</jvmArgument> <jvmArgument>-Xmx512m</jvmArgument> </jvmArguments> <incremental>true</incremental> <optimize>false</optimize> </dex> <!-- 设置android:run目标的行为 --> <run> <debug>true</debug> </run> <!-- true使用Debug keystore签名,false不签名,both同时创建签名/不签名的apk --> <sign> <debug>true</debug> </sign> <!-- 是否跳过代码精简、混淆处理 --> <proguard> <skip>true</skip> </proguard> <!-- 是否跳过测试 --> <test> <skip>true</skip> </test> <!-- 部署前先卸载既有版本 --> <undeployBeforeDeploy>true</undeployBeforeDeploy> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> </plugins> </build> </project> |
Android Maven工程可能引用几种不同格式的库:
- jar:在Eclipse Package Explorer视图中,显示在Maven Dependencies目录下
- apklib:在Eclipse Package Explorer视图中,显示在Android Dependencies目录下
- aar:在Eclipse Package Explorer视图中,显示在Android Dependencies目录下
下面的片段示例了如何引用apklib格式的库:
1 2 3 4 5 6 |
<dependency> <groupId>org.apache.cordova</groupId> <artifactId>cordova-android</artifactId> <version>5.4.1-SNAPSHOT</version> <type>apklib</type> </dependency> |
注意,ADT不支持直接把apklib库作为lib使用(该库格式并非Android官方提出),你必须:
- 在当前Eclipse工作区中创建groupId、artifactId、version与依赖项一致的Android库工程(打包方式设置为apklib)
- 把Maven仓库中的apklib库作为zip格式解包,提取出资源:src目录内为Java源码,存放到apklib工程的src/main/java中。assets、res、AndroidManifest.xml等目录和文件覆盖到Android库工程根目录下
- 在apk工程上点击右键,Maven ⇨ Update Project
如果不执行上述步骤,在POM中添加apklib依赖后,你可能收到错误提示:dependency=[**:**:apklib:**:compile] not found in workspace。
ADT同样也不支持aar库,你也需要在当前Eclipse工作区中创建Android库工程,步骤和apklib类似:
- 在当前Eclipse工作区中创建groupId、artifactId、version与依赖项一致的Android库工程(打包方式设置为aar)
- 把Maven仓库中的aar库作为zip格式解包,提取出资源:
- assets、res、AndroidManifest.xml等目录和文件覆盖到Android库工程根目录下
- classes.jar、libs下所有jar一律作为Android库工程的依赖处理,可以在Maven仓库中识别这些jar的对应构件,缺失的手工添加为构件
- 在apk工程上点击右键,Maven ⇨ Update Project
可重用的Android库有几种打包格式:
- jar:这种格式只能包含Java类,不能包含Android资源
- apklib:maven-compiler-plugin定义的一种打包格式,这种格式可以包含Java类和Android资源
- aar:Google官方在2013年提出的库格式,与apklib一样,同时可以包含Java类和Android资源。两者的主要区别是,aar把所有类放在classes.jar中,而apklib把所有类的源码放在src目录下
第一种格式不需赘述,下面说明如何创建第二种格式的Maven工程:
- 点击Eclipse菜单:File ⇨ New ⇨ Maven Project,在第二步选择groupId为de.akquinet.android.archetypes、artifactId为android-library-quickstart的Maven原型。如果搜索不到此原型,点击Add Archetype添加:
- 点击Next,输入Group Id、Artiface Id等信息,并填写原型属性,点击完成
下面是apklib工程完整的pom.xml(使用 4.3.0版本的android-maven-plugin):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
<?xml version="1.0" encoding="UTF-8"?> <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>org.apache.cordova</groupId> <artifactId>cordova-android</artifactId> <version>5.4.1-SNAPSHOT</version> <packaging>apklib</packaging> <name>cordova-android</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <android.plugin.version>4.3.0</android.plugin.version> </properties> <dependencies> <dependency> <groupId>android</groupId> <artifactId>android</artifactId> <version>5.1.1_r2</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <pluginManagement> <plugins> <plugin> <groupId>com.simpligility.maven.plugins</groupId> <artifactId>android-maven-plugin</artifactId> <version>${android.plugin.version}</version> <extensions>true</extensions> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>com.simpligility.maven.plugins</groupId> <artifactId>android-maven-plugin</artifactId> <configuration> <sdk> <platform>22</platform> </sdk> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.6</source> <target>1.6</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.9.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>attach-artifact</goal> </goals> <configuration> <artifacts> <artifact> <!-- 同时打一个jar格式的包 --> <type>jar</type> <file>${project.build.directory}/${project.build.finalName}.jar</file> </artifact> </artifacts> </configuration> </execution> </executions> </plugin> </plugins> </build> </project> |
一般只有再正式发布(Release)时才需要对APK进行正式的签名,开发期间只需要使用Debug Keystore即可。因此,最好是新建一个Maven Profile,在必要时启用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<profiles> <profile> <id>sign</id> <properties> <!-- 密钥对和Keystore可以通过Keystore Explorer进行生成和管理 --> <jarsigner.keystore>D:\JavaEE\keystores\gmem.keystore</jarsigner.keystore> <!-- 密码可以通过命令行指定,例如mvn -Djarsigner.storepass=password --> <jarsigner.storepass>passwd</jarsigner.storepass> <jarsigner.alias>*.gmem.cc</jarsigner.alias> <jarsigner.keypass>passwd</jarsigner.keypass> </properties> <build> <plugins> <plugin> <!-- 该插件提供了基于jarsigner签名或者验证签名(verify)工程构件和附件的能力 --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jarsigner-plugin</artifactId> <version>1.4</version> <executions> <execution> <id>signing</id> <goals> <goal>sign</goal> </goals> <phase>package</phase> <configuration> <!-- 扫描待处理构件的基目录,支持Ant风格的包含/排除模式 --> <archiveDirectory></archiveDirectory> <!-- 基目录下哪些构件需要被处理,支持Ant风格的包含/排除模式 --> <includes> <include>target/*.apk</include> </includes> <!-- 是否移除构件上既有的签名 --> <!-- 需要移除既有的、通过Debug keystore进行的签名 --> <removeExistingSignatures>true</removeExistingSignatures> <!-- Release版的keystore和alias的信息 --> <keystore>${jarsigner.keystore}</keystore> <storepass>${jarsigner.storepass}</storepass> <alias>${jarsigner.alias}</alias> <keypass>${jarsigner.keypass}</keypass> <!-- 传递给jarsigner命令行的额外参数 --> <!-- JDK 7+出现INSTALL_PARSE_FAILED_NO_CERTIFICATES错误,添加: --> <arguments> <argument>-sigalg</argument> <argument>MD5withRSA</argument> <argument>-digestalg</argument> <argument>SHA1</argument> </arguments> <!-- 是否显示冗余的信息 --> <verbose>true</verbose> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> |
使用下面的命令启用此Profile并执行构建: mvn install -Psign
如果使用该插件的4.x版本,需要注意:
- 插件的groupId已经改变为 com.simpligility.maven.plugins
- lifecycle-mapping的配置不需要了,consume-aar这个Goal已经废弃
- AndroidManifest.xml需要存放到src/main/目录下
- 资产文件需要从assets转移到src/main/assets
- 资源文件需要从res转移到src/main/res
Update Project后,Android Maven Plugin会自动生成文件和目录的链接,以便ADT能够识别:
Goal | 说明 |
android:aar | 创建 Android Archive (aar) 文件 |
android:apk | 创建apk文件,默认使用debug keystore签名 |
android:connect | 通过外部IP地址连接到ADB服务器 |
android:disconnect | 解除到ADB服务器的连接 |
android:deploy | 部署当前工程的apk到所有已连接(attached)的设备,如果没有任何设备,Build结果显示为失败 |
android:deploy-apk | 部署指定的apk到已连接的设备,可以通过参数device/devices指定目标设备 |
android:deploy-dependencies | 部署所有POM中声明的、直接的apk依赖到设备 |
android:redeploy | 删除现有程序,并重新部署指定的apk到已连接的设备,可以通过参数device/devices指定目标设备 |
android:redeploy-apk | 删除现有程序,并重新部署指定的apk |
android:undeploy | 从所有已连接(attached)的设备解除当前工程的apk的部署 |
android:undeploy-apk | 解除部署指定的apk |
android:devices | 列出所有已连接的设备和模拟器 |
android:dex | 把编译好的class文件转换为Android dex格式 |
android:emulator-start | 启动指定的Android模拟器(AVD) |
android:emulator-stop | 停止指定的Android模拟器 |
android:emulator-stop-all | 停止所有Android模拟器 |
android:generate-sources | 根据resources配置参数,生成R.java |
android:proguard | 通过ProGuard进行混淆处理 |
android:run | 运行顶层启动器(top-level launcher)中的第一个Activity |
android:zipalign | 对apk运行zipalign命令 |
install | 该目标除了默认行为以外,还会导致apk在设备上运行 |
可能是android-maven-plugin和Maven运行时的兼容性问题。点击Window ⇨ Preferences,定位到Maven ⇨ Installations,选择一个小于3.2.5版本的Maven即可。
Leave a Reply