UnityPlayerActivity:Android开发核心解析

文章摘要

本文介绍了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()

调用流程:

  1. onCreate
    • 初始化 UnityPlayer 实例(Unity 引擎的核心类)。
    • 设置 UnityPlayer 视图为 Activity 的内容视图。
    • 处理 intent、权限等初始化逻辑。
  2. onStart/onResume
    • 恢复 UnityPlayer 的渲染和音频等。
    • 通知 Unity 引擎应用已进入前台。
  3. onPause/onStop
    • 暂停 UnityPlayer 的渲染和音频。
    • 通知 Unity 引擎应用已进入后台。
  4. 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 的初始化与生命周期绑定

  • UnityPlayerActivityonCreate() 中实例化 UnityPlayer,并将其作为主视图。
  • UnityPlayer 内部会启动 Unity 引擎的 native 层(C++),并负责渲染、输入、音频等所有游戏主循环。
  • 生命周期方法(如 onResumeonPauseonDestroy)会直接调用 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 启动流程(系统调用栈)

  1. Launcher 发送启动 Intent
  2. AMS 检查进程是否存在,如无则 fork 新进程(zygote 派生)。
  3. ActivityThread.main() 启动主线程(UI 线程),创建 Application 实例。
  4. Instrumentation.newActivity() 反射创建 UnityPlayerActivity 实例。
  5. Activity.attach() 绑定 Context、Window、资源等。
  6. 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# 层性能

九、参考资料


<think>我们参考用户提供的引用内容,特别是引用[2]和引用[4],来解答如何自定义UnityPlayerActivity。自定义UnityPlayerActivity的目的是为了在Unity游戏启动前或启动后添加一些自定义的Android原生功能,比如启动动画、权限请求、第三方SDK初始化等。步骤概述:1.创建自定义的Activity类,继承自UnityPlayerActivity。2.重写Activity的生命周期方法(如onCreate, onResume等),在其中添加自定义逻辑。3.修改AndroidManifest.xml,将主Activity指向自定义的Activity。4.处理Unity导出的Android工程(或使用Unity的Plugins/Android目录结构)以确保自定义Activity被正确编译和打包。详细步骤:步骤1:创建自定义Activity类在Unity项目的Assets/Plugins/Android目录下(如果没有则创建),按照以下结构创建Java文件:Assets/Plugins/Android/java/com/yourcompany/yourapp/CustomUnityActivity.java在CustomUnityActivity.java中编写代码,例如:```javapackagecom.yourcompany.yourapp;import android.os.Bundle; importcom.unity3d.player.UnityPlayerActivity; publicclass CustomUnityActivityextends UnityPlayerActivity{@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//在这里添加自定义初始化代码,例如启动一个视频、请求权限等}@Overrideprotectedvoid onResume() {super.onResume();//自定义代码}} ```步骤2:修改AndroidManifest.xml在Assets/Plugins/Android目录下,创建或修改AndroidManifest.xml文件,将主Activity改为自定义的Activity类名。例如,原本的UnityPlayerActivity替换为CustomUnityActivity:```xml<activity android:name="com.yourcompany.yourapp.CustomUnityActivity"android:configChanges="...(保持原有配置)"...><intent-filter><action android:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter> </activity>```注意:如果之前有PrivacyActivity(如引用[3]所示)或启动动画(如引用[4]所示)等,可能需要调整启动顺序。步骤3:处理启动流程(可选)如果需要在Unity游戏启动前显示一个启动动画(如引用[4]所示),则可以采用以下方法:-创建一个新的Activity(如SplashActivity)作为启动Activity,在它的onCreate中播放动画,动画结束后跳转到自定义的UnityPlayerActivity(即CustomUnityActivity)。-在AndroidManifest.xml中,将SplashActivity设置为启动Activity,并将原来的CustomUnityActivity的LAUNCHER intent-filter移除。示例(参考引用[4]):1.创建SplashActivity: ```javapublic classSplashActivity extendsActivity {@Overrideprotectedvoid onCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//设置布局,播放视频或动画//在动画结束后跳转到CustomUnityActivityIntent intent= newIntent(this, CustomUnityActivity.class);startActivity(intent);finish();} }```2.修改AndroidManifest.xml,设置SplashActivity为启动Activity: ```xml<activityandroid:name=".SplashActivity"android:theme="@style/Theme.AppCompat.Light.NoActionBar"><intent-filter><actionandroid:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity> <activity android:name="com.yourcompany.yourapp.CustomUnityActivity"android:configChanges="..."><!--注意:这里移除了LAUNCHER的intent-filter --></activity> ```步骤4:构建Unity项目确保在导出APK或构建Android工程时,自定义的Activity和AndroidManifest.xml被打包进去。注意事项:-自定义Activity的包名和类名必须与AndroidManifest.xml中指定的完全一致。 -如果自定义Activity中需要访问Unity的类(如UnityPlayer),请确保包含Unity的classes.jar(通常Unity在构建时会自动处理,但如果是手动导出工程,需要将classes.jar添加到libs目录)。-如果遇到类找不到的错误,检查Unity的classes.jar是否在构建路径中。通过以上步骤,就可以成功自定义UnityPlayerActivity,并在其中添加所需的功能。引用说明:引用[2]提到了使用自定义Activity和Application,我们这里主要关注自定义Activity部分。引用[4]提供了一个启动动画Activity的例子,展示了如何从SplashActivity跳转到UnityPlayerActivity。相关问题: 1.如何解决自定义UnityPlayerActivity时的类找不到问题?2.如何在自定义UnityPlayerActivity中初始化Android原生插件? 3.如何为Unity游戏添加启动动画(Splash Screen)?</think>### 自定义 UnityPlayerActivity 完整步骤 根据引用内容[2][4],自定义 UnityPlayerActivity核心流程如下: #### 步骤 1:创建自定义 Activity 类 ```java // Assets/Plugins/Android/java/com/yourcompany/yourapp/CustomUnityActivity.java package com.yourcompany.yourapp; import android.os.Bundle; import com.unity3d.player.UnityPlayerActivity; public class CustomUnityActivity extends UnityPlayerActivity { @Override protected void onCreate(Bundle savedInstanceState) { // 先执行自定义逻辑 initSDK(); // 初始化第三方SDK showPrivacyDialog(); // 显示隐私协议 // 再调用父类初始化 super.onCreate(savedInstanceState); } @Override protected void onResume() { super.onResume(); // 添加自定义恢复逻辑 trackAppResume(); // 统计恢复事件 } private void initSDK() { // 初始化广告/分析等SDK } private void showPrivacyDialog() { // 显示GDPR/隐私协议对话框 } } ``` #### 步骤 2:修改 AndroidManifest.xml ```xml <!-- Assets/Plugins/Android/AndroidManifest.xml --> <application> <!-- 替换默认Activity --> <activity android:name="com.yourcompany.yourapp.CustomUnityActivity" android:exported="true" android:configChanges="..."> <!-- 保留MAIN和LAUNCHER --> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> ``` #### 步骤 3:处理启动流程(可选) 如需添加启动动画(参考引用[4]): ```java // SplashActivity.java public class SplashActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { // 播放启动动画 videoView.setOnCompletionListener(mediaPlayer -> { // 跳转到自定义Unity Activity startActivity(new Intent(this, CustomUnityActivity.class)); finish(); }); } } ``` #### 步骤 4:修改 Manifest 启动顺序 ```xml <activity android:name=".SplashActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.yourcompany.yourapp.CustomUnityActivity"> <!-- 移除LAUNCHER属性 --> </activity> ``` #### 关键注意事项 1. **继承关系**:必须继承 `UnityPlayerActivity`(引用[1][2]) 2. **生命周期调用**: ```java super.onCreate(savedInstanceState); // 必须调用! ``` 3. **类名一致性**: - Java 包路径:`com.yourcompany.yourapp` - Manifest 声明:完全一致 4. **Unity 库依赖**: - 包含 `classes.jar`(路径:`Unity安装目录/Editor/Data/PlaybackEngines/AndroidPlayer/Variations/mono/Release/Classes`) #### 典型应用场景 1. **隐私协议处理**(引用[3]): ```java if (!hasAgreedToPrivacyPolicy()) { startActivity(new Intent(this, PrivacyActivity.class)); } else { super.onCreate(savedInstanceState); } ``` 2. **启动动画**(引用[4]) 3. **SDK 初始化**: ```java AdManager.initialize(getApplicationContext()); ``` > **调试提示**:使用 `adb logcat` 查看日志,确保自定义 Activity 被正确加载[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值