【Unity與Android】01-Unity與Android交互通訊的簡易實現

前言

使用Unity也有不短的時間了,安卓包也打過很多,可是對Unity與Android的交互卻知之甚少。java

因工做需求,須要在Android平臺接一些sdk(擴展功能)。我就藉此機會瞭解了下Unity與Android交互的一些知識,並作了一個簡易實現。android

現將實現步驟記錄下來以供往後查閱。後端

1、開發準備

Unity、Android Stuido以及JDK安裝,這些都是基本操做了,網上也有不少教程,這裏不細述。app

本次開發所使用的軟件版本以下:ide

Android Studio 3.5學習

Unity 2018.3.10f1測試

Java 1.8.0191gradle

 

2、要實現的功能

要在unity項目中進行安卓功能擴展,有兩種方式:ui

一、Unity項目導出爲Android工程,而後在Android Studio(之後簡稱爲AS)中進行二次開發,添加擴展功能。這樣的方式開發起來很靈活,改動起來也很方便,可是就是很麻煩,由於每次改動都要打一回安卓工程。this

二、將擴展功能製做成Android庫文件(jar包),而後將jar包導入到Unity中,直接使用。這樣的方式,使用者沒法修改這個庫文件的功能,但也更便於使用 。

 

由於我將要作的功能可能會在團隊內傳播使用,也不須要每一個人都去作改動。所以選擇第二種方式。

因此本文的目的就是:

製做一個Android庫文件(jar包),而後在Unity中使用它。

3、如何製做Android庫文件

一、新建Android工程

 打開AS,新建一個Android工程,選擇Empty Activity,配置工程名稱、包名、位置以及語言,以下圖

 語言最好選Java,由於Java和C#的語法極爲類似,學習成本很低。

 

工程建立以後,默認顯示的是Android視圖下app的工程結構,以下圖。能看到在包名下有一個MainActivity.java的文件,這是安卓app的入口,不過這裏並不打算使用它,忽略便可。

 

二、建立一個Android Library 模塊

 選中app,而後右鍵,選Module,在Create New Module窗口中選擇 Android Library 

 

 填入Library name、Module name 、Package name以及Language後,點完成。

 這裏的Package name好像是能夠改的,沒必要和以前建立工程時徹底同樣(未驗證)。不過爲了少點事,仍是先保持一致吧。

 

 如今能夠看到,在工程中同時存在着app和mysdk模塊,它倆是平級存在的,而且都有本身的源碼目錄(com.letui.mysdk),以及清單目錄(manifests)。

 app部分能夠不用管了,後續只對mysdk模塊進行操做。

 

 三、引入Unity對接Android的庫文件 

  1)在unity的安裝目錄下件,找到一個名爲classes.jar的文件

  個人目錄爲 D:\Unity2018\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Classes

  2)而後將classes.jar粘貼到mysdk模塊的libs目錄下(須要將工程切換到project視圖)

  額外說明:

  在il2cpp目錄下也有一個名稱同樣的classes.jar文件,其目錄爲

   D:\Unity2018\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Development\Classes

  這兩個文件的選擇,與unity的Player Setting中腳本後端設置有關。以下圖

  

    腳本後端用哪一個就,就選哪一個目錄下的classes.jar

  3)選中剛粘貼的classes.jar文件,右鍵,選擇 Add as Library,出現一個彈窗口,默認選中mysdk模塊,直接點肯定

  而後,這個classes.jar文件就被引入到工程中了,展開三角,能夠看到以下三個模塊,其中就有com.unity3d.player。以下

  

 四、建立本模塊的Activity文件

  1)展開mysdk模塊下的src目錄,選中com.leitui.mysdk,而後右鍵,新建一個Activity,選擇Empty Activity,輸入Activity Name以及Package Name和Language,勾掉Generate Layout File, 完成。

 

 新建的SDKMainAcivity.java腳本,默認繼承自AppCompatActivity,並帶有一個onCreate方法,以下:

 

現將SDKMainActivity腳本內容修改成繼續自UnityPlayerActivity ,並添加兩個方法 UnityCallAndroid 和 AndroidCallUnity

UnityCallAndroid 用來接受Unity的調用,AndroidCallUnity用於向unity發起調用。具體代碼以下:

 1 package com.letui.mysdk;
 2 
 3 import androidx.appcompat.app.AppCompatActivity;
 4 
 5 import android.os.Bundle;
 6 import android.widget.Toast;
 7 
 8 import com.unity3d.player.UnityPlayer;
 9 import com.unity3d.player.UnityPlayerActivity;
10 
11 public class SDKMainActivity extends UnityPlayerActivity {
12 
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16     }
17 
18     //unity調用Android
19     public void UnityCallAndroid () {
20 
21         Toast.makeText(this,"unity調用android成功", Toast.LENGTH_LONG).show();
22 
23         AndroidCallUnity();
24     }
25 
26     //android調用unity
27     public void AndroidCallUnity () {
28 
29         //第1個參數爲Unity場景中用於接收android消息的對象名稱
30         //第2個參數爲對象上的腳本的一個成員方法名稱(腳本名稱不限制)
31         //第3個參數爲unity方法的參數
32         UnityPlayer.UnitySendMessage("receiveObj", "UnityMethod", "This is args.");
33     }
34 }

 

五、將模塊打包

  打包方法有兩種。

  一是手動進行構建,而後在Build/intermediates/packaged-classes/release目錄下找到相應的jar包(這個jar包默認名稱爲classes.jar,爲了區分,須要本身更名稱);

  二是用gradle命令。

  打開本模塊的build.gradle文件,在文件尾添加以下的一組命令。

//----------------這是一組將module導出爲jar的gradle命令-------------------
// mysdk爲自定義的jar包名稱
//task to delete the old jar
task deleteOldJar(type: Delete) {
    delete 'release/mysdk.jar'
}

//task to export contents as jar
task exportJar(type: Copy) {
    from('build/intermediates/packaged-classes/release/')
    into('release/')
    include('classes.jar')
    ///Rename the jar
    rename('classes.jar', 'mysdk.jar')
}

exportJar.dependsOn(deleteOldJar, build)
//---------------------------命令結束------------------------------

 這組命令的功能就是打包方法1的自動化版。

 build.gradle文件修改後,會提示要求同步,直接同步便可。同步結束,在IDE右上點開Gradle窗口,在other下找到exportJar命令。

 雙擊exportJar命令,等一會就會自動生成本模塊的jar文件了。

生成的文件位於mysdk/release/目錄下,以下圖

 

六、修改AndroidManifest.xml文件
  1)打開本模塊的AndroidManifest.xml文件,文件位於mysdk/src/main目錄下,以下圖:

  這個文件的內容,目前只有一對application標籤和activity標籤 

  刪掉這三行,將其內容修改成以下: 

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.letui.mysdk">
 4 
 5     <!-- 這個android:label設置後,unity中ProductName就不生效了,記得改這個-->
 6     <application android:label="MySDK">
 7 
 8         <!-- 這個android:name的值必須爲包名+類名-->
 9         <activity android:name="com.letui.mysdk.SDKMainActivity">
10             <intent-filter>
11                 <action android:name="android.intent.action.MAIN" />
12                 <category android:name="android.intent.category.LAUNCHER" />
13             </intent-filter>
14 
15             <!-- 這一行不能少,不然會閃退-->
16             <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
17         </activity>
18     </application>
19 
20 </manifest>

這其中有三個要注意的點,註釋中都有說明。修改完成後保存。

至此,在AS中的操做就結束了。

 

4、在unity中使用jar文件

一、新建一個Unity工程。

  a.新建一個Unity工程,在Assets目錄下新建Plugins/Android/bin目錄。

  b.將第三步修改的AndroidManifest.xml文件拷貝到Assets/Plugins/Android目錄下

  c.將第三步生成的mysdk.jar文件拷貝到Assets/Plugins/Android/bin目錄下

  完成以後文件結構圖以下:

    

  libs目錄用於存放其它android插件的jar文件,沒有也能夠不用建立。

 

 二、製做一個UI界面

 a.在SampleScene場景中建立一個Canvas,並建立一個名爲"receiveObj"的對象,在receiveObj之下再放一個按鈕和一個Text。

 按鈕用於觸發調用Android方法。

 Text用於顯示Android調用Unity方法傳遞來的參數。以下圖:

 這裏要注意,receiveObj的名稱必須與SDKMainActivity類的AndroidCallUnity方法中的UnityPlayer.UnitySendMessage方法的第一個參數保持一致。

  

 b.建立一個SDKTest.cs文件,將腳本掛在receiveObj對象上。以下: 

 

SDKTest腳本的內容以下: 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SDKTest : MonoBehaviour
{
    private AndroidJavaClass jc;
    private AndroidJavaObject jo;

    private Button btn;
    private Text text;

    private void Awake()
    {
        btn = transform.Find("Button").GetComponent<Button>();
        text = transform.Find("Text").GetComponent<Text>();

        //這兩行是固定寫法
        jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        jo = jc.GetStatic<AndroidJavaObject>("currentActivity");

        btn.onClick.AddListener(OnBtnClickHandler);
    }

    private void OnBtnClickHandler ()
    {
        //調用Android中的方法UnityCallAndroid
        jo.Call("UnityCallAndroid");
    }

    /// <summary>
    ///  被Android中AndroidCallUnity調用
    /// </summary>
    /// <param name="str"></param>
    public void UnityMethod(string str)
    {
        Debug.Log("UnityMethod被調用,參數:" + str);
        text.text = str;
    }
}

 其中必需要有UnityMethod方法,由於它在AndroidCallUnity方法中的UnityPlayer.UnitySendMessage的第二個參數已經指定了。若是不存在的話,調用就會出錯。

  jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  jo = jc.GetStatic<AndroidJavaObject>("currentActivity");

這兩句,一個是獲取到UnityPlayer類,一個是獲取到類的實例。
到於爲何這樣能取到我建立的模塊的SDKMainActivity的實例,還有待探究。反正目前這麼寫了就好了。

 三、打包並測試。

  在unity中設置Bundle Identifier和Company等信息以後,打一個apk包。

  安裝後運行,能正常顯示UI。

  點擊按鈕後,顯示了一個Toast,提示「Unity調用Android成功」,說明jar包中的UnityCallAndroid方法被調用。

  Unity->Android通訊成功

  同時屏幕上方的NewText被變動爲「This is args」,"This is args"是 AndroidCallUnity方法中傳遞給UnityMethod方法的參數。

  這表示Android->Unity通訊成功

  演示見下圖:

調用 前:,調用後: 

 

5、一點說明

一、模塊的包名和Unity的Bundle Identifier能夠不一致(至少在Module模式下,是能夠不一致的)。

說明:寫這條是由於其它相關文章全都要求兩邊保持一致,而若是模塊的包名要跟着Unity工程走,也太蛋疼了,因此驗證了下。

二、將AndroidManifest.xml引入到Unity以後,在unity中設置的Product Name就無效了。

須要在AndroidManifest.xml的application標籤中,添加android:label屬性來指定。

  

      初次接觸Android開發,以上內容若有錯誤,還請不吝指出。

 

  本文件所使用的Android工程和Unity工程源碼在此:安卓工程  Unity工程

相關文章
相關標籤/搜索