UnityAndroid(2) Android加載Unity

目錄

一、Android加載Unity

1.1 Unity打包Android項目

1.2 Android加載Unity生成項目

1.3 加載Unity內容

二、Unity和Android交互

2.1 Unity發消息給Java

2.2 Android發消息給Unity


開發環境: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/

https://forum.unity.com/threads/integration-unity-as-a-library-in-native-android-app-version-2.751712/

感覺官方的教程不是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字符串的方式傳遞對象數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章