Read Android intent extra data on Unity app launch
Asked Answered
I

2

12

I am launching an Unity application from another Android application using a custom implicit intent. This is working fine, but I cannot figure out how to read the intent extra data in Unity?

ANDROID INTENT TO LAUNCH UNITY APP

i=new Intent();
i.setAction("com.company.unityapp.MyMethod");
i.putExtra("KEY","This is the message string");
startActivity(i);

UNITY APP AndroidManifest.xml

<intent-filter>
     <action android:name="com.company.unityapp.MyMethod" />
     <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

I have a GameObject in my scene with a script attached. Inside the start method I have this code to try and read the extra data that was passed along with the intent

AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); 
AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

AndroidJavaObject intent = currentActivity.Call<AndroidJavaObject>("getIntent");
bool hasExtra = intent.Call<bool> ("hasExtra", "arguments");

if (hasExtra) {
 AndroidJavaObject extras = intent.Call<AndroidJavaObject> ("getExtras");
 arguments = extras.Call<string> ("getString", "arguments");
}

This is not working and arguments is always empty. Any help would be appreciated.

Inflammable answered 19/3, 2016 at 5:54 Comment(0)
I
12

It took me quite some time to figure this out. All solutions found online were only partly complete. Below is the full solution for launching a Unity application from another android application using a custom implicit Intent and also how to access the extra data sent with the Intent inside Unity.

To accomplish this you need to create a Android plugin that will be used by Unity to access the Intent extra data.

ANDROID PLUGIN:


You need to copy the classes.jar from Unity installation folder to the android plugin folder /lib/classes.jar

public class MainActivity extends UnityPlayerActivity {

  @Override
  protected void onNewIntent(Intent intent) {
      super.onNewIntent(intent);
      handleNewIntent(intent);
  }

  private void handleNewIntent(Intent intent){
      String text = intent.getStringExtra("KEY");
      UnityPlayer.UnitySendMessage("AccessManager","OnAccessToken", text);
  }
}

AndroidManifest.xml

Important here is the package name used: com.company.plugin

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.plugin">
    <application
        android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
        android:supportsRtl="true" android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Gradle build file:

Add the following to the app gradle build file to be able to create a .jar to be used with Unity

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
    sourceSets {
        main {
            java {
                srcDir 'src/main/java'
            }
        }
    }       
...
...

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
    compile files('libs/classes.jar')
}

//task to delete the old jar
task deleteOldJar(type: Delete) {
    delete 'release/AndroidPlugin.jar'
}

//task to export contents as jar
task exportJar(type: Copy) {
    from('build/intermediates/bundles/release/')
    into('release/')
    include('classes.jar')
    ///Rename the jar
    rename('classes.jar', 'AndroidPlugin.jar')
}

exportJar.dependsOn(deleteOldJar, build)

Copy the created AndroidPlugin.jar to Unity Assets/Plugins/Android

UNITY APP:


Set the bundle identifier in PlayerSettings to be the same as set in the Android Plugin - com.company.plugin

Create custom AndroidManifest.xml file in Assets/Plugins/Android

Important here is to use the same package name as used in the plugin. Also note the Intent name: com.company.plugin.do

AndroidManifest.XML

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.plugin"
      android:versionCode="1" android:versionName="1.0">
    <uses-sdk android:minSdkVersion="9" />
    <application 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">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="com.company.plugin.do" />
                <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

Create a unity script named AccessManager and attach the script to a game object in the scene. OnAccessToken is the method that will receive the message sent from the android plugin and will contain the extra data sent from the intent.

public class accessManager : MonoBehaviour {

    public void OnAccessToken(string accessToken)
    {
        Debug.Log("Message Received!!!! :" + accessToken);
    }
}

ANDROID APP:

Create a standard Android application that will launch the Unity Application and send the Intent extra data

public void LaunchUnityApp(){
    Intent i=new Intent();
    i.setAction("com.company.plugin.do");
    i.setType("text/plain");
    i.putExtra("KEY","This is the text message sent from Android");
    startActivity(i);
}
Inflammable answered 24/3, 2016 at 7:56 Comment(3)
Hey Hardy, Thanks for the brief explanation. I followed the whole procedure. Native App does launches the Unity App but unable to get the message. And idea what I might be doing wrong?Bayly
I also see the same behaviour. If the app is running then its fine but if the app has to launch then the GameObject hasn't been spawned yet to receive the messageTerresaterrestrial
There is a problem with the solution: getting launch parameters should be done in onCreate() call instead of onNewIntent(). This is why other were seeing issues with indicated above.Balmoral
P
2

You don't need a plugin to achieve this. Do your intent from Android like this:

Intent launchIntent = getPackageManager().getLaunchIntentForPackage("com.package.game");
launchIntent.putExtra("my_text", "Some data params");
if(launchIntent != null){
    startActivity(launchIntent);
}else{
    Log.d("Unity", "Couldnt start unity game");
}

Then in your unity Monobehaviour Class, receive it like this

private void Awake () {
    getIntentData ();
}

private bool getIntentData () {
#if (!UNITY_EDITOR && UNITY_ANDROID)
    return CreatePushClass (new AndroidJavaClass ("com.unity3d.player.UnityPlayer"));
#endif
    return false;
}

public bool CreatePushClass (AndroidJavaClass UnityPlayer) {
#if UNITY_ANDROID
    AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject> ("currentActivity");
    AndroidJavaObject intent = currentActivity.Call<AndroidJavaObject> ("getIntent");
    AndroidJavaObject extras = GetExtras (intent);

    if (extras != null) {
        string ex = GetProperty (extras, "my_text");
        return true;
    }
#endif
    return false;
}

private AndroidJavaObject GetExtras (AndroidJavaObject intent) {
    AndroidJavaObject extras = null;

    try {
        extras = intent.Call<AndroidJavaObject> ("getExtras");
    } catch (Exception e) {
        Debug.Log (e.Message);
    }

    return extras;
}

private string GetProperty (AndroidJavaObject extras, string name) {
    string s = string.Empty;

    try {
        s = extras.Call<string> ("getString", name);
    } catch (Exception e) {
        Debug.Log (e.Message);
    }

    return s;
}

Credit: https://wenrongdev.com/get-android-intent-data-for-unity/

(updated) https://wenrongdev.com/posts/get-android-intent-data-for-unity/

Phenomena answered 1/12, 2020 at 14:9 Comment(1)
FYI to others: the bundle id must be "com.unity3d.player.UnityPlayer" - I tried using my package name / Application.identifier and it always fails at runtime with AndroidJavaException: java.lang.ClassNotFoundException: com.company.project.UnityPlayerPolycotyledon

© 2022 - 2024 — McMap. All rights reserved.