将两个 Unity 项目导入 Android Studio 无法按预期工作 [英] Importing two Unity projects into Android Studio doesn't work as expected

查看:36
本文介绍了将两个 Unity 项目导入 Android Studio 无法按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在接受培训以制作使用 Unity 添加一些功能(AR、VR 等...)的应用程序.目前,我一直在使用 Android Studio 开发 Android,一旦完成,我将在 iOS 上进行培训.

I am currently training to make applications which use Unity to add some features (AR, VR, etc...). For now I've been working on Android, with Android Studio, and once I'll be done with I'll train on iOS.

我的目标很简单:我的 MainActivity 显示两个按钮,每个按钮调用一个单独的 Unity 项目(从 Unity 导出为 Google Android 项目)来启动它的场景.

My aim is simple: my MainActivity displays two buttons, each one calls a separate Unity project (exported from Unity as Google Android project) to launch its scene.

为此,我将这两个 Unity 项目 Scene1Scene2 作为库导入,并通过启动它们的活动来调用它们(请参阅下面的代码).

To do so, I imported those two Unity projects Scene1 and Scene2 as libraries and I call them by starting their activities (see the code below).

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void goToUnity1(View v){
        Intent intent = new Intent(this, com.example.unityscene1.UnityPlayerActivity.class);
        startActivity(intent);
    }

    public void goToUnity2(View v){
            Intent intent = new Intent(this, com.example.unityscene2.UnityPlayerActivity.class);         
            startActivity(intent);

     }
}

及其 AndroidManifest.xml:

And its AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.multipleunity">

<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">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity android:name="com.example.unityscene1.UnityPlayerActivity"></activity>
    <activity android:name="com.example.unityscene2.UnityPlayerActivity"></activity>


</application>

Scene1Scene2 中的 UnityPlayerActivity 文件是由 Unity 生成的,所以它们是相似的(这里是它们的 onCreate> 方法):

The UnityPlayerActivity files in Scene1 and Scene2 are generated by Unity so they are similar (here are their onCreate method):

public class UnityPlayerActivity extends Activity {
    protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code


    // Setup activity layout
    @Override protected void onCreate (Bundle savedInstanceState)
    {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);

        getWindow().setFormat(PixelFormat.RGBX_8888); // <--- This makes xperia play happy

        mUnityPlayer = new UnityPlayer(this);
        setContentView(mUnityPlayer);
        mUnityPlayer.requestFocus();
    }

    ...
}

代码编译没有任何问题,应用程序启动并显示带有两个按钮的 MainActivity.当我点击第一个按钮时,它会按我的预期启动第一个 Unity 场景.但是,当我点击第二个按钮时,它也会启动第一个 Unity 场景,而不是第二个.

The code compiles without any problem, the application launches and displays the MainActivity with its two buttons. When I click on the first button, it launches the first Unity scene as I expected. However, when I click on the second button it also launches the first Unity scene instead of the second one.

所以我试图理解为什么会发生这种情况,这是我目前能说的:

So I tried to understand why this happens and here is what I can tell so far:

  • 我没有错误地将同一个 Unity 项目放入两次
  • 在将 Scene2 转换为库之前,它自己运行良好
  • 活动 com.example.unityscene2.UnityPlayerActivity 在我点击第二个按钮时被调用
  • I didn't put twice the same Unity project by mistake
  • Before transforming Scene2 into library it works well on its own
  • The activity com.example.unityscene2.UnityPlayerActivity is called when I click on the second button

更新

在这上面花了几个小时后,我确定问题出在我在 Google Android 项目中导出时 Unity 提供的资源名称,这些资源总是相同的 (unity-classes.jar).

After spending hours on this I'm sure the problem comes from the name of the ressources Unity delivers when I exported in Google Android project which are always the same (unity-classes.jar).

这是我在此处阅读的内容:

Android 开发工具将库项目的资源与应用项目的资源合并.在多次定义资源 ID 的情况下,工具会从应用程序或优先级最高的库中选择资源,并丢弃其他资源.

The Android development tools merges the resources of a library project with the resources of the application project. In the case that a resource’s ID is defined several times, the tools select the resource from the application, or the library with highest priority, and discard the other resource.

此外,如果我有多个库,则优先级与依赖项顺序(它们出现在 Gradle 依赖项块中的顺序)相匹配.

Adding to that, if I have multiple libraries the priority matches the dependency order (the order they appear in the Gradle dependencies block).

所以我试图颠倒依赖关系的顺序,我将第二个 Unity 项目放在第一个之前,正如预期的那样,两个按钮都启动了 Unity 的第二个场景.

So I tried to reverse the order of the dependencies, I put the second Unity project before the first one and as that was expected both buttons launch the second Scene of Unity.

现在我知道了,有没有办法避免这个名字冲突?

Now I know that, is there a way to avoid this name conflict ?

推荐答案

我没有解决我的问题,但我设法找到了避免它的方法:我决定制作一个更大的项目,而不是导入两个小的 Unity 项目包括两个不同的场景(一个带有 Vuforia AR,另一个带有一些 UI 文本).然后挑战是找到一种方法,当我点击我在 Android 上设计的相关按钮时调用正确的 Unity 场景.

I did not solve my problem, but I managed to find a way to avoid it: instead of importing two small Unity projects I decided to make a bigger one which includes two different scenes (one with Vuforia AR and the other with some UI text). Then the challenge was to find a way to call the right Unity scene when I click on the associated button I designed on Android.

统一

在每个场景中,我创建了一个空对象(我称它为SceneManagerObject),该对象将附加脚本GoToScene.在这个脚本中会有以下方法:

On each scene I created an empty object (I called it SceneManagerObject) which will be attached the script GoToScene. In this script there will be the following methods:

private void ChangeScene(string sceneName)
{
    SceneManager.LoadScene (sceneName);
}

public void ReceiveJavaMessage(string message)
{
    if (message.Equals ("Scene1") || message.Equals ("Scene2")) 
    {
        ChangeScene (message);
    } 
    else 
    {
        Debug.Log ("The scene name is incorrect");
    }
}

第二种方法是从 Java 代码中调用的方法.

The second method will be the one being called from the Java code.

然后我在每个场景上创建了一个 UI 按钮,它会在点击时调用 onClick 方法,其目的是能够在不破坏 Unity Activity 的情况下返回 Android 以便我们可以在 if 之后恢复它我想.为此,我创建了另一个带有 GoBackToAndroid 脚本的空对象:

Then I created a UI button on each scene which will call onClick method when clicked, its purpose is to be able to go back to Android without destroying the Unity activity so we can resume it after if I wanted to. For this, I created another Empty Object with the script GoBackToAndroid attached:

public class GoBackToAndroid : MonoBehaviour {
public string activityName; // contains the name of the activity I want to go when I quit this scene

public void onClick()
{
    callJavaMethod();
}


private void callJavaMethod()
{
    AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer);
    AnroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
    jo.Call("ReceiveUnityMessage", activityName); // Will call a method in Java with activityName as parameter
}

Unity 就是这样,在我将项目导出为 Google Android 项目并为下一步保持温暖之后.

That's it for the Unity, after I exported the project as a Google Android project and I kept it warm for the next step.

Android Studio

将 Unity 项目作为库导入后.我创建了三个活动:MainActivitySecondActivityMultipleScenesUnityActivity:

After importing the Unity project as a library. I created three activities: MainActivity, SecondActivity and MultipleScenesUnityActivity:

public class MultipleScenesUnityActivity extends UnityPlayerActivity {
    public static boolean unityIsRunning = false; // true if a Unity Activity is running on background


    @Override protected void onDestroy()
    {
        unityIsRunning = false;
        super.mUnityPlayer.quit();
        super.onDestroy();
    }

    @Override protected void onResume()
    {
        Intent currentIntent = getIntent();
         // If there's no Unity Activity inside the back stack
        // (meaning it just had been created)
        if (!unityIsRunning)
        {
             super.mUnityPlayer.UnitySendMessage("SceneManagerObject", "ReceiveJavaMessage", currentIntent.getStringExtra("sceneName");
        }
        unityIsRunning = true;
        super.onResume();
        super.mUnityPlayer.resume();
    }

    public void ReceiveUnityMessage (String messageFromUnity)
    {
        Intent intent;
        if (messageFromUnity.equals("MainActivity"))
        {
            intent = new Intent(this, MainActivity.class);
            startActivity(intent);
        }
        else if (messageFromUnity.equals("SecondActivity"))
        {
            intent = new Intent(this, SecondActivity.class);
            startActivity(intent);
        }
        else 
            Log.d("Test", "The activity " + messageFromUnity + " doesn't exist");
    }
}

ReceiveUnityMessage 是我们离开 Unity Activity 时调用的方法,其目的是引导我们进入我们想要去的 Activity.

The ReceiveUnityMessage is the method called when we leave the Unity activity and its purpose is to lead us to the activity we desire to go.

然后是 MainActivity(SecondActivity 遵循相同的模式):

Then the MainActivity (the SecondActivity follows the same pattern):

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void goToActivity2(View view) // called when I click on a button
    {
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
    }

    public void goToUnity(View view) // called when I click on another button
    { 
        Intent intentUnity = new Intent(this, MultipleScenesUnityActivity.class);

        if (unityIsRunning)
        {
            intentUnity.removeExtra("sceneName"); // We have to clean the extra before putting another one otherwise we'll get always the same Unity scene

            /*  If set in an Intent passed to Context.startActivity(), this flag will cause the launched activity to be brought
             *  to the front of its task's history stack if it is already running. */
            intentUnity.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

            /* We send a string to Unity which, when received, will change the scene.
            * This ONLY works when the Unity activity is running on background. */
            UnitySendMessage("SceneManagerObject", "ReceiveJavaMessage", "Scene1");
        }

        else
        {
            /* The intent gets a key with its String value. The value has to be the name of the Unity
            * scene and is received in UnityActivity1 when the activity starts.*/
            intentUnity.putExtra("sceneName", "Scene1");
        }
        startActivity(intentUnity);
    }
}

所以我所做的是通过发送消息来连接所有内容,这样我就可以管理我想要启动的场景,活动也是如此.

So what I did is connecting everything by sending messages so I can manage the scene I'd like to launch and the same goes for the activities.

我确信有更好的方法可以做到这一点,我仍然是新手,我可能会很笨拙..无论如何,我设法避免了我原来的问题,所以如果有人面临同样的问题,这个答案可能是一个有趣的选择.

I'm sure there are a better ways to do so, I'm still a novice and I can be clumsy.. Anyway, I managed to avoid my original problem so if anyone faces the same issue this answer might be an interesting alternative.

这篇关于将两个 Unity 项目导入 Android Studio 无法按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆