unity配置

​ 创建一个3D mobile项目,在File-Build Settings中勾选Export Project,会出现Export按钮,点击即可导出unity工程作为Android工程的module

Android配置

​ 在settings.gradle中添加:

include ':unityLibrary'
project(':unityLibrary').projectDir=new File('unity导出地址\\unityLibrary')

​ 在Project的build.gradle的repositories下添加:

flatDir {
dirs "${project(':unityLibrary').projectDir}/libs"
}

​ 在使用到unity的module依赖中添加:

implementation project(':unityLibrary')
implementation fileTree(dir: project(':unityLibrary').getProjectDir().toString() + ('\\libs'), include: ['*.jar'])

​ 最后在gradle.properties中添加:

unityStreamingAssets=.unity3d, google-services-desktop.json, google-services.json, GoogleService-Info.plist

unity在Android中的使用

unity作为activity

​ 直接创建一个activity继承于UnityPlayerActivity,此时在activity中不需要setContentView,UnityPlayerActivity中会创建一个UnityPlayer并调用setContentView(mUnityPlayer);。UnityPlayer本质是一个FrameLayout,可以使用addView来在其中添加其他View

unity作为fragment

​ 在onCreateView中初始化unityPlayer

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mUnityPlayer = new UnityPlayer(Objects.requireNonNull(this.getActivity()));
mUnityPlayer.requestFocus();
mUnityPlayer.windowFocusChanged(true); // 如果不调用这两句会导致unity黑屏不显示画面
return playerView;
}

​ 另外在fragment的onResume、onPause、onDestroy等生命周期中需要相应的调用UnityPlayer的对应生命周期的方法。

unity与Android的交互

Android调用unity中的方法
  • 使用UnityPlayer.UnitySendMessage(String gameObjectName, String methodName, String param);(不推荐)

    UnityPlayer.UnitySendMessage有三个参数,且都为string类型,第一个参数为需要调用的gameObject名称,第二个参数为需要调用的方法名称,第三个参数为需要调用的方法中的参数。

    因为只有一个参数来进行参数传递,因此使用这种方法不能调用unity中参数大于一个的方法,并且也获取不到方法的返回值。当unity中的方法没有参数时,UnityPlayer.UnitySendMessage中的第三个参数需要为空字符串,不能为null!

    此方法的好处在于当unity没有加载完成时调用此方法,unity将在加载完成后完成unity方法的调用。

  • 使用接口:在Android中创建一个接口并在unity中实现(推荐)

    例:在Android工程中创建一个名为IUnityController的接口:

    public interface IUnityController {
    void openDoor(float angle, float time, int doorId);
    }

    unity中的实现:

    private class UnityController : AndroidJavaProxy
    {
    public UnityController() : base("包名.IUnityController")
    {
    }

    public void openDoor(float angle, float time, int doorId)
    {
    _doorAnim.DoorRotate(angle, time, doorId);
    }
    }

    在Android的activity或fragment中添加接口的设置方法,例如在fragment中添加:

    private IUnityController listener;
    public void setListener(IUnityController listener) {
    this.listener = listener;
    }

    unity中对应的设置方法:

        private void Awake()
    {
    #if !UNITY_EDITOR && UNITY_ANDROID
    var activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").
    GetStatic<AndroidJavaObject>("currentActivity");
    using var fragment = _activity.Get<AndroidJavaObject>("mUnityFragment");
    fragment.Call("setListener", new UnityController());
    #endif
    }

    这样在unity加载完成时就会给fragment中的listener赋值,可以直接使用listener.openDoor()方法来调用unity中的方法。

unity中调用Android方法:
var activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").
GetStatic<AndroidJavaObject>("currentActivity"); // 获取activity
using var fragment = _activity.Get<AndroidJavaObject>("mUnityFragment"); // 获取java中的变量
_activity.Call("removeBlackScreen"); // 调用java中的方法

​ unity调用android方法默认不是在主线程中调用的,如果调用涉及到UI操作或其他必须在主线程中进行的操作时,需要在Android代码中添加runOnUiThread或者是在unity代码中添加:

currentActivity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
{

}
));

出现的问题

  • apk打包安装后出现两个图标

    解决方案:在unityLibrary的AndroidManifest中删除<category android:name="android.intent.category.LAUNCHER" />