最近由于工作需要,研究unity如何接入Google Play以实现游戏内购买。目前IAB的实现,prime31做的插件比较好,各平台的IAB均有,但费用相对过高(几乎都是70刀左右,可怜穷小子)。在blogspot上找到仅有的一篇相关文章,特此转载在这以供大家相互交流学习。由于编程基础较差加上没学过java,按照该作者的方法暂时没有实现,希望看到此文章的程序猿们共同探讨解决方案。以下是文章原文:
底下是 Unity 介接 Google Play In-app Billing (IAB) 金流的步驟,使用的環境是 OSX,IAB 是 V3 版 :
其中 -cp 指示編譯時參考之 library (android-10, Android 2.3.3)。編譯完成後輸入 :
jar cvfM ./iiabs.jar com/
產生的 iiabs.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
注意要刪除資料夾 com,以免後續執行 jar 時,打包到舊的 com package。
2. 編譯 class IabHelper
a. 此類別由九個檔案組成,方便用來介接 Google IAB,九個 java 檔案應該位於前步驟下載之程式碼的 marketbilling/v3/src/com/example/android/trivialdrivesample/util 底下。
b. 逐一修改九個檔案裡的 "package com.example.android.trivialdrivesample.util" 改為你的 package name,例如 package com.macaronics.iab.util。
c. 建立欲編譯的檔案的 list,在 Terminal 底下的話直接輸入 cat > sources 然後依序輸入九個檔案檔名後按 control+d 儲存離開。
其中 @sources 表示參考檔案 sources 裡的路徑。此外,引入的 library 除了 android-10/android.jar (Android 2.3.3) 外,還包含前一步驟所編譯的檔案 iiabs.jar。完成後接著輸入 :
jar cvfM ./iabhelper.jar com/
產生的 iabhelper.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
3. 處理 onActivityResult 的結果訊息
a. 為了讓 IabHelper 能在 Activity 結束時處理 Activity 的結果,這裡我們需要自己撰寫繼承 UnityPlayerActivity 的類別來將結果 Relay 給 IabHelper。底下是範例的程式碼 :
其中函數 registerOnActivityResultCBFunc 只能記憶單一個 call back function,讀者可以把功能擴充成使用佇列來記憶更多的 call back function。
b. 同樣的編譯這個 class :
javac ./overrideActivity.java -cp /Users/macaronics/android-sdks/platforms/android-10/android.jar:/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/bin/classes.jar -d .
其中引入的 library 有 android-10/android.jar (Android 2.3.3),及 Unity 的 classes.jar。然後輸入 :
jar cvfM ./overrideActivity.jar com/
產生的 overrideActivity.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
4. 撰寫 iabWrapper.java
a. 主要用於介接 IabHelper 及 Unity ,提供基本的下單功能。程式碼分別敘述如下 :
值得注意的是這裡引入 UnityPlayer,步驟2編譯的 IabHelper (com.macaronics.iab.util),及步驟3編譯的 overrideActivity (com.macaronics.iab.overrideActivity)。
底下是 class iabWrapper 的私有變數部分 :
其中 mEventHandler 是回呼 Unity 時,接收訊息的 GameObject 名稱。此 class 有一個 Constructor 函數,三個成員函數及兩個給 IabHelper 回呼的函數,分別敘述如下 :
Constructor 函數在呼叫時給予 GooglePlay API PublicKey (由 GooglePlay 提供),以及回呼 Unity 時,接收訊息的 GameObject 之名稱 :
其中的 UnitySendMessage 用來呼叫 Unity GameObject 之函數 "msgReceiver", 並傳送字串訊息 (JSON 格式)。此外值得注意的是此 Constructor 函數還向 overrideActivity 註冊用來接收 onActivityResult 訊息的回呼函數。底下的dispose 函數主要用於釋放 mHelper :
purchase 函數會啟動購買商品的介面,其中第一項參數是 Product SKU (在 GooglePlay 設定的產品 SKU),第二項是回呼 onActivityResult 函數時用來分辨購買動作的 reqCode,第三項是用來確認此筆講買是否合法的 payloadString (購買成功之後, GooglePlay 回覆的資訊裡會包含此字串。)。
底下是完成購買之後回呼的函數 (onIabPurchaseFinished),這裡把接收的資訊以 JSON 格式轉送給 Unity :
產品在購買 (Purchase) 之後若再次購買則會失敗,在 Console 裡可以看到 "Item already owned" 訊息。若產品的類型屬於消耗性的產品,則需要執行 consume 指令才可再次購買 :
其中參數 itemType 在此範例為 "inapp",jsonPurchaseInfo 及 signature 是在 purchase 完成後, IabHelper 回呼 onIabPurchaseFinished 所給的資料。consume 完成之後回呼的函數如下 :
b. 編譯 iabWrapper.java
javac ./iabWrapper.java -cp /Users/macaronics/android-sdks/platforms/android-10/android.jar:/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/bin/classes.jar:/Users/macaronics/UnityIabProj/Assets/Plugins/Android/iabhelper.jar:/Users/macaronics/UnityIabProj/Assets/Plugins/Android/overrideActivity.jar -d .
其中引入的 library 有 android-10/android.jar (Android 2.3.3), Unity 的 classes.jar,先前編譯的 iabhelper.jar 及 overrideActivity.jar。然後輸入 :
jar cvfM ./iabWrapper.jar com/
產生的 iabWrapper.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
5. 設定 Permission ( AndroidManifest.xml )
若要執行 GooglePlay Billing 功能則要設定 AndroidManifest.xml,將底下的 AndroidManifest.xml 置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android 資料夾。
注意其中的 package="com.macaronics.iab" 要改成你自己的 package 名稱,與 Unity 裡的 Bundle Identifier 相同。此外,這裡還設定了主要啟動的 Activity 為 overrideActivity,以及 uses-permission。
到目前為止 /Users/macaronics/UnityIabProj/Assets/Plugins/Android 資料夾底下應該會有這些檔案 (iabhelper.jar, iabWrapper.jar, iiabs.jar, overrideActivity.jar, AndroidManifest.xml ) :
6. Unity 部分的 iabWrapper.cs
利用 AndroidJNI 介接 Java 程式 (注意為了接收 java 回傳的字串訊息,此 script (component) 必須加入到名為 iabWrapper 的 GameObject 裡)。 :
其中 init 負責呼叫 iabWrapper.java 之建構函數並建立該物件,dispose 則是負責刪除釋放 iabWrapper.java 物件。底下是主要的兩個功能,purchase 和 consume :
其中先將 callback 函數記錄起來,然後呼叫其對應的 java function。最後一部分是 msgReceiver,負責接收 java 回呼的結果並將資訊回呼對應的 callback function (先前呼叫 purchase 或是 consume 所給予的 callback function)。
程式碼先將 JSON 字串轉為 object 物件並依照物件種類做對應的處理,其中 purchase 的 callback (case 2),回傳的參數依序為 : 1. 是否成功,2. purchase 結果字串以及 3. purchase 結果之 signature (可作為驗証之用,參考
這篇)。
7. 實作 IAB APP
建立一個 script 名為 main,並將此 script 加入至 Camera。這裡實作一個 purchase 功能,並在 purchase 完成之後立刻執行 consume。
其中的 PUBLIC_KEY,更換成你的 Public Key,代入 purchase 函數的參數更改成你的參數。範例原始碼可以從這裡取得 : http://github.com/phardera/unity3d_googleplay_iab.git
unity playforward
1. 編譯 IInAppBillingService.java
a. 按照 GooglePlay 官方網站的指示 (
http://developer.android.com/training/in-app-billing/preparing-iab-app.html) 產生此檔案,其實這是一個自動產生的檔案,詳細方法可以參考連結網頁敘述。此外值得注意的是,程式碼也可以由 git 從此處下載 :
git clone https://code.google.com/p/marketbilling/
(附註 : 也許現在已經更新了,但文章撰寫的當下,若是從 SDK Manager 勾選 Google Play Billing Library 下載的版本有 Bug,所以才由 git 下載。 ref :
http://stackoverflow.com/questions/14397343/google-play-in-app-billing-version-3-crash-on-item-already-owned-and-missing )
git clone https://code.google.com/p/marketbilling/
(附註 : 也許現在已經更新了,但文章撰寫的當下,若是從 SDK Manager 勾選 Google Play Billing Library 下載的版本有 Bug,所以才由 git 下載。 ref :
http://stackoverflow.com/questions/14397343/google-play-in-app-billing-version-3-crash-on-item-already-owned-and-missing )
b. 編譯 IInAppBillingService.java,指令如下 (此處假設
android sdk 之資料夾路徑在 /Users/macaronics/android-sdks/) :
javac ./IInAppBillingService.java -cp /Users/macaronics/android-sdks/platforms/android-10/android.jar -d .
其中 -cp 指示編譯時參考之 library (android-10, Android 2.3.3)。編譯完成後輸入 :
jar cvfM ./iiabs.jar com/
產生的 iiabs.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
注意要刪除資料夾 com,以免後續執行 jar 時,打包到舊的 com package。
2. 編譯 class IabHelper
a. 此類別由九個檔案組成,方便用來介接 Google IAB,九個 java 檔案應該位於前步驟下載之程式碼的 marketbilling/v3/src/com/example/android/trivialdrivesample/util 底下。
b. 逐一修改九個檔案裡的 "package com.example.android.trivialdrivesample.util" 改為你的 package name,例如 package com.macaronics.iab.util。
c. 建立欲編譯的檔案的 list,在 Terminal 底下的話直接輸入 cat > sources 然後依序輸入九個檔案檔名後按 control+d 儲存離開。
![](http://3.bp.blogspot.com/-huIEKI285dQ/UV6V9owQknI/AAAAAAAAD9E/YOzKLq_wOFM/s320/catsources.jpg)
在 terminal 底下利用 cat 建立 sources file
d. 編譯 class IabHelper,輸入指令如下 :
javac @sources -cp /Users/macaronics/android-sdks/platforms/android-
10/android.jar:/Users/macaronics/UnityIabProj/Assets/Plugins/Android/iiabs.jar
其中 @sources 表示參考檔案 sources 裡的路徑。此外,引入的 library 除了 android-10/android.jar (Android 2.3.3) 外,還包含前一步驟所編譯的檔案 iiabs.jar。完成後接著輸入 :
jar cvfM ./iabhelper.jar com/
產生的 iabhelper.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
3. 處理 onActivityResult 的結果訊息
a. 為了讓 IabHelper 能在 Activity 結束時處理 Activity 的結果,這裡我們需要自己撰寫繼承 UnityPlayerActivity 的類別來將結果 Relay 給 IabHelper。底下是範例的程式碼 :
package
com.macaronics.iab;
import
com.unity3d.player.UnityPlayerActivity;
import
android.os.Bundle;
import
android.util.Log;
import
android.content.Intent;
public
class
overrideActivity
extends
UnityPlayerActivity {
public
interface
cbEvent{
public
boolean
cbEvent(
int
requestCode,
int
resultCode, Intent data);
}
protected
cbEvent ie;
static
protected
overrideActivity inst;
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
inst =
this
;
// print debug message to logcat
Log.d(
"overrideActivity"
,
"onCreate called!"
);
}
@Override
public
void
onDestroy(){
super
.onDestroy();
inst =
null
;
Log.d(
"overrideActivity"
,
"onDestroy called!"
);
}
@Override
public
void
onActivityResult(
int
requestCode,
int
resultCode, Intent data){
Log.d(
"overrideActivity"
,
"onActivityResult called!"
);
boolean
ret =
false
;
if
(ie !=
null
){
try
{
ret =ie.cbEvent(requestCode, resultCode, data);
}
catch
(Exception e){
ret =
false
;
}
}
if
(ret ==
false
){
super
.onActivityResult(requestCode, resultCode, data);
}
}
static
public
void
registerOnActivityResultCBFunc(
final
cbEvent pcbfunc){
if
(inst !=
null
)
inst.ie =pcbfunc;
}
}
|
b. 同樣的編譯這個 class :
javac ./overrideActivity.java -cp /Users/macaronics/android-sdks/platforms/android-10/android.jar:/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/bin/classes.jar -d .
其中引入的 library 有 android-10/android.jar (Android 2.3.3),及 Unity 的 classes.jar。然後輸入 :
jar cvfM ./overrideActivity.jar com/
產生的 overrideActivity.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
4. 撰寫 iabWrapper.java
a. 主要用於介接 IabHelper 及 Unity ,提供基本的下單功能。程式碼分別敘述如下 :
package
com.macaronics.iab;
import
com.unity3d.player.UnityPlayer;
import
android.app.Activity;
import
android.util.Log;
import
android.os.Bundle;
import
android.os.Looper;
import
android.content.Intent;
import
java.util.*;
import
com.macaronics.iab.util.*;
import
com.macaronics.iab.overrideActivity;
|
底下是 class iabWrapper 的私有變數部分 :
public
class
iabWrapper{
private
Activity mActivity;
private
IabHelper mHelper;
private
String mEventHandler;
...
|
Constructor 函數在呼叫時給予 GooglePlay API PublicKey (由 GooglePlay 提供),以及回呼 Unity 時,接收訊息的 GameObject 之名稱 :
public
iabWrapper(String base64EncodedPublicKey, String strEventHandler){
mActivity =UnityPlayer.currentActivity;
mEventHandler =strEventHandler;
if
(mHelper !=
null
){
dispose();
}
mHelper =
new
IabHelper(mActivity, base64EncodedPublicKey);
mHelper.enableDebugLogging(
true
);
mHelper.startSetup(
new
IabHelper.OnIabSetupFinishedListener() {
public
void
onIabSetupFinished(IabResult result){
if
(!result.isSuccess()){
//回呼 Unity GameObject 之函數 "msgReceiver", 並傳送字串訊息 (JSON 格式)
UnityPlayer.UnitySendMessage(mEventHandler,
"msgReceiver"
,
"{\"code\":\"1\",\"ret\":\"false\",\"desc\":\""
+result.toString()+
"\"}"
);
dispose();
return
;
}
//回呼 Unity GameObject 之函數 "msgReceiver", 並傳送字串訊息 (JSON 格式)
UnityPlayer.UnitySendMessage(mEventHandler,
"msgReceiver"
,
"{\"code\":\"1\",\"ret\":\"true\",\"desc\":\""
+result.toString()+
"\"}"
);
//register mHelper
//向 overrideActivity 註冊 onActivityResult 回呼函數,並將資料 Relay 給 mHelper
overrideActivity.registerOnActivityResultCBFunc(
new
overrideActivity.cbEvent(){
public
boolean
cbEvent(
int
requestCode,
int
resultCode, Intent data)
{
if
(mHelper.handleActivityResult(requestCode, resultCode, data)){
return
true
;
}
else
{
return
false
;
}
}
}
);
}
});
}
|
public
void
dispose()
{
if
(mHelper !=
null
)
{
mHelper.dispose();
}
mHelper =
null
;
}
|
public
void
purchase(String strSKU, String reqCode, String payloadString)
{
int
intVal =Integer.parseInt(reqCode);
if
(mHelper !=
null
)
mHelper.launchPurchaseFlow(mActivity, strSKU, intVal, mPurchaseFinishedListener, payloadString);
}
|
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener =
new
IabHelper.OnIabPurchaseFinishedListener() {
public
void
onIabPurchaseFinished(IabResult result, Purchase purchase) {
if
(result.isFailure()){
UnityPlayer.UnitySendMessage(mEventHandler,
"msgReceiver"
,
"{\"code\":\"2\",\"ret\":\"false\",\"desc\":\"\",\"sign\":\"\"}"
);
return
;
}
boolean
ret =
false
;
String result_json =
""
;
String result_sign =
""
;
if
(purchase !=
null
){
ret =
true
;
result_json =purchase.getOriginalJson().replace(
'\"'
,
'\''
);
result_sign =purchase.getSignature();
}
UnityPlayer.UnitySendMessage(mEventHandler,
"msgReceiver"
,
"{\"code\":\"2\",\"ret\":\""
+ret+
"\",\"desc\":\""
+result_json+
"\",\"sign\":\""
+result_sign+
"\"}"
);
}
};
|
public
void
consume(String itemType, String jsonPurchaseInfo, String signature)
{
String transedJSON =jsonPurchaseInfo.replace(
'\''
,
'\"'
);
if
(mHelper ==
null
)
return
;
Purchase pp =
null
;
try
{
pp =
new
Purchase(itemType, transedJSON, signature);
}
catch
(Exception e){
pp=
null
;
}
if
(pp !=
null
){
final
Purchase currpp =pp;
mActivity.runOnUiThread(
new
Runnable(){
public
void
run(){
mHelper.consumeAsync(currpp, mConsumeFinishedListener);
}
});
}
}
|
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
new
IabHelper.OnConsumeFinishedListener() {
public
void
onConsumeFinished(Purchase purchase, IabResult result) {
if
(result.isSuccess()){
Log.d(
"iabWrapper"
,
"Consumption successful. Provisioning"
);
UnityPlayer.UnitySendMessage(mEventHandler,
"msgReceiver"
,
"{\"code\":\"3\",\"ret\":\"true\",\"desc\":\""
+purchase.getOriginalJson().replace(
'\"'
,
'\''
)+"\
",\"sign\":\""
+purchase.getSignature()+
"\"}"
);
}
else
{
UnityPlayer.UnitySendMessage(mEventHandler,
"msgReceiver"
,
"{\"code\":\"3\",\"ret\":\"false\",\"desc\":\"\",\"sign\":\"\"}"
);
}
}
};
|
b. 編譯 iabWrapper.java
javac ./iabWrapper.java -cp /Users/macaronics/android-sdks/platforms/android-10/android.jar:/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/bin/classes.jar:/Users/macaronics/UnityIabProj/Assets/Plugins/Android/iabhelper.jar:/Users/macaronics/UnityIabProj/Assets/Plugins/Android/overrideActivity.jar -d .
其中引入的 library 有 android-10/android.jar (Android 2.3.3), Unity 的 classes.jar,先前編譯的 iabhelper.jar 及 overrideActivity.jar。然後輸入 :
jar cvfM ./iabWrapper.jar com/
產生的 iabWrapper.jar 放在 Unity 專案的 Assets/Plugins/Android/ 資料夾底下( 此範例將檔案置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android/) 。
5. 設定 Permission ( AndroidManifest.xml )
若要執行 GooglePlay Billing 功能則要設定 AndroidManifest.xml,將底下的 AndroidManifest.xml 置於 /Users/macaronics/UnityIabProj/Assets/Plugins/Android 資料夾。
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
manifest
android:versionCode
=
"1"
android:versionName
=
"1.0"
android:installLocation
=
"preferExternal"
package
=
"com.macaronics.iab"
xmlns:android
=
"http://schemas.android.com/apk/res/android"
>
<
supports-screens
android:anyDensity
=
"true"
android:smallScreens
=
"true"
android:normalScreens
=
"true"
android:largeScreens
=
"true"
android:xlargeScreens
=
"true"
/>
<
application
android:label
=
"@string/app_name"
android:icon
=
"@drawable/app_icon"
android:debuggable
=
"false"
>
<
activity
android:label
=
"@string/app_name"
android:name
=
"com.macaronics.iab.overrideActivity"
android:screenOrientation
=
"portrait"
android:configChanges
=
"locale|mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
>
<
intent-filter
>
<
action
android:name
=
"android.intent.action.MAIN"
/>
<
category
android:name
=
"android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
<
activity
android:label
=
"@string/app_name"
android:name
=
"com.unity3d.player.UnityPlayerActivity"
android:screenOrientation
=
"portrait"
android:configChanges
=
"locale|mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
/>
<
activity
android:label
=
"@string/app_name"
android:name
=
"com.unity3d.player.UnityPlayerNativeActivity"
android:screenOrientation
=
"portrait"
android:configChanges
=
"locale|mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
>
<
meta-data
android:name
=
"android.app.lib_name"
android:value
=
"unity"
/>
<
meta-data
android:name
=
"unityplayer.ForwardNativeEventsToDalvik"
android:value
=
"false"
/>
</
activity
>
<
activity
android:label
=
"@string/app_name"
android:name
=
"com.unity3d.player.VideoPlayer"
android:screenOrientation
=
"behind"
android:configChanges
=
"locale|mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale"
/>
</
application
>
<
uses-feature
android:glEsVersion
=
"0x20000"
/>
<
uses-permission
android:name
=
"com.android.vending.BILLING"
/>
<
uses-permission
android:name
=
"android.permission.INTERNET"
/>
<
uses-permission
android:name
=
"android.permission.ACCESS_NETWORK_STATE"
/>
</
manifest
>
|
到目前為止 /Users/macaronics/UnityIabProj/Assets/Plugins/Android 資料夾底下應該會有這些檔案 (iabhelper.jar, iabWrapper.jar, iiabs.jar, overrideActivity.jar, AndroidManifest.xml ) :
![](http://1.bp.blogspot.com/-vtS-sUyekwg/UV6V9MezQQI/AAAAAAAAD9A/qIYeDH06cfw/s1600/iabpluginsfiles.jpg)
到目前為止應該要有的檔案
6. Unity 部分的 iabWrapper.cs
利用 AndroidJNI 介接 Java 程式 (注意為了接收 java 回傳的字串訊息,此 script (component) 必須加入到名為 iabWrapper 的 GameObject 裡)。 :
using
UnityEngine;
using
System.Collections;
using
System.Collections.Generic;
public
class
iabWrapper : MonoBehaviour
{
public
delegate
void
cbFunc(
object
[] retarr);
cbFunc iabSetupCB =
null
;
cbFunc iabPurchaseCB =
null
;
cbFunc iabConsumeCB =
null
;
AndroidJavaObject mIABHelperObj =
null
;
static
iabWrapper g_inst =
null
;
void
Start(){
g_inst =
this
;
}
static
public
void
init(
string
base64EncodedPublicKey, cbFunc tmpIabSetupCBFunc){
if
(g_inst ==
null
)
return
;
g_inst.iabSetupCB =tmpIabSetupCBFunc;
dispose();
g_inst.mIABHelperObj =
new
AndroidJavaObject(
"com.macaronics.iab.iabWrapper"
,
new
object
[2]{base64EncodedPublicKey,
"iabWrapper"
});
}
static
public
void
dispose(){
if
(g_inst ==
null
)
return
;
if
(g_inst.mIABHelperObj !=
null
){
g_inst.mIABHelperObj.Call(
"dispose"
);
g_inst.mIABHelperObj.Dispose();
g_inst.mIABHelperObj =
null
;
}
}
...
|
static
public
void
purchase(
string
strSKU,
int
reqCode,
string
payload, cbFunc tmpIabPurchaseCBFunc){
if
(g_inst ==
null
)
return
;
g_inst.iabPurchaseCB =tmpIabPurchaseCBFunc;
if
(g_inst.mIABHelperObj !=
null
){
g_inst.mIABHelperObj.Call(
"purchase"
,
new
object
[3]{strSKU, reqCode.ToString(), payload});
}
}
static
public
void
consume_inapp(
string
strPurchaseJsonInfo,
string
strSignature, cbFunc tmpIabConsumeCBFunc){
if
(g_inst ==
null
)
return
;
g_inst.iabConsumeCB =tmpIabConsumeCBFunc;
if
(g_inst.mIABHelperObj !=
null
){
g_inst.mIABHelperObj.Call(
"consume"
,
new
object
[3]{
"inapp"
, strPurchaseJsonInfo, strSignature});
}
}
|
void
msgReceiver(
string
msg){
if
(g_inst ==
null
)
return
;
//parse json
Dictionary<
string
,
object
> cache =(Dictionary<
string
,
object
>)MiniJSON.Json.Deserialize(msg);
//dispatch msg
if
(cache.ContainsKey(
"code"
)==
true
){
int
val =0;
int
.TryParse((
string
)cache[
"code"
],
out
val);
switch
(val){
case
0:{
//unknown
Debug.Log(
"Unity-iabWrappe :cannot parse cache[code]"
);
}
break
;
case
1:{
//OnIabSetupFinishedListener
if
(cache.ContainsKey(
"ret"
)==
true
){
string
retval =(
string
)cache[
"ret"
];
if
(retval ==
"true"
){
//可使用
if
(iabSetupCB !=
null
){
iabSetupCB(
new
object
[1]{
true
} );
}
}
else
if
(retval ==
"false"
){
//不可使用
if
(iabSetupCB !=
null
)
{
iabSetupCB(
new
object
[1]{
false
} );
}
}
else
{
Debug.Log(
"Unity-iabWrapper :cannot parse cache[ret], code=1"
);
}
}
}
break
;
case
2:{
//onIabPurchaseFinished
if
(cache.ContainsKey(
"ret"
)==
true
){
string
retval =(
string
)cache[
"ret"
];
if
(retval ==
"true"
){
//可使用
if
(iabPurchaseCB !=
null
){
iabPurchaseCB(
new
object
[3]{
true
, (
string
)cache[
"desc"
], (
string
)cache[
"sign"
]} );
}
}
else
if
(retval ==
"false"
){
//不可使用
if
(iabPurchaseCB !=
null
)
{
iabPurchaseCB(
new
object
[3]{
false
,
""
,
""
} );
}
}
else
{
Debug.Log(
"Unity-iabWrapper :cannot parse cache[ret], code=2"
);
}
}
}
break
;
case
3:{
//OnConsumeFinishedListener
if
(cache.ContainsKey(
"ret"
)==
true
){
string
retval =(
string
)cache[
"ret"
];
if
(retval ==
"true"
){
//可使用
if
(iabConsumeCB !=
null
)
{
iabConsumeCB(
new
object
[3]{
true
, (
string
)cache[
"desc"
], (
string
)cache[
"sign"
]} );
}
}
else
if
(retval ==
"false"
){
//不可使用
if
(iabConsumeCB !=
null
)
{
iabConsumeCB(
new
object
[3]{
false
,
""
,
""
} );
}
}
else
{
Debug.Log(
"Unity-iabWrapper :cannot parse cache[ret], code=3"
);
}
}
}
break
;
}
}
}
|
7. 實作 IAB APP
建立一個 script 名為 main,並將此 script 加入至 Camera。這裡實作一個 purchase 功能,並在 purchase 完成之後立刻執行 consume。
using
UnityEngine;
using
UnityEngine;
using
System.Collections;
public
class
main : MonoBehaviour {
// Use this for initialization
void
Start () {
iabWrapper.init(
"PUBLIC_KEY"
,
delegate
(
object
[] ret){
if
(
true
==(
bool
)ret[0]){
Debug.Log(
"iab successfully initialized"
);
}
else
{
Debug.Log(
"failed to initialize iab"
);
}
});
}
void
OnGUI(){
if
(GUI.Button(
new
Rect(0, 0, 100, 100),
"purchase"
)){
iabWrapper.purchase(
"PRODUCT_SKU"
, 10001,
"PRODUCT_SKU_AND_USER_ID_AND_DATE"
,
delegate
(
object
[] ret){
if
(
false
==(
bool
)ret[0]){
Debug.Log(
"purchase cancelled"
);
}
else
{
string
purchaseinfo =(
string
)ret[1];
string
signature =(
string
)ret[2];
iabWrapper.consume_inapp(purchaseinfo, signature,
delegate
(
object
[] ret2){
if
(
false
==(
bool
)ret2[0])
{
Debug.Log(
"failed to consume product"
);
}
});
}
});
}
}
void
OnApplicationQuit(){
iabWrapper.dispose();
}
}
|