美文网首页
Android Studio项目集成Unity详细教程

Android Studio项目集成Unity详细教程

作者: 拉基简书已退 | 来源:发表于2017-12-08 17:25 被阅读0次

    Foreword


    上一篇介绍了Xcode项目集成Unity的步骤,本篇介绍AS项目集成Unity,其实在AS上集成相比Xcode简单多了,但也有不少坑需要注意。我们知道Unity可以直接打包apk,也可以导出AS或Eclipse工程,我的应用场景是已经有个Android Studio大项目了,Unity所做的功能属于其一部分,所以选择将Unity导出AS工程,为了方便主项目调用,还将Unity部分打包成aar。
    环境:Android Studio 3.0 + Unity 2017

    Step


    1.将Unity工程导出AS工程

    如下图红框处,Build System选择Gradle,Export Project勾选,按图中箭头把包名填好,不能使用Unity默认的,否则导出不了,点击Export导出。



    导出结果:


    2.AS导入上一步的工程,选择Import project (Gradle,Eclipse ADT,etc)


    导入多半是会报错的,一般错误就是gradle版本没选对,按自己的情况选好就行了,比如我的是3.0.0。


    3.继承UnityPlayer

    此时我们来看看这个工程结构,就一个界面UnityPlayerActivity,因为做Unity游戏的话也不需要显示其它原生界面,网上有些教程就是用继承UnityPlayerActivity的方法来显示Unity,然而这样做不够灵活。查看UnityPlayerActivity我们可以发现真正关键的是UnityPlayer所以仿照UnityPlayerActivity直接操作UnityPlayer不就好了么,但是。。。但是这里有个坑,我直接用UnityPlayer正确显示了Unity界面,可是在退出含Unity界面的Activity时,整个应用退出了,难道有Bug导致整个应用崩了?经过查找,发现原来在UnityPlayer源码中:



    这个kill方法在Activity finish时会被调用,然而它竟然给我把当前应用进程杀死了!没办法,自己写个类 MyUnityPlayer 继承它,并重写父类的kill方法。

    package com.unity.demo;
    
    import android.content.Context;
    
    import com.unity3d.player.UnityPlayer;
    
    public class MyUnityPlayer extends UnityPlayer {
        public MyUnityPlayer(Context context) {
            super(context);
        }
    
        @Override
        protected void kill() {
            //不要杀死当前应用进程
        }
    }
    
    

    4.导出aar包

    百度“Android Studio导出aar包”,发现还要创建Module,有那么麻烦吗?直接改build.gradle就行了。如下图,apply plugin: 'com.android.application' 改为 apply plugin: 'com.android.library',注释掉applicationId,然后Rebuild Project。完成后在工程的build - outputs - aar文件夹下就可以看到aar包了。



    5.在主AS工程中使用unity aar包

    这里我就用一个简单的Demo来演示,把aar文件放入新工程的app - libs文件夹下,修改app的build.gradle:



    Demo项目

    Demo项目用两个界面呈现,主界面和第二界面,Unity内容使用FrameLayout或LinearLayout显示,代码如下:

    MainActivity.java
    package com.my.unityapp;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
        private Button firstButton;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            firstButton = findViewById(R.id.firstButton);
            firstButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                    startActivity(intent);
                }
            });
        }
    }
    
    activity_main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.my.unityapp.MainActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="First Activity"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.032" />
    
        <Button
            android:id="@+id/firstButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:text="跳转到Unity界面"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView" />
    
    </android.support.constraint.ConstraintLayout>
    
    SecondActivity.java 基本就是仿照UnityPlayerActivity写的
    package com.my.unityapp;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.content.res.Configuration;
    import android.graphics.PixelFormat;
    import android.os.Bundle;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.Button;
    import android.widget.LinearLayout;
    
    import com.unity.demo.MyUnityPlayer;
    import com.unity3d.player.UnityPlayer;
    
    public class SecondActivity extends Activity {
    
        private LinearLayout unityLayout;
        private Button secondButton;
        private MyUnityPlayer mUnityPlayer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
    
            unityLayout = findViewById(R.id.unityLayout);
            secondButton = findViewById(R.id.secondButton);
            secondButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    SecondActivity.this.finish();
                }
            });
    
    
            getWindow().setFormat(PixelFormat.RGBX_8888); // <--- This makes xperia play happy
            // 创建Unity视图
            mUnityPlayer = new MyUnityPlayer(this);
            // 添加Unity视图
            unityLayout.addView(mUnityPlayer.getView());
            mUnityPlayer.requestFocus();
    
        }
    
        @Override protected void onNewIntent(Intent intent)
        {
            // To support deep linking, we need to make sure that the client can get access to
            // the last sent intent. The clients access this through a JNI api that allows them
            // to get the intent set on launch. To update that after launch we have to manually
            // replace the intent with the one caught here.
            setIntent(intent);
        }
    
        // Quit Unity
        @Override protected void onDestroy ()
        {
            mUnityPlayer.quit();
            super.onDestroy();
        }
    
        // Pause Unity
        @Override protected void onPause()
        {
            super.onPause();
            mUnityPlayer.pause();
        }
    
        // Resume Unity
        @Override protected void onResume()
        {
            super.onResume();
            mUnityPlayer.resume();
        }
    
        // Low Memory Unity
        @Override public void onLowMemory()
        {
            super.onLowMemory();
            mUnityPlayer.lowMemory();
        }
    
        // Trim Memory Unity
        @Override public void onTrimMemory(int level)
        {
            super.onTrimMemory(level);
            if (level == TRIM_MEMORY_RUNNING_CRITICAL)
            {
                mUnityPlayer.lowMemory();
            }
        }
    
        // This ensures the layout will be correct.
        @Override public void onConfigurationChanged(Configuration newConfig)
        {
            super.onConfigurationChanged(newConfig);
            mUnityPlayer.configurationChanged(newConfig);
        }
    
        // Notify Unity of the focus change.
        @Override public void onWindowFocusChanged(boolean hasFocus)
        {
            super.onWindowFocusChanged(hasFocus);
            mUnityPlayer.windowFocusChanged(hasFocus);
        }
    
        // For some reason the multiple keyevent type is not supported by the ndk.
        // Force event injection by overriding dispatchKeyEvent().
        @Override public boolean dispatchKeyEvent(KeyEvent event)
        {
            if (event.getAction() == KeyEvent.ACTION_MULTIPLE)
                return mUnityPlayer.injectEvent(event);
            return super.dispatchKeyEvent(event);
        }
    
        // Pass any events not handled by (unfocused) views straight to UnityPlayer
        @Override public boolean onKeyUp(int keyCode, KeyEvent event)     { return mUnityPlayer.injectEvent(event); }
        @Override public boolean onKeyDown(int keyCode, KeyEvent event)   { return mUnityPlayer.injectEvent(event); }
        @Override public boolean onTouchEvent(MotionEvent event)          { return mUnityPlayer.injectEvent(event); }
        /*API12*/ public boolean onGenericMotionEvent(MotionEvent event)  { return mUnityPlayer.injectEvent(event); }
    }
    
    activity_second.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="5dp"
        tools:context="com.my.unityapp.SecondActivity">
    
        <LinearLayout
            android:id="@+id/unityLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="8dp"
            android:layout_weight="10"
            android:orientation="horizontal"
            app:layout_constraintTop_toTopOf="parent"
            tools:layout_editor_absoluteX="104dp">
    
        </LinearLayout>
    
        <Button
            android:id="@+id/secondButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:layout_marginTop="8dp"
            android:layout_weight="1"
            android:text="退出当前页面"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/unityLayout"
            tools:layout_editor_absoluteX="154dp" />
    
    </LinearLayout>
    

    运行结果:

    Postscript


    • 还有Unity与Android的交互问题,网上教程很多,这里就不赘述了:
      Unity调用Android,通过 AndroidJavaClass、AndroidJavaObject;
      Android调用Unity,通过 UnityPlayer.UnitySendMessage()。

    相关文章

      网友评论

          本文标题:Android Studio项目集成Unity详细教程

          本文链接:https://www.haomeiwen.com/subject/vvueixtx.html