Unity 与 Android/iOS 交叉开发主要有两种方式,以 Android 为例,一是 Android 生成 jar 或者 aar 包,导入到 unity3d plugin/bin/ 目录下;二是 Unity 导出 Android 工程,在 Android Studio 中作为库继续开发。网上的教程几乎全是第一种方式,而本文主要分析第二种方式。

这种方式可以在移动端的 NativeApp 中以,库的形式集成已经写好的 Unity 工程,利用 Unity 游戏引擎便捷的开发手段进行跨平台开发。

Unity官方文档 Unity as a Library integration example to iOS and Android

以下以安卓平台作为示例。

环境

  • Android Studio 3.5.3
  • Unity version 2019.3.7f1

新建工程

  • Android Studio 新建项目:
  • Unity 新建项目:
  • 最终工程结构如下:

Unity导出

  • 通过 Unity 打开 UnityProject

  • 选择 File -> Build Settings -> Switch Android Platform -> Export Project

  • 这时候选择Export可能会提示JDK路径配置出错,没关系我们到 Preference -> Externl Tools 设置路径

  • 现在就可以点击 Export 了,路径选择可以自由选择,这里建议按照官方来

Android接入

  • 通过 Android Studio 打开 NativeAndroidApp

  • 选择 setting.gradle 文件添加 unityLibrary module

    include ':unityLibrary'project(':unityLibrary').projectDir = new File('..\\UnityProject\\androidBuild\\unityLibrary')
  • 选择 build.gradle(Module:app)添加 dependencies

    dependencies {    implementation project(':unityLibrary')    implementation fileTree(dir: project(':unityLibrary').getProjectDir().toString() + ('\\libs'), include: ['*.jar'])    // 自己项目的配置}
  • 选择 build.gradle(Module:NativeAndroidApp)

    allprojects {    repositories {        google()        jcenter()        // Add Code        flatDir {            dirs "${project(':unityLibrary').projectDir}/libs"        }        // End    }}
  • 选择 NativeAndroidApp 的 strings.xml 添加

        NativeAndroidApp    Settings    // Add Code    Game view    // End
  • 点击 AS 的 sync project,可以看到已经多了一个 module:


    现在我们可以直接使用这个 module 里的 java class 了。

如何使用

作为Activity

现在我们的工程包含了两个 module ,一个是新建工程自带的 app,一个是刚才导入的 unityLibrary。点开 unityLibrary 的目录可以看到两个主要的 class :

其中 UnityPlayerActivity 是最重要的 class ,我们可以通过这个类在安卓 app 中显示 Unity 的场景。至于怎么使用—— OverrideUnityActivity 则是对 UnityPlayerActivity 用法的一个官方示例,里面的代码也很简单

import com.unity3d.player.UnityPlayerActivity;public abstract class OverrideUnityActivity extends UnityPlayerActivity{    public static OverrideUnityActivity instance = null;    abstract protected void showMainActivity(String setToColor);    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        instance = this;    }    @Override    protected void onDestroy() {        super.onDestroy();        instance = null;    }}

显然官方是希望我们在安卓内用一个 Activity 去显示 Unity 渲染的场景,至于这个 Activity ,直接继承 UnityPlayerActivity 就基本完事了,非常简单。

那么我们新建一个 Activity,这里我起名为 MainUnityActivity:

public class MainUnityActivity extends UnityPlayerActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }}

你大可什么都不写,只要继承 UnityPlayerActivity 就行了。现在构建 app,进入 MainUnityActivity 的时候就会显示 Unity 的场景了。

作为subView

当然你可能需要将 Unity 的场景作为子视图显示,而不是让 Unity 占据你的整个屏幕,这套简单方法就不适合了,不过仍然有解决方案,参考 Display Unity Scene as Sub View in android studio 。

我们先来观察 UnityPlayerActivity 里面到底写了什么:

public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents{    protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code    // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player    // The command line arguments are passed as a string, separated by spaces    // UnityPlayerActivity calls this from 'onCreate'    // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan    // See https://docs.unity3d.com/Manual/CommandLineArguments.html    // @param cmdLine the current command line arguments, may be null    // @return the modified command line string or null    protected String updateUnityCommandLineArguments(String cmdLine)    {        return cmdLine;    }    // Setup activity layout    @Override protected void onCreate(Bundle savedInstanceState)    {        requestWindowFeature(Window.FEATURE_NO_TITLE);        super.onCreate(savedInstanceState);        String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity"));        getIntent().putExtra("unity", cmdLine);        mUnityPlayer = new UnityPlayer(this, this);        setContentView(mUnityPlayer);        mUnityPlayer.requestFocus();    }    ......}

其实关键就在于这几行

protected UnityPlayer mUnityPlayer;    ......mUnityPlayer = new UnityPlayer(this, this);setContentView(mUnityPlayer);//←

我们只要照猫画虎的把 UnityPlayer 写进一个 FrameLayout 里就行了:

private UnityPlayer mUnityPlayer;protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // Create the UnityPlayer    mUnityPlayer = new UnityPlayer(this);    setContentView(R.layout.activity_sub);    FrameLayout layout = (FrameLayout) findViewById(R.id.FrameLayout);        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);    layout.addView(mUnityPlayer.getView(), 0, layoutParams);    }

这样下来 UnityActivity 就能显示在一个 FrameLayot 里了。

简单通信

互调函数的通信方法和安卓打包进 Unity 工程是一样的。

Android调用Unity

//向unity发消息UnityPlayer.UnitySendMessage("Main Camera", //gameobject的名字                             "ChangeColor", //调用方法的名字                             "");//参数智能传字符串,没有参数则传空字符串

Unity调用Android

//通过该API来实例化java代码中对应的类AndroidJavaObject jc = new AndroidJavaObject("com.xxx.xxx.UnityPlayer");jo.Call("Test");//调用void Test()方法jo.Call("Text1", msg);//调用string Test1(string str)方法jo.Call("Text2", 1, 2);//调用int Test1(int x, int y)方法

进阶用法

举个例子,Unity中有很多内置插件可以自动操控摄像头,编译到移动平台时,使用这些插件可以满足大部分场景,不需要额外编程,直接在 Unity 做好后打包就可以了。但是当你需要以下应用场景:

  • 检测摄像头视频数据中的人脸
  • 自定义美颜(CPU美颜算法)

的时候,使用Unity内置或扩展插件就难以完成这个任务了。这时候,就需要 Unity 和移动平台交叉开发,比如以下这套流程

Android/iOS native app 操作摄像头 -> 获取视频流数据 -> 人脸检测或美颜 -> 传输给 Unity 渲染 -> Unity做出更多的效果(滤镜/粒子)

但是由于 UnitySendMessage 只能把字符串传入 Unity,用这个API传入视频流到 Unity 是不可能的,效率太差。比较好的解决方案就是 Render to texture。

之后会发一篇安卓和 Unity 线程共享 eglcontext 的博客,视频流数据传输就会用到 Render to texture 的方法,先占个坑位。

参考资料:

  • AAR plug-ins and Android Libraries

  • JAR plug-ins

  • Extending the UnityPlayerActivity Code

  • Native (C++) plug-ins

  • Using Java and Kotlin source files as plug-ins

  • Unity as a Library

  • Unity into Android API

  • Unity into Android Step Details

  • Display Unity Scene as Sub View in android studio

更多相关文章

  1. [转]Android的Camera架构介绍[有图]
  2. Android(安卓)开发工程师面试指南
  3. Android打包jar 和使用第三方库
  4. 构建Android电话相关的应用
  5. Android(安卓)面试题
  6. Android(安卓)studio删除工程项目
  7. android手把手教你开发launcher(一)(AndroidStudio版)
  8. android 图形底层实现
  9. Android的Camera架构简介

随机推荐

  1. android 自动换行布局
  2. Android隐藏程序及调用
  3. Android之开源中国客户端源码分析(二)
  4. Android快速上手
  5. Layout1.3
  6. android 骁龙相机预览宽度方向全屏
  7. Android(安卓)抽屉导航
  8. Android(安卓)5.1 SDK下载与配置
  9. Android(安卓)系统级应用守护进程
  10. 最新Android(安卓)ADT, SDK, SDK_tool等