Unity completions for Sublime Text

This might be a technical post, about Sublime Text. Or it could be a community post, about Unity editors. I don’t know yet. In any case it’s about Unity Completions, my first package for ST.

Unity Completions does one thing: It allows me to develop for Unity using ST. I know ST’s got its quirks, but it’s homey. And I eventually fell for its simultaneous editing – it’s stupendous! I’ve been using it quite contently for a long while. But the lack of Unity auto-completions, though, was dissatisfying. I couldn’t let it slide.

What Was

I searched the forums for solutions. There was no solution available for Boo developers. I found a post with a good solution for C-sharp developers only, based on CompleteSharp. And I found Jacob Pennock’s package. It fell short on content — it only offered completions for a handful of GUI-related completions — but it showed me how it can be done.

What Is

The next step was natural: I had to create a plugin that covers the full API. But I needed the info – the Unity API. I took a naive approach and wrote a crawler that just scans the entire scripting reference section and produces all the class names and definitions, including variables and function definitions. The output contained a little over 10,000 items. I then wrote a generator that converts it all to ST snippet files for 3 languages. It worked.

I wrote the package in March (9 months ago), when Unity 4.1 was out. I also tried to add it to Package Control, but those guys were wondering why it is should be added when a package with a similar name already exists (Jacob’s). At this point I tried to contact Jacob, but got no reply. By the time I got back to the subject, a new version of PC was in the pipes, soon to be released. So I decided to wait. Then I forgot about it for a while.

A couple of weeks ago I was reminded about it, and soon after added it to PC. It was immediately downloaded by users. In the first 14 days it was downloaded 128 times. It’s not a lot, but it seems a demand exists. The next step was to update the package – Unity v4.3.1 was recently released. I had to update the crawler because changes in Unity’s website broke it.

What’s Next

Now, two challenges remain. One is how to make the package smaller. The package currently holds snippets for a little over 12,000 Unity items. Each has two files (upper case and lower case – or it won’t work well) and all this for each of the 3 languages. This brings the total number of files to 72,399 and the entire package size to 26 MB.

Another challenge is how to keep updating the package easily. The process breaks whenever something changes in Unity’s website. Perhaps a better approach would be to dig into the DLLs?

Google Analytics for mobile apps in Unity

Google Analytics + Unity

There are several solutions out there for integrating Google Analytics into Unity apps. However, as far as I can tell they all wrap the good old web tracking service. The guys at Google have long ago tailored a more suitable solution for mobile platforms: Mobile App Analytics. It provides a few mobile-only features (e.g.: user engagement, crashes and exceptions, device info) and has the added benefit of being official. Google have released SDKs for Android and iOS. In this post I will demonstrate how to integrate the Android SDK v2 into Unity apps. Be patient, iOS is on the road map.

Setup your Analytics Account

First of all you need to have a Google Analytics account. To use Mobile App Analytics you also need to add to your account an app tracking property and a profile. When you’re done you shall be the proud owner of a Tracking ID. It should look something like this: UA-123456-7.

Create an Android Plugin

I already covered the subject of creating an Android plugin in another post. I will expand on it to keep this post short.

Get the Analytics SDK

Download the Android SDK. (At the time of writing the version was 2.0 beta 5 and the download page warned that the SDKs are under “active development”.)  After downloading the ZIP file, extract libGoogleAnalyticsV2.jar from it (or whatever the JAR file is called) and add it to your Eclipse project.

This includes copying it to the libs directory and adding it to the build path. You may not see the JAR file in Eclipse until you refresh (F5). To add the JAR file to the build path right click on it and select Build Path => Add to Build Path.


We will subclass UnityPlayerActivity and use the EasyTracker class:

package com.companyname.appname;

import android.util.Log;

import com.google.analytics.tracking.android.EasyTracker;
import com.unity3d.player.UnityPlayerActivity;

public class MainActivity extends UnityPlayerActivity {
    protected void onStart() {
        Log.d("Unity", "Starting Analytics activity");

    protected void onStop() {
        Log.d("Unity", "Stopping Analytics activity");

    public void sendView(String screenName) {
        Log.d("Unity", "Sending Analytics view: " + screenName);

    public void sendEvent(String category, String action, String label, Long value) {
        // value is optional
        Log.d("Unity", "Sending Analytics event: " + category + ", " + action + ", " + label + ", " + value);
        EasyTracker.getTracker().sendEvent(category, action, label, value);

    public void sendTiming(String category, long intervalInMilliseconds, String name, String label) {
        // name and label are optional
        Log.d("Unity", "Sending Analytics timing: " + category + ", " + intervalInMilliseconds + ", " + name + ", " + label);
        EasyTracker.getTracker().sendTiming(category, intervalInMilliseconds, name, label);

The calls to activityStart and activityStop are fundamental. They frame the session, allowing tracking of users, demographics and uncaught exceptions. Calling activityStart also sets the context for later sendXxxx calls to work.

The sendViewsendEvent and sendTiming methods allow manual sending of specific app information (screens, events and timings appropriately). These will be called by Unity scripts. By the way, don’t use trackXxxx methods – they’re deprecated.

There’s more stuff you can track which I haven’t covered here such as: campaigns, caught exceptions and in-app payments. See the dev guide for information on those.

You may want to know that EasyTracker is a wrapper for two other classes: GoogleAnalytics and Tracker. It makes life easier, but leaves out a few advanced features.

A note about onStop: When I pressed the Home button, my app was paused and onStop was called. When I called Application.Quit, it wasn’t. I don’t think it matters, but if it does to you feel free to read about session management.


This is the configuration file for EasyTracker. Here we’ll setup our app’s Tracking ID as well as some other parameters:

<!--?xml version="1.0" encoding="utf-8" ?-->

    <!--Tracking ID-->

    <!--Enable automatic activity tracking-->

    <!--Enable automatic exception tracking-->

    <!--Enable debug mode-->

    <!--Set dispatch period in seconds-->

Some of these parameters are self explanatory. And you can read about them and others here. A few notes though:

  • ga_debug – Enables writing of debug information to the log. The default is false (disabled). This may be useful for debugging, but be prepared to see error messages even when everything’s working smoothly (examples below.)  The output will be printed to logcat using the tag GAV2. For example, you can read both Unity’s logs and Analytics with the following command:
    adb logcat Unity:V GAV2:V *:S
  • ga_dispatchPeriod – The dispatch period in seconds. The default is 1800 (30 minutes). Yup, that’s a lot! It’s only 2 minutes on iOS. Feel free to reduce it. Setting it to 0 (zero) is useful for debugging. (But I suggest you don’t leave it that way in release versions.) Even then you can only find real-time information in the “Real-time” section in Analytics dashboard. Everything else is updated daily.
  • ga_appVersion – Your app version. No, this is not a mistake – it’s not used in the file above. No reason to! It defaults to the version found in the package, which in turn is determined by the bundle version in Unity’s player settings.

The analytics.xml file should generally be placed in the res/values directory in the project. However, the location doesn’t matter much until we copy it into the Unity project later. (It will reside in Assets/Plugins/Android/res/values.)

The Unity App

In your Unity app you’d probably want to call sendXxxx methods to track user engagement. The following Boo code calls the Java methods:

    static def Call(methodName as string, *args):
        jc = AndroidJavaClass("com.unity3d.player.UnityPlayer")
        jo = jc.GetStatic[of AndroidJavaObject]("currentActivity")
        jo.Call(methodName, *args)

    static def SendView(screenName as string):
        Call("sendView", screenName)

    static def SendEvent(category as string, action as string, label as string, value as long):
        joValue = AndroidJavaObject("java.lang.Long", value)
        Call("sendEvent", category, action, label, joValue)

    static def SendEvent(category as string, action as string, label as string):
        Call("sendEvent", category, action, label, null)

    static def SendTiming(category as string, intervalInMilliseconds as long, name as string, label as string):
        Call("sendTiming", category, intervalInMilliseconds, name, label)

The SendEvent method’s value parameter is optional. So are SendTiming method’s name and label parameters.

Adding the Plugin

To integrate the plugin we created into Unity:

  1. Copy the JAR file we created earlier to Assets/Plugins/Android.
  2. Copy libGoogleAnalyticsV2.jar to Assets/Plugins/Android.
  3. Copy analytics.xml to Assets/Plugins/Android/res/values. Create the subdirectories if needed.
  4. Edit your AndroidManifest.xml file in Assets/Plugins/Android and add the INTERNET and ACCESS_NETWORK_STATE permissions (see below).

See this post for more information about this file. Here I will only mention the additions required by Google Analytics:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


As I mentioned earlier it make take a while before you can see results online. So how can you tell if it’s working? Assuming you enabled debug mode (“ga_debug”) you should be able to get some feedback from the logs. However, some messages are quite confusing. Here are a few examples I encountered.

False error #1: Need to call initialize() and be in fallback mode to start dispatch

W/GAV2 ( 4211): Thread[main,5,main]: Need to call initialize() and be in fallback mode to start dispatch.
I/GAV2 ( 4211): Thread[main,5,main]: ExceptionReporter created, original handler is com.unity3d.player.ab

This error may appear when you call activityStart from your onStart method. I ignore it.

False error #2: connect: bindService returned false for Intent

I/GAV2 ( 3680): Thread[GAThread,5,main]: connecting to Analytics service
I/GAV2 ( 3680): Thread[GAThread,5,main]: connect: bindService returned false for Intent { act=com.google.android.gms.analytic
s.service.START (has extras) }
W/GAV2 ( 3680): Thread[GAThread,5,main]: Service unavailable (code=1), will retry.
I/GAV2 ( 3680): Thread[GAThread,5,main]: No campaign data found.
I/GAV2 ( 3680): Thread[GAThread,5,main]: putHit called

And then some:

I/GAV2 ( 3680): Thread[Service Reconnect,5,main]: connecting to Analytics service
I/GAV2 ( 3680): Thread[Service Reconnect,5,main]: connect: bindService returned false for Intent { act=com.google.android.gms
.analytics.service.START (has extras) }
W/GAV2 ( 3680): Thread[Service Reconnect,5,main]: Service unavailable (code=1), using local store.
I/GAV2 ( 3680): Thread[Service Reconnect,5,main]: falling back to local store
I/GAV2 ( 3680): Thread[GAThread,5,main]: Sending hit to store

It appears when the Analytics service tries to dispatch the data. This may be a few seconds after the app started, or maybe later if ga_dispatchPeriod is high. Anyway, it seems to happen consistently for me. It’s fine to ignore it, assuming it’s followed by good stuff.

Good stuff

Hopefully you’ll see something like this:

V/GAV2 ( 4211): Thread[GAThread,5,main]: dispatch running...
I/GAV2 ( 4211): Thread[GAThread,5,main]: User-Agent: GoogleAnalytics/2.0 (Linux; U; Android 4.0.4; en-us; GT-P7500 Build/IMM76D)
I/GAV2 ( 4211): Host: ssl.google-analytics.com
I/GAV2 ( 4211): GET /collect?................. HTTP/1.1
V/GAV2 ( 4211): Thread[GAThread,5,main]: sent 1 of 1 hits

Hits sent? You’re good to go.

A word on legality

The Google Analytics Terms of Service prohibit sending of any personally identifiable information (PII) to Google Analytics servers. So don’t.

Sending data from Unity

Share Text + Unity

I’m pretty new to Unity-Android integration, so I’m filled with pride after every little success. And I bet this one is pretty trivial, especially for Android veterans. But I’m posting it anyway – for the sake of Unity developers. There just aren’t enough examples out there that tie the pieces together.

I wanted my Unity app to have a share function. All it needs to do is send some text as is easily done on Android. All that is missing is a tiny Android plugin.

Android Plugin

I already covered the subject of creating an Android plugin in another post. I will expand on it to keep this post short.


Again I subclassed UnityPlayerActivity. This utilizes the main activity as context for starting a new intent. I then added a small method, shareText:

package com.companyname.appname;

import android.content.Intent;

public class MainActivity extends UnityPlayerActivity {
    public void shareText(String subject, String text, String chooserTitle) {
        Intent sendIntent = new Intent();
        sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
        sendIntent.putExtra(Intent.EXTRA_TEXT, text);
        startActivity(Intent.createChooser(sendIntent, chooserTitle));

shareText takes 3 string parameters:

  1. subject – The desired subject line of a message. Note that not all senders send the subject. Make sure that your text is sufficient by itself.
  2. text – The actual text message to be sent.
  3. chooserTitle – The title for the chooser dialog. It is displayed when the user is prompted to choose how to send the data. For example, it can be “Share via”.

The Unity App

Now all that is left is to call the shareText method from within Unity. This Boo method does the trick:

    static def ShareText(subject as string, text as string, chooserTitle as string):
        jc = AndroidJavaClass("com.unity3d.player.UnityPlayer")
        jo = jc.GetStatic[of AndroidJavaObject]("currentActivity")
        jo.Call("shareText", subject, text, chooserTitle)

This method simply calls the Java method as documented by Unity.

That’s the whole deal. Enjoy.

Serverless authentication with Instagram

Instagram + Unity

In this post I will explain how to implement a Unity app for Android which allows the user to authenticate using an Instagram account – without a server (i.e., directly against Instagram’s server.) In the process we’ll also learn how to write an Android plugin.


Instagram supports client-side authentication (OAuth implicit flow, a.k.a. 2-legged OAuth). This flow enables an app to obtain a user’s OAuth credentials directly: the access token is delivered to the app via the response URI. However, the flow was designed with JavaScript applications in mind, as the app is expected to have access to the response URI (“Simply grab the access_token off the URL fragment and you’re good to go.”)  Alas, this is a challenge for a mobile app, as the app needs to relinquish control to the browser when directing the user to authenticate. How then can the app regain control and obtain the response URI with the access token?

The solution is to configure a redirect URI with a custom scheme (instead of https). An intent filter will be added to the app to handle this custom scheme. This will result in the browser directing the flow back to the app when the response URI arrives. Adding an intent filter to an Android Unity app is seemingly a simple task, but it has its share of pit falls and online examples are scarce. Full instructions ahead.


The chronological order of events in runtime (once everything is already set up and running):

  1. A user opens the app manually
  2. The user chooses to sign in. The app redirects the user to a browser to sign in on Instagram’s page
  3. Upon successful authentication Instagram redirects the browser to a URI with a custom scheme
  4. The Android OS opens the app automatically to handle this URI
  5. The plugin (Java) code is called, which parses the URI and then hands over the data to a script in the Unity project


I’m using Windows 7. The tools I used for the job:

  1. Unity Android Pro v4.1.3
  2. Android SDK v21
  3. Eclipse 4.2.1 + ADT v22

For help with installation see my previous post.

Note: The Unity scripts in this example are written in Boo. There’s about a 98% chance you’re writing in C# or UnityScript, but I’m sure you’ll find no problem understanding the scripts – they’re quite minimal.

Register Your Application with Instagram

First you will need an Instagram account. Then you should register your app.

Configure the Redirect URI using a custom scheme.
For example: mycustomscheme://oauth/callback/instagram/.
The important part is the scheme: mycustomscheme. Choose something unique.

The Website URL is not important. Choose whatever you want.

When the registration is complete you will get a Client ID. It looks something like this: c46692e6a1e57748a2b3f2b553f84c67. Keep it for later. You can access and edit this information any time.

Tip: You can manage your applications to revoke access. This might come in handy later, during debugging, in case you’ve already signed in and granted your application access but want to deny it. (Suppose you want to test the error case.)

Create an Android Plugin

The plugin will handle the response URI, extract the access token and send it to the Unity app. It will be written in Java.

Time to open Eclipse. Create a new Android Application Project. Most of the parameters are not important, such as application name, project name or Android SDK versions. They are controlled by Unity’s build settings. You should, however, pay attention to 3 things:

  1. Package name. For example: com.companyname.appname. Make sure this is the same as the Bundle Identifier in Unity’s Player Settings.
  2. Check the “Mark this project as a library” to produce a JAR file. (This can also be done later from the project properties under Android.)
  3. Activity Name. I’ll use MainActivity (the default) in this example. You will need to use this later when adding the plugin to your Unity project.

Add classes.jar to the Classpath

The location of classes.jar depends on your installation of Unity. The default location is: C:\Program Files (x86)\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\classes.jar. More info here.

  1. Open: Project => Properties => Java Build Path => Add External JARs…
  2. Locate and select classes.jar


We will subclass UnityPlayerActivity and implement onNewIntent:

package com.companyname.appname;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;

public class MainActivity extends UnityPlayerActivity {
    protected void onNewIntent(Intent intent) {

    private void handleAccessToken(Intent intent) {
        Uri uri = intent.getData();
        if (uri != null && uri.toString().startsWith("mycustomscheme")) {
            String accessToken = "";
            if (uri.getFragment() != null) {
                accessToken = uri.getFragment().replace("access_token=", "");
                Log.d("Unity", "Found access token: " + accessToken);
            } else {
                Log.d("Unity", "Access token not found. URI: " + uri.toString());
            UnityPlayer.UnitySendMessage("AccessManager", "OnAccessToken", accessToken);

Our new activity extends the standard UnityPlayerActivity class. The onNewIntent method will be called when the activity is re-launched. If a URI is found, it is parsed and the access token is extracted. UnityPlayer.UnitySendMessage sends the token to a script inside Unity, where AccessManager is the name of the game object and OnAccessToken is the name of the method. We’ll later create them in Unity.

That’s it. You should find an output JAR file in the project’s bin folder. We’ll copy it later to the Unity project.

Tip: When writing log output (Log.d) I used “Unity” for the tag. This is the same tag that Unity uses for Debug.Log. So when I use logcat to read the log output I can filter easily:

adb logcat Unity:V *:S

Error Handling

The response URI for a successful sign-in looks like this:


For a failure it looks something like this:


When the code above detects there is no fragment, it passes an empty string instead of an access token.

The Unity App

The Unity app needs to open the sign-in URL when the user chooses to sign in. And it needs to receive the access token from the plugin we wrote earlier.

Open Sign-In URL in Browser

All you need to do is open this link:

  • Fill in the Client ID you received from Instagram.
  • Use the Redirect URI you configured earlier. Replace the colon with “%3A” and all the slashes with “%2F” as above.

Notice the last parameter: response_type=token. This instructs Instagram to use the implicit flow and return the access token in the response URI.

The following Boo code simply formats the link string and calls Application.OpenURL:

SIGN_IN_URL_FORMAT = "https://instagram.com/oauth/authorize/?client_id={0}&redirect_uri={1}&response_type=token"
CLIENT_ID = "c46692e6a1e57748a2b3f2b553f84c67"
SIGN_IN_REDIRECT_URL = "mycustomscheme%3A%2F%2Foauth%2Fcallback%2Finstagram%2F"


Handling the Response

Create a game object named AccessManager and attach a script to it with a method named OnAccessToken. Make sure to use the same game object and method names as in the Java plugin code (UnityPlayer.UnitySendMessage). The method should have one parameter of type string, which will receive the access token. You can then use it to access Instagram API. (You may also want to store it using PlayerPrefs.)

Example code in Boo:

def OnAccessToken(accessToken as string):
    Debug.Log("Received access token: " + accessToken)
    PlayerPrefs.SetString("access_token", accessToken)
    // do something useful here

Adding the Plugin

The last part is to add the plugin we created earlier to the Unity project:

  1. Create a subdirectory Assets/Plugins/Android in your Unity project directory
  2. Copy the JAR file we created earlier to Assets/Plugins/Android.
  3. Create an AndroidManifest.xml file in Assets/Plugins/Android.

Here we define our activity, MainActivity, as the main activity and also add an intent filter:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <application android:icon="@drawable/app_icon" android:label="@string/app_name">
    <activity android:name=".MainActivity" android:label="@string/app_name" android:launchMode="singleTask" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:screenOrientation="sensor">
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <data android:scheme="mycustomscheme" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

Use the same names you used in the Java plugin:

  • Activity (.MainActivity). Mind the prepending dot!
  • Custom scheme (mycustomscheme)

There is no need to specify the package name (com.companyname.appname) here. It is determined by Unity’s Player Settings (“Bundle Identifier”).

Notice the parameter android:launchMode=”singleTask”. This is the only mode that worked for me.

During a build Unity will extend this file and merge a few bits into it, such as the bundle identifier (package name), Android versions and permissions. The extended file, with the same name, can be found in the Temp/StagingArea subdirectory, which is deleted when Unity is closed.

That’s it! Should be working now.

Testing the Custom Scheme URI

If you open a browser on your mobile and try to open your URI (e.g. mycustomscheme://oauth/callback/instagram/) you will most likely find yourself in a Google search results page. That’s just how the browser works. To manually open your URI you’ll have to find a creative way to open a URI directly. For example:

  • Create a simple HTML that redirects to your URI, copy (email?) it to the mobile device and open it with some HTML viewer
  • Create a redirecting HTML and put it on your server, if you have one
  • Open the URI using your Unity app using Application.OpenURL (haven’t tried this one myself)

What’s Next?

There are two issue worth mentioning. I haven’t finished investigating them and tinkering with them yet, but I’ll say a few words.

UnityPlayerNativeActivity and UnityPlayerProxyActivity

In this solution we subclassed UnityPlayerActivity. We ignored two other (important?) classes, UnityPlayerNativeActivity and UnityPlayerProxyActivity, which were introduced in Gingerbread.

  • UnityPlayerNativeActivity – Parallel to UnityPlayerActivity. Can also be subclassed.
  • UnityPlayerProxyActivity – The top activity; it determines which of the other two activities (regular or native) should be started.

It is possible that ignoring the native player results in reduced performance in some cases.


I managed to open a WebView inside Unity using gree’s plugin. I will soon try to use a WebView for signing in instead of sending the user to the browser.

Edit: I’ve tried using WebView and it didn’t work. It would not delegate handling of a custom scheme. Instead it shows an error. I assume this behavior could be overridden if I had a way to set my own WebViewClient and override shouldOverrideUrlLoading.


See you then.


Building Unity for Android with Eclipse

Eclipse + Unity

While working on a Unity project for Android I found the need to move the build process to Eclipse. This process used to be complicated and tricky, but thankfully it became rather simple with Unity 4.

Note: The instructions below relate to Windows 7. YMMV.

Before we begin, you’ll need to install two tools:

  1. Android SDK
  2. Eclipse + ADT Plugin

You can download them both here. They’re bundled together, named “ADT Bundle”. In the same page you can click “Use an existing IDE” to download only the SDK.

Android SDK

If you’re not familiar with the Android SDK, you should know that it consists of multiple components. After you install it you can manage which components are installed using the SDK Manager. The components that you must have are SDK Tools (installed by default) and at least one SDK Platform. I decided to go with Android 4.0.3 (API 15). Choose whatever suits you. Once you choose your platform, you only have to install “SDK Platform”. The rest is optional. (You may want “ARM EABI v7a System Image” to use the emulator.)

I also recommended installing whatever the SDK Manager suggest under Tools and Extras, namely: SDK Platform-tools, SDK Build-tools, Android Support Library and Google USB Driver.

Invokation Failed

I’ve encountered a bug with version 22 of the SDK. Unity could not build with it. I’d get the following error:

Edit: This bug seems to have been solved with version 22.0.1 of Android SDK.

At least this is the case with version 4.1.2f1 of Unity. If you have this problem, try downgrading your Android SDK version: Uninstall version 22 and then install version 21 (available here). Strangely enough, after you install version 21 you can let the SDK Manager upgrade “Android SDK Tools” (under “Tools”) to rev. 22 and Unity will still be able to work with it. Voodoo.

After you downgrade to rev. 21 and you’ll be seeing this error each time you open Eclipse:


Don’t worry about it. Just hit Close.

Eclipse & ADT Plugin

If you’ve already built stuff for Android using Unity then you probably already have the SDK installed. You could install Eclipse for Mobile separately and then the ADT Plugin. But you can also download the ADT Bundle and take from it only the “eclipse” directory. It’s a download overkill (>400MB), but it’s easier to install.

Anyway, all Eclipse installations are simply ZIP files. There is no installer. Extract the ZIP file contents to wherever you want, e.g. “C:\eclipse”.

Export Eclipse Project from Unity

It’s time to open Unity. Open the build settings for Android and you’ll see a check box “Create Eclipse project”. Selecting it directs Unity to create an Eclipse project instead of building an APK file. When asked, choose a target directory for the Eclipse project.

Import Project into Eclipse

Open Eclipse. Choose “File => Import”. Under “Android” choose “Existing Android Code Into Workspace”. Fill the “Root Directory” field with the path of the project directory and hit Enter. You should see your project in the list. You might see more than one project if you’re using plugins. Deselect the plugins, you don’t need to import them – they’re included in the main project. Click “Finish”. That’s it. Your project is ready to be built.