文章摘要
本文介绍了UnityPlayerActivity在Android平台下的核心作用,作为Unity游戏的主入口Activity,它继承自Android的Activity类并集成了Unity运行环境。文章详细解析了其主要生命周期方法(onCreate、onResume、onPause等)的调用流程,重点说明了UnityPlayer的初始化和资源管理机制。同时介绍了输入事件分发、Unity通信接口等关键技术点,并提供了常见扩展方案,如自定义Activity、SDK集成等。最后通过简化流程图直观展示了关键方法的调用关系,为开发者进行二次开发提供了清晰的指导。
下面详细介绍 UnityPlayerActivity 的主要方法调用流程:
1. 生命周期方法(Activity 生命周期)
UnityPlayerActivity 继承自 Activity,生命周期方法会被系统自动调用,主要包括:
onCreate(Bundle savedInstanceState)
onStart()
onResume()
onPause()
onStop()
onDestroy()
onRestart()
调用流程:
- onCreate
- 初始化 UnityPlayer 实例(Unity 引擎的核心类)。
- 设置 UnityPlayer 视图为 Activity 的内容视图。
- 处理 intent、权限等初始化逻辑。
- onStart/onResume
- 恢复 UnityPlayer 的渲染和音频等。
- 通知 Unity 引擎应用已进入前台。
- onPause/onStop
- 暂停 UnityPlayer 的渲染和音频。
- 通知 Unity 引擎应用已进入后台。
- onDestroy
- 销毁 UnityPlayer,释放资源。
2. 关键方法调用流程
onCreate(Bundle savedInstanceState)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUnityPlayer = new UnityPlayer(this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
- 创建 UnityPlayer 实例。
- 将 UnityPlayer 作为主视图。
- 请求焦点,准备接收输入事件。
onResume/onPause
@Override
protected void onResume() {
super.onResume();
mUnityPlayer.resume();
}
@Override
protected void onPause() {
mUnityPlayer.pause();
super.onPause();
}
- 恢复/暂停 UnityPlayer 的运行状态。
onDestroy
@Override
protected void onDestroy() {
mUnityPlayer.quit();
super.onDestroy();
}
- 退出 UnityPlayer,释放资源。
onActivityResult/onRequestPermissionsResult
- 处理外部 Activity 返回结果(如调用相机、文件选择等)。
- 处理权限请求结果。
onWindowFocusChanged
- 通知 UnityPlayer 焦点变化,影响输入和渲染。
onNewIntent
- 处理新的 Intent(如推送、深链等)。
3. 输入与事件分发
UnityPlayerActivity 会将输入事件(如触摸、按键、手势等)分发给 UnityPlayer:
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
return mUnityPlayer.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return mUnityPlayer.onTouchEvent(event) || super.onTouchEvent(event);
}
4. UnityPlayer 的作用
- UnityPlayer 是 Unity 引擎在 Android 上的桥梁,负责渲染、输入、生命周期管理等。
- UnityPlayerActivity 主要负责生命周期和事件的转发,绝大部分逻辑都在 UnityPlayer 内部。
5. 常见扩展点
- 自定义 Activity:可继承 UnityPlayerActivity,重写生命周期方法,插入广告、SDK 初始化等逻辑。
- 与 Unity 通信:通过
UnityPlayer.UnitySendMessage
向 Unity C# 发送消息。
6. 方法调用流程图(简化版)
onCreate
└─> new UnityPlayer
└─> setContentView(UnityPlayer)
└─> UnityPlayer.init
onResume
└─> UnityPlayer.resume
onPause
└─> UnityPlayer.pause
onDestroy
└─> UnityPlayer.quit
输入事件
└─> UnityPlayer.dispatchKeyEvent/onTouchEvent
7. 参考资料
总结:
UnityPlayerActivity 主要负责生命周期管理和事件分发,核心逻辑都在 UnityPlayer 内部。你可以通过继承和重写相关方法,实现自定义需求。实际开发中,常见的扩展点包括 SDK 初始化、权限处理、与 Unity 通信等。
下面将更深入地剖析 UnityPlayerActivity 的方法调用流程,包括其与 UnityPlayer 的交互细节、生命周期的特殊处理、与 Unity 引擎的通信机制、常见扩展点的实现方式,以及在实际项目中如何安全地自定义和扩展 UnityPlayerActivity。
一、UnityPlayerActivity 与 UnityPlayer 的深度交互
1. UnityPlayer 的初始化与生命周期绑定
- UnityPlayerActivity 在
onCreate()
中实例化UnityPlayer
,并将其作为主视图。 UnityPlayer
内部会启动 Unity 引擎的 native 层(C++),并负责渲染、输入、音频等所有游戏主循环。- 生命周期方法(如
onResume
、onPause
、onDestroy
)会直接调用UnityPlayer
的对应方法,确保 Unity 引擎状态与 Activity 状态同步。
关键代码片段
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUnityPlayer = new UnityPlayer(this);
setContentView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
UnityPlayer(this)
会初始化 JNI 层,启动 Unity 引擎主线程。setContentView(mUnityPlayer)
将 Unity 渲染视图嵌入 Activity。mUnityPlayer.requestFocus()
让 Unity 视图获得输入焦点。
2. 生命周期方法的特殊处理
- onPause()
- 调用
mUnityPlayer.pause()
,暂停渲染和音频,挂起 Unity 引擎主循环。 - 适用于切到后台、弹出系统对话框等场景。
- 调用
- onResume()
- 调用
mUnityPlayer.resume()
,恢复渲染和音频,唤醒 Unity 引擎主循环。
- 调用
- onDestroy()
- 调用
mUnityPlayer.quit()
,销毁 Unity 引擎,释放 native 层资源,防止内存泄漏。
- 调用
3. 输入事件的分发机制
- Activity 的输入事件(如触摸、按键、手势等)会优先传递给 UnityPlayer。
- UnityPlayer 负责将事件通过 JNI 传递到 Unity C# 层(如 Input 类)。
@Override
public boolean onTouchEvent(MotionEvent event) {
return mUnityPlayer.onTouchEvent(event) || super.onTouchEvent(event);
}
二、UnityPlayerActivity 与 Unity 引擎的通信机制
1. Java 调用 Unity(Java → C#)
- 通过
UnityPlayer.UnitySendMessage(String gameObject, String methodName, String message)
静态方法,将消息发送到 Unity C# 层的指定 GameObject。 - 典型用法:SDK 回调、原生事件通知 Unity。
示例:
UnityPlayer.UnitySendMessage("GameManager", "OnReceiveMessage", "Hello from Java");
2. Unity 调用 Java(C# → Java)
- 通过 AndroidJavaObject/AndroidJavaClass 反射调用 Java 方法。
- 典型用法:Unity 调用原生 SDK、系统功能。
示例:
using UnityEngine;
void CallJavaMethod() {
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
AndroidJavaObject activity = jc.GetStatic<AndroidJavaObject>("currentActivity");
activity.Call("yourJavaMethod", "param");
}
}
三、常见扩展点与安全自定义
1. 扩展 UnityPlayerActivity 的场景
- 集成第三方 SDK(如广告、支付、统计等)
- 处理特殊权限(如相机、存储、定位等)
- 自定义启动流程(如闪屏页、热更、资源预加载等)
- 处理系统事件(如深度链接、推送、外部唤起等)
2. 安全自定义的注意事项
- 必须调用父类方法
重写生命周期方法时,务必调用super.xxx()
,否则 UnityPlayer 可能无法正常工作。 - 事件分发要兼容 UnityPlayer
输入、权限、ActivityResult 等事件要优先传递给 UnityPlayer。 - 避免阻塞主线程
不要在生命周期方法中执行耗时操作,防止 ANR。
3. 典型扩展代码示例
public class MyUnityActivity extends UnityPlayerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化第三方SDK
MySDK.init(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 先交给 UnityPlayer 处理
mUnityPlayer.onActivityResult(requestCode, resultCode, data);
// 再处理自定义逻辑
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
mUnityPlayer.onRequestPermissionsResult(requestCode, permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
四、UnityPlayerActivity 的特殊场景处理
1. 多 Activity 切换
- Unity 项目默认只有一个 UnityPlayerActivity。如果需要多 Activity(如接入原生页面),建议:
- 切换到原生 Activity 时,暂停 UnityPlayer。
- 返回 UnityPlayerActivity 时,恢复 UnityPlayer。
2. 插件开发与热更
- 插件开发时,建议所有原生事件都通过 UnitySendMessage 传递到 Unity 层,由 C# 统一处理。
- 热更场景下,Activity 的生命周期管理尤为重要,防止资源未释放导致崩溃。
五、UnityPlayerActivity 源码结构(简要)
public class UnityPlayerActivity extends Activity {
protected UnityPlayer mUnityPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) { ... }
@Override
protected void onDestroy() { ... }
@Override
protected void onPause() { ... }
@Override
protected void onResume() { ... }
@Override
public boolean onTouchEvent(MotionEvent event) { ... }
@Override
public boolean dispatchKeyEvent(KeyEvent event) { ... }
// 其他事件分发和生命周期方法
}
六、调试与排查建议
- Logcat 日志:关注 UnityPlayerActivity 和 UnityPlayer 的日志输出,便于排查生命周期和事件分发问题。
- ANR/崩溃排查:确保所有生命周期方法都调用了 super,且无耗时操作。
- UnityPlayer 版本兼容:不同 Unity 版本的 UnityPlayerActivity 可能有差异,升级时需关注官方变更日志。
七、参考资料
下面将从安卓系统层面,深入讲解 UnityPlayerActivity 的调用流程,帮助你理解 Unity 游戏在 Android 平台的启动、生命周期管理、事件分发、与 native 层的交互等底层机制。
一、UnityPlayerActivity 启动流程(系统层面)
1. APK 安装与启动
- 用户点击 Unity 游戏图标,Launcher 通过 Intent 启动 AndroidManifest.xml 中声明的主 Activity(通常是 UnityPlayerActivity 或其子类)。
- Android 系统的 ActivityManagerService(AMS)负责创建进程、启动 Activity。
2. Activity 启动流程(系统调用栈)
- Launcher 发送启动 Intent
- AMS 检查进程是否存在,如无则 fork 新进程(zygote 派生)。
- ActivityThread.main() 启动主线程(UI 线程),创建 Application 实例。
- Instrumentation.newActivity() 反射创建 UnityPlayerActivity 实例。
- Activity.attach() 绑定 Context、Window、资源等。
- Activity.onCreate() 回调,进入 UnityPlayerActivity 的 onCreate。
二、UnityPlayerActivity 生命周期与 Unity 引擎的绑定
1. onCreate
- 系统调用 UnityPlayerActivity.onCreate()
- 你在 onCreate 里实例化 UnityPlayer,UnityPlayer 内部会:
- 加载 libunity.so(JNI 层,C++ 引擎核心)
- 初始化 EGL/OpenGL ES 渲染环境
- 启动 Unity native 主线程(C++ 层的游戏主循环)
- 通过 JNI 与 Java 层通信
2. onStart/onResume
- 系统调用 onStart、onResume
- UnityPlayer.resume() 恢复渲染、音频、输入
- 通知 native 层 Unity 引擎进入前台
3. onPause/onStop
- 系统调用 onPause、onStop
- UnityPlayer.pause() 挂起渲染、音频
- 通知 native 层 Unity 引擎进入后台
4. onDestroy
- 系统调用 onDestroy
- UnityPlayer.quit() 释放 native 层资源,销毁 C++ 引擎
三、输入事件分发流程(系统到 Unity)
1. 事件产生
- 用户触摸、按键、传感器等事件由 Linux 内核驱动产生,传递到 Android 的 InputManagerService。
2. 事件分发
- InputManagerService 将事件分发到当前前台 Activity 的 Window。
- Window -> ViewRootImpl -> UnityPlayer(继承自 SurfaceView)
3. UnityPlayer 事件处理
- UnityPlayer 重写 onTouchEvent、dispatchKeyEvent 等方法
- 事件通过 JNI 传递到 native 层(libunity.so)
- native 层将事件同步到 Unity C# 层(如 Input.GetTouch、Input.GetKey)
四、渲染流程(系统到 Unity)
1. Surface 创建
- UnityPlayer 继承自 SurfaceView,onCreate 时会创建 Surface。
- SurfaceFlinger 管理 Surface,负责合成最终画面。
2. EGL/OpenGL ES 初始化
- UnityPlayer 初始化 EGLContext,native 层通过 OpenGL ES 渲染到 Surface。
3. VSync/帧同步
- Android 系统通过 Choreographer/VSync 信号驱动渲染
- Unity native 层主循环根据 VSync 信号进行帧渲染
五、JNI 交互与线程模型
1. Java ↔ Native 交互
- UnityPlayerActivity/UnityPlayer 通过 JNI 调用 native 方法(如 UnityPlayer.nativeInit)
- native 层通过 JNI 回调 Java 方法(如 UnitySendMessage)
2. 线程模型
- Java 层主线程(UI 线程):负责 Activity 生命周期、输入事件分发
- Unity native 主线程:负责游戏主循环、渲染、物理、脚本等
- 其他线程:如音频、资源加载、网络等
六、特殊场景
1. 多 Activity 切换
- 切换到原生 Activity 时,UnityPlayerActivity.onPause(),UnityPlayer.pause()
- 返回时 onResume(),UnityPlayer.resume()
2. 插件与原生 SDK
- 插件通过 JNI 与 Unity 交互,需注意线程安全和生命周期同步
七、系统层面调用流程图(简化)
[用户点击图标]
↓
[Launcher 发送 Intent]
↓
[AMS 创建进程/Activity]
↓
[ActivityThread.main()]
↓
[Instrumentation.newActivity()]
↓
[UnityPlayerActivity.onCreate()]
↓
[UnityPlayer 初始化]
↓
[libunity.so 加载 & native 主线程启动]
↓
[SurfaceView 创建 Surface]
↓
[输入事件/渲染事件分发]
↓
[Unity native 层处理]
↓
[Unity C# 脚本响应]
八、调试建议
- adb logcat:查看系统、Unity、Activity 生命周期日志
- systrace/Perfetto:分析 Activity 启动、渲染、输入延迟
- StrictMode:检测主线程阻塞
- Unity Profiler:分析 native 层与 C# 层性能