scala+maven开发android程序

scala+maven开发android程序
Shiva Wu


转载请注明出处

0、前言

刚刚入了一个android手机,想玩一玩开发。

本想用eclipse了事,如果只用java的话,eclipse的adt确实很不错,还有可视化的界面设计。无奈scala-ide太不给力,卡的要命,而且根本不能正常识别scala写出来的Activity,无奈放弃。

引用
参考 http://blog.caokee.com/index.php/2010/11/11/scala-android-eclipse/
大部分都是这个思路,不过我没搞明白scala-android.jar是神马,感觉应该已经停止更新了,有没有2.8的新特性不好说。


IDEA也尝试了一下,IDEA的scala插件一向是最稳定的,不过IDEA本身实在是慢,而且启动模拟器程序部署不上去,打开模拟器之后IDEA就一直在Waiting for device中,不知道什么情况,估计linux下没这个问题。

以上问题如果谁知道怎么办麻烦告知。

还有一篇用ant做scala on android开发的文章, http://chneukirchen.org/blog/archive/2009/04/programming-for-android-with-scala.html,很专业。

言归正传。

emacs的scala-mode+ensime还是很不错的,可以和sbt、maven结合。于是决定尝试maven。

顺便说,maven-scala-plugin的continuous build在windows下有问题,但是ensime本身提供了这个功能,所以也没有关系。

引用
http://riddell.us/AndroidWithEmacsOnUbuntu.html
此人写了一个简单的android-mode,可以作为参考,不过如果使用maven就不用这么麻烦了。

https://github.com/jberkel/android-plugin
这里还有一个sbt-android-plugin,没有试用,对sbt不熟悉。


使用的系统环境:
System Windows 7
Maven 3.0
Scala 2.8.1
Proguard 4.4
maven-android-plugin 2.8.3
proguard-maven-plugin 2.0.4


1、生成archetype

archetype参考了java的,具体看这里:
https://github.com/akquinet/android-archetypes

这里使用简单的quickstart,执行
mvn archetype:generate -DarchetypeGroupId=de.akquinet.android.archetypes -DarchetypeArtifactId=android-quickstart -DarchetypeVersion=1.0.4 -DgroupId=com.ga -DartifactId=hello -Dversion=1.0-SNAPSHOT
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
[INFO]
[INFO] --- maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom ---
[INFO] Generating project in Interactive mode
[INFO] Archetype repository missing. Using the one from [de.akquinet.android.archetypes:android-quickstart:1.0.4] found in ca
talog remote
[INFO] Using property: groupId = com.ga
[INFO] Using property: artifactId = hello
[INFO] Using property: version = 1.0-SNAPSHOT
[INFO] Using property: package = com.ga
[INFO] Using property: platform = 7
Confirm properties configuration:
groupId: com.ga
artifactId: hello
version: 1.0-SNAPSHOT
package: com.ga
platform: 7
 Y: :
[WARNING] Don't override file D:\Temp\hello\pom.xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.052s
[INFO] Finished at: Mon Jan 17 16:50:10 CST 2011
[INFO] Final Memory: 5M/10M
[INFO] ------------------------------------------------------------------------


还说不要改动pom.xml,这里只好无视了。

2、加入scala nature

引用
参考了davidB的scala-archetype-simple, https://github.com/davidB/scala-archetype-simple


1、首先在pom.xml加入scala-library依赖,将原来的dependencies tag改成
	<properties>
		<encoding>UTF-8</encoding>
		<scala.version>2.8.1</scala.version>
	</properties>

	<repositories>
		<repository>
			<id>scala-tools.org</id>
			<name>Scala-Tools Maven2 Repository</name>
			<url>http://scala-tools.org/repo-releases</url>
		</repository>
	</repositories>

	<dependencies>
		<dependency>
			<groupId>com.google.android</groupId>
			<artifactId>android</artifactId>
			<version>2.2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.scala-lang</groupId>
			<artifactId>scala-library</artifactId>
			<version>${scala.version}</version>
		</dependency>
	</dependencies>


2、加上scala-plugin的依赖,在build标签中:
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
	<plugin>
		<groupId>org.scala-tools</groupId>
		<artifactId>maven-scala-plugin</artifactId>
		<version>2.15.0</version>
		<executions>
			<execution>
				<goals>
					<goal>compile</goal>
					<goal>testCompile</goal>
				</goals>
				<configuration>
					<args>
						<arg>-make:transitive</arg>
						<arg>-dependencyfile</arg>
						<arg>${project.build.directory}/.scala_dependencies</arg>
					</args>
				</configuration>
			</execution>
		</executions>
	</plugin>
</plugins>


3、由于我用2.2的系统,所以把platform标签改成8。

4、下面删掉原来的HelloAndroidActivity.java,创建HelloAndroidActivity.scala。
package com.ga

import android.app.Activity
import android.os.Bundle
import android.util.Log

class HelloAndroidActivity extends Activity {
	override def onCreate(savedInstanceState: Bundle) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.main)
	}
}


这个时候使用mvn compile编译应该是通过的,前提是Android SDK已经装好,可能还要在环境变量里面设置一下ANDROID_HOME。

3、打包发布

这个时候使用mvn package,经过漫长的等待之后,应该会出现错误。

究其原因,dx.bat不能正确打包scala-library,主要集中在scala.actors和scala.concurrency。这里有一个issue提交, http://code.google.com/p/android/issues/detail?id=7147,2.7.7版本是正常的,可能2.8.1改动了代码就又有问题了。

Anyway,即使能够正确运行,打出来的包的大小也是很恐怖的。所以要减肥。

这里使用proguard 4.4,虽然最新版是4.5.1,但是maven repo上没有更新,不知道为什么,如果想用最新版可以将相应的版本install的本地仓库上。

引用
参考maven-android-plugin的一篇wiki, http://code.google.com/p/maven-android-plugin/wiki/ProGuard,以及这个页面下面的Scala Sample,但是那个是错误的,以下方法解决了其问题。


首先在pom.xml里面加入proguard-maven-plugin的依赖,这个插件也很久没有更新,有些功能上的缺陷,留待后面谈。
			<plugin>
				<groupId>com.pyx4me</groupId>
				<artifactId>proguard-maven-plugin</artifactId>
				<version>2.0.4</version>
				<executions>
					<execution>
						<phase>process-classes</phase>
						<goals>
							<goal>proguard</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<maxMemory>512m</maxMemory>
					<injar>android-classes</injar>
					<inFilter>
						!scala/Enumeration**,!scala/collection**
					</inFilter>
					<libs>
						<lib>${java.home}/lib/rt.jar</lib>
					</libs>
					<exclusions>
						<exclusion>
							<groupId>org.scala-lang</groupId>
							<artifactId>scala-library</artifactId>
						</exclusion>
					</exclusions>
					<!--<proguardInclude>${basedir}/proguard.conf</proguardInclude>-->
				</configuration>
				<dependencies>
					<dependency>
						<groupId>net.sf.proguard</groupId>
						<artifactId>proguard</artifactId>
						<version>4.4</version>
						<scope>runtime</scope>
					</dependency>
				</dependencies>
			</plugin>


比较一下上面的代码和wiki页面上的不同。
  1. 使用版本4.4
  2. 将-Xmx参数设到512m,实际不需要,下面解释。
  3. 加入了scala-library的exclusion。这个原因是,android-plugin会把整个scala-library解压到classes里面,但这个jar包还在依赖中,所以也会以libraryjars的形式输入给proguard,会导致大片的duplicated classes definition,而且读入两遍之后会出现OutOfMemoryError,这也是2的目的。这里把它从libraryjars中排除就彻底解决了这个问题。
  4. 去掉了keep class等,把它放到了一个新的文件中,这样更容易配置,因为插件给出的设置选项还是有限。其次,wiki上的配置是错误的,会把scala-library整个精简掉,导致程序崩溃。下载附件中的proguard.conf,和pom.xml放在一起,如果想要使用其他文件名,参见上面注释的proguardInclude。
  5. 加入了scala.Enumeration和scala.collection的filter,前者会生成大把莫名其妙的warning,而且Enumeration已经是不推荐使用的类了;后者由于太大了,为了减小体积。此条为个人喜好,不加也没有问题。


这个时候执行mvn package就可以看到生成的hello-1.0-SNAPSHOT.apk,大小为70k,还算可以。

启动一个模拟器,然后mvn android:deploy就可以部署上去了。实际还可以直接部署到真机上,windows用一个usb driver,官网有下,还没有尝试过。

放一张截图。

scala+maven开发android程序

4、优化
上面的过程实际还可以优化,一个完整的mvn clean package android:deploy还是要花上将近一分钟的时间。

主要还是集中在proguard的打包上,而且这也涉及到发布程序的时候的大小。

引用
proguard的官网上给出了很多例子, http://proguard.sourceforge.net/index.html#/manual/examples.html,其中包括一个scala的。但是这个会造成不必要的依赖,所以在本文中只使用了其一部分。


目前想到的可以加速的几点:
  1. 每次android-plugin都会把所有的依赖库解压一遍,这个非常慢,可以作为一个feature request提出来,对于库依赖这个插件没有处理好。
  2. rt.jar的读取也是很慢的,可以在rt.jar加入过滤(java/**,javax/**),这个也是官网推荐的。但是由于proguard-maven-plugin不支持这个选项,所以可以把-libraryjars rt.jar(filter)加入到proguard.conf里面,去掉上面的libs标签。有一利就有一弊,这样的话就不能跨平台,因为rt.jar的路径是固定的。
  3. filter掉一部分scala-library,篇头提到的scala-android.jar应该也是做了同样的事情。甚至可以直接做一个精简的jar出来install到本地仓库上,这样也可以减小第一条浪费的时间。前面也提到actors和concurrency不能被dx正确打包,所以估计这两个特性是不能用了。collection虽然很强大,但是本身也太大了,如果注重效率还是用java的容器吧。
  4. proguard还有obfuscate和optimize特性可以用,都能减小大小,不过optimize可能会让程序崩溃。上面的程序obfuscate后变成50K,可以运行。optimize后40K,但是会崩溃,可能需要调整一些细微的参数。


如果有更好的方法建议欢迎讨论。

你可能感兴趣的:(eclipse,maven,scala,android,Google)