目錄
開發環境: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字符串的方式傳遞對象數據。