目录
开发环境:Unity2019.2.17f,AndroidStudio3.5.3,VS2019。
我要达到的功能是
1.在unity里面点击一个按钮,在Unity三维内容前面弹出一个窗口,显示Android内容。
2.在Android界面的一部分显示Unity的三维内容。
一、Android加载Unity
1.1 Unity打包Android项目
参考:Unity 工程 融合 AndroidStudio工程
Unity导出Android项目,AndroidStudio导入过程中提示了几个窗口
总之继续下去,打开项目。
下载SDK,能够正常导入了。
加入现在打包运行的话,看到的就是Unity程序了。
--------------------------------------------------------------------------
1.2 Android加载Unity生成项目
将刚刚导出的项目从application改成library,修改成类库。
根据错误提示把下面的bundle和applicationId注释掉
可以打包成aar文件了。
放入Android项目中的libs文件夹中
加入到项目中
Build后出现错误:Manifest merger failed with multiple errors, see logs
参考:https://blog.csdn.net/dengweijunkedafu/article/details/80541104
输入gradlew processDebugManifest --stacktrace,结果
总之把Unity导出项目里面的AndroidManifest.xml的<Application ...>里面的冲突的都删除了。
也就是前面教程中的
就像这样
可以Build了。
---------------------------------------------------------
1.3 加载Unity内容
接下来在Android界面中加载Unity的内容
private UnityPlayer mUnityPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("MainActivity","onCreate");
//initUnityPlayer();
Button btnInit=findViewById(R.id.btnInitUnity);
btnInit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("MainActivity","btnInit onClick");
initUnityPlayer();
}
});
}
private void initUnityPlayer() {
try {
Log.i("MainActivity","initUnityPlayer");
LinearLayout layout = findViewById(R.id.unityview);
mUnityPlayer = new UnityPlayer(this);
layout.addView(mUnityPlayer.getView());
mUnityPlayer.requestFocus();
}catch (Exception ex){
Log.e("MainActivity","Exception:"+ex);
}
}
运行测试的结果,initUnityPlayer放到onCreate或者onStart里面会闪退,而且没有提示。
加工按钮后,提示E/Unity: Failed to load 'libmain.so'
搜索E/Unity: Failed to load 'libmain.so',在百度上找不到相关资料,感觉它对于纯英文的比较无力....
libmain.so是Unity生成项目里面的
google到 https://forum.unity.com/threads/integration-unity-as-a-library-in-native-android-app.685240/
这个好像是Version1,还有个Version2
相关的还有:https://forum.unity.com/threads/using-unity-as-a-library-in-native-ios-android-apps.685195/
感觉官方的教程不是aar加载而是作为一个Model加载进来的。
另外,有个官方Demo:https://github.com/Unity-Technologies/uaal-example
按照这个
把Unity生成项目的ndk拷贝过来
ndk {
abiFilters 'armeabi-v7a'
}
结果,不崩溃了,但是还是出不来,那个要显示Unity的区域变成黑色了。
------------------------------------------------------------------------------------
经过研究、思考,理解UnityPlayer是什么,观察Unity打包项目的UnityPlayerActivity后,算是弄出来了。
把前面的initUnityPlayer放到onCreate中,同时把UnityPlayerActivity里面的其他Override方法都拷贝过来。
public class MainActivity extends AppCompatActivity {
private UnityPlayer mUnityPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("MainActivity","onCreate");
initUnityPlayer();
}
private void initUnityPlayer() {
try {
Log.i("MainActivity","initUnityPlayer");
LinearLayout layout = findViewById(R.id.unityview);
mUnityPlayer = new UnityPlayer(this);
layout.addView(mUnityPlayer.getView());
mUnityPlayer.requestFocus();
}catch (Exception ex){
Log.e("MainActivity","Exception:"+ex);
}
}
@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.
super.onNewIntent(intent);
setIntent(intent);
mUnityPlayer.newIntent(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();
}
。。。。。
拷贝过来后,onNewIntent会让你加个super.onNewIntent。
运行后,在预定的区域(一个LinearLayout里面)显示了Unity的内容了。
测试发现显示Unity内容是用mUnityPlayer.resume();,在requestFocus,马上resume的话,三维能够出来。按钮点击触发resume的话也能出来。
----------------------
直接继承UnityPlayerActivity其实就可以了
public class MainActivity extends UnityPlayerActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initUnityPlayer();
}
private void initUnityPlayer() {
try {
Log.i("MainActivity","initUnityPlayer");
LinearLayout layout = findViewById(R.id.unityview);
//mUnityPlayer = new UnityPlayer(this);
layout.addView(mUnityPlayer.getView());//UnityPlayerActivity里面已经new了
//mUnityPlayer.requestFocus();
}catch (Exception ex){
Log.e("MainActivity","Exception:"+ex);
}
}
}
-------------------------------------------
不过有发现,1.默认的标题栏不见了; 2.手机旋转时会崩溃退出。
第一个不是问题,第二个必须处理。
直接横屏再打开是可以的。
Unity导出项目,生成运行测试,旋转不会崩溃。
。。。。。
===============================================================
二、Unity和Android交互
参考:Unity与Android Studio交互,Unity 与 Android 互调用
2.1 Unity发消息给Java
public void ClickF()
{
Debug.Log("ClickF");
Count++;
Result.text = Count + "";
AndroidJavaClass jc = new AndroidJavaClass("com.example.myapplication.MainActivity");
AndroidJavaObject overrideActivity = jc.GetStatic<AndroidJavaObject>("instance");
int r=overrideActivity.Call<int>("UnityClick", Count);
Result.text += "|" + r;
}
Java中有相应的类->对象->方法,com.example.myapplication.MainActivity->instance->UnityClick。
public class MainActivity extends UnityPlayerActivity {
public static MainActivity instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
instance = this;
//...
}
@Override
protected void onDestroy() {
super.onDestroy();
instance = null;
}
public int UnityClick(int c){
return c+1;
}
}
2.2 Android发消息给Unity
// objectName: Unity 对象的名称
// methodName: Unity 对象绑定的脚本方法名
// message: 自定义消息
UnityPlayer.UnitySendMessage(String objectName, String methodName, String message);
Button btn=findViewById(R.id.btnInitUnity);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
UnityPlayer.UnitySendMessage("JavaInterface","ReceiveFromAndroid","abc");
}
});
同样的Unity中必须有相应的GameObject->Function
public class JavaInterfaceABC : MonoBehaviour
{
public void ReceiveFromAndroid(string a)
{
Debug.Log("ReceiveFromAndroid:" + a);
}
}
类名不重要,重要的GameObject的名称。
另外假如JavaInterface对象上有多个脚本有ReceiveFromAndroid方法,都会被调用一次的。
-----------
总的来说,和Unity(Webgl)与Html交互很像。
因此实际功能开发时打算也是做成单一入口,所有的交互都从一个接口进入、一个接口出去,用json字符串的方式传递对象数据。