Unity Android Plugins and `onActivityResult` callback

I am currently develop some native plugins for Asset Store and one of them is Android Goodies which allows to do lots of Android native things.

One of the problems that I encountered was getting onActivityResult callback. This is needed for example when you want to pick an image and receive the receive the result.

static void dispatchPickImageIntent(Activity context, int requestCode) {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("image/*");
context.startActivityForResult(photoPickerIntent, requestCode);
}

And onActivityResult should look something like this:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Log.d(Constants.LOG_TAG, ">>> onActivityResult: " + requestCode + " " + resultCode + " " + intent);
currentStatus = Status.IDLE;

switch (requestCode) {
case REQ_CODE_PICK_IMAGE:
PhotoPickerUtils.handlePhotoReceived(resultCode, intent, this);
break;
case REQ_CODE_TAKE_PHOTO_SMALL:
case REQ_CODE_TAKE_PHOTO_BIG:
TakePhotoUtils.handlePhotoReceived(requestCode, resultCode, intent, this);
break;
default:
finish();
break;
}

finish();
}

The problem is that Unity has its own `UnityPlayerActivity` which handles `onActivityResult` itself.

I found two possible ways of dealing with this problem:

  1. Extending UnityPlayerActivity with my activity and forcing developers to substitute the main activity with my custom activity in manifest file. I quickly gave up this approach as only one plugin can override Unity activity and people sometime use multiple Android plugins.
  2. Creating a custom activity that will be short-lived and its sole purpose would be to get created, do the job (user picks photo from gallery e.g.), deliver result (picked image) into onActivityResult and terminate itself. I chose this approach.

So the only thing user has to do is to add my custom activity to AndroidManifest.xml file (translucent theme is for activity not to have any visual effects):

<activity android:name="com.deadmosquitogames.AndroidGoodiesActivity" android:theme="@android:style/Theme.Translucent.NoTitleBar"></activity>

Now to implementation details:

Activity has static methods that are invoked from Unity (AndroidJavaObject API) to prepare it for certain tasks just before they are executed e.g. for picking photo:

public static void prepareToPickPhoto(OnTextureReceivedListener listener, int format, int maxSize) {
resetStatus();
currentActionReqCode = REQ_CODE_PICK_IMAGE;
PhotoPickerUtils.setImagePickSettings(listener, format, maxSize);
}

Then launch the activity from C# (some details are skipped for briefty):

public static void StartAndroidGoodiesActivity()
{
using (var clazz = AGUtils.ClassForName(AndroidGoodiesActivityClassSignature))
{
using (var intent = new AndroidIntent(AGUtils.Activity, clazz))
{
AGUtils.StartActivity(intent.AJO);
}
}
}

Of course AndroidGoodiesActivity has its onActivityResult method overridden which handles the result, passes it over to unity side via AndroidJavaProxy API and finish() is called to terminate the activity instance.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Log.d(Constants.LOG_TAG, ">>> onActivityResult: " + requestCode + " " + resultCode + " " + intent);
currentStatus = Status.IDLE;

switch (requestCode) {
case REQ_CODE_PICK_IMAGE:
PhotoPickerUtils.handlePhotoReceived(resultCode, intent, this);
break;
case REQ_CODE_TAKE_PHOTO_SMALL:
case REQ_CODE_TAKE_PHOTO_BIG:
TakePhotoUtils.handlePhotoReceived(requestCode, resultCode, intent, this);
break;
default:
finish();
break;
}

finish();
}

To recap: set static data to tell Activity what it should do, launch the Activity and pass the delivered results from onActivityResult to Unity.

Hope this article helped you, if you have any questions don’t hesitate to reach me out on FB and checkout my plugins on Asset Store or check our company web-site.