Downloading APKs from Android Market

Note: This is a very old post and will no longer work because the Google Play API has changed significantly. This post has been left here for historical reference.

Sometimes I need to get hold of an Android application from the Market for analysis. One way to do this is to manually use the Market on an Android device or emulator, install the App, and then copy it off. For various reasons this isn't always ideal - I sometimes don't want to install an App if I don't know what it does, and I may want to get it a lot faster (i.e. automate it).

In this post I share what worked for me in creating a command line script to login to the Market and download the application's APK. This isn't anything particularly new as an unofficial Market API already exists for searching the Market and Tim Strazzere posted some Java source to emulate a download request. However, in Tim's example you have to manually specify the App's assetID and your authToken which means it isn't automated. What I wanted was a script which takes a package name as a parameter and downloads it. To achieve this I used the Market API to login, get an authToken, search for the package, get its assetID, and then submit a download request.

I've documented this for interest, it isn't supported software and there isn't much error checking. If you use this it is assumed you know what you are doing.

What was used:

I'm using Ubuntu Linux and PHP with curl support. To install it you need something like this:

$ sudo apt-get install php5-curl

The first step is to get the Android Market userID which is required in the download request for APKs. I'm not aware of an easy way to get this at the moment but it is simple enough to sniff from the real Market App and only needs to be done once. Tim Strazzere comes to the rescue again with a nice tip for easily sniffing traffic on Android.

Open up the Market App on the device and find an app to install, start the following ADB command and then click install:

$ adb shell tcpdump -vv -s 0 -w /sdcard/output.cap

After install hit Ctrl+C to to stop sniffing. Open up the .cap file in something like wireshark and look for a GET request which contains the deviceID and userID parameters and make a note of them. I found that on my phone the GET request was different from the one in Tim's post, it had extra parameters and when I manually emulated it I was given a 302 redirect to download the file. However, using the older GET request as per Tim's post and ignoring the extra parameters seems to still work and leads to the direct download of the APK.

Download PHP Android Market API and unzip it somewhere. In the subfolder examples create a file called local.php with the following contents (replacing my values with yours):

<?php
define('GOOGLE_EMAIL','youremail@gmail.com');
define('GOOGLE_PASSWD','yourpassword');
// Use a random number with the same number of digits:
define('ANDROID_DEVICEID','0000000000000000');
// Use your real deviceID here that you sniffed:
define('ANDROID_REALID','0000000000000000000');
// Use your sniffed userID parameter here:
define('ANDROID_USERID','00000000000000000000');

I found that the Market API worked with a fake deviceID but not my real one, and the APK download request worked with my real deviceID but not the fake one. I didn't look into it too much as it seems to work okay as above.

Download test_download.php.txt and save it in the examples folder as test_download.php.

Edit MarketSession.php in /Market so this line:

private $authSubToken = "";

Becomes:

public $authSubToken = "";

Okay that is the preparation. We can now use the script to grab any free app from the Market by passing the package name as a parameter. In this example I found a Notepad application on Android Market and saw the package name in the URL was bander.notepad, so:

user@linux:~/market-api/examples$ php test_download.php bander.notepad
* About to connect() to android.clients.google.com port 80 (#0)
*   Trying 74.125.71.139... * connected
* Connected to android.clients.google.com (74.125.71.139) port 80 (#0)
> POST /market/api/ApiRequest HTTP/1.1
User-Agent: Android-Market/2 (sapphire PLAT-RC33); gzip
Host: android.clients.google.com
Accept: */*
Cookie: ANDROID=DQAAAREDACTED
Content-Type: application/x-www-form-urlencoded
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Content-Length: 586

< HTTP/1.1 200 OK
< Content-Type: application/binary
< Date: Sun, 12 Jun 2011 23:34:37 GMT
< Expires: Sun, 12 Jun 2011 23:34:37 GMT
< Cache-Control: private, max-age=0
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Content-Length: 140
< Server: GSE
< 
* Connection #0 to host android.clients.google.com left intact
* Closing connection #0

Downloading Notepad (3073103588488610805)

user@linux:~/market-api/examples$ ls -hl *.apk
-rw-r--r-- 1 user user 45K 2011-06-13 00:34 bander.notepad.apk

And now we have the APK. The Market API is actually really good and it can also get other data about the app such as author, version, what permissions it needs, screenshots, etc. It would be a fairly trivial enhancement to get the script to save this extra metadata at the same time as the APK if needed.