Unity3D與Android通信


Unity3D與Android平台通信

  分為兩種,一種導入jar包,一種是導入aar包。

jar包方式

什么是jar包

  jar包的全稱是Java Archive File,它是一種壓縮文件格式,和zip格式兼容,與zip格式不同的是它包含一個META/INF/MANIFEST.MF的清單文件,這個是jar包生成過程中自動創建的,非常的關鍵,主要是用來設置執行入口類和支持庫的路徑,比如:

Manifest-verion:1.0
Class-Path:./lib/msbase.jar	./libs/mysql.jar
Created-By:1.6.0(sun Microsystem inc.)
Main-Class: HelloWorld

  其中Class-Path比較容易被忽略,它的作用是用來設置支持庫的路徑。上述例子中當前目錄下lib文件夾中的幾個jar包都能被運行時找到。關於這塊內容的一個簡單解釋可參考:https://blog.csdn.net/Jungle_hello/article/details/51235331

  jar包中的主要類容是類文件,還有其他的文件,比如jsp文件,html文件,圖片等,所以簡單的來說jar包就是把你寫的代碼打包成的一個壓縮文件。

jar包的作用

  jar包的一個用途就是作為程序使用,但和平時我們理解的二進制程序不同,這個程序是使用運行時解釋執行的,執行這種程序的命令通常為:java xxx.jar,而另一個用途就是代碼重用,即把我們自己寫的代碼打包成一個jar包給他人使用。具體的使用教程可自行google。

  那在Unity3D中我們如何導入jar包呢?首先我們先使用android studio創建一個jar包。

創建jar包

  android studio中默認打包成aar包,如果想要eclipse打包jar包的功能,需要自己定制。

  首先使用默認的模板創建一個新工程,在工程中右鍵項目New-》Module

  選擇Android Library


  設置模塊名稱后和最低支持android SDK版本后,直接finish。若果創建之后想刪除則右鍵項目-》Open Module setting,選擇模塊

 

 

  創建好模塊之后,接下來我們有個可選的步驟,就是添加外部的jar包,我們先介紹最簡單的不引用其它jar包的方法。首先添加一個新類,方法是切換到android視圖,右鍵該模塊下java文件夾中第一個子文件夾,選擇new-》class,填寫類名稱后確定即可。

  新建的類中我們填寫一個簡單的方法,代碼如下:

package com.androidaddin.androidlib;
import android.util.Log;
public class Helper {
public static String HelloWorld()
{
return “hello world”;
}
}

 

  之后我們構建模塊,如圖:

 

  這樣的話我們會生成一個aar的包,把aar包解壓(直接把后綴改為zip),我們可在其中找到classes.jar的包,這個jar包即我們想要的jar包。
  除此之外,可以自己寫gradle的方法,自定義生成jar包,方法是打開module中的build.gradle文件,添加如下方法:

//添加生成jar的方法
task buildJar(type:Jar){
baseName'lib' //jar包命名
from('build/intermediates/classes/debug/com/example/administrator/myapplication')
into('com/example/administrator/myapplication')
exclude('BuildConfig.class','R.class') //去除無用的資源類及build資源類文件
exclude{it.name.startsWith('R$');}
}
//添加清除jar包的方法
ask cleanJar(type:Delete){
delete'build/libs/lib.jar'
}
//將library的build任務和clean的任務添加到jar包的大包任務之前:
buildJar.dependsOn(cleanJar,build);
//取消打包過程中的錯誤檢查打斷:
android{
lintOptions{
abortOnErrorfalse
}
}

參考網址:https://www.jianshu.com/p/756693ee7e6e

向Unity3D中導入jar包

  新建Unity3D工程,添加Plugins/Android的文件夾,把我們生成的classes.jar(文件名不一定是classes)文件添加到這個文件夾中,然后新建一個腳本,在start中添加如下方法:

void Start()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.xin.yichen.unitytest.utest"))
{
string content = jc.CallStatic<string>("HelloWorld");
Text t = GetComponentInChildren<Text>();
t.text = content;
Debug.Log(content);
}
} 

  然后在場景中添加一個Text(右鍵->create->UI->Text),把這個方法掛在Canvas物體上,保存,然后發布到手機運行即可(因為jar包需要java運行時來執行,在editor中運行獲取android對象,所以執行會報錯)。

  但在Unity3D中,我們需要的不是這么簡單的一些功能(這些功能我們完全可以使用c#中實現),而是與android當前顯示unity3d渲染內容的activity通信,這個怎么做呢?在這里需要一個關鍵的jar包——Unity3D打包的一個jar包。我們需要把這個jar包引入到我們的模塊中,接下來我們就來看看如何把一個jar包引入到我們的模塊當中。
首先找到Unity3D的jar包,其位置在:

(Win path) unity3d的安裝路徑\Unity\Editor\Data\PlaybackEngines\androidplayer\bin\classes.jar

(Mac path) Unity.app(show packages)Applications\Unity(rightclick ShowPackageContent)PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar

 

  復制這個jar到模塊的libs文件夾下,然后右鍵jar包-》add as library。

  這樣即導入了jar包,結果如下圖所示。

 

  這個jar中包含了Unity3D針對Android平台封裝的UnityPlayerActivity的類,這個類我們接下來要關注的類。
首先我們切換到Android視圖,右鍵模塊下java文件夾下的第一個字文件夾-》new-》activity-》Empty Active,創建一個空Acitivity。然后讓它繼承UnityPlayerActivity類,同時刪除布局代碼和布局文件(不需要)。

 

  刪除布局代碼和布局文件

 


  然后添加我們的方法。比如這里我們添加了一個add的方法來計算兩個數的和。之后我們就還剩下一個工作,修改AndroidMenifest.xml文件。
我們可以簡單的把工程下的androidmanifest.xml拷貝過來,修改。標為紅色的表示錯誤,我們把它刪除,包名和App的名字按你自己的需求設置。在activity標簽中最后添加一行:<meta-data android:name="unityplayer.UnityActivity" android:value="true" />。
  修改后如下圖:

   然后選擇build-》make module “xxx”,會生成aar包。在這里可以有兩種方式提取jar包,第一種還是把aar包解壓了,提取其中的classes.jar、libs、res文件夾。需要注意的是,這一次我們引用了Unity3D的jar包並繼承了它,所以不能像之前一樣簡單的把classes.jar放入Plugins/Android下,不然會報:D8: Program type already present: com.unity3d.player.Camera2Wrapper的錯誤,也就是重復文件。這個問題產生的原因也很簡單,就是Unity3D發布APK的時候走的還是Android發布的那一套,gradle或ant,不管哪一種,它都引用了之前我們拷貝的那個classes.jar這個jar包,也可以簡單的理解為Unity3D會生成一個android工程,然后使用gradle或這ant發布,而Unity3D會把這個jar包放入這個工程的libs這個文件夾下。而如果我們在Unity3D中添加了Plugins/Android文件夾的話,它也會把這個文件夾合並到工程中。所以如果把classes.jar直接放到Plugins/Android下,就會造成工程目錄下有一個classes.jar,libs下也就一個classes.jar,重復文件問題就出現了。解決辦法很簡單,把外層的classes.jar挪到libs下替換到原先的classes.jar(這個classes.jar其實就是Unity3D的那個,所以我們用自己新的這個替換它),然后把libs、res、AndroidManifest.xml拷貝到Plugin/Android下即可。  

  這里還有一個要注意的地方是AndroidManifest.xml包名的修改,要求拷貝到Plugin/Android的AndroidManifest.xml的包名要與Unity3D發布時的包名一致,即下圖中的package name。

 


  這里如果使用Android模塊的包名發布出錯的話,可以考慮換個包名,但要保證AndroidManifest.xml中的包名和這里的一致。
  在Unity3D中新建腳本,代碼如下:

void Start()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
Text t = GetComponentInChildren<Text>();
t.text = jo.Call<int>("add",10,10).ToString();
}
} 

  Unity3D中通信我們可以簡單的使用其封裝的AndroidJavaClass和AndroidJavaObject兩個類來操作,它們是對JNI操作的封裝,想了解細節的話可以到Unity3D的官方文檔查閱。
其實這里也可以不用解壓aar,自己拼一個jar出來。首先我們在Android Studio中切換到Project視圖,進入模塊目錄下的src/main文件夾下,復制res和AndroidManifest.xml文件,然后到模塊目錄下build/intermediates/packaged-classes下找到libs和classes.jar,同樣的拷貝外層的這個classes.jar放入libs文件中,然后把這個libs連同之前的res和AndroidManifest.xml導入Unity3D中即可。
  在改AndroidManifest.xml之后可能會遇到一個問題,app莫名的崩潰。原因是activity名稱路徑不對,我拷貝工程的AndroidManifest.xml內容修改之后的結果如下:

 


  activity的名稱是”.MainActivity”,這個“.”表示包名,也就是說如果我的包名是com.xxx.unitytest,則它會被解釋為”com.xxx.unitytest.MainActivity”,如果我們沒有更改包名,這個是沒有問題的,如果我們在Unity3D的AndroidManifest.xml修改了包名,則Activity會找不到入口類,所以崩潰。解決方案,在這里使用全名即可。
這個問題的出現是因為對AndroidManifest.xml不了解,所以我們簡單的來了解一下AndroidManifest.xml。
  AndroidManifest.xml可以理解為應用程序和Android系統之間的接口,任何一個應用程序都有這個文件。它用來向系統描述應用程序的信息。比如一個典型的AndroidManifest.xml內容如下:

   其中uses-sdk標簽說明應用程序需要的android sdk的版本,Application標簽是關於應用程序的詳細信息,如Android:icon表示應用程序的圖標,Android:label表示應用程序的顯示名稱,android:theme表示使用的UI主題,activity標簽表示活動,其屬性android:name表示activity的類名,intent-filter表示活動的意圖,action的名稱設置為android.intent.action.MAIN表示這個活動被設置為應用程序的入口,category設置為”android.intent.category.LANUCHER”表示應用程序可通過設備啟動器的圖標來啟動。

aar包方式

  導入aar包和導入jar包的流程一樣,不一樣的只是aar包和jar包。我們先了解一下aar包和jar包的區別,主要的區別就是aar包可以附帶資源文件,比如圖片和res中的所有文件。

創建aar包

  創建aar包的過程已在jar包的創建過程中介紹,即Android Studio默認就是創建aar包,我們新建模塊后直接build->make module xxx即可。aar包可在模塊目錄下(project視圖)outputs/aar下找到。

Unity3D導入aar包

  在拷貝aar包之前,還需要處理一下這個aar包,即把libs外的classes.jar諾到libs里替換libs里的那個classes.jar。在window下可以使用解壓軟件打開aar包,直接操作,在mac下,需要修改aar包的后綴為zip,然后解壓,修改后再使用zip命令或者jar命令再次打包為aar包

zip –r path/my-aar-lib.aar ./*
jar cvf my-aar-lib –C ./ .    

  與使用jar包流程中的操作一樣修改AndroidManifest.xml,讓后把aar包和AndroidManifest.xml寶貝到Plugins/Android中即可。Unity3D的調用代碼相同。

Android向Unity3D發送消息

  Android向Unity3D發送消息使用UnityPlayer的UnitySendMessage即可,示例:

UnityPlayer.UnitySendMessage("Main Camera","messgae",edit.getText().toString());

  其中第一個參數“Main Camera"是Unity3D場景的物體,“message”是方法,后面的是傳給這個方法的參數。我猜測這個UnitySendMessage的方法是調用了Unity3D中GameObject.SendMessage的方法。

結語

  Unity3D與Android通信的重點就是要理解jar包和aar包的原理和Unity3D中如何合並工程中Plugins/Android文件夾中的內容,jar包和aar包可以理解為代碼庫,而Unity3D對於Plugins/Android文件夾中內容的合並就是替換,即使用用戶的Android代碼庫和資源替換Unity3D默認的代碼庫(classes.jar、AndroidManifest.xml),理解這兩個再來看它們之間的通信就顯得不那么神秘了。

 

參考資料:

https://blog.csdn.net/u010377179/article/details/53105062

https://blog.csdn.net/ChinarCSDN/article/details/80012456

https://xinyustudio.wordpress.com/2015/12/31/step-by-step-guide-for-developing-android-plugin-for-unity3d-i/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM