onHandleIntent not being called in Unity app Android plugin, how to fix?

117 Views Asked by At

I'm developing a Unity app which will be able to interface with the Android app Termux via the Intent described here:

https://github.com/termux/termux-app/wiki/RUN_COMMAND-Intent#advance-examples

In my Unity-Android plugin I have two classes:

  1. PluginInstance.java:
package com.saricden.exd2termux;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import com.termux.shared.termux.TermuxConstants.TERMUX_APP.RUN_COMMAND_SERVICE;
import com.unity3d.player.UnityPlayer;
import java.util.Arrays;

public class PluginInstance {
    private static Activity unityActivity;

    public static void receiveUnityActivity(Activity tActivity) {
        unityActivity = tActivity;
    }

    private String unityGameObjectName = null;

    public void debugLog(String msg) {
        UnityPlayer.UnitySendMessage("DebugParent/DebugListener", "LogMessage", "BIGTEST (" + msg + ")");
    }

    public void loginToTermux() {
        Intent intent = new Intent();

        intent.setClassName("com.termux", "com.termux.app.RunCommandService");
        intent.setAction("com.termux.RUN_COMMAND");
        intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/login");
        intent.putExtra("com.termux.RUN_COMMAND_WORKDIR", "/data/data/com.termux/files/home");
        intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", true);
        intent.putExtra("com.termux.RUN_COMMAND_SESSION_ACTION", "0");

        unityActivity.startForegroundService(intent);
    }

    public void sendToUnity(String msg) {
        UnityPlayer.UnitySendMessage(unityGameObjectName, "ReceiveTermuxOutput", msg);
    }

    public void execTermuxCMD(String cmd) {
        debugLog("Started command...");
        String[] cmdParts = cmd.split(" ");

        String cmdRoot = cmdParts[0];
        String[] cmdArgs = Arrays.copyOfRange(cmdParts, 1, cmdParts.length);

        Intent intent = new Intent();

        intent.setClassName("com.termux", "com.termux.app.RunCommandService");
        intent.setAction("com.termux.RUN_COMMAND");
        intent.putExtra("com.termux.RUN_COMMAND_PATH", "/data/data/com.termux/files/usr/bin/" + cmdRoot);
        intent.putExtra("com.termux.RUN_COMMAND_ARGUMENTS", cmdArgs);
        intent.putExtra("com.termux.RUN_COMMAND_WORKDIR", "/data/data/com.termux/files/home");
        intent.putExtra("com.termux.RUN_COMMAND_BACKGROUND", true);
        intent.putExtra("com.termux.RUN_COMMAND_SESSION_ACTION", "0");

        Intent pluginResultsServiceIntent = new Intent(unityActivity, PluginResultsService.class);

        int executionId = PluginResultsService.getNextExecutionId();

        pluginResultsServiceIntent.putExtra(PluginResultsService.EXTRA_EXECUTION_ID, executionId);

        PendingIntent pendingIntent = PendingIntent.getService(unityActivity, executionId, pluginResultsServiceIntent, PendingIntent.FLAG_ONE_SHOT);
        intent.putExtra(RUN_COMMAND_SERVICE.EXTRA_PENDING_INTENT, pendingIntent);


        unityActivity.startForegroundService(intent);

        debugLog("Started foreground service, with run_background 'true'");
    }

    public void setUnityGameObjectName(String name) {
        unityGameObjectName = name;
    }
}
  1. PluginResultsService.java:
package com.saricden.exd2termux;
import android.app.IntentService;
import android.content.Intent;
import androidx.annotation.Nullable;
import com.unity3d.player.UnityPlayer;

public class PluginResultsService extends IntentService {

    public static final String EXTRA_EXECUTION_ID = "execution_id";

    private static int EXECUTION_ID = 1000;

    public static final String PLUGIN_SERVICE_LABEL = "PluginResultsService";

    private static final String LOG_TAG = "PluginResultsService";

    public PluginResultsService(){
        super(PLUGIN_SERVICE_LABEL);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        UnityPlayer.UnitySendMessage("DebugParent/DebugListener", "LogMessage", "onHandleIntent!!!");
    }

    public static synchronized int getNextExecutionId() {
        EXECUTION_ID++;
        UnityPlayer.UnitySendMessage("DebugParent/DebugListener", "LogMessage", "Get next execution_id (" + EXECUTION_ID + ")");
        return EXECUTION_ID;
    }

}

Then finally, my Unity MonoBehaviour class that kicks it all off:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Vuplex.WebView;

public class TerminalManager : MonoBehaviour
{
  private AndroidJavaClass unityClass;
  private AndroidJavaObject unityActivity;
  private AndroidJavaObject _pluginInstance;
  private WebViewPrefab webViewPrefab;

  void InitializePlugin(string pluginName) {
    unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
    _pluginInstance = new AndroidJavaObject(pluginName);

    if (_pluginInstance == null) {
      Debug.Log("!!!!! >> PLUGIN INSTANCE ERROR << !!!!!");
    }
    
    _pluginInstance.CallStatic("receiveUnityActivity", unityActivity);
    _pluginInstance.Call("loginToTermux");
  }

  async void Start() {
    webViewPrefab = GetComponent<WebViewPrefab>();

    InitializePlugin("com.saricden.exd2termux.PluginInstance");

    _pluginInstance.Call("setUnityGameObjectName", transform.root.name + "/" + transform.name);

    await webViewPrefab.WaitUntilInitialized();

    webViewPrefab.WebView.MessageEmitted += (sender, eArgs) => {
      Debug.Log("Dispatching Termux command...");
      Debug.Log(eArgs.Value);

      _pluginInstance.Call("execTermuxCMD", eArgs.Value);
    };
  }

  public void ReceiveTermuxOutput(string res) {
    Debug.Log("Receiving Termux response...");
    webViewPrefab.WebView.ExecuteJavaScript("appendResponse(`" + res + "`)");
  }
}

I can confirm the Termux commands are running. I have tested by running mkdir testFolder, then opening Termux and checking the home directory. The "testFolder" was successfully created.

The problem: PluginResultsService -> onHandleIntent never gets called!

How can I go about further debugging this? And/or does anyone have any suggestions as to what the problem might be?

1

There are 1 best solutions below

0
saricden On

I figured out the solution.

I was defining:

<service android:name=".PluginResultsService" android:exported="false" />

Inside my Unity app's top-level AndroidManifest.xml, but really it needed to be defined in the plugin-level AndroidManifest.xml!

Let's goo!