示例工程链接
基于你当前环境:Unity 2022.3.62f3c1 、Gradle 7.5.1 、AGP 7.4.2 、JDK 11 、compileSdk 33 、ARM64。按顺序做即可。
一、版本对照(先记住,避免踩坑)
| 组件 | 推荐版本 | 不要混用 |
|---|---|---|
| Gradle(Wrapper) | 7.5.1 | ≠ AGP 版本号(没有 7.5.1 的 AGP) |
| Android Gradle Plugin | 7.4.2 | ≠ 8.11(新版 Studio 默认) |
| Gradle JDK | 11(Unity 自带 OpenJDK) | 不用 8、不用 21 |
| compileSdk / targetSdk | 33(与 Unity 一致) | 不必追 API 37 |
| Unity 架构 | ARM64 | 真机调试优先 |
Unity OpenJDK 路径示例:
text
F:\UnityEditor\2022.3.62f3c1\Editor\Data\PlaybackEngines\AndroidPlayer\OpenJDK
Unity SDK 路径示例:
text
F:\UnityEditor\2022.3.62f3c1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK
二、Unity 侧(导出 unityLibrary)
1. Player Settings
Edit → Project Settings → Player → Android
- Package Name:按项目填写(可与宿主不同)
- Minimum / Target API:与宿主一致
- Scripting Backend :IL2CPP
- Target Architectures :与宿主一致(如 ARM64)
2. 导出工程
File → Build Settings → Android
- Switch Platform(若未切换)
- 勾选 Export Project
- Export ,输出到空目录,例如
F:\UnityExport\AndroidDemoExport
导出后重点目录:
text
AndroidDemoExport/
└── unityLibrary/ ← 整个拷贝到 Android 工程
├── libs/ ← 含 unity-classes.jar(必须有)
├── src/main/
└── build.gradle
3.(可选)自定义 Gradle 模板
若项目有 Assets/Plugins/Android/:
settingsTemplate.gradle:仓库顺序google()→mavenCentral()→gradlePluginPortal()- 根
gradle.properties需含:unityStreamingAssets=
三、Android Studio 侧(新建宿主工程)
1. 新建工程
- 模板:Empty Views Activity(或 Empty Activity)
- Language:Java
- Package :如
com.zg.MyTest - Minimum SDK:≥ Unity 的 Min SDK
2. 拷贝 unityLibrary
将 Unity 导出的 unityLibrary 整个文件夹 放到工程根目录,与 app 同级:
text
HostApp/
├── app/
├── unityLibrary/
├── build.gradle
└── settings.gradle
3. settings.gradle
gradle
include ':app'
include ':unityLibrary'
project(':unityLibrary').projectDir = new File(rootDir, 'unityLibrary')
4. 根 build.gradle / libs.versions.toml(AGP 版本)
AGP 必须是 7.4.2,不是 7.5.1、不是 8.11:
gradle
// build.gradle 示例
id 'com.android.application' version '7.4.2' apply false
id 'com.android.library' version '7.4.2' apply false
5. gradle-wrapper.properties

properties
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
(可改 file:///F:/Tools/gradle-7.5.1-bin.zip 使用本地 zip)
6. 工程根 gradle.properties
properties
org.gradle.jvmargs=-Xmx4096M
android.useAndroidX=true
android.enableJetifier=true
unityStreamingAssets=
org.gradle.java.home=F\:\\UnityEditor\\2022.3.62f3c1\\Editor\\Data\\PlaybackEngines\\AndroidPlayer\\OpenJDK
android.builder.sdkDownload=false
7. app/build.gradle
gradle
dependencies {
implementation project(':unityLibrary')
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
不要 使用过高的 activity:1.13+(会拉 navigationevent 等难解析依赖)。
如编译报错可以去掉部分代码

8. unityLibrary/build.gradle
- 确认有:
api fileTree(dir: 'libs', include: ['*.jar'])(api 不是 implementation,否则 app 找不到UnityPlayer)

-
删除
buildToolsVersion '34.0.0'(若 AGP 提示与 35 冲突) -
compileSdk/minSdk与 app 一致
9. Android Studio 设置
| 项 | 设置 |
|---|---|
| Gradle JDK | Unity OpenJDK 11(勿用 1.8 / 21) |
| Android SDK Location | 与 Unity 一致(Unity 自带 SDK 更稳) |
| 安装向导 | 选 Custom,不要装 Emulator、Build-Tools 37、API 37 |
| SDK | 保留 API 33 、Build-Tools 34.0.0 ;删掉本机 SDK 里的 android-36 、build-tools 35(若曾装过) |
四、Manifest(嵌入最关键)
1. unityLibrary/AndroidManifest.xml
-
删除
UnityPlayerActivity的MAIN+LAUNCHER(避免桌面进全屏 Unity 闪退)

-
UnityPlayerActivity可保留但exported="false",或最终在 app 里tools:node="remove"

-
嵌入时建议:
unity.launch-fullscreen= False

2. app/AndroidManifest.xml 要点
-
只有
MainActivity带 LAUNCHER -
MainActivity使用@style/UnityThemeSelector -
Application:
android:extractNativeLibs="true"

-
不要 在 app 里重复写与 unityLibrary 相同的 Unity
meta-data(会合并冲突)Unity meta-data 由 unityLibrary中 AndroidManifest.xml合并,勿在 app 重复声明
xml
<!-- Unity meta-data 由 unityLibrary 合并,勿在 app 重复声明 -->
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="notch_support" android:value="true" />
3. uses-feature
从 unityLibrary 合并或复制到 app:glEsVersion、vulkan、touchscreen 等。

五、资源与代码
1. unityLibrary 补充 strings.xml
路径:unityLibrary/src/main/res/values/strings.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="game_view_content_description">Game view</string>
</resources>
避免 UnityPlayer 初始化时 String resource ID #0x0。

2. 布局 activity_main.xml
app>src>main>res>layout>activity_main.xml
全部替换
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 上半:原生 UI(可改成按钮、列表等) -->
<TextView
android:id="@+id/native_title"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.55"
android:gravity="center"
android:text="这是原生 Android 区域"
android:textSize="20sp"
android:background="#EEEEEE" />
<!-- 下半:Unity 嵌入区域(指定位置 = 这块容器) -->
<FrameLayout
android:id="@+id/unity_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.45"
android:background="#000000" />
</LinearLayout>

3. MainActivity.java(嵌入核心)

要点:
- 继承
Activity(不要AppCompatActivity) requestWindowFeature(Window.FEATURE_NO_TITLE)在super.onCreate之前- 处理 Intent 的
unity命令行参数(与UnityPlayerActivity一致) new UnityPlayer(this, this)后addView到unity_container- 完整转发 生命周期:
onResume/onPause/onDestroy/onStart/onStop、onWindowFocusChanged、onConfigurationChanged、按键/触摸等(参考UnityPlayerActivity)
包名与目录一致,例如:package com.zg.MyTest; 对应 .../com/zg/MyTest/MainActivity.java。
完整代码,需替换安卓项目包名
csharp
package com.zg.Debug001;//你的包名
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.IUnityPlayerLifecycleEvents;
public class MainActivity extends Activity implements IUnityPlayerLifecycleEvents {
private UnityPlayer unityPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
String cmdLine = getIntent().getStringExtra("unity");
getIntent().putExtra("unity", cmdLine);
setContentView(R.layout.activity_main);
FrameLayout container = findViewById(R.id.unity_container);
unityPlayer = new UnityPlayer(this, this);
container.addView(
unityPlayer,
new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
);
unityPlayer.requestFocus();
}
@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
if (unityPlayer != null) {
unityPlayer.newIntent(intent);
}
}
@Override
protected void onDestroy() {
if (unityPlayer != null) {
unityPlayer.destroy();
}
super.onDestroy();
}
@Override
protected void onStop() {
super.onStop();
if (unityPlayer != null) {
unityPlayer.onStop();
}
}
@Override
protected void onStart() {
super.onStart();
if (unityPlayer != null) {
unityPlayer.onStart();
}
}
@Override
protected void onPause() {
if (unityPlayer != null) {
unityPlayer.onPause();
}
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
if (unityPlayer != null) {
unityPlayer.onResume();
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
if (unityPlayer != null) {
unityPlayer.lowMemory();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (unityPlayer != null) {
unityPlayer.configurationChanged(newConfig);
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (unityPlayer != null) {
unityPlayer.windowFocusChanged(hasFocus);
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_MULTIPLE && unityPlayer != null) {
return unityPlayer.injectEvent(event);
}
return super.dispatchKeyEvent(event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return unityPlayer != null ? unityPlayer.onKeyUp(keyCode, event) : super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return unityPlayer != null ? unityPlayer.onKeyDown(keyCode, event) : super.onKeyDown(keyCode, event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return unityPlayer != null ? unityPlayer.onTouchEvent(event) : super.onTouchEvent(event);
}
@Override
public void onUnityPlayerUnloaded() {
}
@Override
public void onUnityPlayerQuitted() {
}
}
六、编译与运行
- File → Sync Project with Gradle Files
- Build → Clean Project → Rebuild Project
- 终端验证(可选):
bat
cd F:\A_UTest
gradlew -version
应显示:Gradle 7.5.1 、JVM 11.x
- 手机 USB 调试 → 顶部选 app + 设备 → Run
- 每次改 Unity 场景后:Unity 重新 Export → 覆盖
unityLibrary→ 再 Rebuild
七、常见问题速查
| 现象 | 处理 |
|---|---|
| Java 21 + Gradle 7.5 不兼容 | Gradle JDK 改为 11 |
| AGP 7.5.1 找不到 | AGP 应为 7.4.2,不是 Gradle 版本号 |
unityStreamingAssets 报错 |
根 gradle.properties 加 unityStreamingAssets= |
UnityPlayer 找不到符号 |
api fileTree(libs) + 确认 unity-classes.jar 存在 |
navigationevent 解析失败 |
降低 AndroidX 版本,去掉 activity:1.13 |
| SDK XML v4 警告 | 删 API 36 / build-tools 35;用 Unity SDK;AGP 保持 7.4.2 |
| 要求下载 API 37 | 安装向导选 Custom 不装;SDK 指 Unity;勿追 37 |
桌面启动闪退 UnityPlayerActivity |
去掉 unityLibrary 的 LAUNCHER;app 只保留 MainActivity |
| Manifest 合并冲突 meta-data | 只在 unityLibrary 写 Unity meta-data,app 不重复 |
String resource ID #0x0 |
加 strings.xml;MainActivity 用 Activity + UnityThemeSelector ;加 unityplayer.UnityActivity meta-data |
| 黑屏无画面 | 检查生命周期是否转发给 unityPlayer |
| 模拟器不行 | Unity 用 ARM64 真机 |
八、推荐目录结构(最终)
text
A_UTest/
├── app/
│ ├── build.gradle ← implementation project(':unityLibrary')
│ └── src/main/
│ ├── AndroidManifest.xml ← 仅 MainActivity 为 LAUNCHER
│ ├── java/.../MainActivity.java
│ └── res/layout/activity_main.xml
├── unityLibrary/ ← Unity 导出,可整体覆盖更新
│ ├── libs/unity-classes.jar
│ ├── build.gradle ← api fileTree(libs)
│ └── src/main/AndroidManifest.xml ← 无 LAUNCHER
├── gradle.properties ← JDK 11、unityStreamingAssets
├── settings.gradle ← include unityLibrary
└── gradle/wrapper/ ← Gradle 7.5.1
九、流程总览(一张表)
| 步骤 | 位置 | 动作 |
|---|---|---|
| 1 | Unity | Player 设 Android / IL2CPP / API 33 |
| 2 | Unity | Build Settings → Export Project |
| 3 | AS | 新建 app 工程 |
| 4 | 磁盘 | 拷贝 unityLibrary 到工程根 |
| 5 | Gradle | 7.5.1 + AGP 7.4.2 + JDK 11 |
| 6 | Gradle | app 依赖 unityLibrary;unityLibrary api jars |
| 7 | Manifest | 仅 MainActivity 启动;去掉 Unity LAUNCHER |
| 8 | 代码 | MainActivity 嵌入 UnityPlayer + 生命周期 |
| 9 | 资源 | game_view_content_description + Unity 主题 |
| 10 | SDK | 使用 Unity SDK,不装 API 37 |
| 11 | 运行 | Sync → Rebuild → 真机 Run |
完整工程链接:https://pan.baidu.com/s/1GS8dVtry9wSkwl3NvJI0xg?pwd=vjwc