A Sceptic’s View of Google Glass

Posted in Android, Hardware by Dan on July 18th, 2014

Back in 1999, I was one of a group of Computer Science students invited to visit the research labs of a large consumer electronics company. I don’t remember a great deal about the prototype products we were shown but I do clearly remember being told that wearable computing was the next big thing. 15 years later wearable computers are still the next big thing.

This time around the devices have made it beyond the lab with a slew of underwhelming “smart” watches already on sale. In addition, Apple has been rumoured to be preparing its own for years now. Google on the other hand has taken a different approach by creating a new category of product with Google Glass.

It’s been over two years since Glass sky-dived into public view but it remains subject to a pretty exclusive public beta that you have to pay a hefty premium to join ($1500/£1000). Until a few weeks ago Glass headsets could only be purchased in the US. They are now also available in the UK. On Wednesday evening Google held its first European Glass developer meet-up at Skills Matter in London.

Since first hearing about Glass I’ve been deeply sceptical about it. It’s clearly capable of doing a few neat things that could be useful in a few niche areas but it just seems so inessential, it looks thoroughly ridiculous, and the current price tag is not destined to appeal to sensible individuals. However, I’ve often been too dismissive of new technologies in the past, so I was prepared to at least give it a go.

There was a full house at the Skills Matter Exchange including several Glass-adorned Googlers and a surprising number of other people who had presumably been parted from a grand of their own money. Interestingly, almost everybody had opted for the version with the plastic lenses. When the alternative is the bizarre lens-less titanium forehead band with nose perch it is entirely understandable, whether you need vision correction or not. The spectacle facade makes Google Glass look a lot less conspicuously weird. It’s still not a good look though, even without the beyond-parody third-party add-ons.

Google developer advocates Hoi Lam and Timothy Jordan delivered a couple of presentations suggesting how you should approach building apps for Glass (or Glassware as Google likes to call them). One major drawback for those who might be interested in building these apps is that at present there is no direct way for developers to make money from developing Glassware. Presumably that has to change at some point but for now apps can only be distributed free-of-charge (subject to Google’s approval), and in-app advertising is, mercifully, banned.

Following the presentations, those of us who hadn’t experienced Glass firsthand were given the opportunity to try out the headsets. Due to time constraints and the number of people who wanted to have a go, we didn’t get long enough to be able to get a feel for what it would be like to have this thing on your face all day but here are a few things I noted that might be of interest to those who haven’t tried one of the devices yet.

  1. The early promo shots of Glass tended to avoid showing the battery pack that rests behind your right ear and those pictures that did show it made it look awkwardly bulky. In reality this battery is quite thin and the headset is not as heavy as it looks.
  2. As a POV camera, Glass works well. It’s very easy to take snapshots or video (although I didn’t get an opportunity to check the quality of the results on a bigger screen). Unfortunately, according to Scoble, the battery is only good for 45 minutes of video and it will cook your face in the process. If all you care about is POV photography there are probably much better/cheaper options available.
  3. In a room with a lot of background conversation, the voice recognition worked well. The microphone clearly does a good job of isolating the voice of the wearer.
  4. The “screen” was underwhelming, albeit in a poorly-lit environment. The resolution wasn’t great and the focus didn’t feel entirely comfortable. It may well have been possible to adjust the focus but I didn’t have the time to find out.
  5. The user interface doesn’t feel like it would scale well to having a large number of apps installed. At the moment there is a lot of swiping through cards in a linear fashion.
  6. Unsurprisingly, Glass appears to be tightly integrated with Google+.

I was never going to be a person who would consider paying £1000 for one of these devices but having tried it very briefly I’m now certain that I wouldn’t buy one at a lower price either, even if I ignored the way it looks. There is, as yet, no compelling use case for the average person. One of the main features is that you can get your e-mails, SMS messages and other Android notifications beamed directly on to your retina without having to remove your phone from your pocket. I really don’t have any need for that kind of urgency. I’d rather ignore interruptions until I choose to deal with them. That’s not to say that there aren’t people who could find a use for Glass given better battery life and a more attractive price tag, but for most of us it’s a clever solution in search of a problem – the hardware equivalent of Google Wave.

 

Deploying an APK to Multiple Devices/Emulators Simultaneously Using Ant

Posted in Android, Ant by Dan on January 4th, 2014

Following my detour to Djangoland, the last week or so I have been back in the world of mobile app development. One of the things I’ve been working on is updating an Android app that has two versions built from the same codebase. Part of this update has been to re-skin both versions of the app and to make sure that everything looks reasonable on various devices running versions of Android from 2.2 up to the latest 4.4. When I build a new APK I want to check it on each of the three devices connected to my machine. If I had more spare USB ports I would conceivably be testing with even more devices. In some scenarios I might also have one or more emulators running to test configurations not represented among my devices. Installing the new APK on each of these from the command line is cumbersome. The adb tool will only install on one device/emulator at a time and, if you have more than one connected, you have to specify a long unique device ID to tell it which one to use. You could write a bash script to retrieve the IDs of connected devices and emulators and to run the adb install command for each, but since I’m using Ant I have written a custom task to do the job. For bonus points I’ve made it issue the adb commands in parallel so that the total install time is determined by the slowest device and not the sum of all the devices.

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
 
/**
 * Custom task that uses the ADB tool to install a specified APK on all
 * connected devices and emulators.
 * @author Daniel Dyer
 */
public class InstallAPK extends Task
{
    private File apkFile;
 
    public void setAPK(File apkFile)
    {
        this.apkFile = apkFile;
    }
 
    @Override
    public void execute() throws BuildException
    {
        if (apkFile == null)
        {
            throw new BuildException("APK file must be specified");
        }
        try
        {
            List<String> devices = getDeviceIdentifiers();
            System.out.printf("Installing %s on %d device(s)...%n", apkFile, devices.size());
            ExecutorService executor = Executors.newFixedThreadPool(devices.size());
            List<Future<Void>> futures = new ArrayList<Future<Void>>(devices.size());
            for (final String device : devices)
            {
                futures.add(executor.submit(new Callable<Void>()
                {
                    public Void call() throws IOException, InterruptedException
                    {
                        installOnDevice(device);
                        return null;
                    }
                }));
            }
            for (Future<Void> future : futures)
            {
                future.get();
            }
            executor.shutdown();
            executor.awaitTermination(60, TimeUnit.SECONDS);
        }
        catch (Exception ex)
        {
            throw new BuildException(ex);
        }
    }
 
    private void installOnDevice(String device) throws IOException, InterruptedException
    {
        String[] command = new String[]{"adb", "-s", device, "install", "-r", apkFile.toString()}
        Process process = Runtime.getRuntime().exec(command);
        consumeStream(process.getInputStream(), System.out, device);
        if (process.waitFor() != 0)
        {
            consumeStream(process.getErrorStream(), System.err, device);
            throw new BuildException(String.format("Installing APK on %s failed.", device));
        }
    }
 
    private void consumeStream(InputStream in, PrintStream out, String tag) throws IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        try
        {
            for (String line = reader.readLine(); line != null; line = reader.readLine())
            {
                out.println(tag != null ? String.format("[%s] %s", tag, line.trim()) : line);
            }
        }
        finally
        {
            reader.close();
        }
    }
 
    private List<String> getDeviceIdentifiers() throws IOException, InterruptedException
    {
        Process process = Runtime.getRuntime().exec("adb devices");
        List devices = new ArrayList<String>(10);
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        try
        {
            for (String line = reader.readLine(); line != null; line = reader.readLine())
            {
                if (line.endsWith("device"))
                {
                    devices.add(line.split("s")[0]);
                }
            }
            if (process.waitFor() != 0)
            {
                consumeStream(process.getErrorStream(), System.err, null);
                throw new BuildException("Failed getting list of connected devices/emulators.");
            }
        }
        finally
        {
            reader.close();
        }
        return devices;
    }
}

Once compiled and on your classpath, using it is simple:

<taskdef name="installapk" classname="yourpackage.InstallAPK" />
<installapk apk="path/to/yourapp.apk" />

Android ListView – Fixing Missing/Blank Dividers

Posted in Android, Java by Dan on January 24th, 2013

A post with code in it. Because it’s been a long time since the last one.

If you work with ListViews in Android, as all Android developers will do at some point, you may notice that if you set your list items to be non-selectable the dividers that are drawn between each cell disappear. In the Holo Light theme you would normally get a thin light grey dividing line between cells. Depending on how you’ve implemented your adapter, you may find that these dividers become white/transparent when the cells are not selectable. According to Android framework engineer Romain Guy, this is the intended behaviour.

As Haythem Souissi points out in this Stack Overflow answer, you can work around this by ensuring that the areAllItemsEnabled method returns true, even though all items are not enabled (maybe none of them are). The isEnabled method will take care of actually disabling the cells and the dividers will be drawn between each of them.

All very straightforward so far but it all goes wrong again when you try to add a non-selectable header view to the list. The way that ListView deals with headers and footers is that it creates its own adapter to wrap/decorate yours and insert the header/footer views in the appropriate places. This is fine but it’s not delegating the areAllItemsEnabled method, so our above fix no longer works.

Fortunately, and unusually for Android, everything we need to resolve this issue is part of the public API. The adapter decorator class is android.widget.HeaderViewListAdapter. We just need to create our own instance, wrapping our own adapter, and override areAllItemsEnabled as above. There’s a slight complication in that we have to wrap the header view in an instance of ListView.FixedViewInfo and this is a non-static inner class of ListView, but we can reach into our bag of obscure Java tricks to create an instance from outside the enclosing class.

// I assume you know how get a reference to the ListView and create your own adapter.
ListView listView = (ListView) view.findViewById(android.R.id.list);
CustomAdapter adapter = new CustomAdapter(context, listOfItems);
 
// You can create any view you like for the header.
TextView listHeader = (TextView) inflater.inflate(R.layout.list_header, null);
listHeader.setText("My Header Text");
 
// This is how you create an instance of the non-static nested class, providing
// it with a reference to an instance of the containing class (ListView).
ListView.FixedViewInfo headerInfo = listView.new FixedViewInfo();
 
headerInfo.view = listHeader;
headerInfo.isSelectable = false;
 
// HeaderViewListAdapter insists on concrete ArrayLists.
ArrayList headers = new ArrayList(1);
headerInfoList.add(headerInfo);
ArrayList footers = new ArrayList(0);
 
HeaderViewListAdapter wrapper = new HeaderViewListAdapter(headers, footers, adapter)
{
    @Override
    public boolean areAllItemsEnabled()
    {
        return true;
    }
};
listView.setAdapter(wrapper);

Google’s Lag Problem – Or Why Android App Development is 22 Months Behind iOS

Posted in Android, iOS by Dan on January 20th, 2013

On 12th October 2011 Apple unveiled iOS 5.0 to the world. 7 days later Google released Android 4.0 (Ice Cream Sandwich).

Apple rarely announces how many devices are running each version of its mobile operating system but, according to third-party stats[1], today only a few percent of iPhone/iPad/iPod Touch owners are still running an earlier version of iOS.

In contrast, Google is much more up-front about how many people are running each version but it doesn’t compare favourably. Just 39.3% of users have access to the 15-month-old Android OS or one of its later revisions.

Of course, there are some mitigating factors. Android is a much more open ecosystem with dozens of manufacturers needing to test and approve updates for hundreds or even thousands of devices. Apple on the other hand retains a strict control over its (smaller) mobile empire and is able to push out updates directly to end users. But whatever the reasons, and despite Google’s recent efforts to rein in manufacturers and network operators, the fact remains that, unlike their iOS counterparts, Android app developers cannot target a recent version of the operating system and hope to have their app runnable by the majority of device owners.

Google has tried to address this issue with its support library, which brings some of the more recent API additions to earlier Android versions but this is only a partial solution that adds complexity and does nothing to resolve the vast visual differences between Android 4.x and its predecessors.

Today if you want to reach over 90% of iOS users you must support iOS 5.1, which was released in March 2012, and later versions. To reach the same proportion of Android users you would have to target Android 2.2 (Froyo), which dates back to May 2010.

The many comparisons of the relative merits of the latest iOS versus the latest Android version are largely irrelevant to Android app developers who are working from a baseline that is almost two years older than that of their iOS counterparts. An iOS developer can build an app that requires the absolute latest version of the operating system confident that the user base will soon be there (iOS 6 has reached 78.5% penetration in four months). Android developers will always need to be more conservative.

1. These stats may not be fully representative of all iOS users but they provide useful ballpark figures.

Thoughts on Droidcon London 2012

Posted in Android by Dan on October 27th, 2012

Twelve months on from my first visit to the UK edition of Droidcon, I was back in Islington this week for this year’s version. The format was the same: barcamp on day 1, conference proper on day 2. I’m not sure the distinction between the two days is all that worthwhile. After the initial hour of pitching and organising, the first day proceeds along similar lines to the second, with four tracks of presentations. I’d vote for just having two normal conference days with the programme for both days published in advance, which appears to be how the Dutch Droidcon works. If there is a need to democratise the programme, this could be done online beforehand.

Anyway, while it’s all still fresh in the memory, here are some of the things I thought worth noting. These may or may not be of interest to other Android developers. If you want to watch some of the talks, keep an eye on the Skills Matter website as I suspect the videos will start appearing on there shortly.

Proguard author Eric Lafortune talked about obfuscation and optimisation of Android apps. I’ve been using his Java obfuscator for many years, since well before it became an integral part of the Android tool set, so it was good to speak to him and finally put a face to the name. Eric’s start-up has another Proguard-based obfuscator/optimiser, called DexGuard, with extra Android-specific features, which may be of interest to app developers who need stronger protection and are willing to pay for it.

Erik Hellman made using OpenCV for computer vision on Android look reasonably painless. I’d previously discarded a good app idea that required this kind of functionality as too complicated and too processor-intensive. Might need to revisit that.

David Teitelbaum of Apkudo showed step-by-step how to crack an APK and inject code. He was able to cheat at one of Zynga’s word games by reverse-engineering the obfuscated code. It was an eye-opening demo and may well have caused a few app developers to seriously consider DexGuard as an extra line of defence against this kind of attack.

Jenkins contributors Christopher Orr and Jørgen Tjernø spoke about the plugins that are available for continuous integration on Android projects. If you have the server resources to dedicate to it, you can use Jenkins to automatically build and test your app with an emulator for every combination of Android version, screen size and configuration that you are interested in. A long time ago I wrote why you should use Jenkins for general Java projects, or Hudson as it was then (technically Hudson still exists as a separate Oracle-backed project but the community has moved en masse to the Jenkins fork). Christopher and Jørgen made the case for using it to improve the quality of your Android apps.

James Hugman gave an updated overview of Kirin, a hybrid approach to cross-platform app development that uses native-specific UIs and Javascript for logic. This was one of the more interesting topics from last year but I never got around to actually trying it out. It was interesting to see how the project has progressed. It now seems to be based around Node.js.

Given my interest in artificial intelligence, the session I was most interested in attending was the one called “Integrating AI into your app”. Unfortunately this was a complete waste of time and served only to prevent me from taking an earlier train home. It was nothing more than an advert for some tool for building expert systems. Neither the tool itself nor the generated systems had anything to do with Android. You expect some degree of being advertised at from the fee-paying keynote speakers who are subsidising the event but at least they have the decency not to stray too far from the main theme of the conference.

That’s the type of session I’d like to see fewer of but I’d like to see more like the preceding session by Anders Ericsson. He delivered a live-coding demo of a fairly clean approach to applying animation to custom views. The results were impressive (the approach is also outlined in this blog post) and the presentation followed on nicely from Chiu-Ki Chan‘s earlier talk on developing custom views. A couple of people pointed out that the new animation features in Android 3.0 and later can be used to achieve similar effects but this approach also works on the large number of Android devices that are still running Android 2.x. This session and David Teitelbaum’s APK cracking were probably the two best talks and are the kind of things I’d like to see if I attend next year.

Using an O2 Mobile Broadband Dongle SIM in an Android Tablet

Posted in Android by Dan on October 24th, 2012

O2 mobile broadband APN settingsA couple of months ago I purchased an O2 Mobile Broadband USB dongle so that I could continue working during an ADSL outage. Once the ADSL was back on I had no further use for it. Seeing as I also had a 3G-enabled Samsung Galaxy Tab 10.1 without a SIM, I thought it would make sense to use the remaining data allowance on that. However I was initially unable to find the right settings to make the tablet connect to O2’s network.

Having given it another shot before the unused data expires, I have eventually stumbled upon the correct settings, which I’ll document here for anyone who might need to achieve the same. Previously I was trying the device’s default O2 access point configurations and the APN settings I found on the web. The problem with these is that they are for pay-monthly and pay-as-you-go SIMs sold specifically for use in phones and tablets. The settings for the mobile broadband SIMs are different. You need to use the m-bb.o2.co.uk APN rather than payandgo.o2.co.uk or mobile.o2.co.uk. The full working settings from my Galaxy Tab are shown to the right (the obscured password is, predictably, ‘password’).

Update (30/1/2013): After the remaining data had expired, I didn’t use the 3G functionality of the tablet for a while, during which time I updated the tablet to Android 4.0.4. For whatever reason, the settings shown here no longer worked after adding more credit to the SIM. Eventually I discovered that the “APN type” field had to be set to “default” rather than “internet”. I also switched to using the “o2bb” username that the OS X connection manager software uses with the dongle.

Attack of the Clones – Android Market Plagiarism

Posted in Android by Dan on March 3rd, 2012

Appmonger vs. Crapmonger

I was rather surprised on Thursday to be shown a newly released free app on Android Market that looked suspiciously like one of my paid apps. To me and other observers it appeared that this app was simply a modified version of Appmonger being touted by someone who claimed to have paid somebody over four thousand dollars to write it for her so that she could give it away for nothing.

I provide more details about the whole situation over at the Rectangular Software blog. The episode has left me somewhat confused both as to the motivations of this individual and the extent to which she and/or her coder have ripped off my work. Clearly (screenshots to the right to judge for yourself) this app is more than just inspired by or competing with Appmonger but after running the app and digging into the .apk I am now uncertain how much code, if any, has been copied/reused. She may actually have paid somebody else a tidy sum to write the whole thing from scratch. That sounds even more insane to me than just cracking somebody else’s code and passing it off as your own. Why go to all the effort of building an entire app without putting your own stamp on it to avoid any accusations of plagiarism or copyright infringement?

The Android-To-PlayBook App Repackaging Experience

Posted in Android, Blackberry by Dan on February 11th, 2012

Having convinced myself that I’d quite like a new Blackberry PlayBook courtesy of RIM’s bribe-an-Android-developer program, I have just completed the process of repackaging a couple of Android apps and submitting them to Blackberry App World. This was my first experience of publishing on a Blackberry platform. Previously I had been scared off by horror stories of the pain involved.

The first step was to become a registered Blackberry App World Vendor. This involved e-mailing some documents to RIM to prove that my company actually exists (if you are selling apps as an individual you have to provide proof of your own identity). I submitted the documents on Friday and was approved by Tuesday, which is not too bad considering that they were probably processing a much larger volume of applications than usual due to the free PlayBook offer. It was not as straightforward as signing up for Android Market or the Amazon App Store but it was a lot quicker than the 3 weeks it took Apple to process my application for the iTunes App Store.

The process of acquiring a code-signing certificate involves submitting another form and waiting an hour or two for a pair of e-mails containing a RIM Development Key (RDK) and a PlayBook Debug Token (PBDT). It took me two attempts at this to get both as the first time only the RDK arrived. Once you have the necessary files you then have to use the tools provided to register with RIM and create a developer certificate. This degree of cryptographic hoop-jumping is beyond that required by Google or Amazon and more comparable to Apple’s Provisioning Profile rituals (except much slower due to the waiting around). The whole process is unnecessarily convoluted.

When you’re ready to convert your Android app you’ll want to install the PlayBook simulator so that you can test it. The simulator is provided as a VMWare machine image wrapped up in an installer that is only available as a .exe (for Windows) or .dmg (for OS X). If you develop on Windows this is fine, you can use the free VMWare Player. RIM doesn’t seem to encourage development on Linux but if you can extract the files from the installer you can run the simulator using the free VMWare Player for Linux. The situation on OS X is less satisfactory. There is no free VMWare Player so you’d have to buy VMWare Fusion (£39.99). I was unable to get VirtualBox to boot the image. The simulator also has a major limitation in that it is not possible to change the device orientation, which is less than ideal for testing.

Finally it’s time to convert your app. Firstly you need to make sure it doesn’t use any of the many Android features that are not currently supported by the Blackberry Android app player. There is a verifier tool that will check your .apk and warn you of any problems. You can then convert the .apk into a .bar file, which is a simple one-step process.

Load this .bar onto the simulator, launch your app and then feel the disappointment really kick-in. On the simulator (on my laptop at least, under both Windows and Linux) the experience is abysmal. The apps flicker very badly with artifacts from the previous activity frequently appearing on top of the current activity. On top of this, font rendering is atrocious. Getting useful screenshots for uploading to App World is just about impossible.

I tried multiple Android apps and I know others have experienced similar problems with their apps. I can only hope that it is specific to the simulator and is not a problem on the actual hardware. If not, it needs to be fixed in the final Blackberry Tablet OS 2.0 release otherwise there is absolutely no point in repackaging your Android apps since they will be unusable.

Ignoring the app’s performance on the simulator, the final step is to sign the .bar file and upload it to App World. Signing is straightforward. Submitting the app is not too much different to other app stores. Bizarrely App World restricts screenshots to a maximum of 640×640 pixels (the PlayBook’s screen is 1024×600 so you have to reduce the size). As with Android Market, you are required to upload a feature graphic, although in this case it needs to be a massive 1920×1186 pixels. If you are selling paid apps you don’t have the pricing freedom that Android Market provides. Instead you have to pick from one of the pre-defined price points, just as on iTunes.

I’d be more enthusiastic about Android apps on Blackberry devices if it weren’t for the simulator glitches. As it stands I’ll have to wait until I get my hands on the hardware to judge just how worthwhile it is for Android developers to deploy to non-Android platforms.

RIM’s PlayBook Push – Repackage An Android App, Get A Free Tablet

Posted in Android, Blackberry, Hardware by Dan on February 3rd, 2012

It’s fair to say that Blackberry maker RIM’s tablet offering, the 7-inch PlayBook, has not been a commercial success. Launched in the UK at a £399 price point last June, by October the 16GB model’s price had been slashed to £249 in the face of underwhelming demand and last week RIM cut the price again – this time to £169.

In the VAT-free US the asking price is even lower, just $199 – exactly the same as Amazon’s Android-powered Kindle Fire. The two devices are both 7-inch tablets with 1Ghz dual-core processors and 1024×600 displays but the PlayBook has twice the internal storage (16GB vs 8GB), twice the RAM (1GB vs 512MB) and both front (3Mp) and rear (5Mp) cameras (the Kindle Fire has neither).  If Amazon struggles to break-even on the Kindle Fire, preferring instead to make its money selling content, then the current selling price of the higher-spec PlayBook must represent a significant loss for RIM.

To counter the growing consensus that it couldn’t give the devices away, RIM has started doing just that. Specifically, the Canadian firm is targeting developers in a last-ditch effort to rescue its ailing tablet platform from the squeeze being applied by Apple’s iPad and the myriad Android pretenders. All attendees at Blackberry’s Devcon in Amsterdam next week will be rewarded with a shiny new PlayBook and yesterday the company announced that it would give a device to every Android developer that repackaged an existing Android app for distribution on Blackberry App World (the PlayBook is capable of running Android apps non-natively). Today that offer was extended to include any developer publishing any kind of app (native, Android or Adobe AIR) on App World before the 13th February.

This industrial scale bribing of developers represents a concerted push to revitalise the PlayBook platform with the upcoming release of version 2.0 of the device’s QNX-based operating system. Increasing the number of tablet apps available on Blackberry App World is a core part of this strategy. For Android developers it’s an opportunity to get hold of what is by most accounts a decent bit of hardware for the minimal effort of repackaging an existing app.

Accessing Local Name-Based Virtual Hosts From the Android Emulator

Posted in Android by Dan on January 12th, 2012

To test mobile versions of websites, it is useful to be able to connect to a web server on your local machine from a web browser on an Android emulator without having to expose the web server to the Internet.  You can’t use the normal loop-back IP address of 127.0.0.1 because that refers to the emulated Android device itself.  Instead you have to use 10.0.2.2 to connect to the host machine.

That’s fine if your local web server is serving a single site, but if you are using name-based virtual hosting to serve different sites depending on the host name of the request (with aliases for localhost defined in your machine’s hosts file), then you need to be making requests from the browser using the correct host name, not the IP address.

The Android emulator does not use the host machine’s hosts file for name resolution so attempting to access http://myvirtualhost in the emulator’s browser will not work.  This is because the emulated Android device has its own hosts file, so you have to update this to map the virtual host names to the local machine.

The first step is to start the AVD with an increased partition size otherwise you may get an out of memory error when you try to save the modified hosts file:

  emulator -avd MyAVD -partition-size 128

You then have to remount the system partition so that it is writeable:

  adb remount

Then copy the hosts file from the emulated device to the host machine:

  adb pull /etc/hosts

Edit the hosts file so that it includes mappings for all relevant virtual host names:

127.0.0.1        localhost
10.0.2.2         myvirtualhost1 myvirtualhost2

Then copy the updated file back to the emulated device:

  adb push hosts /etc/hosts

You should then be able to visit http://myvirtualhost1 in the emulator’s browser and see the correct site.

« Older Posts