1. Untiy接入文檔------Android端
- Android端的作用是對接ASCSDK打包工具與unity原生端的中間件。
- ASCUnityContext是主要的連接配接類,這個類繼承UnityPlayerActivity ,也是遊戲的啟動Activity。
package com.asc.sdk;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.asc.sdk.platform.ASCExitListener;
import com.asc.sdk.platform.ASCInitListener;
import com.asc.sdk.platform.ASCPlatform;
import com.asc.sdk.plugin.ASCUser;
import com.asc.sdk.verify.UToken;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
/***
* 記得将遊戲工程中的AndroidManifest.xml中application節點,增加一個android:name="ASCApplication"
* 如果遊戲有自己的Application。那麼通過實作IApplicationListener接口來實作,而不要使用繼承Application。
* 然後将自己的Application類,配置到AndroidManifest.xml中的meta-data節點中,name為"ASC_Game_Application"
* @author xiaohei
*
*/
public class ASCUnityContext extends UnityPlayerActivity{
public final static String CALLBACK_GAMEOBJECT_NAME = "(ascsdk_callback)"; //unity中接收回調通知的GameObject的名稱
public final static String CALLBACK_INIT = "OnInitSuc"; //SDK初始化成功的回調方法名稱和Unity中一緻
public final static String CALLBACK_LOGIN = "OnLoginSuc"; //SDK登入成功的回調方法名稱和Unity中一緻
public final static String CALLBACK_SWITCH_LOGIN = "OnSwitchLogin"; //SDK切換帳号的回調方法名稱和Unity中一緻
public final static String CALLBACK_LOGOUT = "OnLogout"; //SDK登出的回調方法名稱和Unity中一緻
public final static String CALLBACK_PAY = "OnPaySuc"; //SDK支付成功回調方法名稱和Unity中一緻
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSDK();
}
private void initSDK(){
ASCPlatform.getInstance().init(this, new ASCInitListener() {
@Override
public void onSwitchAccount(UToken data) {
//遊戲中通過SDK切換到新賬号的回調,遊戲收到該回調,需要引導使用者重新登入,重新加載該新使用者對應的角色資料
if(data == null){
tip("切換帳号失敗,請重試");
return;
}
sendLoginResult(data, true);
}
@Override
public void onPayResult(int code, String msg) {
Log.d("ASCSDK", "pay result. code:"+code+";msg:"+msg);
/*switch(code){
case ASCCode.CODE_PAY_SUCCESS:
//tip("支付成功");
break;
case ASCCode.CODE_PAY_FAIL:
//tip("支付失敗");
break;
case ASCCode.CODE_PAY_CANCEL:
//tip("支付取消");
break;
case ASCCode.CODE_PAY_UNKNOWN:
//tip("支付失敗,未知錯誤");
break;
}*/
}
@Override
public void onLogout() {
//使用者登出回調(需要收到該回調需要傳回遊戲登入界面,并調用login接口,打開SDK登入界面)
sendCallback(ASCUnityContext.CALLBACK_LOGOUT, null);
}
@Override
public void onLoginResult(int code, UToken data) {
switch(code){
case ASCCode.CODE_LOGIN_SUCCESS:
sendLoginResult(data, false);
tip("登入成功");
break;
case ASCCode.CODE_LOGIN_FAIL:
tip("登入失敗");
break;
}
}
@Override
public void onInitResult(int code, String msg) {
Log.d("ASCSDK", "init result.code:"+code+";msg:"+msg);
switch(code){
case ASCCode.CODE_INIT_SUCCESS:
sendCallback(CALLBACK_INIT, null);
tip("初始化成功");
break;
case ASCCode.CODE_INIT_FAIL:
tip("初始化失敗");
break;
}
}
@Override
public void onProductQueryResult(List<ProductQueryResult> result) {
// TODO Auto-generated method stub
}
@Override
public void onVideoResult(int code, String msg) {
// TODO Auto-generated method stub
Log.d("ASCSDK", "onVideoResult result:"+msg);
Toast.makeText(ASCUnityContext.this, "視訊回調成功", Toast.LENGTH_LONG).show();
}
@Override
public void onSinglePayResult(int code, ASCOrder order) {
Log.d("ASCSDK", "onSinglePayResult result:"+order.getProductID());
JSONObject json = new JSONObject();
String pId = "";
pId = order.getProductID();
try{
if(code == ASCCode.CODE_PAY_SUCCESS){
json.put("payResult", 0);
}else{
json.put("payResult", 1);
}
json.put("productId", pId);
}catch(Exception e){
e.printStackTrace();
}
sendCallback(ASCUnityContext.CALLBACK_PAY,json.toString());
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
}
});
}
public void sendLoginResult(UToken authResult, boolean isSwitchAccount) {
JSONObject json = new JSONObject();
try{
json.put("isSuc", authResult.isSuc());
json.put("isSwitchAccount", isSwitchAccount);
if(authResult.isSuc()){
json.put("userID", authResult.getUserID());
json.put("sdkUserID", authResult.getSdkUserID());
json.put("username", authResult.getUsername());
json.put("sdkUsername", authResult.getSdkUsername());
json.put("token", authResult.getToken());
}
}catch(Exception e){
e.printStackTrace();
}
this.sendCallback(ASCUnityContext.CALLBACK_LOGIN, json.toString());
}
public void nativeLog(String msg){
Log.d("ASC_LOG_UNITY", msg);
}
//登入接口
public void login(){
ASCPlatform.getInstance().login(this);
}
//顯示使用者中心接口
public void showAccountCenter(){
ASCPlatform.getInstance().showAccountCenter();
}
//登出
public void logout(){
ASCPlatform.getInstance().logout();
}
//送出擴充資料
public void submitExtraData(String data){
final UserExtraData extraData = parseGameData(data);
ASCPlatform.getInstance().submitExtraData(extraData);
}
//SDK退出接口
public void exit(){
ASCPlatform.getInstance().exitSDK(new ASCExitListener() {
@Override
public void onGameExit() {
//遊戲自己的退出确認框
AlertDialog.Builder builder = new AlertDialog.Builder(ASCUnityContext.this);
builder.setTitle("退出确認");
builder.setMessage("現在還早,要不要再玩一會?");
builder.setCancelable(true);
builder.setPositiveButton("好吧",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
//這裡什麼都不用做
}
});
builder.setNeutralButton("一會再玩",
new DialogInterface.OnClickListener() {
@SuppressLint("NewApi")
public void onClick(DialogInterface dialog,
int whichButton) {
//退出遊戲
ASCUnityContext.this.finish();
System.exit(0);
}
});
builder.show();
}
});
}
//支付接口
public void pay(String data){
final PayParams params = parsePayParams(data);
ASCPlatform.getInstance().pay(this, params);
}
//SDK是否支援使用者中心
public boolean isSupportAccountCenter(){
return ASCUser.getInstance().isSupport("showAccountCenter");
}
//SDK是否支援退出确認框
public boolean isSupportExit(){
return ASCUser.getInstance().isSupport("exit");
}
//SDK是否支援退出确認框
public boolean isSupportLogout(){
return ASCUser.getInstance().isSupport("logout");
}
public boolean isSDKShowSplash(){
return ASCSDK.getInstance().isSDKShowSplash();
}
//向Unity中發送消息
public void sendCallback(String name, String jsonParams){
if(jsonParams == null){
jsonParams = "";
}
UnityPlayer.UnitySendMessage(CALLBACK_GAMEOBJECT_NAME, name, jsonParams);
}
private UserExtraData parseGameData(String str){
UserExtraData data = new UserExtraData();
try {
JSONObject json = new JSONObject(str);
data.setDataType(json.getInt("dataType"));
data.setRoleID(json.getString("roleID"));
data.setRoleName(json.getString("roleName"));
data.setRoleLevel(json.getString("roleLevel"));
data.setServerID(json.getInt("serverID"));
data.setServerName(json.getString("serverName"));
data.setMoneyNum(json.getInt("moneyNum"));
String roleCreateTime = json.getString("roleCreateTime");
String roleLevelUpTime = json.getString("roleLevelUpTime");
if(!TextUtils.isEmpty(roleCreateTime.trim())){
data.setRoleCreateTime(Long.valueOf(roleCreateTime.trim()));
}
if(!TextUtils.isEmpty(roleLevelUpTime.trim())){
data.setRoleLevelUpTime(Long.valueOf(roleLevelUpTime.trim()));
}
data.setVip(json.optString("vip", "0"));
} catch (JSONException e) {
e.printStackTrace();
}
return data;
}
private PayParams parsePayParams(String str){
PayParams params = new PayParams();
try{
JSONObject json = new JSONObject(str);
params.setProductId(json.getString("productId"));
params.setProductName(json.getString("productName"));
params.setProductDesc(json.getString("productDesc"));
params.setPrice(json.getInt("price"));
params.setRatio(0);//該字段廢棄不用
params.setBuyNum(json.getInt("buyNum"));
params.setCoinNum(json.getInt("coinNum"));
params.setServerId(json.getString("serverId"));
params.setServerName(json.getString("serverName"));
params.setRoleId(json.getString("roleId"));
params.setRoleName(json.getString("roleName"));
params.setRoleLevel(json.getInt("roleLevel"));
params.setPayNotifyUrl(json.getString("payNotifyUrl"));
params.setVip(json.getString("vip"));
params.setExtension(json.getString("extension"));
}catch(Exception e){
e.printStackTrace();
}
return params;
}
public void onActivityResult(int requestCode, int resultCode, Intent data){
ASCSDK.getInstance().onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, data);
}
public void onStart(){
ASCSDK.getInstance().onStart();
super.onStart();
}
public void onPause(){
ASCSDK.getInstance().onPause();
super.onPause();
}
public void onResume(){
ASCSDK.getInstance().onResume();
super.onResume();
}
public void onNewIntent(Intent newIntent){
ASCSDK.getInstance().onNewIntent(newIntent);
super.onNewIntent(newIntent);
}
public void onStop(){
ASCSDK.getInstance().onStop();
super.onStop();
}
public void onDestroy(){
ASCSDK.getInstance().onDestroy();
super.onDestroy();
}
public void onRestart(){
ASCSDK.getInstance().onRestart();
super.onRestart();
}
private void tip(final String tip){
ASCSDK.getInstance().runOnMainThread(new Runnable() {
@Override
public void run() {
//Toast.makeText(ASCUnityContext.this, tip, Toast.LENGTH_SHORT).show();
}
});
}
private void OnRate(){
try {
String str = "market://details?id=" + ASCSDK.getInstance().getApplication().getPackageName();
Log.d("ASCSDK", "OnRate url:"+str);
Intent localIntent = new Intent(Intent.ACTION_VIEW);
localIntent.setData(Uri.parse(str));
ASCSDK.getInstance().getContext().startActivity(localIntent);
} catch (Exception e) {
// 打開應用商店失敗 可能是沒有手機沒有安裝應用市場
e.printStackTrace();
Toast.makeText(ASCSDK.getInstance().getContext().getApplicationContext(), "打開應用商店失敗", Toast.LENGTH_SHORT).show();
// 調用系統浏覽器進入商城
String url = "http://app.mi.com/detail/163525?ref=search";
openLinkBySystem(url);
}
}
private void openLinkBySystem(String url) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
ASCSDK.getInstance().getContext().startActivity(intent);
}
}
說明:
- 其中,CALLBACK_GAMEOBJECT_NAME就是Unity中這個負責接收回調通知的GameObject的名稱
- 此類包含了初始化SDK,登陸,登出,退出,支付,送出擴充資料方法。
- ASCInitListener此接口為所有回調的監聽接口。
- onPayResult------支付回調(網遊專用接口)。
- onLoginResult------登陸結果回調。
- onInitResult------初始化結果回調。
- onSinglePayResult------單機支付結果回調。
- 還有一些登出,查詢訂單,視訊回調等,詳情看代碼注解。
2. Untiy接入文檔------Unity端
- 拷貝上面Android端生成的ascsdk_unitylib.jar到unity工程libs目錄中。
- 拷貝ASCSDK的抽象層工程中的bin目錄下生成的ascsdk3.jar拷貝到libs目錄中。
- 在Unity中怎麼來完成Android中相關接口的調用以及封裝。
- 我們定義一個ASCSDKInterface的抽象單例類:
public abstract class ASCSDKInterface{
public delegate void LoginSucHandler(ASCLoginResult data);
public delegate void LogoutHandler();
private static ASCSDKInterface _instance;
public LoginSucHandler OnLoginSuc;
public LogoutHandler OnLogout;
public static ASCSDKInterface Instance
{
get
{
if (_instance == null)
{
#if UNITY_EDITOR || UNITY_STANDLONE
_instance = new SDKInterfaceDefault();
#elif UNITY_ANDROID
_instance = new SDKInterfaceAndroid();
#elif UNITY_IOS
_instance = new SDKInterfaceIOS();
#endif
}
return _instance;
}
}
//初始化
public abstract void Init();
//登入
public abstract void Login();
//自定義登入,用于騰訊應用寶,QQ登入,customData="QQ";微信登入,customData="WX"
public abstract void LoginCustom(string customData);
//切換帳号
public abstract void SwitchLogin();
//登出
public abstract bool Logout();
//顯示個人中心
public abstract bool ShowAccountCenter();
//上傳遊戲資料
public abstract void SubmitGameData(ASCExtraGameData data);
//調用SDK的退出确認框,傳回false,說明SDK不支援退出确認框,遊戲需要使用自己的退出确認框
public abstract bool SDKExit();
//調用SDK支付界面
public abstract void Pay(ASCPayParams data);
//SDK是否支援退出确認框
public abstract bool IsSupportExit();
//SDK是否支援使用者中心
public abstract bool IsSupportAccountCenter();
//SDK是否支援登出
public abstract bool IsSupportLogout();
//去ASCServer擷取遊戲訂單号,這裡邏輯是通路遊戲伺服器,然後遊戲伺服器去ASCServer擷取訂單号
//并傳回
public ASCPayParams reqOrder(ASCPayParams data)
{
//TODO 去遊戲伺服器擷取訂單号
//測試
data.orderID = "345435634534";
data.extension = "test";
return data;
}
}
- 有了這個抽象類,對于各個平台,我們需要分别實作該抽象類中的接口,進而間接地調用平台中的方法。對于Android平台,我們定義一個SDKInterfaceAndroid類:
public class SDKInterfaceAndroid : ASCSDKInterface
{
private AndroidJavaObject jo;
public SDKInterfaceAndroid()
{
using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
jo = jc.GetStatic<AndroidJavaObject>("currentActivity");
}
}
private T SDKCall<T>(string method, params object[] param)
{
try
{
return jo.Call<T>(method, param);
}
catch (Exception e)
{
Debug.LogError(e);
}
return default(T);
}
private void SDKCall(string method, params object[] param)
{
try
{
jo.Call(method, param);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
//這裡Android中,在onCreate中直接調用了initSDK,是以這裡就不用調用了
public override void Init()
{
//SDKCall("initSDK");
}
public override void Login()
{
SDKCall("login");
}
public override void LoginCustom(string customData)
{
SDKCall("loginCustom", customData);
}
public override void SwitchLogin()
{
SDKCall("switchLogin");
}
public override bool Logout()
{
if (!IsSupportLogout())
{
return false;
}
SDKCall("logout");
return true;
}
public override bool ShowAccountCenter()
{
if (!IsSupportAccountCenter())
{
return false;
}
SDKCall("showAccountCenter");
return true;
}
public override void SubmitGameData(ASCExtraGameData data)
{
string json = encodeGameData(data);
SDKCall("submitExtraData", json);
}
public override bool SDKExit()
{
if (!IsSupportExit())
{
//return false;
}
SDKCall("exit");
return true;
}
public override void Pay(ASCPayParams data)
{
string json = encodePayParams(data);
SDKCall("pay", json);
}
public override bool IsSupportExit()
{
return SDKCall<bool>("isSupportExit");
}
public override bool IsSupportAccountCenter()
{
return SDKCall<bool>("isSupportAccountCenter");
}
public override bool IsSupportLogout()
{
return SDKCall<bool>("isSupportLogout");
}
private string encodeGameData(ASCExtraGameData data)
{
Dictionary<string, object> map = new Dictionary<string, object>();
map.Add("dataType", data.dataType);
map.Add("roleID", data.roleID);
map.Add("roleName", data.roleName);
map.Add("roleLevel", data.roleLevel);
map.Add("serverID", data.serverID);
map.Add("serverName", data.serverName);
map.Add("moneyNum", data.moneyNum);
return MiniJSON.Json.Serialize(map);
}
private string encodePayParams(ASCPayParams data)
{
Dictionary<string, object> map = new Dictionary<string, object>();
map.Add("productId", data.productId);
map.Add("productName", data.productName);
map.Add("productDesc", data.productDesc);
map.Add("price", data.price);
map.Add("buyNum", data.buyNum);
map.Add("coinNum", data.coinNum);
map.Add("serverId", data.serverId);
map.Add("serverName", data.serverName);
map.Add("roleId", data.roleId);
map.Add("roleName", data.roleName);
map.Add("roleLevel", data.roleLevel);
map.Add("vip", data.vip);
map.Add("orderID", data.orderID);
map.Add("extension", data.extension);
return MiniJSON.Json.Serialize(map);
}
}
- 接下來,我們就定義一個專門負責回調的腳本:
public class ASCSDKCallback : MonoBehaviour
{
private static ASCSDKCallback _instance;
private static object _lock = new object();
//初始化回調對象
public static ASCSDKCallback InitCallback()
{
UnityEngine.Debug.LogError("Callback->InitCallback");
lock (_lock)
{
if (_instance == null)
{
GameObject callback = GameObject.Find("(ascsdk_callback)");
if (callback == null)
{
callback = new GameObject("(ascsdk_callback)");
UnityEngine.Object.DontDestroyOnLoad(_instance);
_instance = callback.AddComponent<ASCSDKCallback>();
}
else
{
_instance = callback.GetComponent<ASCSDKCallback>();
}
}
return _instance;
}
}
//初始化成功回調
public void OnInitSuc()
{
//一般不需要處理
UnityEngine.Debug.LogError("Callback->OnInitSuc");
}
//登入成功回調
public void OnLoginSuc(string jsonData)
{
UnityEngine.Debug.LogError("Callback->OnLoginSuc");
ASCLoginResult data = parseLoginResult(jsonData);
if (data == null)
{
UnityEngine.Debug.LogError("The data parse error." + jsonData);
return;
}
if (ASCSDKInterface.Instance.OnLoginSuc != null)
{
ASCSDKInterface.Instance.OnLoginSuc.Invoke(data);
}
}
//切換帳号回調
public void OnSwitchLogin()
{
UnityEngine.Debug.LogError("Callback->OnSwitchLogin");
if (ASCSDKInterface.Instance.OnLogout != null)
{
ASCSDKInterface.Instance.OnLogout.Invoke();
}
}
//登出回調
public void OnLogout()
{
UnityEngine.Debug.LogError("Callback->OnLogout");
if (ASCSDKInterface.Instance.OnLogout != null)
{
ASCSDKInterface.Instance.OnLogout.Invoke();
}
}
//支付回調,網遊不需要實作該接口,該接口用于單機遊戲
public void OnPaySuc(string jsonData)
{
//Nothing...
}
private ASCLoginResult parseLoginResult(string str)
{
object jsonParsed = MiniJSON.Json.Deserialize(str);
if (jsonParsed != null)
{
Dictionary<string, object> jsonMap = jsonParsed as Dictionary<string, object>;
ASCLoginResult data = new ASCLoginResult();
if (jsonMap.ContainsKey("isSuc"))
{
data.isSuc = bool.Parse(jsonMap["isSuc"].ToString());
}
if (jsonMap.ContainsKey("isSwitchAccount"))
{
data.isSwitchAccount = bool.Parse(jsonMap["isSwitchAccount"].ToString());
}
if (jsonMap.ContainsKey("userID"))
{
data.userID = jsonMap["userID"].ToString();
}
if (jsonMap.ContainsKey("sdkUserID"))
{
data.sdkUserID = jsonMap["sdkUserID"].ToString();
}
if (jsonMap.ContainsKey("username"))
{
data.username = jsonMap["username"].ToString();
}
if (jsonMap.ContainsKey("sdkUsername"))
{
data.sdkUsername = jsonMap["sdkUsername"].ToString();
}
if (jsonMap.ContainsKey("token"))
{
data.token = jsonMap["token"].ToString();
}
return data;
}
return null;
}
}
- 到這裡,ASCSDK在Unity中的封裝基本就算完成了,接下來,我們就來測試下接口的調用。我們用UGUI建立一個建立一個簡單的面闆,然後包含一個登入按鈕和支付按鈕,然後通過綁定一個ClickObject.cs腳本來簡體按鈕的響應事件:
public class ClickObject : MonoBehaviour {
// Use this for initialization
private Text txtState;
void Start () {
ASCSDKCallback.InitCallback();
GameObject loginObj = GameObject.Find("BtnLogin");
Button btnLogin = loginObj.GetComponent<Button>();
btnLogin.onClick.AddListener(delegate()
{
OnLoginClick();
});
GameObject payObj = GameObject.Find("BtnPay");
Button btnPay = payObj.GetComponent<Button>();
btnPay.onClick.AddListener(delegate()
{
OnPayClick();
});
GameObject stateObj = GameObject.Find("TxtState");
txtState = stateObj.GetComponent<Text>();
ASCSDKInterface.Instance.OnLoginSuc = delegate(ASCLoginResult result)
{
OnLoginSuc(result);
};
ASCSDKInterface.Instance.OnLogout = delegate()
{
OnLogout();
};
}
void Update()
{
if (Input.GetKeyUp(KeyCode.Escape))
{
if (!ASCSDKInterface.Instance.SDKExit())
{
//TODO 退出确認框
Application.Quit();
}
}
}
void OnLoginSuc(ASCLoginResult result)
{
if (!result.isSuc)
{
txtState.text = "登入失敗";
return;
}
if (result.isSwitchAccount)
{
txtState.text = "切換帳号成功:" + result.token;
}
else
{
txtState.text = "登入成功:" + result.token;
}
}
void OnLogout()
{
txtState.text = "未登入";
}
void OnLoginClick()
{
ASCSDKInterface.Instance.Login();
}
void OnPayClick()
{
ASCPayParams data = new ASCPayParams();
data.productId = "1";
data.productName = "元寶";
data.productDesc = "購買100元寶,贈送20元寶";
data.price = 100;
data.buyNum = 1;
data.coinNum = 300;
data.serverId = "10";
data.serverName = "地獄之戀";
data.roleId = "asc_24532452";
data.roleName = "麻利麻利吼";
data.roleLevel = 15;
data.vip = "v15";
data = ASCSDKInterface.Instance.reqOrder(data);
ASCSDKInterface.Instance.Pay(data);
}
}
-
最後說明:
我們将提供unity的工程的demo,具體可以參考我們demo,此文檔暫時沒有提供廣告接口的說明,原理與login支付一樣,調用我給你們提供的方法就可以,具體以我們給的demo為準。有任何問題可以聯系我們的商務人員。