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为准。有任何问题可以联系我们的商务人员。