(轉)SDK接入與整合——小白入門篇
閱讀目錄
回到頂部一、簡介
通常一款遊戲開發到後期,一般都會涉及到第三方SDK的接入與整合,對於不熟悉SDK接入的同學來說,接SDK每次都是雲裡霧裡,而熟悉SDK接入的同學又覺得不斷地重複做接入SDK工作這樣沒有成就感,太尼瑪無聊了(Android渠道一弄就十幾個,直接吐血)。其實通常情況下接入SDK都是很簡單的一個過程,本系列部落格就讓馬三和大家從小白開始,從零基礎開始學習如何接入SDK以及一些常見的SDK的接入流程。本系列部落格規劃為以下幾篇:
- SDK接入與整合——小白入門篇(介紹環境搭建以及Unity和Android的基本互動與呼叫)
- SDK接入與整合——信鴿SDK篇(介紹訊息推送框架--信鴿SDK的接入)
- SDK接入與整合——QQ與微信SDK篇(都是騰訊開放平臺的,就放在一起學了)
- SDK接入與整合——科大訊飛SDK篇(遊戲中的語音通訊和語音識別會用到此SDK)
- SDK接入與整合——百度地圖SDK篇(做LBS遊戲必不可少)
- SDK接入與整合——第三方SDK接入解決方案AnySDK篇
- SDK接入與整合——構建自己的Android整合多SDK框架篇
先挖了這麼多坑,以後慢慢填吧,放心博主肯定不會太監的。
回到頂部二、淺談常用的兩種接入方案
1.第三方SDK接入解決方案
其實遊戲SDK接入發展到現在,已經有很多成熟的第三方SDK接入解決方案了,比如AnySDK,ShareSDK,U8SDK等等。這些第三方SDK接入解決方案的整個接入過程,不改變任何SDK的功能、特性、引數等,對於最終玩家而言是完全透明無感知的。讓CP商能有更多時間更專注於遊戲本身的品質。第三方SDK包括了渠道SDK、使用者系統、支付系統、廣告系統、統計系統、分享系統等等。利用他們可以輕鬆快速接入第三方SDK。
第三方SDK的統一驗證流程基本如下:
2.手動接入SDK
既然上面說的第三方解決方案那麼好,為什麼我們還有手動去接入SDK呢?造輪子就這麼上癮?其實接入了一些第三方的SDK解決方案以後,我們有的遊戲資料是要經過他們的伺服器的,對於一些遊戲廠商來說,不想讓自己的資料經過別人的伺服器,或者需要對驗證伺服器有完全自主的控制權,那麼必然要手動接入各種SDK了。另外還有一些奇奇怪怪,非常詭異的SDK,我們也是要手動去接入的,不能都指望第三方的整合。而且作為一名合格的猿類來說,知其然更要知其所以然,掌握SDK的接入原理和過程很有必要。
回到頂部三、開始接入!Unity與Android的互動
前面囉嗦了那麼多,到這裡終於可以開始實戰操作了。
1.Android開發環境搭建
關於Android環境的搭建,網上已經有很多部落格了,介紹的很詳細,馬三就不在這裡水了。這裡給大家安利一個關於Android開發工具的好網站:http://www.androiddevtools.cn/。上面提供了很多可用的AndroidADK國內映象和教程。
2.Android端的開發工作
(1)開啟IDE建立一個空的Android庫工程,這裡我用Eclispe舉例。注意Min Required SDK最好選擇4.0以上,要不然還需要引入android-support-v7相容包,比較麻煩,之後我們可以把這個Min Required SDK 再該回來的。需要注意的兩步已經截圖了,剩下一路Next操作即可。注意包名和勾選Mark this project as a library選項。
(2)匯入Classes.jar包到Android工程中
Unity和Android做互動,他們兩個之間不認識肯定,沒法直接通訊,因此需要一箇中間的搭橋牽線的人,Classes.jar就起到了這個作用。Classes.jar是由Unity提供給我們的,我們需要找到它並且引入到我們的Android專案中。Claess.jar的路徑一般如下 X盤:\xxx目錄\Unity\Editor\Data\PlaybackEngines\androidplayer\release\bin\classes.jar(不同的計算機上,這個位置可能會有所不同,大家按照自己的路徑新增即可)。我們找到它直接拖到我們的Android工程的libs目錄下。然後在它上面右鍵,將其新增到Build Path中。
新增到Build Path成功以後,工程是這個樣子的。
(3)編寫Android端的程式碼
我們在Android端編寫一些程式碼,提供一些介面來供Unity一會的呼叫。開啟我們的MainActivity.java,然後新增程式碼。需要注意的是,讓我們的MainActivity繼承Jar包中的UnityPlayerActivity類,這樣,Unity才能調的到哦,缺什麼包,直接讓Eclipe自動導下包即可,快捷鍵ctrl+shift+o。對了,還需要把setContentView(R.layout.activity_main); 這段程式碼註釋掉,要不然會顯示Android的預設佈局檔案,上面就一個 Hello World。
簡單的寫了幾個普通方法和一個靜態方法,供一會的測試呼叫。(無論是靜態方法還是普通方法,在Unity中都是可以呼叫的到的)MainActicity.java的程式碼內容如下:
1 package com.mx.sdkbase; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.Menu; 6 import android.view.MenuItem; 7 import android.widget.Toast; 8 9 import com.unity3d.player.UnityPlayer; 10 import com.unity3d.player.UnityPlayerActivity; 11 12 public class MainActivity extends UnityPlayerActivity { 13 14 private static MainActivity instance; 15 16 @Override 17 protected void onCreate(Bundle savedInstanceState) { 18 super.onCreate(savedInstanceState); 19 // setContentView(R.layout.activity_main); 20 21 instance = this; 22 } 23 24 @Override 25 public boolean onCreateOptionsMenu(Menu menu) { 26 // Inflate the menu; this adds items to the action bar if it is present. 27 getMenuInflater().inflate(R.menu.main, menu); 28 return true; 29 } 30 31 @Override 32 public boolean onOptionsItemSelected(MenuItem item) { 33 // Handle action bar item clicks here. The action bar will 34 // automatically handle clicks on the Home/Up button, so long 35 // as you specify a parent activity in AndroidManifest.xml. 36 int id = item.getItemId(); 37 if (id == R.id.action_settings) { 38 return true; 39 } 40 return super.onOptionsItemSelected(item); 41 } 42 43 44 /** 45 * 供Unity呼叫的求和函式 46 * @param x 47 * @param y 48 * @return 49 */ 50 public int Sum(int x, int y) { 51 return x + y; 52 } 53 54 /**供Unity呼叫的比較最大值函式 55 * @param x 56 * @param y 57 * @return 58 */ 59 public int Max(int x, int y) { 60 return Math.max(x, y); 61 } 62 63 64 /**供Unity呼叫的顯示吐司的函式 65 * @param str 66 */ 67 public void MakeToast(String str) { 68 Toast.makeText(this, str, Toast.LENGTH_LONG).show(); 69 } 70 71 72 /**供Unity呼叫的自加一函式 73 * @param x 74 * @return 75 */ 76 public int AddOne(int x) { 77 return x + 1; 78 } 79 80 81 /**供Unity呼叫的靜態方法,單例類,返回當前的Activity物件 82 * @return 83 */ 84 public static MainActivity GetInstance() { 85 return instance; 86 } 87 88 89 /**供Unity呼叫的函式,此函式會回撥指定的一個Unity中的方法,完成資料的雙向互動 90 * @param str 91 */ 92 public void CallUnityFunc(String str){ 93 str=str+"Android Call Unity."; 94 String ReceiveObject="MessageHandler"; 95 String ReceiverMethod="Receive"; 96 UnityPlayer.UnitySendMessage(ReceiveObject, ReceiverMethod, str); 97 } 98 }
(4)匯出我們的Android專案為Jar包供Unity呼叫
在我們的專案上面右鍵,然後選擇Export,選擇Java目錄下的 Jar file。因為沒有用到第三方的jar包或者lib庫,因此只要勾選src/和res/目錄匯出為jar包即可。
(5)Unity端工程的開發
建立一個新的空Unity工程,然後在Asset/目錄下建立如下路徑的資料夾:Plugins/Android。從名字就可以看出來,這個資料夾是用來存放安卓的外掛的。然後將我們上面剛剛匯出的SDKBase.jar 包匯入到這個目錄下,並且將Andoird工程目錄下的,libs/ 、res/ 、AndroidMainFest.xml 都複製到該路徑下。
需要特別注意的是要將Unity 專案中 libs下的classes.jar檔案刪除掉,這個就是上面提到的那個起到中介作用的jar包,一定要刪掉!一定要刪掉!一定要刪掉!(重要的事情說三遍,網上不少教程都是針對Unity老版的教程,沒有提到要刪除這個classes.jar包,結果在Unity 5.x中打包肯定會出錯)。出錯截圖如下所示。
然後我們建立一個場景,簡單地在裡面放上一些Label和輸入框、按鈕,供我們驗證互動操作。並且編寫一個指令碼(MessageHandler.cs即是我建立的指令碼), 在其中編寫用來呼叫Jar包的C#方法,然後將按鈕和這些函式繫結(Unity基本操作,不贅述了)。
MessageHandler.cs 指令碼的內容如下,函式的功能看註釋就行了,寫得很全。
1 using System; 2 using UnityEngine; 3 using UnityEngine.UI; 4 5 public class MessageHandler : MonoBehaviour 6 { 7 private AndroidJavaClass _jc; 8 private AndroidJavaObject _jo; 9 10 public InputField inputFieldA; 11 public InputField inputFiledB; 12 public Text resultLabel; 13 14 // Use this for initialization 15 void Start() 16 { 17 //初始化 18 //"com.unity3d.player.UnityPlayer"和"currentActivity"這兩個引數都是固定的 19 //UnityPlayerActivity裡面對其進行了處理 20 _jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); 21 _jo = _jc.GetStatic<AndroidJavaObject>("currentActivity"); 22 } 23 24 public void AddOne() 25 { 26 int a = Convert.ToInt32(inputFieldA.text); 27 28 //注意,這裡使用的就不是之前預設的com.unity3d.player.UnityPlayer,而是需要傳入自己的類(實現了需要呼叫相應方法的類) 29 //因為預設的UnityPlayer中是沒有我們所需要的方法的,所以需要載入自己的類 30 AndroidJavaClass jc = new AndroidJavaClass("com.mx.sdkbase.MainActivity"); 31 //呼叫Java中的靜態方法,單例模式,返回當前Activity例項 32 AndroidJavaObject jo = jc.CallStatic<AndroidJavaObject>("GetInstance"); 33 resultLabel.text = "AddOne" + jo.Call<int>("AddOne",a); 34 } 35 36 public void Sum() 37 { 38 int a = Convert.ToInt32(inputFieldA.text); 39 int b = Convert.ToInt32(inputFiledB.text); 40 //呼叫Java類中的普通方法,返回值為int型 41 resultLabel.text = "Sum: " + _jo.Call<int>("Sum", a, b); 42 } 43 44 public void Max() 45 { 46 int a = Convert.ToInt32(inputFieldA.text); 47 int b = Convert.ToInt32(inputFiledB.text); 48 resultLabel.text = "Max: " + _jo.Call<int>("Max", a, b); 49 } 50 51 public void CallUnityFunc() 52 { 53 //呼叫Java中的一個方法,該方法會回撥Unity中的指定的一個方法,這裡會回撥Receive( ) 54 _jo.Call("CallUnityFunc","Unity Call Android.\n"); 55 } 56 57 public void Receive(string str) 58 { 59 resultLabel.text = str; 60 } 61 62 public void Toast() 63 { 64 _jo.Call("MakeToast","Unity 呼叫Toast"); 65 } 66 }
通過上面的程式碼,我們就可以看出來,想在Unity中呼叫Android的程式碼,主要涉及到了兩個類。AndroidJavaClass 和AndroidJavaObject 。這兩個類在Unity API手冊裡面有詳細的解釋。
下面的程式碼是獲取到對應包名的java.lang.Class例項,這裡獲取到的是com.unity3d.player.UnityPlayer類。
_jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
下面的程式碼是獲取到UnityPlayer類中的靜態欄位,它的返回值型別是AndroidJavaObject物件。
_jo = _jc.GetStatic<AndroidJavaObject>("currentActivity");
通過以上兩行程式碼,我們可以獲取到這個AndroidJavaObject 物件,然後用AndroidJavaObject 物件就可以任意地呼叫Android中的靜態和非靜態函數了。其中兩個函式中的字串引數 "com.unity3d.player.UnityPlayer" 和 "currentActivity" 都是固定的寫法,我們不用去改變。
AndroidJavaObject 類的一些常用方法及功能如下表所示:
AndroidJavaObject | 建構函式,根據類名返回AndroidJavaObject物件 |
Call | 呼叫Android程式碼中的非靜態方法 |
CallStatic | 呼叫Android程式碼中的靜態方法 |
Dispose | IDisposable 回撥 |
Get | 獲取Android程式碼中的非靜態欄位 |
GetRawClass | 獲取一個指向Java class的原始引用 |
GetRawObject | 獲取一個指向Java object的原始引用 |
GetStatic | 獲取Android程式碼中的靜態欄位 |
Set | 設定Android程式碼中的非靜態欄位 |
SetStatic | 設定Android程式碼中的靜態欄位 |
另外,我們還有第二種方法去訪問Java的程式碼,那就是利用我們之前在Java程式碼中寫的GetInstance() 靜態方法,它會返回一個MainActivity的例項,我們拿到這個例項以後,就能訪問裡面的方法和欄位了。需要注意的是此時的AndroidJavaClass建構函式中傳遞的字串就不是"com.unity3d.player.UnityPlayer" 了。而是要傳入自己的包名,比如程式碼中的 “com.mx.sdkbase.MainActivity” 。程式碼如下:
int a = Convert.ToInt32(inputFieldA.text); //注意,這裡使用的就不是之前預設的com.unity3d.player.UnityPlayer,而是需要傳入自己的類(實現了需要呼叫相應方法的類) //因為預設的UnityPlayer中是沒有我們所需要的方法的,所以需要載入自己的類 AndroidJavaClass jc = new AndroidJavaClass("com.mx.sdkbase.MainActivity"); //呼叫Java中的靜態方法,單例模式,返回當前Activity例項 AndroidJavaObject jo = jc.CallStatic<AndroidJavaObject>("GetInstance"); resultLabel.text = "AddOne" + jo.Call<int>("AddOne",a);
不止Unity可以呼叫Android的程式碼,Android也可以反過來回調Unity的程式碼。下面這段程式碼就是用來回調Unity函式的:
/**供Unity呼叫的函式,此函式會回撥指定的一個Unity中的方法,完成資料的雙向互動 * @param str */ public void CallUnityFunc(String str){ str=str+"Android Call Unity."; String ReceiveObject="MessageHandler"; String ReceiverMethod="Receive"; UnityPlayer.UnitySendMessage(ReceiveObject, ReceiverMethod, str); }
利用UnityPlayer.UnitySendMessage(ReceiveObject, ReceiverMethod, str); 就可以返回過來回調一個Unity中的方法,完成Unity和Android的雙向通訊。其中第一個引數是接受該回調的gameobject名稱,第二個引數是掛載在該gameobject上面的一個指令碼中接受該訊息的方法,最後一個引數是本條訊息傳送的字串資訊。比如上面例子中的程式碼就會呼叫名稱為MessageHandler的gameobject上面掛載的指令碼中的Receive方法。
(6)打包釋出Android平臺的APK
程式碼寫好以後,我們會習慣性地在Unity Editor 裡面執行檢視一下效果,但是如果要呼叫 Android 程式碼的話,是不可以這樣做的,一定要在真機上執行(模擬器上也行),在Editor中執行會報錯的。所以我們還是打包釋出到Android端檢視效果吧。
在Unity中按快捷鍵 ctrl +b ,開啟Build Setting介面,然後把平臺切換為 Android 平臺並將我們的測試場景加到Build Setting佇列中。點選PlayerSetting,對工程的資訊進行配置。注意要把裡面的Company Name和Product Name修改成和包名一致。如下圖所示:
然後 ,Bundle Identifier的值也要修改成和包名一樣,並且調整下Minimum API Level。如下圖:
最後,還記得我們在最一開始建立Android庫工程的時候,將最小安裝需求的API調成了4.0嗎,這就意味著,打出來的APK包安裝執行的最低系統要求是Android 4.0。這樣肯定是不可以的,要考慮到低版本的Android系統。因此還需要做最後一步的修改,才能打包。
找到我們Unity專案中的AndroidManifest.xml 檔案,用文字編輯器開啟它,將android:minSdkVersion的值修改成上一步在面板中設定的Minimum API Level 對應的版本號,比如我這裡面的Minimum API Level 為2.3.3,其版本號為 10。
之後,我們就可以放心地打包了,打包成功後安裝到手機上測試下效果,下面是我在模擬器上測試的幾張效果圖:
可以看到Unity成功地呼叫到了Android中的方法,並返回正確的結果,而且Android反過來也回調了Unity中的方法。
回到頂部四、結語
關於“SDK接入與整合的小白入門篇”就寫到這裡了,通過本篇部落格,我們一起初步地瞭解和學習了一下Unity和Android是如何互動的。下篇部落格,我們將會實戰地練習一下“訊息推送框架”信鴿SDK的接入與使用,敬請期待!
最後放上本篇部落格中演示的專案原始碼:
Github地址:https://github.com/XINCGer/Unity3DTraining/tree/master/SDK/SDKBase 歡迎fork!