1.Unity 代码结构
由研发部门导出 Android Studio IDE可以识别的 Unity Module,手动进行依赖。代码结构同正常的Android Module 结构一致。
Unity module -
-build
-libs
-src
-main
-assets
-java
-jni
-res
AndroidManifest.xml
build.gradle
Gradle.properties
Local.properties
2.Unity通信
项目中Unity 与Android由两种方式进行交互
方式一:unity 调用Android代码
在主Activity中声明与unity端协调好的方法及接收参数的类型
Public void toAppXXX( 参数类型 参数名)
方式二:Android 调用unity代码,底层实现方式由unity-class.jar 这个jar包进行封装。
UnitySendMessage(“GuiCamera”,“UserDataForUnity”,parameter);
Tip:
Unity 与 android 通信的原则,需要双方通信之前开启与unity的链接,onResume(),退出当前界面同时及时停止通信onPause( )
3.Unity初始化及资源解压
首先创建UnityPlayer,该对象继承Framlayout,需要将该对象添加到ViewTree中进行渲染
FrameLayout unityFrameLayout = getView(R.id.unity);
UnityPlayer mUnityPlayer = new UnityPlayer(this);
unityFrameLayout.addView(mUnityPlayer)。
将mUnityPlayer的生命周期与Activity进行绑定
主要关注
- mUnityPlayer.resume(); //开启通信
- mUnityPlayer.pause(); //暂停通信
资源解压分为obb(海外),非obb。
- 包含obb的海外版本,需要加载obb之后解压
- 非obb的国内版,在初始化mUnityplayer之后,展示第一个场景自动解压资源。
4.快速编写具有通信能力的类
4.1 新建空白Activity,取名DemoActivity,并且在DemoActivity布局文件中添加一个Framlayout,作为mUnityPlay的容器。
<FrameLayout
android:id="@+id/unity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
4.2 在DemoActivity的onCreate()或者OnResume()生命周期中进行初始化。初始化方式:
Void onCreate(){
UnityPlayer mUnityPlayer = UnityPlayViewManager.getUnityPlay();
unityGameFrameLayout.addView(mUnityPlayer);
}
Tip:UnityPlayViewManager 是一个单例,存储管理全局唯一的UnityPlayer对象
4.3 . 完成通信能力关键,将UnityPlayer 的生命周期与Activity的生命周期进行绑定,通过下面模板代码进行绑定。
@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.destroy();
super.onDestroy();
}
// Pause Unity
@Override protected void onPause()
{
super.onPause();
mUnityPlayer.pause();
}
// Resume Unity
@Override protected void onResume()
{
super.onResume();
mUnityPlayer.resume();
}
@Override protected void onStart()
{
super.onStart();
mUnityPlayer.start();
}
@Override protected void onStop()
{
super.onStop();
mUnityPlayer.stop();
}
// 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); }
4.4 开启通信开关进行通信
这里用开始游戏地方的样例代码
if ( mUnityPlayer != null)
mUnityPlayer.resume() //打开开关
//向Unity 发送消息参数。
UnityHelper.roomDataForUnity(
mapId.toString(),
detailModel.mapName,
detailModel.mapMd5,
detailModel.mapScreenSchema.toString(),
detailModel.thumb270x153,
if (StringUtil.isEmpty(detailModel.mapCreateUserNickName)) "" else detailModel.mapCreateUserNickName)
//进入游戏
UnityHelper.enterGameForUnity()
4.5 关闭通信开关
override fun onPause() {
super.onPause()
if (isGameSwitch && mUnityPlayer != null) {
mUnityPlayer.pause() //在生命周期中关闭
}
}
Tips:
通信开关,一直处于开启状态,会造成界面卡顿。
5.Unity集成需要修改的文件
替换Unity最新导出的Unity_Module 中assert文件夹全部内容,进入Assert文件夹里面修改config.json,config_en.json,config_plat.json,config_versionType.json四个文件中相应的配置与对应环境匹配。
海外版。需要额外替换清单文件中unity.build-id对应的值value,否则会导致obb合成失败,app模块下,AndroidManifest.xml
<meta-data
android:name="unity.build-id"
android:value="5402c169-290b-44af-aa8a-378569ae6916" />
6.Unity通信步骤
1.进入新的activity,关闭上一个activity类中unity通信,将上一个类中mUnityPalyer对象移到新的activity中使用。(mUnityPalyer 全局唯一)
2.在新的activity中奖unity-player 对象添加到新的activity,unity容器中。
3.在新的activity中需要进行通信地方,调用unity-player.resume( ) 方法开启通信开关(这里会有延时)
4.进行unity通信,发送message给unity
5.在MainActivity中处理Unity对activity的响应信息,编写分发逻辑。(EvenBus 进行通知),将响应信息分发到发起通信的类中,进行处理
6.退出新的Activity,在onPause()中暂停消息。