U8SDK——Flash游戏快速接入U8SDK
Flash中接入U8SDK,需要使用Air ANE的方式 ,按照air官方ANE文档,我们需要实现以下几个部分。 以下仅仅简单说明下接入的步骤。完整工程和实现代码请参考自己购买的U8SDK中U8SDKDemo目录下的AIR相关的几个工程。
1、Android部分接入工程
新建一个Android库工程U8SDKANELib,在这里我们调用U8SDK抽象层中的接口,同时处理抽象层抛出的回调事件,然后通知到AS层
这个工程引用U8SDK2抽象层工程,编译之后,在bin目录下生成u8sdkanelib.jar
AIR针对Android平台,我们要想监听Activity的生命周期方法,必须要绕点弯路了。 在com.adobe.air包名下,新建一个U8ActivityCallbackWrapper类,实现AndroidActivityWrapper.ActivityResultCallback和AndroidActivityWrapper.StateChangeCallback非public类型的接口,然后在这里来监听air底层Activity的生命周期事件
但是,对于onNewIntent事件,暂时还没有好的办法,对于需要在onNewIntent中做工作的渠道SDK,我们必须采用一些其他的措施。
目前就腾讯应用宝需要,我们需要在WXEntryActivity中重写onResp方法,否则微信登录没有任何回调,因为他就是基于onNewIntent的机制。
实现很简单,主要的类实现如下:
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 |
package com.u8.sdk.ane; import java.util.HashMap; import java.util.Map; import org.json.JSONObject; import android.util.Log; import android.widget.Toast; import com.adobe.air.U8ActivityCallbackWrapper; import com.adobe.fre.FREContext; import com.adobe.fre.FREExtension; import com.adobe.fre.FREFunction; import com.u8.sdk.IU8SDKListener; import com.u8.sdk.InitResult; import com.u8.sdk.PayResult; import com.u8.sdk.U8Code; import com.u8.sdk.U8SDK; import com.u8.sdk.verify.UToken; public class U8ANEExtension implements FREExtension{ public static final String FUC_LOG = "u8_log"; public static final String FUC_INIT = "u8_init"; //初始化,在游戏一启动的时候就调用 public static final String FUC_LOGIN = "u8_login"; //登录 public static final String FUC_PAY = "u8_pay"; //支付 public static final String FUC_SWITCH = "u8_switchLogin"; //切换帐号 public static final String FUC_SUPPORT_LOGOUT = "u8_isSupportLogout";//是否支持登出 public static final String FUC_LOGOUT = "u8_logout"; //登出 public static final String FUC_SUPPORT_ACCOUNT_CENTER = "u8_isSupportAccoutCenter";//是否支持用户中心 public static final String FUC_ACCOUNT_CENTER = "u8_showAccountCenter"; //显示用户中心 public static final String FUC_SUBMIT = "u8_submitExtraData"; //提交游戏数据 public static final String FUC_SUPPORT_EXIT = "u8_isSupportExit";//是否支持退出确认框 public static final String FUC_EXIT = "u8_exit"; //打开SDK确认退出界面 public final static String CALLBACK_INIT = "OnInitSuc"; //初始化成功 public final static String CALLBACK_LOGIN = "OnLoginSuc"; //SDK登录成功的回调方法名称和Unity中一致 public final static String CALLBACK_LOGOUT = "OnLogout"; //SDK登出的回调方法名称和Unity中一致 public final static String CALLBACK_PAY = "OnPayResult"; //支付成功或者失败 @Override public FREContext createContext(String params) { return new U8ANEContext(); } @Override public void dispose() { } @Override public void initialize() { } private void tip(final String tip){ U8SDK.getInstance().runOnMainThread(new Runnable() { @Override public void run() { Toast.makeText(U8SDK.getInstance().getContext(), tip, Toast.LENGTH_SHORT).show(); } }); } /*** * * context * @author xiaohei * */ public class U8ANEContext extends FREContext{ private U8ActivityCallbackWrapper callback; private boolean isSwitchAccount = false; //当前是否为切换帐号 public U8ANEContext(){ callback = new U8ActivityCallbackWrapper(); callback.init(); //设置U8SDK回调监听类 initSDKListener(); } @Override public Map<String, FREFunction> getFunctions() { Map<String, FREFunction> functions = new HashMap<String, FREFunction>(); functions.put(FUC_LOG, new U8Function(FUC_LOG)); functions.put(FUC_INIT, new U8Function(FUC_INIT)); functions.put(FUC_LOGIN, new U8Function(FUC_LOGIN)); functions.put(FUC_PAY, new U8Function(FUC_PAY)); functions.put(FUC_SWITCH, new U8Function(FUC_SWITCH)); functions.put(FUC_LOGOUT, new U8Function(FUC_LOGOUT)); functions.put(FUC_SUBMIT, new U8Function(FUC_SUBMIT)); functions.put(FUC_EXIT, new U8Function(FUC_EXIT)); return functions; } @Override public void dispose() { callback.destroy(); } private void initSDKListener(){ U8SDK.getInstance().setSDKListener(new IU8SDKListener(){ @Override public void onResult(final int code, final String message) { Log.d("U8SDK", "onResult:"+message); switch(code){ case U8Code.CODE_INIT_SUCCESS: Log.d("U8SDK_ANE", "init success"); try{ dispatchStatusEventAsync(CALLBACK_INIT, ""); }catch(Exception e){ e.printStackTrace(); } break; case U8Code.CODE_INIT_FAIL: Log.d("U8SDK_ANE", "init failed"); break; case U8Code.CODE_LOGIN_FAIL: Log.d("U8SDK_ANE", "login failed"); break; case U8Code.CODE_SHARE_SUCCESS: Log.d("U8SDK_ANE", "share success"); break; case U8Code.CODE_SHARE_FAILED: Log.d("U8SDK_ANE", "share failed"); break; case U8Code.CODE_LOGOUT_SUCCESS: Log.d("U8SDK_ANE", "logout success"); break; case U8Code.CODE_PAY_FAIL: Log.d("U8SDK_ANE", "pay failed"); try{ dispatchStatusEventAsync(CALLBACK_PAY, "1"); }catch(Exception e){ e.printStackTrace(); } break; case U8Code.CODE_PAY_SUCCESS: Log.d("U8SDK_ANE", "pay success"); try{ dispatchStatusEventAsync(CALLBACK_PAY, "0"); }catch(Exception e){ e.printStackTrace(); } break; default: Log.d("U8SDK_ANE", "not supported event"); } } @Override public void onLoginResult(String result) { isSwitchAccount = false; Log.d("U8SDK", "SDK 登录成功,不用做处理,在onAuthResult中处理登录成功, 参数如下:"); Log.d("U8SDK", result); } @Override public void onAuthResult(final UToken authResult) { U8SDK.getInstance().getContext().runOnUiThread(new Runnable() { @Override public void run() { if(!authResult.isSuc()){ tip("SDK登录认证失败,确认U8Server是否配置"); return; } 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(); } dispatchStatusEventAsync(CALLBACK_LOGIN, json.toString()); } }); } @Override public void onSwitchAccount() { Log.d("U8SDK", "SDK 切换帐号成功,游戏中收到事件,需要返回登录界面"); dispatchStatusEventAsync(CALLBACK_LOGOUT, ""); } @Override public void onSwitchAccount(String result) { isSwitchAccount = true; Log.d("U8SDK", "SDK 切换帐号并登录成功,不用做处理,在onAuthResult中处理登录成功, 参数如下:"); Log.d("U8SDK", result); } @Override public void onLogout() { Log.d("U8SDK", "SDK logout成功,游戏中收到事件,需要返回登录界面"); dispatchStatusEventAsync(CALLBACK_LOGOUT, ""); } @Override public void onPayResult(final PayResult result) { //网游,此接口不用实现;该接口给单机使用 } @Override public void onInitResult(InitResult result) { //此接口废弃 } }); } } } |
2、as端接入工程(flex手机库工程)
新建一个Flex手机库工程(U8SDKExtension),我们在这个工程中,作为ANE中as端,在这里封装游戏中可以直接使用的接口,同时,调用Android层对应的方法。
并接收来自Android层的事件回调,收到底层事件的时候,继续抛出AS层的事件。
为了简单方便,我们直接封装一个单例接口,使得游戏中的调用,更加简单。在Flex Builder中编译之后,在bin目录下生成一个U8SDKExtension.swc文件
主要的单例接口如下:
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 |
package com.u8.sdk.extension { import com.u8.sdk.extension.data.U8ExtraGameData; import com.u8.sdk.extension.data.U8LoginResult; import com.u8.sdk.extension.data.U8PayParams; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.StatusEvent; import flash.external.ExtensionContext; /*** * SDK统一调用接口 * ***/ public class U8SDKInterface extends EventDispatcher { private static const EXT_ID:String = "com.u8.sdk.flash.extension"; private static var _instance:U8SDKInterface; private var context:ExtensionContext; public function U8SDKInterface() { if(_instance) { throw new Error("U8SDKInterface is a singleton class. please use U8SDKInterface.getInstance() to get the only instance"); } this.context = ExtensionContext.createExtensionContext(EXT_ID, ""); this.context.addEventListener(StatusEvent.STATUS, onStatus); _instance = this; } public static function getInstance():U8SDKInterface { if(!_instance) { new U8SDKInterface(); } return _instance; } //调用底层的logcat日志输出 public function log(msg:String):void { this.context.call("u8_log", msg); } //初始化,如果底层直接调用,游戏中不需要调用 public function init():void { log("init called in extension"); this.context.call("u8_init"); } //打开SDK登录界面 public function login():void { log("login called in extension"); this.context.call("u8_login"); } //调用SDK的切换帐号接口,可以不调用 public function switchLogin():void { log("switchLogin called in extension"); this.context.call("u8_switchLogin"); } //调用logout之前,进行判断 public function isSupportLogout():Boolean { log("isSupportLogout called in extension"); return Boolean(this.context.call("u8_isSupportLogout")); } //调用SDK退出当前帐号接口,可以不调用 public function logout():void { log("logout called in extension"); this.context.call("u8_logout"); } //调用showAccountCenter之前,必须判断 public function isSupportAccountCenter():Boolean { log("isSupportAccountCenter called in extension"); return Boolean(this.context.call("u8_isSupportAccoutCenter")); } //显示用户中心,游戏界面中,必须要有【个人中心】按钮,可以打开部分渠道SDK的个人中心界面,强制要求的 //游戏中,可以根据isSupportAccountCenter接口先判断,当前渠道是否有该接口,有则显示按钮,并调用;否则,直接隐藏该按钮 public function showAccountCenter():void { log("showAccountCenter called in extension"); this.context.call("u8_showAccountCenter"); } //当前渠道是否支持退出确认,调用sdkExit之前,需要先调用该方法判断 public function isSupportExit():Boolean { log("isSupportExit called in extension"); return Boolean(this.context.call("u8_isSupportExit")); } //调用SDK退出确认框。在游戏退出时调用。但是,部分渠道SDK没有该接口。需要,调用isSupportExit判断,如果有,则调用该接口;没有,则调用游戏自己的退出确认框。 //监听手机返回键,按返回键的时候,必须要触发该接口 public function sdkExit():void { log("sdkExit called in extension"); this.context.call("u8_exit"); } //提交游戏中玩家角色数据,必须调用,否则部分渠道SDK上不了,强制要求 //调用时机,在U8ExtraGameData中dataType字段,该类中有几个常量,分别对应不同的调用时机。 //游戏中,根据自己的逻辑,在合适的地方调用。 public function submitGameData(data:U8ExtraGameData):void { var json:String = JSON.stringify(data); log("submitGameData called in extension:"+data); this.context.call("u8_submitExtraData", json); } //打开SDK支付界面 public function pay(data:U8PayParams):void { var json:String = JSON.stringify(data); log("pay called in extension:"+json); this.context.call("u8_pay", json); } private function onStatus(event:StatusEvent):void { log("onStatus code:"+event.code); log("onStatus level:"+event.level); switch(event.code) { case "OnInitSuc": dispatchEvent(new Event("OnU8InitSuc")); break; case "OnLoginSuc": var data:String = event.level; var result:U8LoginResult = U8LoginResult(JSON.parse(event.level)); dispatchEvent(new U8SDKLoginEvent("OnU8LoginSuc", result)); break; case "OnLogout": dispatchEvent(new Event("OnU8Logout")); break; case "OnPayResult": var suc:String = event.level; if(suc == "0") { dispatchEvent(new Event("OnPayResultSuc")); }else { dispatchEvent(new Event("OnPayResultFail")); } } } } } |
3、打包ane
新建一个目录,比如叫U8SDK_ANE。
3.1、拷贝第二步中生成的U8SDKExtension.swc文件到这个目录
3.2、新建一个android子目录
3.3、解压U8SDKExtension.swc,将里面的library.swf和catalog.xml拷贝到android子目录下(注意:每次修改了U8SDKExtension工程,生成新的U8SDKExtension.swc的时候,也要解压,拷贝到android目录下,替换library.swf和catalog.xml)
3.4、拷贝U8SDKANELib工程中bin目录下生成的u8sdkanelib.jar 和U8SDK2抽象层工程的bin目录下生成的u8sdk2.jar到这个文件夹中
3.5、在android文件夹中运行cmd, 然后执行 jar -xf u8sdk2.jar 这个时候,会在当前目录下解压u8sdk2.jar,生成com 和META-INF文件夹.紧接着执行jar -uf u8sdkanelib.jar com 将u8sdk2的文件合并到u8sdkanelib.jar文件中,同时删除解压生成的com和META-INF文件夹。
因为ANE打包,不支持同时存在多个jar包的情况,所以,我们需要合并这两个jar包
3.6、在U8SDK_ANE目录下,新建一个extension.xml,配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<extension xmlns="http://ns.adobe.com/air/extension/3.1"> <id>com.u8.sdk.flash.extension</id> <versionNumber>1</versionNumber> <platforms> <platform name="Android-ARM"> <applicationDeployment> <nativeLibrary>u8sdkanelib.jar</nativeLibrary> <initializer>com.u8.sdk.ane.U8ANEExtension</initializer> <finalizer>com.u8.sdk.ane.U8ANEExtension</finalizer> </applicationDeployment> </platform> <platform name="default"> <applicationDeployment/> </platform> </platforms> </extension> |
3.7、通过Flash Builder 生成一个p12的证书,用来打包ANE。 我们这里生成的是u8sdk.p12。
3.8、在U8SDK_ANE目录下运行cmd,执行如下命令:
1 2 3 4 |
adt -package -storetype PKCS12 -keystore u8sdk.p12 -storepass uustory -targ et ane com.u8.sdk.flash.extension.ane extension.xml -swc U8SDKExtension.swc -platform And roid-ARM -C android . |
这样,会在当前目录下生成一个com.u8.sdk.flash.extension.ane文件。可以在游戏工程中导入该ane文件,这样游戏中就可以调用了
4、引入ane,测试工程
我们在Flash Builder中创建一个Android界面应用程序,然后在界面中,有登录和支付按钮,点击,分别触发登录和支付:
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 |
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="320" creationComplete="initApp();"> <fx:Script> <![CDATA[ import com.u8.sdk.extension.U8SDKInterface; import com.u8.sdk.extension.U8SDKLoginEvent; import com.u8.sdk.extension.data.U8LoginResult; import com.u8.sdk.extension.data.U8PayParams; private function initApp():void { trace("onAppStart......"); U8SDKInterface.getInstance().addEventListener("OnU8InitSuc", onU8InitSuc); U8SDKInterface.getInstance().addEventListener("OnU8LoginSuc", onU8LoginSuc); U8SDKInterface.getInstance().addEventListener("OnU8Logout", onU8Logout); U8SDKInterface.getInstance().addEventListener("OnPayResultSuc", onU8PaySuc); U8SDKInterface.getInstance().addEventListener("OnPayResultFail", onU8PayFail); U8SDKInterface.getInstance().init(); } protected function onU8InitSuc(event:Event):void { trace("onU8InitSuc......"); //U8SDKInterface.getInstance().log("onU8InitSuc......"); lblTip.text = "初始化成功"; } protected function onU8LoginSuc(event:U8SDKLoginEvent):void { trace("onU8LoginSuc......"); U8SDKInterface.getInstance().log("onU8LoginSuc......"); var result:U8LoginResult = event.loginResult; lblTip.text = event.loginResult.username; } protected function onU8Logout(event:Event):void { trace("onU8Logout......"); U8SDKInterface.getInstance().log("onU8Logout......"); lblTip.text = "未登录"; } protected function onU8PaySuc(event:Event):void { trace("onU8PaySuc......"); U8SDKInterface.getInstance().log("onU8PaySuc......"); lblTip.text = "支付成功"; } protected function onU8PayFail(event:Event):void { trace("onU8PayFail......"); U8SDKInterface.getInstance().log("onU8PayFail......"); lblTip.text = "支付失败"; } protected function btnLogin_clickHandler(event:MouseEvent):void { trace("click login....."); U8SDKInterface.getInstance().log("click login...."); U8SDKInterface.getInstance().login(); } protected function btnPay_clickHandler(event:MouseEvent):void { trace("click pay....."); try{ var data:U8PayParams = new U8PayParams(); data.buyNum = 1; data.coinNum = 100; data.extension = ""; data.price = 100; data.productId = "1"; data.productName = "元宝"; data.productDesc = "购买100元宝"; data.roleId = "1"; data.roleLevel = 1; data.roleName = "测试角色名"; data.serverId = 10; data.serverName = "测试"; data.vip = "vip1"; data.orderID = "3544354354352345676"; //这个订单号是U8server分配的订单号,调用pay之前,需要去u8server下单。 trace("click pay 2....."); U8SDKInterface.getInstance().pay(data); }catch(err:Error) { trace("error caught:"+err); } } ]]> </fx:Script> <fx:Declarations> <!-- 将非可视元素(例如服务、值对象)放在此处 --> </fx:Declarations> <s:DataGroup width="700" height="700" horizontalCenter="0" verticalCenter="0"/> <s:Label id="lblTip" x="890" y="307" fontFamily="Georgia" fontSize="36" fontWeight="bold" text="U8SDK Demo"/> <s:Button id="btnLogin" x="872" y="457" width="300" label="登 录" click="btnLogin_clickHandler(event)" fontFamily="Arial"/> <s:Button id="btnPay" x="872" y="635" width="300" label="支 付" click="btnPay_clickHandler(event)" fontFamily="Arial"/> </s:Application> |
本文出自 U8SDK技术博客,转载时请注明出处及相应链接。
本文永久链接: http://www.uustory.com/?p=2036