多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## **1. 关于Android版接入** Android版游戏接入EUSDK,只需接入一次,即可通过EUSDK在线打包平台,批量打出各个渠道SDK的渠道包。 ## **2. 接入准备** ### **2.1.引入jar包** 将EUSDK\_android\_1.0.0/01-客户端接入文档及demo/demo/libs下面所有jar包放到游戏接入工程中的libs目录下;如果是用androidstudio,请在build.gradle文件中,增加这里所有jar包的依赖 ![](https://box.kancloud.cn/df4cfe592c56c604e00a7206227c700b_943x229.png) ### **2.2.添加配置文件** 将EUSDK\_android\_1.0.0/01-客户端接入文档及demo/demo/assets目录下的eu\_developer\_config.properties和eu\_plugin\_config.xml两个文件,拷贝到游戏工程的assets目录下。 ![](https://box.kancloud.cn/40dc6e04d66712924cd677c38c378b96_943x231.png) Note:然后打开eu\_developer\_config.properties中,将其中EU\_APPID,EU\_APPKEY改为我方分配的AppID和AppKey;EU\_Channel改为当前EU默认渠道在该游戏下面的渠道ID ### **2.3.添加资源** 将EUSDK\_android\_1.0.0/01-客户端接入文档及demo/demo/res目录,覆盖到游戏工程的res目录下。 为了避免和游戏资源冲突,EU默认资源文件都是以x\_开头 ![](https://box.kancloud.cn/96e0cd74d4423e96799577473f4778dd_943x329.png) ### **2.4.配置AndroidManifest.xml** #### **2.4.1添加权限** ``` <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.GET_TASKS"/> <uses-permission android:name="android.permission.VIBRATE"/> ``` #### **2.4.2声明activity** ``` <activity android:name="com.eu.sdk.impl.activities.LoginActivity" android:configChanges="orientation|keyboardHidden|navigation|screenSize" android:exported="true" android:screenOrientation="behind" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" > <activity android:name="com.eu.sdk.impl.activities.PayActivity" android:configChanges="orientation|keyboardHidden|navigation|screenSize" android:exported="true" android:screenOrientation="behind" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" > <mata-data android:name="ulog.enable" android:value="true"/> <mata-data android:name="ulog.level" android:value="DEBUG"/> <mata-data android:name="ulog.local" android:value="true"/> ``` ### **2.5.配置Application** #### **2.5.1.游戏层没有自己的Application** 如果游戏层没有自己的Application,那么游戏需AndroidManifest.xml中的application指定com.eu.sdk.EUApplication。 ![](https://box.kancloud.cn/d49cccfd47dd027f0b0bcb8e34945392_943x364.png) #### **2.5.2.游戏层有自己的Application** 如果游戏有自己的Application需求,有以下两种方式实现: **方式一**:直接让游戏内的Application继承com.eu.sdk.EUApplication即可 **方式二**:我们定义一个GameProxyApplication实现IApplicationListener接口: ``` public class GameProxyApplication implements IApplicationListener { @Override public void onProxyCreate() { // *TODO* *需要在Application的onCreate中的操作,放在这里* //如果需要获取到原始Application对象,通过 EUSDK.getInstance().getApplication()来获取 } @Override public void onProxyAttachBaseContext(Context context) { // *TODO* *需要在Application的attachBaseContext中的操作,放在这里* } @Override public void onProxyConfigurationChanged(Configuration configuration) { // *TODO* *需要在Application的onConfigurationChanged中的操作,放在这里* } @Override public void onProxyTerminate() { // *TODO* *需要在Application的onTerminate中的操作,放在这里* } } ``` 上面定义了游戏的Application,紧接着,在AndroidManifest.xml中,将上面我们定义的GameProxyApplication,配置到meta-data中,android:name为EU\_Game\_Application,同时需要在AAndroidManifest.xml原application节点配置android:name="com.eu.sdk.EUApplication",请参考demo或者下面截图。 ![](https://box.kancloud.cn/a385a81ed755fcb0e55ac34ceda626db_943x291.png) ## **3. 必须调用的API** Note:所有api都通过com.eu.sdk.platform.EUPlatform单例类来调用 ### **3.1.初始化(必接)** Note:**onSwitchAccount、onLogout两处回调必须按照文档中描述处理** 该方法必须在游戏启动Activity的onCreate方法中,调用 ``` EUPlatform.getInstance().init(this, new EUInitListener() { @Override public void onSwitchAccount(UToken data) { //游戏中通过SDK切换到新账号的回调,游戏收到该回调,需要引导用户重新登录,重新加载该新用户对应的角色数据 } @Override public void onPayResult(int code, String msg) { Log.d("EUSDK", "pay result. code:" + code + ";msg:" + msg); switch (code) { case EUCode.CODE_PAY_SUCCESS: Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_LONG).show(); break; case EUCode.CODE_PAY_FAIL: Toast.makeText(MainActivity.this, "支付失败", Toast.LENGTH_LONG).show(); break; case EUCode.CODE_PAY_CANCEL: Toast.makeText(MainActivity.this, "支付取消", Toast.LENGTH_LONG).show(); break; case EUCode.CODE_PAY_UNKNOWN: Toast.makeText(MainActivity.this, "未知错误", Toast.LENGTH_LONG).show(); break; } } @Override public void onLogout() { //用户登出回调(需要收到该回调需要返回游戏登录界面,并调用login接口,打开SDK登录界面) } //渠道SDK登录并去euserver登录认证成功,会回调改方法。 //UToken中的参数如下: //userID:euServer生成的唯一用户ID,游戏服务器需要将游戏账户ID和该userID进行绑定。 //sdkUserID:渠道SDK平台用户唯一ID,一般不需要使用 //username:euServer生成的用户名,比如234234234.uc,4353453453.baidu,65756756756.360 //sdkUserName:渠道SDK平台用户名,可能为空,部分渠道SDK没有返回用户名 //token:euServer生成的会话ID,游戏服务器拿该字段去euServer做二次登录验证 //extension:euServer返回的扩展字段,部分渠道SDK需要,游戏中无需使用该字段的值 //timestamp:euServer生成的时间戳,游戏服务器去euServer做二次登录验证时,传给euServer @Override public void onLoginResult(int code, UToken data) {/ switch (code) { case EUCode.CODE_LOGIN_SUCCESS: //进入游戏 //从UToken中获取用户信息 break; case EUCode.CODE_LOGIN_FAIL: Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_LONG).show(); break; } } @Override public void onInitResult(int code, String msg) { Log.d("EUSDK", "init result.code:" + code + ";msg:" + msg); switch (code) { case EUCode.CODE_INIT_SUCCESS: Toast.makeText(MainActivity.this, "初始化成功", Toast.LENGTH_LONG).show(); break; case EUCode.CODE_INIT_FAIL: Toast.makeText(MainActivity.this, "初始化失败", Toast.LENGTH_LONG).show(); break; } } @Override public void onSinglePayResult(int i, EUOrder euOrder) { //单机游戏额外的支付回调 } @Override public void onProductQueryResult(List<ProductQueryResult> list) { //商品查询结果 } @Override public void onDestroy() { //资源清理回调 } @Override public void onResult(int i, String s) { //状态回调,根据实际情况处理 } }); ``` ### **3.2.登录(必接)** 调用登录接口,打开SDK登录界面,登录成功或者失败,会触发上面初始化监听器中的onLoginResult回调函数 ``` EUPlatform.getInstance().login(this); ``` ### **3.3.登出(必接)** 调用登出接口, SDK账户登出, 但是不是每个SDK都具有登出逻辑,对应没有提供登出接口的SDK,调用该函数,什么也不操作(v1.2.1及以后版本EUSDK已兼容渠道侧没有登出接口) ``` EUPlatform.getInstance().logout(); ``` ### **3.4. 提交扩展数据(必接)** Note: 部分渠道要求在 选择服务器,创建角色,登录游戏,角色升级,退出游戏 等时刻,必须要上报游戏中玩家数据,以便渠道后台统计用户数据。所以,游戏层需要在特定的地方多次调用该方法。 ``` //提交角色信息 UserExtraData data = new UserExtraData(); data.setDataType(dataType); data.setMoneyNum(100); data.setRoleCreateTime(System.currentTimeMillis() / 1000); data.setRoleID("role_100"); data.setRoleName("test_112"); data.setRoleLevel("10"); data.setRoleLevelUpTime(System.currentTimeMillis() / 1000); data.setServerID(10); data.setServerName("server_10"); data.setRoleCareer("法师"); EUPlatform.getInstance().submitExtraData(data); ``` 该方法将调用的时机分为以下几种类型: 创建角色 进入游戏 等级提升 退出游戏 所以在上面4个地方,都需要调用 EUPlatform.getInstance().submitExtraData(UserExtraData extraData) 其中,UserExtraData就是游戏内玩家的数据,dataType赋值分别为: UserExtraData.TYPE\_CREATE\_ROLE:创建角色 UserExtraData. TYPE\_ENTER\_GAME:进入游戏 UserExtraData. TYPE\_LEVEL\_UP:等级提升 UserExtraData. TYPE\_EXIT\_GAME:退出游戏 Note:选择服务器时,因为还没有进入游戏,无法知道角色数据,extraData中只需要传入服务器信息即可。 | 参数名 | 参数类型 | 参数说明 | | --- | --- | --- | |dataType | int |调用时机 | |serverID | String |玩家所在服务区ID | |serverName | String |玩家所在服务器的名称 | |roleID | String |玩家角色ID | |roleName | String |玩家角色名称 | |roleLevel | String |玩家角色等级 | |moneyNum | String |当前角色身上拥有的游戏币数量 | |roleCreateTime | Long |角色创建时间,从1970年到现在的时间,单位秒,必须传入真实的数据,否则UC审核不过 | |roleLevelUpTime | Long |角色等级变化时间,从1970年到现在的时间,单位秒 | |vip | String |玩家VIP等级 | |roleCareer| String |职业名称(非必传,没有职业分类可忽略 ) | ### **3.5. 退出游戏(必接)** 当玩家点击手机上返回键或者游戏中【退出游戏】按钮时,部分渠道SDK会弹出一个“退出确认对话框”,让玩家确认退出,或者取消退出时,游戏层需要在EUExitListener的onGameExit中, 来调用游戏自己的退出游戏确认弹窗(对于没有提供退出确认弹窗接口的SDK,会触发该回调) ``` EUPlatform.getInstance().exitSDK(new EUExitListener() { @Override public void onGameExit() { //游戏自己的退出确认框 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.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() { public void onClick(DialogInterface dialog, int whichButton) { //退出游戏 MainActivity.this.finish(); System.exit(0); } }); builder.show(); } }); ``` ### **3.6. 支付(必接)** 调用充值接口,打开SDK充值界面。 充值成功或者失败,会触发上面初始化监听器中的onPayResult接口 ``` PayParams params = new PayParams(); params.setBuyNum(1); //购买数量,固定1 params.setCoinNum(100); //当前玩家身上拥有的游戏币数量 params.setExtension(System.currentTimeMillis() + ""); //游戏自定义数据,充值成功,回调游戏服的时候,会原封不动返回(cp订单唯一标识) params.setPrice(1); //单位 整数 元 params.setProductId("1"); //产品ID params.setProductName("元宝"); //产品名称 params.setProductDesc("购买100元宝"); //产品描述 params.setRoleId("1"); //角色ID params.setRoleLevel(1); //角色等级 params.setRoleName("测试角色名"); //角色名称 params.setServerId("10"); //服务器ID params.setServerName("测试"); //服务器名称 params.setVip("vip1"); //角色VIP等级 params.setProductType("1"); //物品类型:1、氪金 2、购买商品(道具或服务) params.setPayNotifyUrl("http://www.game.com/pay/callback"); //支付成功,euServer异步通知该地址,告诉游戏服务器发货 EUPlatform.getInstance().pay(this, params); ``` | 参数名 | 参数类型 | 参数说明 | | --- | --- | --- | | productId | int | 充值商品ID,游戏内的商品ID | | productName | String | 商品名称,比如100元宝,500钻石... | | productDesc | String | 商品描述,比如 充值100元宝,赠送20元宝| | price | int | 充值金额(单位:元) | | buyNum | int | 购买数量,一般都是1 | | coinNum | int | 玩家当前身上剩余的游戏币 | | serverID | String | 玩家所在服务器的ID | | serverName | String | 玩家所在服务器的名称| | roleId | String | 玩家角色ID | | roleName | String | 玩家角色名称 | | roleLevel | String | 玩家角色等级 | | vip | String | 玩家vip等级 | | payNotifyUrl | String | 游戏服务器支付回调地址,渠道SDK支付成功,异步通知EUServer,EUServer根据该地址,通知游戏服务器发货| | extension | String | 支付成功之后,EUServer原样返回给游戏服务器(cp订单唯一标识) | |productType| String | 物品类型:1、氪金,2、购买商品(道具或服务);购买的物品属性,氪金是指元宝、钻石此类游戏内代币,商品是指武器装备或VIP等此类非氪金物品 | ## **4. 声明周期函数(必接)** ``` public void onActivityResult(int requestCode, int resultCode, Intent data) { EUSDK.getInstance().onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } public void attachBaseContext(Context newBase) { EUSDK.getInstance().attachBaseContext(this, newBase); super.attachBaseContext(newBase); } public void onStart() { EUSDK.getInstance().onStart(); super.onStart(); } public void onPause() { EUSDK.getInstance().onPause(); super.onPause(); } public void onResume() { EUSDK.getInstance().onResume(); super.onResume(); } public void onNewIntent(Intent newIntent) { EUSDK.getInstance().onNewIntent(newIntent); super.onNewIntent(newIntent); } public void onStop() { EUSDK.getInstance().onStop(); super.onStop(); } public void onDestroy() { EUSDK.getInstance().onDestroy(); super.onDestroy(); } public void onRestart() { EUSDK.getInstance().onRestart(); super.onRestart(); } public void onConfigurationChanged(Configuration newConfig) { EUSDK.getInstance().onConfigurationChanged(newConfig); super.onConfigurationChanged(newConfig); } protected void onSaveInstanceState(Bundle outState) { EUSDK.getInstance().onSaveInstanceState(outState); super.onSaveInstanceState(outState); } public void onWindowFocusChanged(boolean hasFocus) { EUSDK.getInstance().onWindowFocusChanged(hasFocus); super.onWindowFocusChanged(hasFocus); } public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { EUSDK.getInstance().onRequestPermissionResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults); } ```