U8SDK——Unity手游接入U8SDK(Android篇)
U8SDK的设计之初,就是为了能够支持各种游戏引擎开发的游戏,而不仅仅是Android的原生平台。目前一大半的手游,都是采用Unity3D和Cocos2dx开发,那么这里,我们就先来一步步给大家演示,用Unity开发的游戏,如何通过U8SDK来快速地完成多家渠道SDK的接入。
Unity研发的手游,只需要调用U8SDK抽象层即可完成多家渠道SDK的接入,而不需要在Unity中耦合各个渠道SDK,保证游戏层逻辑层的简单,以及SDK部分的绝对重用。
下面,我们看看,在Unity中调用U8SDK主要需要完成的工作:
1、建立一个Android工程,作为U8SDK和Unity平台通信的中间协调工程
2、定义一致的通信数据类型,我们这里采用JSON格式
3、在Unity中,通过C#完成一套统一的SDK调用接口,给逻辑层调用。同时多个平台(Android,IOS,PC等)的接口完全相同。
这一篇,我们就先来完成第一步和第二步。
1,新建一个Android工程,将IsLibrary设置为true,将该工程作为库工程,这样当你编译的时候,会在bin目录下产生一个jar包,而不是一个apk
2,设置依赖工程为U8SDK2抽象层工程,同时将Unity3D提供的Android的jar包,复制到该工程的libs目录下
3、然后建立两个类,一个为U8UnityContext ,这个类继承UnityPlayerActivity ,也是游戏的启动Activity。
4、另一个是IU8SDKListener 的实现类,主要实现一些SDK的回调方法
我们先来看看这两个类的实现,之后再来解释一些关键的东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
package com.u8.sdk; import org.json.JSONException; import org.json.JSONObject; import android.content.Intent; import android.os.Bundle; import com.u8.sdk.plugin.U8Pay; import com.u8.sdk.plugin.U8User; import com.unity3d.player.UnityPlayer; import com.unity3d.player.UnityPlayerActivity; /*** * 记得将游戏工程中的AndroidManifest.xml中application节点,增加一个android:name="U8Application" * 如果游戏有自己的Application。那么通过实现IApplicationListener接口来实现,而不要使用继承Application。 * 然后将自己的Application类,配置到AndroidManifest.xml中的meta-data节点中,name为"U8_Game_Application" * @author xiaohei * */ public class U8UnityContext extends UnityPlayerActivity{ public final static String CALLBACK_GAMEOBJECT_NAME = "(u8sdk_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(); } //U8SDK 初始化 public void initSDK(){ U8SDK.getInstance().setSDKListener(new UnityU8SDKListener(this)); U8SDK.getInstance().init(this); U8SDK.getInstance().onCreate(); } //登录接口 public void login(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().login(); } }); } //自定义登录接口 public void loginCustom(final String customData){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().login(customData); } }); } //切换帐号接口 public void switchLogin(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().switchLogin(); } }); } //显示用户中心接口 public void showAccountCenter(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().showAccountCenter(); } }); } //登出 public void logout(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().logout(); } }); } //提交扩展数据 public void submitExtraData(String data){ final UserExtraData extraData = parseGameData(data); U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().submitExtraData(extraData); } }); } //SDK退出接口 public void exit(){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8User.getInstance().exit(); } }); } //支付接口 public void pay(String data){ final PayParams params = parsePayParams(data); U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { U8Pay.getInstance().pay(params); } }); } //SDK是否支持退出确认功能 public boolean isSupportExit(){ return U8User.getInstance().isSupport("exit"); } //SDK是否支持用户中心 public boolean isSupportAccountCenter(){ return U8User.getInstance().isSupport("showAccountCenter"); } //SDK是否支持登出 public boolean isSupportLogout(){ return U8User.getInstance().isSupport("logout"); } //向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")); } 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("");//该字段废弃不用 params.setVip(json.getString("vip")); params.setOrderID(json.getString("orderID")); params.setExtension(json.getString("extension")); }catch(Exception e){ e.printStackTrace(); } return params; } public void onActivityResult(int requestCode, int resultCode, Intent data){ U8SDK.getInstance().onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data); } public void onStart(){ U8SDK.getInstance().onStart(); super.onStart(); } public void onPause(){ U8SDK.getInstance().onPause(); super.onPause(); } public void onResume(){ U8SDK.getInstance().onResume(); super.onResume(); } public void onNewIntent(Intent newIntent){ U8SDK.getInstance().onNewIntent(newIntent); super.onNewIntent(newIntent); } public void onStop(){ U8SDK.getInstance().onStop(); super.onStop(); } public void onDestroy(){ U8SDK.getInstance().onDestroy(); super.onDestroy(); } public void onRestart(){ U8SDK.getInstance().onRestart(); super.onRestart(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
package com.u8.sdk; import org.json.JSONObject; import com.u8.sdk.verify.UToken; import android.util.Log; import android.widget.Toast; public class UnityU8SDKListener implements IU8SDKListener{ private U8UnityContext context; private boolean isSwitchAccount = false; //当前是否为切换帐号 public UnityU8SDKListener(U8UnityContext context){ this.context = context; } @Override public void onResult(final int code, String msg) { // TODO Auto-generated method stub U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { switch(code){ case U8Code.CODE_INIT_SUCCESS: context.sendCallback(U8UnityContext.CALLBACK_INIT, null); break; case U8Code.CODE_INIT_FAIL: Toast.makeText(context, "SDK初始化失败", Toast.LENGTH_SHORT).show(); break; case U8Code.CODE_LOGIN_FAIL: Toast.makeText(context, "SDK登录失败", Toast.LENGTH_SHORT).show(); break; case U8Code.CODE_PAY_FAIL: Toast.makeText(context, "支付失败", Toast.LENGTH_SHORT).show(); break; case U8Code.CODE_PAY_SUCCESS: Toast.makeText(context, "支付成功,到账时间可能稍有延迟", Toast.LENGTH_SHORT).show(); break; } } }); } //此接口已经废弃 @Override public void onInitResult(InitResult result) { // TODO Auto-generated method stub // 此接口已经废弃 } //SDK登录成功的回调 @Override public void onLoginResult(String data) { Log.d("U8SDK", "SDK 登录成功,不用做处理,在onAuthResult中处理登录成功, 参数如下:"); Log.d("U8SDK", data); this.isSwitchAccount = false; } //切换帐号,需要回到登录界面,并弹出SDK登录界面 @Override public void onSwitchAccount() { context.sendCallback(U8UnityContext.CALLBACK_SWITCH_LOGIN, null); } //切换帐号,并登录成功,到这里和Login的回调onLoginResult一样 @Override public void onSwitchAccount(String data) { Log.d("U8SDK", "SDK 切换帐号并登录成功,不用做处理,在onAuthResult中处理登录成功, 参数如下:"); Log.d("U8SDK", data); this.isSwitchAccount = true; } //登出,需要回到登录界面,并弹出SDK登录界面 @Override public void onLogout() { context.sendCallback(U8UnityContext.CALLBACK_LOGOUT, null); } //SDK登录成功之后,去U8Server进行登录认证 @Override public void onAuthResult(UToken authResult) { 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(); } context.sendCallback(U8UnityContext.CALLBACK_LOGIN, json.toString()); } //对于手机网游,不需要实现这个接口,因为网游支付是通过服务器回调通知加虚拟币的。 //这个接口主要用于单机游戏,作为单机的支付结果回调接口 @Override public void onPayResult(PayResult result) { //TODO } } |
在U8UnityContext 中,我们定义了一系列的接口。这些接口就是给Unity中调用的。比如Login,switchLogin,logout等。而这些方法本身仅仅是对U8SDK抽象层提供的方法进行了一个简单的包裹。通过,U8SDK.getInstance().runOnMainThread()来让所有的接口都在UI主线程中完成。
关于U8SDK的初始化,有两部分。第一部分是U8SDK本身的初始化,包括参数的读取和解析等,这个需要将AndroidManifest.xml中application接口的android:name设置为”com.u8.sdk.U8Application”。注意,这里一定要设置,否则U8SDK无法初始化。如果,游戏有自己的某些业务需要在Application中完成,可以通过实现U8SDK提供的IApplicationListener接口来完成。
第二部分需要在Activity的onCreate中完成(根据游戏不同,也可以在Unity中合适的地方调用初始化接口),包括,设置U8SDK的回调监听,初始化加载插件,以及调用onCreate回调。表现为以下三步:
1 2 3 4 |
U8SDK.getInstance().setSDKListener (new UnityU8SDKListener(this)); U8SDK.getInstance().init(this); U8SDK.getInstance().onCreate(); |
UnityU8SDKListener 是U8SDK的回调简体接口的实现类。所有SDK相关的回调都是通过这些接口完成的。
onLoginResult: SDK登录成功的回调
onSwitchAccount: SDK中切换帐号的回调
onLogout: SDK登出的回调
onAuthResult: U8Server登录验证的回调
onResult: 所有SDK操作成功或者失败的状态回调
当我们收到部分回调的时候,我们需要通知到Unity中,包括之前,我们写的那些接口,比如Pay和submitExtraData都是含有参数的。
这里就来解决Unity和Android中通信的数据结构问题。虽然Unity和Android通信也可以使用复杂的结构,但是我还是推荐采用简单统一的数据协议比较好,这里我们选择JSON,简单高效。只要保证,两边数据的key一致就可以了。
Unity调用Android的接口,比如Pay和submitExtraData都通过一个JSON字符串传递过来,然后这边解析一下。
对于Android中需要通知Unity中的也是一样,使用JSON格式的字符串,然后通过
UnityPlayer.UnitySendMessage( “#0000c0;”>gameObject, methodName, jsonParams)接口来完成通信。
好了,完成这个,Android中的部分,就完成了。再提醒一次,不要忘记配置AndroidManifest.xml哦,这里附上AndroidManifest.xml文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.u8.sdk" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:name="com.u8.sdk.U8Application"> <activity android:name="com.u8.sdk.U8UnityContext" android:label="@string/app_name" android:screenOrientation="landscape" android:launchMode="singleTask" android:configChanges="orientation|keyboardHidden|screenSize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> |
本文出自 U8SDK技术博客,转载时请注明出处及相应链接。
本文永久链接: http://www.uustory.com/?p=1859