Targeting Android with Scala 2.8 Trunk builds
The definitive reference for using Scala on android seems to be here: http://www.scala-lang.org/node/160
Unfortunately, all the references on using scala with android are based around Scala 2.7 and refer to a custom build android-library.jar, with a couple of cryptic references suggesting that this custom build i开发者_JS百科sn't needed for later versions of android (I'm using 2.1 / API v7)
So... What are the steps needed to use Scala 2.8 in an android project? Preferably using eclipse and the Android tools that Google supplies for that IDE.
Edit:
My new way of doing this is to use my Eclipse plugin: https://github.com/banshee/AndroidProguardScala (the readme has instructions for installing and a pointer to a normal Eclipse update site).
The old answer still works, but the new way is just better.
[The old way] My approach:
- Use the normal Android/eclipse tools for creating a Java project.
- Add a second project containing the Scala code. That way I get to keep the generated code for future reference (I'm new at both Android and Scala). This project can reference android.jar.
- The scala project produces a jar file that's used in the java project
- Use proguard to strip the library. I believe this avoids the need for the scala-android.jar that was used in 2.7
I haven't used this for anything more ambitious than hello, world though, so take it as more of a set of hints.
In the scala project, I add a builder (Builder > New) that's just a shell script called pguard in the root directory of the project containing:
#!/bin/sh
cd $1
PROGUARD=$HOME/dev/proguard/lib/proguard.jar
LIBS=
OUTPUT=lib/proguard.jar
rm -f $OUTPUT
AJAR=/Users/jamesmoore/dev/android-sdk-mac_86/platforms/android-7/android.jar
# java -jar $PROGUARD -injars 'bin:lib/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)' -outjar $OUTPUT -libraryjars @proguard.txt
java -Xmx1g -jar $PROGUARD -injars 'bin:lib/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)' -outjar $OUTPUT -libraryjars $AJAR @proguard.txt
The builder has Location set to:
${build_project}/pguard
And both working directory and arguments set to
${build_project}
Also in the root of the scala project, there's a proguard arguments file @proguard.txt:
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep public class com.banshee.** {
public protected *;
}
You'll want to change the -keep arguments to keep your own code, of course.
In the java project, I add the jar file that's produced by the scala project (I use lib/proguard.jar in the script above).
Don't add the scala project as a required project in the java project's build path, though. That will add the scala class files in addition to the jar file and confuse dex (since it'll get both the .class files and the same things in the jar). As far as I can tell, Eclipse will build everything in the workspace, so when you hit the go button, both projects get built.
After much investigation, it really does look like Proguard is essential to keep the size and speed of deploying the application to reasonable levels.
Sadly, there is no suitable way to embed proguard as a build step. Using scripts might be a possibility, but I also need to support Windows, Linux and OSX environments.
I was also unsure about the twin-project solution, as it prevented Scala code from using the generated resources file R.java, which I wanted to be able to do.
In the end, I was able to make both SBT and Ant build an android 2.1 application using Scala 2.8. Ant was the favourite final solution as it works with the same file organisation as Android's eclipse plugin. I've written up the solution here: http://scala-ide.assembla.com/wiki/show/ae55a-oWSr36hpeJe5avMc/Developing_for_Android
Eclipse then launches Ant as an external tool to package and install the application.
I'm now using a modification of my previous answer to run on Windows: just move everything into @proguard_windows.txt so you don't have to worry about running as a script.
My new @proguard_windows.txt looks like:
-injars bin;lib/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)
-outjar gen/scandroid.jar
-libraryjars lib/android.jar
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep public class com.banshee.** { public protected *; }
-keep public class org.xml.sax.EntityResolver { public protected *; }
And note that in windows, you need to use a semicolon for -injars. Nasty.
The builder looks like this:
(running cygwin here, so the cat option path takes a slash)
James@Greine:/cygdrive/c/Users/james/workspace/Scala2$ cat .externalToolBuilders/proguard.launch
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="C:\Windows\System32\java.exe"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-Xmx1g -jar lib/proguard.jar @proguard_windows.txt"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${build_project}"/>
</launchConfiguration>
You'll want to put this in .externalToolBuilders/proguard.launch.
The interesting thing here is that it's just a java command, not any kind of shell script, so it's fairly easy to port between Windows/Mac (and I'm assuming Linux, but haven't done that yet), since you're just changing the location of the actual java binary.
(Submitting this as a new answer because it's a bit different than the one that got marked as the correct(ish) answer)
I have been using Proguard to treeshake the Scala library in Eclipse/ADT builds, but it leaves a lot to be desired. It's slow and it messes up the other .class files, so you have to rebuild the project more often than not.
Inspired by these questions and some of the issues in the Android issue tracker, I have made another tool (based on Jar Jar Links) which I now use to treeshake the scala library. With this build step I'm actually fairly happy with the whole Eclipse+ADT Scala on Android situation. Maybe it'll work for you too, give it a spin, it's available from http://code.google.com/p/treeshaker/
If you are comfortable using the Gradle build tool, then the Android plugin for Gradle makes this whole process extremely simple. See: https://github.com/jvoegele/gradle-android-plugin/wiki
精彩评论