Capture screenshots from the Android Emulator or Mobile Device
The first few times I needed screenshots of an Android app for the Android Market description I alt-printscreen
'd the emulator then sliced the app screenshot out of the resulting image. This is a pain and - as it turns out - completely unnecessary.
For capturing screenshots from physical devices there are (paid) apps in the store, but again, this is completely unnecessary if you are a developer and have set up the Android Development Tools.
Why? Because a screenshot tool comes packaged as part of the android sdk!
From Eclipse you can grab a screenshot by opening DDMS (Window -> Open Perspective -> DDMS
), then in the Device
pane, select the device you want to take a screenshot from (which can be the emulator or a "real" mobile device), then click the camera icon (top right in the following screenshot):
From the command-line I'm afraid you're pretty much out of luck right now unless you feel like a bit of hacking to create your own cmdline screenshot grabber by connecting to the same service that DDMS connects to.
Comment on this postThe dreaded UNEXPECTED TOP-LEVEL EXCEPTION
I'm working on extracting library projects to factor out common code shared between multiple projects. With everything compiling successfully I attempted to run my apk project in an emulator, and got hit with the following:
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException:
already added:
Lcom/android/vending/licensing/Manifest$permission;
Now it seems there's been a lot of problems with this recently due to changes in ADT, but the added complexity of Maven in my setup throws a few more spanners into the machinery. Robert Schmid describes a project hierarchy very similar to mine here, and actually gave me the final clue I needed to unravel the mess.
The difference between my situation and Robert's is that I'm using Maven for release builds and continuous integration - and so far its proving to be ... tricky ... to get the combination of Eclipse, Maven and ADT to play well together.
I got the dreaded UNEXPECTED TOP-LEVEL EXCEPTION because somewhere in the build cycle the Maven-Eclipse plugin is injecting its apklib dependencies into my eclipse build as well as the referenced projects in Eclipse. Having finally worked out what was causing my problem it was pretty easy to resolve:
- right-click the project, select properties
- go to the Maven pane
- uncheck "Resolve dependencies from workspace projects"
- repeat for all of the apklib projects referenced by your apk project
The down-side of this is that if I make changes in my eclipse apklib projects I have to build the jars with Maven before the changes are available to the dependent apk projects. I actually slightly prefer working this way anyway - I find that a little bit of isolation helps.
I should probably point out that I am using Maven-3.0.3, the m2eclipse and m2e-android Eclipse plugins, and the very latest SDK at time of writing (r16). YMMV.
Comment on this postSetting up Maven, Android and SVN for team development of multiple applications
If you don't yet have your Eclipse - ADT - Maven tool-chain set up you might be interested in the previous post. If you are joining a team that has already set up as I describe here you probably want this post instead.
Google's ADT is great if you're working alone, but falls short when a team needs to work on the same Android project. It gets worse when you have multiple projects - especially if some are library projects.
It gets worse still if the development team is distributed (as we are) and/or running different development platforms - Windows, Linux, Mac OSX - (as we do). A description of how I've set things up follows this brief interlude:
The important things I wanted to enable in our team environment are:
- That the whole team can "get" the latest code quickly and easily
- That the whole team can contribute updates to the codebase quickly and easily
- That any new team member coming on-board can build immediately from check-out (given a short list of pre-requisites)
- That any team member can easily, consistently and correctly build a signed apk for release to the market
- New projects can be created quickly and easily with minimum of re-work and copy-paste in configuration
- Componentisation (e.g. jars and apklibs) is a Good Thing, and should be encouraged by making it as straight-forward as possible
- Developers have their choice of OS
Here's how I've set things up to support these goals...
Pre-requisites
I am assuming that:
- You use some form of source-code control (Subversion/GIT/other...). Of course you do :)
- All developers will install Eclipse and ADT for themselves as a pre-requisite.
- If, as a team, you use Maven and/or Continuous integration, all developers will also install m2eclipse and m2e-android eclipse plugins and Maven 3 (see previous article).
- You have some common practices in your team like, for example, checking out all projects as siblings in a single workspace directory (otherwise you'll have problems with sharing relative paths to referenced projects between developers).
Our Setup
I've set up projects in the workspace such that all of the following are siblings in a single workspace directory:
- A parent project that hosts most of the maven-android config as a parent pom.
- A project that hosts the keystore, and is checked in to source-code control (I actually use the same project for both the parent pom and keystore).
- A (Android Library) project that contains a copy of the market licensing code (Google recommend keeping a separate copy outside of the SDK install directory). Ours is checked in to SVN for convenient sharing.
- Multiple Android library (apklib) projects for our own code that is shared between multiple apps (apk's).
- Multiple Android (apk) projects
Since most of the maven configuration is provided by the parent pom, each new project requires only minimal configuration. The parent pom for our android projects currently looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>android</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<build>
<sourceDirectory>src/java/main</sourceDirectory>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store
Eclipse m2e settings only. It has no influence
on the Maven build itself.-->
<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>[3.0.0,)</versionRange>
<goals>
<goal>proguard</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<androidManifestFile>
${project.basedir}/AndroidManifest.xml
</androidManifestFile>
<assetsDirectory>${project.basedir}/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/res</resourceDirectory>
<nativeLibrariesDirectory>
${project.basedir}/src/main/native
</nativeLibrariesDirectory>
<sdk>
<platform>14</platform>
</sdk>
<proguard>
<skip>false</skip>
</proguard>
<sign>
<debug>false</debug>
</sign>
<deleteConflictingFiles>true</deleteConflictingFiles>
<undeployBeforeDeploy>true</undeployBeforeDeploy>
</configuration>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>signing</id>
<goals>
<goal>sign</goal>
</goals>
<phase>package</phase>
<inherited>true</inherited>
<configuration>
<archiveDirectory></archiveDirectory>
<includes>
<include>target/*.apk</include>
</includes>
<keystore>../android/keystore</keystore>
<storepass>keystore-password-goes-here</storepass>
<keypass>key-password-goes-here</keypass>
<alias>key-alias-goes-here</alias>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
An example of a pom from a library (apklib) project looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany</groupId>
<artifactId>android</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>android.util</artifactId>
<version>1.0.1-SNAPSHOT</version>
<name>Android Utils</name>
<packaging>apklib</packaging>
<description></description>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>2.2.1</version>
<scope>provided</scope>
</dependency>
<!-- made available to android by
"maven android sdk deployer" -->
<dependency>
<groupId>android.support</groupId>
<artifactId>compatibility-v13</artifactId>
<version>r6</version>
</dependency>
<dependency>
<groupId>oauth.signpost</groupId>
<artifactId>signpost-core</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>oauth.signpost</groupId>
<artifactId>signpost-commonshttp4</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>
<scm>
<connection>scm:svn:svn://repo/project/trunk</connection>
<developerConnection>
scm:svn:svn://repo/project/trunk
</developerConnection>
</scm>
</project>
An example pom for an app (apk) project looks like this:
<project xsi:schemaLocation="
http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany</groupId>
<artifactId>android</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>android.ui</artifactId>
<version>1.0.1-SNAPSHOT</version>
<packaging>apk</packaging>
<description></description>
<dependencies>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>domain</artifactId>
<version>1.0.1-SNAPSHOT</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>android.util</artifactId>
<version>1.0.1-SNAPSHOT</version>
<type>apklib</type>
</dependency>
<!-- this project contains a copy of
the sdk licensing code -->
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>android.licensing</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>apklib</type>
</dependency>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>2.2.1</version>
<scope>provided</scope>
</dependency>
<!-- made available to android
by "maven android sdk deployer" -->
<dependency>
<groupId>android.support</groupId>
<artifactId>compatibility-v13</artifactId>
<version>r6</version>
</dependency>
<dependency>
<groupId>oauth.signpost</groupId>
<artifactId>signpost-core</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>oauth.signpost</groupId>
<artifactId>signpost-commonshttp4</artifactId>
<version>1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.twitter4j</groupId>
<artifactId>twitter4j-core</artifactId>
<version>2.1.0</version>
</dependency>
<!-- prevent commons-logging from being included by
the Google HTTP client dependencies, which creates
a truck load of warnings and eventually kills eclipse -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<scm>
<connection>scm:svn:svn://repo/project/trunk</connection>
<developerConnection>
scm:svn:svn://repo/project/trunk
</developerConnection>
</scm>
</project>
Building a Release
Building a release, including running proguard to optimise and obfuscate the apk, and signing the apk from the shared keystore is now available from the maven cmdline with (as you'd expect):
mvn clean package
Its still early days for us, so I'm sure there are still wrinkles to iron out, but so far it seems to be working pretty well.
You can start the emulator and deploy the packaged apk into it using two further commands:
mvn android:emulator-start android:deploy
Enjoy!
Comment on this postConverting Eclipse ADT Android projects to build with Maven
Getting Android Development Tools (ADT) for Eclipse to play nicely with Maven is quite a fiddle, involving a bunch of plugins for both Eclipse and Maven. Here's how I got it working (details after the comic-strip...). You might also be interested in two follow posts - setting up for team development with Android, Maven and Eclipse and joining a team developing with Android, Maven and Eclipse:
Plugins, Tools and Dependencies
- The Maven-Android plugin is Maven-3.0.3+ only, so you'll need to upgrade Maven if you are running an older version. The good news for Maven-2 users is the Maven guys worked hard to make 3 backwards compatible - and so far I've had no problems on some pretty complex projects.
- Eclipse Helios (3.6) or Indigo (3.7)
- The Android Developer Tools and SDK (of course).
- The m2eclipse Eclipse plugin (supposedly not required with Eclipse Indigo, but I had to install it)
Setup and Configuration
First, install maven 3.0.3 (or whatever newer maven is available).
Next install the m2eclipse plugin (you might want to check if you have it already - Indigo is supposed to come pre-supplied, but that probably depends on which Eclipse bundle you install. I usually go with Classic, and did not have m2eclipse. YMMV).
Now update your android sdk:
- Using sdk manager, install all api levels you are interested in, including "google apis by google inc."
- note: be sure to accept the license agreement for each selected jar (the ? should change to a green tick for ALL).
- note: I find that the sdk manager either does not install all ticked packages in one go, or incorrectly reports the number of packages remaining to be installed - it "completes" but there are still pending installs (the "install N packages..." button re-enables with N > 0). I find it safest to restart SDK manager between each attempt so that it correctly shows what is installed.
If you want to work with Android 3 you need to perform an additional step. Maven Central does not have the jars available, so you'll need to use sdk deployer to push them into your repository.
- check out with git (git clone https://github.com/mosabua/maven-android-sdk-deployer.git)
- install android jars as required by running mvn from inside the sdk deployer project directory, example:
mvn install -P 1.6
, or install the whole lot withmvn install
if you have a shared / remote / central repository as we do, you will want to deploy the android jars there too. To do this you need to fill two fields in the android-sdk-deployer's pom.xml that the creator Manfred Moser helpfully separated out
<repo.id>kv-repository</repo.id> <repo.url>scp://my-repo-host/repository</repo.url>
OK, we're done with installing!
Create your pom.xml
There are various ways you can create a pom for your existing Android projects. I went with the simple expedient of using mvn archetype:generate ...
- from a directory you are happy to create projects in, execute
mvn archetype:generate
- you will be presented with an enormous list of archetypes - type android and hit return
- the list should have been filtered down to about 3 from "de.acquinet.android..."
- select "de.akquinet.android.archetypes:android-quickstart" - for me this was option 1
- follow the prompts to conclusion - this will create a simple android project, including the pom.xml for an apk project.
Once you've done that you can copy the pom to your existing project(s) and modify it manually - this is what I did.
(Note: If you are starting a fresh new project you can just run mvn clean eclipse:eclipse
to generate the eclipse project and classpath, then "import" the project into eclipse. After importing your project will just appear as a normal java project (neither maven nor android natures will be ascribed). To remedy that, right-click your project, go to configure->convert to Maven project
, both natures are added automatically and you're ready to rock'n'roll.)
Integrate Eclipse and Maven
OK, last part ... Getting Eclipse and Maven to play nicely.
If you open the project in Eclipse now you'll probably find that it doesn't like your pom.xml. When you open the pom with m2eclipse installed it will open with the graphical xml editor. You'll notice that there's an error plugin execution not covered by lifecycle configuration...
.
Click the error and some details open up, including two quick fixes. Click the first quick fix ("discover new m2e connectors"). The following dialog pops up and after a short search, shows the m2e-android connector:
Install the connector and the warnings should go away. Actually on one of my two machines they did not - I don't know why, but I had to take the 2nd quick-fix option of turning it off in Eclipse. For me that's just about ok, as I want the maven build to be the master anyway.
Congrats, you should now have a happy Eclipse project, and be able to build it using maven as expected.
What about android library projects?
Well basically its the same deal. I actually started with the library projects. The main difference is
Android Source Code available!
I'm quite surprised it took this long, but as of 13th December 2011 the source-code for Android is finally available as part of the SDK downloads, and can be grabbed with the SDK Manager.
There's no jar file available yet, just a folder containing the source for API level 14 and upwards only. The Android dev who announced this stated that it is "extremely unlikely" that the source for earlier API levels would ever be made available as part of the SDK.
Android Developer Tools (Eclipse plugin) doesn't automatically link to this folder either, so you need to set it up manually.
First, get the source:
- Fire up the SDK Manager - from Eclipse's "Window" menu, select "Android SDK Manager".
- Check the boxes next to "Sources for Android SDK" (at time of writing this is available for both API level 14 and 15).
- Click the "Install X packages..." button (bottom right corner), and wait while your new goodies download and install.
Once you're done downloading, head back to Eclipse and configure your Android project to use the source directory:
- In the package-explorer, locate the Android jar file (you may have to turn on "Show referenced libraries" from the little down-arrow icon in the top-right corner of the Package Explorer toolbar before it will show up in the list).
- Right-click the jar and choose "Properties" - a dialog pops up.
- Select "Java Source Attachment", then click "External Folder..."
- Navigate to the source directory, which will be located inside your Android SDK install directory (mine is at /home/steve/dev/sdks/android-sdk-linux/sources/android-14. Select OK to leave the file-chooser dialog, and OK again to leave the jar Properties dialog.
- Hover any Android class and ctrl-click (or place the caret on the class name and hit F3) to enjoy the source code for that class :)
For the full source-code saga check out the issue-tracker entry requesting the source to be made available (be prepared for a long read!)
Comment on this post