## 一、概述
1.  此文档为Unity3D游戏接入
2.  文档对应SDK版本为3.1.5
3.  详细接入步骤请参考Demo

## 二、接入准备

### 2.1、工程导入

将FuncellSDKForUnity.unitypackage导入unity工程中
![](images/doc_img/doc_06.png)

![](images/doc_img/doc_07.png)

![](images/doc_img/doc_08.png)

GameObject对象绑定脚本为FuncellSDKCallBack,游戏接入者可按照自己的流程进行操作,该脚本主要为回调信息接收文件

### 2.2、配置AndroidManifest.xml文件

 添加权限：

```xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<activity
    android:name="com.funcell.platform.android.game.proxy.FuncellSDKLoginActivity"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:screenOrientation="behind"
    android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
<activity
    android:name="com.funcell.platform.android.game.proxy.pay.funcell.FunSdkUiActivity"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:screenOrientation="behind"
    android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />

<meta-data android:name="FUNCELL_CHANNEL_TEST" android:value="@string/FUNCELL_CHANNEL_TEST" />
```

## 三、 接入接口

> 注意事项：
1：各个接口参数等请参考packunitydemo的Eclipse工程中的具体实现，请仔细阅读FuncellSDKForUnity.unitypackage中实现方法注释,android工程已经封装了各种数据,包括数据统计、支付数据、如需新增其他接口，详细查看demo!
2：以下接口都是Android工程中接口，接口的调用也是Android接口，此工程为CP研发自行维护管理.其中的支付、数据统计部分只是演示，展示所需参数及相关字段，相关接口已进行封装处理！
3：CP接入时仔细查看C#脚本SDK相关注释,在C# 脚本中对数据进行设置

### 3.1、初始化接口（必接）

 初始化方法，在Unity游戏的主Activity的onCreat()方法中调用 
```java
	FuncellGameSdkProxy.getInstance().Init(this, new IFuncellInitCallBack(){

			@Override
			public void onInitFailure(String paramString) {
				// TODO Auto-generated method stub
				Log.e(TAG,"-------onInitFailure");
				JSONObject job = new JSONObject();
				try {
					job.put("Init", "onInitFailure");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.InitCallback, FuncellSDKUtils.ResultCode.Fail.toString(),job.toString());
			}

			@Override
			public void onInitSuccess() {
				// TODO Auto-generated method stub
				Log.e(TAG,"------onInitSuccess");
				JSONObject job = new JSONObject();
				try {
					job.put("Init", "onInitSuccess");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.InitCallback, FuncellSDKUtils.ResultCode.Success.toString(), job.toString());
			}
			
		}, new IFuncellSessionCallBack(){

			@Override
			public void onLoginSuccess(FuncellSession session) {
				// TODO Auto-generated method stub
				Log.e(TAG,"-------onLoginSuccess");
				Log.e(TAG,"-------session"+session.getmToken());
				mSession = session;
				JSONObject job = new JSONObject();
				try {
					job.put("Login", "onLoginSuccess");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.LoginCallback,FuncellSDKUtils.ResultCode.Success.toString(), job.toString());
				
			}

			@Override
			public void onLoginCancel() {
				// TODO Auto-generated method stub
				Log.e(TAG,"------onLoginCancel");
				JSONObject job = new JSONObject();
				try {
					job.put("Login", "onLoginCancel");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.LoginCallback,FuncellSDKUtils.ResultCode.Cancel.toString(), job.toString());
			}

			@Override
			public void onLoginFailed(String paramString) {
				// TODO Auto-generated method stub
				Log.e(TAG,"paramString:"+paramString);
				Log.e(TAG,"------onLoginFailed");
				JSONObject job = new JSONObject();
				try {
					job.put("Login", "onLoginFailed");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.LoginCallback,FuncellSDKUtils.ResultCode.Fail.toString(), job.toString());
			}

			@Override
			public void onLogout() {
				// TODO Auto-generated method stub
				Log.e(TAG,"------onLogout");
				/**
				 * 游戏需要返回登录界面
				 */
				JSONObject job = new JSONObject();
				try {
					job.put("Logout", "onLogout");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.LogoutCallback,FuncellSDKUtils.ResultCode.Success.toString(), job.toString());
			}

			@Override
			public void onSwitchAccount(FuncellSession arg0) {
				// TODO Auto-generated method stub
				/**
				 * 切换帐号回调(使用回调信息进行登录验证)
				 * 部分渠道在切换帐号回调中，可能是以登录成功回调来 回调给SDK
				 * 因此当接到该回调信息时候，需要先通知游戏退回登录主界面进行当前角色切换
				 */
				Log.e(TAG,"------onSwitchAccount");
				JSONObject job = new JSONObject();
				try {
					job.put("SwitchAccount", "onSwitchAccount");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.SwitchAccountCallback,FuncellSDKUtils.ResultCode.Success.toString(), job.toString());
				
			}
			
		}, new IFuncellPayCallBack(){


			@Override
			public void onFail(String paramString) {
				// TODO Auto-generated method stub
				Log.e(TAG,"IFuncellPayCallBack onFail");
				JSONObject job = new JSONObject();
				try {
					job.put("pay", "onFail");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.PayCallback,FuncellSDKUtils.ResultCode.Fail.toString(), job.toString());
			}

			@Override
			public void onCancel(String paramString) {
				// TODO Auto-generated method stub
				Log.e(TAG,"IFuncellPayCallBack onCancel");
				JSONObject job = new JSONObject();
				try {
					job.put("pay", "onCancel");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.PayCallback,FuncellSDKUtils.ResultCode.Cancel.toString(), job.toString());
			}

			@Override
			public void onSuccess(String cpOrder, String sdkOrder,
					String extrasParams) {
				// TODO Auto-generated method stub
				/**
				 * 渠道充值成功，不代表游戏服务器到账，请知晓
				 * 返回的参数，如果游戏接入者有自己的逻辑，可以不试用以上参数
				 */
				Log.e(TAG,"IFuncellPayCallBack onSuccess");
				Log.e(TAG,"cpOrder:"+cpOrder); //游戏方的订单，
				Log.e(TAG,"sdkOrder:"+sdkOrder);//平台订单号
				Log.e(TAG,"extrasParams:"+extrasParams);//透传参数
				JSONObject job = new JSONObject();
				try {
					job.put("pay", "onSuccess");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.PayCallback,FuncellSDKUtils.ResultCode.Success.toString(), job.toString());
			}

			@Override
			public void onClosePayPage(String arg0, String arg1, String arg2) {
				// TODO Auto-generated method stub
				/**
				 * 渠道充值关闭界面
				 * 可能由于某些SDK的支付方式中，采用网页形式进行支付，但是又不能明确支付的状态（成功，失败，取消等）
				 */
				JSONObject job = new JSONObject();
				try {
					job.put("pay", "onClosePayPage");
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.PayCallback,FuncellSDKUtils.ResultCode.Unknown.toString(), job.toString());
			}
		});
```

### 3.2、生命周期接口（必接）

 在Unity的主Activity的生命周期中调用SDK生命周期接口：
```java
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    FuncellGameSdkProxy.getInstance().onCreate(this);
}
public void onStop() {
	super.onStop();
	FuncellGameSdkProxy.getInstance().onStop(this);
}
public void onDestroy() {
	super.onDestroy();
	FuncellGameSdkProxy.getInstance().onDestroy(this);
}
public void onResume() {
	super.onResume();
	FuncellGameSdkProxy.getInstance().onResume(this);
}
public void onPause() {
	super.onPause();
	FuncellGameSdkProxy.getInstance().onPause(this);
}
public void onStart() {
	super.onStart();
	FuncellGameSdkProxy.getInstance().onStart(this);
}
public void onRestart() {
	super.onRestart();
	FuncellGameSdkProxy.getInstance().onRestart(this);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	FuncellGameSdkProxy.getInstance().onActivityResult(this, requestCode, resultCode,data);
}
public void onNewIntent(Intent intent){
	super.onNewIntent(intent);
	FuncellGameSdkProxy.getInstance().onNewIntent(intent);
}
public void onRequestPermissionsResult(int requestCode,String[] permissions, int[] grantResults) {
	// TODO Auto-generated method stub
    FuncellGameSdkProxy.getInstance().onRequestPermissionsResult(requestCode, permissions, grantResults);
}

```

### 3.3、登录接口（必接,主线程调用）

```java
FuncellGameSdkProxy.getInstance().Login(UnityPlayerNativeActivity.this);
```

### 3.4、登出接口（必接）

```java
FuncellGameSdkProxy.getInstance().Logout(MainActivity.this);
```

### 3.5、支付接口（必接,主线程调用）

```java
FuncellRoleInfo roleInfo = new FuncellRoleInfo(); //角色信息
roleInfo.setGameGoldBalance("888");//角色剩余元宝数
roleInfo.setGameUnionName("游戏工会");//游戏工会
roleInfo.setRoleId(“123”);//角色ID
roleInfo.setRoleLevel("2");//角色等级
roleInfo.setRoleName("test");//角色名
roleInfo.setServerId("998");//区服ID
roleInfo.setServerName("天下");//区服名
roleInfo.setVipLevel("3");//角色VIP等级

FuncellPayParams PayParams = new FuncellPayParams();
PayParams.setmExtrasParams("test"); //透传参数，支付成功后，返回给客户端的数据
PayParams.setmItemAmount("10"); //商品价格
PayParams.setmItemCount(10);//钻石数量 ,10个元宝
PayParams.setmItemDescription("商品描述");
PayParams.setmItemId("100002"); //商品ID
PayParams.setmItemName("10元宝"); //商品名
PayParams.setmItemType("元宝"); //商品类型
PayParams.setmCurrency("RMB");//货币设置
//游戏方订单号，若无则不传该参数或者不设置，该字段为支付成功后，返回的数据
PayParams.setmOrderId("游戏接入方订单号");
PayParams.setmRoleInfo(roleInfo);
FuncellGameSdkProxy.getInstance().Pay(UnityPlayerNativeActivity.this, PayParams);
```

### 3.6、数据统计接口（必接）

 创建角色事件：创建角色后调用 
```java
ParamsContainer pc = new ParamsContainer();
pc.putString("usermark", mSession.getmUserID());//用户ID，登录成功后返回的数据
pc.putString("role_id", "123");//角色ID
pc.putString("serverno", "998");//区服ID
pc.putString("server_name", "天下");//区服名
pc.putString("role_name", "test");//角色名
pc.putString("role_gamegold_balance", "游戏玩家金币余额"); //游戏金币，并非充值后的钻石数量
pc.putString("role_gameunion_name", "公会名字");
pc.putString("role_vip_level", "1");//VIP等级
pc.putString("role_level", "1"); //角色等级
pc.putString("role_creat_time", "服务器时间戳");//角色创建时间
pc.putString("role_upgrade_time", "服务器时间戳"); //角色升级时间
pc.putString("role_recharge_balance", "游戏玩家充值游戏币余额"); //充值后的游戏币余额(钻石、元宝等余额)
FuncellGameSdkProxy.getInstance().setDatas(UnityPlayerNativeActivity.this,FuncellDataTypes.DATA_CREATE_ROLE, pc);
```

 登录事件：登录游戏并选择了服务器后调用 
```java
ParamsContainer pc = new ParamsContainer();
pc.putString("usermark", mSession.getmUserID());//用户ID，登录成功后返回的数据
pc.putString("serverno", "998");//区服ID
FuncellGameSdkProxy.getInstance().setDatas(UnityPlayerNativeActivity.this, FuncellDataTypes.DATA_LOGIN, pc);
```

 角色升级事件：角色升级后调用 
```java
ParamsContainer pc = new ParamsContainer();
pc.putString("usermark", mSession.getmUserID());//用户ID，登录成功后返回的数据
pc.putString("serverno", "998");//区服ID
pc.putString("role_level", "999");//等级
pc.putString("role_id", "123");//角色ID
pc.putString("role_name", "test");//角色名
pc.putString("server_name","天下");//区服名
pc.putString("role_gamegold_balance", "游戏玩家金币余额"); //游戏金币，并非充值后的钻石数量
pc.putString("role_gameunion_name", "公会名字");
pc.putString("role_vip_level", "1");//VIP等级
pc.putString("role_creat_time", "服务器时间戳");//角色创建时间
pc.putString("role_upgrade_time", "服务器时间戳"); //角色升级时间
pc.putString("role_recharge_balance", "游戏玩家充值游戏币余额"); //充值后的游戏币余额(钻石、元宝等余额)
FuncellGameSdkProxy.getInstance().setDatas(UnityPlayerNativeActivity.this,FuncellDataTypes.DATA_ROLE_LEVELUP, pc);
```
 角色服务器事件：可在进入游戏主场景时调用 
```java
ParamsContainer pc = new ParamsContainer();
pc.putString("usermark", mSession.getmUserID());//用户ID，登录成功后返回的数据
pc.putString("role_id", "123");//角色ID
pc.putString("role_level", "999");//等级
pc.putString("role_name", "test");//角色名
pc.putString("role_gameunion_name", "工会");//工会名
pc.putString("role_vip_level", "VIP等级");//VIP等级
pc.putString("serverno", "998");//区服ID
pc.putString("server_name", "天下");//区服名
pc.putString("role_gamegold_balance", "游戏玩家金币余额"); //游戏金币，并非充值后的钻石数量
pc.putString("role_creat_time", "服务器时间戳");//角色创建时间
pc.putString("role_upgrade_time", "服务器时间戳"); //角色升级时间
pc.putString("role_recharge_balance", "游戏玩家充值游戏币余额"); //充值后的游戏币余额(钻石、元宝等余额)
FuncellGameSdkProxy.getInstance().setDatas(UnityPlayerNativeActivity.this,FuncellDataTypes.DATA_SERVER_ROLE_INFO, pc);
```

### 3.7、游戏退出接口（必接,主线程调用）
-- 查询渠道是否有退出界面接口：
```java
FuncellGameSdkProxy.getInstance().GetExitUI(this);
```
0代表渠道无退出界面，其他值代表渠道有退出界面

 SDK退出接口：
```java
FuncellGameSdkProxy.getInstance().Exit(this, new IFuncellExitCallBack(){
    @Override
    public void onChannelExit() {
        // TODO Auto-generated method stub
        Log.e(TAG, "-------onChannelExit");
        finish();
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    @Override
    public void onGameExit() {
        // TODO Auto-generated method stub
        Log.e(TAG, "-------onGameExit");
		sendMsg2Unity(mGameObject, FuncellSDKUtils.CallbackType.ExitCallback, FuncellSDKUtils.ResultCode.Success.toString(), job.toString());
		/**
		* 以下为demo演示，具体游戏自行处理
		*/
        AlertDialog.Builder builder = new Builder(UnityPlayerNativeActivity.this);
        builder.setTitle("游戏退出界面");
        builder.setPositiveButton("退出",
        new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog,int which) {
                dialog.dismiss();

                / 退出逻辑需确保能够完全销毁游戏 /
                finish();
                android.os.Process.killProcess(android.os.Process.myPid());
                / 退出逻辑请根据游戏实际情况，勿照搬Demo /
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });

        dialog = builder.create();
        dialog.show();
    }

});

```

> ### 以下接口为选接：

### 3.8、扩展方法接口（选接）
```java
FuncellGameSdkProxy.getInstance().callFunction(MainActivity.this, "functionTest");
```

参数详解：

| 参数 | 说明 |
| --- | --- |
| MainActivity.this | 上下文 |
| functionTest | 调用方法名 |

### 3.9、获取登录状态（选接）
```java
FuncellGameSdkProxy.getInstance().GetLoginFlag();
```
参数详解：

返回值：boolen类型

### 3.10、获取EVE数据（选接）
```java
FuncellGameSdkProxy.getInstance().GetEveData();
```
参数详解：

返回值：json数据类型

### 3.11、获取公告列表（选接）
```java
FuncellGameSdkProxy.getInstance().GetNoticeList(MainActivity.this, new IPlatformNoticeListCallBack(){}, "type", "server_id");
```
参数详解：

| 参数 | 是否必传 | 参数说明 |
| --- | --- | --- |
| MainActivity.this | Y | 上下文 |
| IPlatformNoticeListCallBack | Y | 回调接口 |
| type | Y | 类型(如：登录公告、活动公告、退出公告类型) |
| server_id | N | 缺省参数，服务器ID |

公告类型(type字段详解)：

| 字段 | 含义 |
| --- | --- |
| general | 游戏普通公告 |
| login | 游戏登录公告 |
| activity | 游戏活动公告 |
| update | 游戏更新公告 |
| sdk\_pop | SDK登陆弹窗 |
| sdk\_exit | SDK退出弹窗 |

注：可以一次性获取多种类型的公告，以逗号&quot;,&quot;分割

### 3.12、获取服务器列表（选接）
```java
FuncellGameSdkProxy.getInstance().GetServerList(this, new IPlatformServerListCallBack(){}, "white_key");
```
参数详解：

| 参数 | 是否必传 | 参数说明 |
| --- | --- | --- |
| this | Y | 上下文 |
| IPlatformServerListCallBack | Y | 回调接口 |
| white_key | N | 缺省参数，白名单Key |

### 3.13、获取商品列表（选接）
```java
FuncellGameSdkProxy.getInstance().GetPayList(this, true, "category", new IFuncellPayListCallBack(){});
```
参数详解：

| 参数 | 是否必传 | 参数说明 |
| --- | --- | --- |
| this | Y | 上下文 |
| true | Y | 是否刷新数据的标志 |
| category | Y | 请求商品列表 类型 |
| IFuncellPayListCallBack | Y | 回调接口 |

### 3.14、获取平台参数（选接）
```java
FuncellGameSdkProxy.getInstance().GetPlatformParams(this, PlatformParamsType.GameID);
```
参数详解：

| 参数 | 是否必传 | 参数说明 |
| --- | --- | --- |
| this | Y | 上下文 |
| PlatformParamsType | Y | 获取平台参数类型 |

PlatformParamsType类型解释

| GameID | 平台对应的游戏ID |
| --- | --- |
| PlatformID | 平台对应的渠道ID |
| PlatformType | 平台对应的渠道类型(如，UC，360) |
| AppVersion | 平台对应的游戏版本号 |
| ClientId | 平台ClientId |

### 3.15、设置初始化参数（选接）

FuncellGameSdkProxy.getInstance().setConfigParams(this,jsonObject.toString());
以下参数均为json数据中对应Key值（String类型）
若游戏设置了以下字段，默认使用游戏设置参数

| 参数(Key) |  含义 |
| --- | --- |
| datacenter	| 平台分配（数据中心） |
| gameId	| 平台分配（游戏ID） |
| platformId	| 平台分配（渠道ID） |
| eve	| 平台分配（eve地址） |
| ChannelVersionCode	| 平台分配（渠道版本） |
| report	| 平台分配（BI上报地址） |
| platformType	| 平台分配（渠道类型） |
| area	| 平台分配（地区） |
| resVersion	| 打包工具填写（资源版本） |
| appVersion	| 打包工具填写（应用版本） |

## 四、导出设置

配置完成后，即可导出apk进行测试，测试通过后，即可以打Android渠道包