How to quickly and efficiently access sdks-channel SDK access (that is, implementing the abstraction layer interface) and SDK Channels
Question: Many people who develop games probably take over the Channel SDK, UC, dangle, 91, Xiaomi, 360 ...... according to statistics, there are currently no more than 100 channels in the domestic market, and there are also some small channels without sdks. The SDK access methods for each channel are mostly the same. However, these differences allow SDK access to produce endless variables. Therefore, if you have no experience or have never been pitted by the SDK before accessing the SDK, You will be lucky when you see this series of articles. You can avoid this. If you have been pitted before and are still being pitted, now is the time for your relief.
Index each previous article for reference:
Note: Xiao Hei-Unified SDK access framework (similar to prism and AnySDK)
How to quickly and efficiently access the SDK-overall idea and architecture
How to quickly and efficiently access the design of the abstract layer of SDK--SDK access
How to quickly and efficiently access the SDK-game Access SDK (only accessing the abstract framework)
In the previous article, we showed how to call a game when you need to access the SDK. It only calls the singleton packaging class of each plug-in provided by the abstraction layer. In each Singleton packaging class, the corresponding plug-in interface is referenced. So how is this interface instantiated? in the previous article, we mentioned that it is the configuration read from asssets. It is then instantiated based on the complete class name entered in the configuration. This implementation class is implemented when various channels are connected. In this article, we will take the UC channel as an example to connect it to our U8 SDK.
First, according to the documents provided by UC, we know that the login and payment functions are required. In this case, we need two classes, one class implementing the IUser interface of the abstract SDK and the other implementing the IPay interface of the abstract SDK. So, let's review the points that need attention for implementation classes. In the article on the abstraction layer, we will look at the instantiation process of each plug-in:
public Object initComponent(int type){Class localClass = null;try {if(!isSupportComponent(type)){Log.e("U8SDK", "The config of the U8SDK is not support plugin type:"+type);return null;}String name = getComponentName(type);localClass = Class.forName(name);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();return null;}try {return localClass.getDeclaredConstructor(new Class[]{Activity.class}).newInstance(new Object[]{U8SDK.getInstance().getContext()});} catch (Exception e) {e.printStackTrace();}return null;}
We can see that the constructor with an Activity parameter of the implementation class is called for instantiation. This requires us to define a constructor with Activity parameters when implementing the plug-in interface. Let's take a look at the login implementation class and payment implementation class of UC.
package com.u8.sdk;import com.u8.sdk.IUser;import com.u8.sdk.U8SDK;import android.app.Activity;public class UCUser implements IUser {private Activity context;public UCUser(Activity context){this.context = context;this.initSDK();}public void initSDK(){UCSDK.getInstance().initSDK(this.context, U8SDK.getInstance().getSDKParams());}@Overridepublic void login() {UCSDK.getInstance().login(this.context, U8SDK.getInstance().getSDKParams());}}
Payment:
package com.u8.sdk;import com.u8.sdk.IPay;import com.u8.sdk.PayParams;import android.app.Activity;public class UCPay implements IPay {private Activity context;public UCPay(Activity context){this.context = context;}@Overridepublic void pay(PayParams data) {UCSDK.getInstance().pay(this.context, data);}}
Let's first look at the implementation class of the login plug-in above. We can see that it implements the login interface and defines a constructor with Activity as the parameter. In the login method, call the login of the ucsdk Singleton class to call the logon interface. At the same time, it is noted that there is an initSDK method in the login implementation class, which is called during instantiation. This is because the uc sdk requires that the SDK be initialized at the beginning of the game.
Similarly, the pay method is implemented in the payment implementation class, and the payment interface is called by calling the UCSDK Singleton.
As you can see, all the problems are now simplified. It is necessary to implement all functions required by the uc sdk in the ucsdk Singleton class. Let's take a look at the code in UCSDK:
Package com. u8.sdk; import org. json. JSONException; import org. json. JSONObject; import com. u8.sdk. activityCallbackAdapter; import com. u8.sdk. loginResult; import com. u8.sdk. payParams; import com. u8.sdk. SDKConfigData; import com. u8.sdk. u8Code; import com. u8.sdk. u8SDK; import com. u8.sdk. utils. SDKTools; import android. app. activity; import android. app. progressDialog; import android. content. dialogInterface; import and Roid. util. log; import cn. uc. gamesdk. UCCallbackListener; import cn. uc. gamesdk. UCCallbackListenerNullException; import cn. uc. gamesdk. UCFloatButtonCreateException; import cn. uc. gamesdk. UCGameSDK; import cn. uc. gamesdk. UCGameSDKStatusCode; import cn. uc. gamesdk. UCLogLevel; import cn. uc. gamesdk. UCLoginFaceType; import cn. uc. gamesdk. UCOrientation; import cn.uc.gamesdk.info. featureSwitch; import cn.uc.gamesdk.info. G AmeParamInfo; import cn.uc.gamesdk.info. orderInfo; import cn.uc.gamesdk.info. paymentInfo; public class UCSDK {enum SDKState {StateDefault, StateIniting, StateInited, StateLogin, StateLogined} private SDKState state = SDKState. stateDefault; private boolean loginAfterInit = false; private ProgressDialog loadingActivity = null; private static UCSDK instance; private UCLogLevel logLevel = UCLogLevel. DEBUG; private Int cpId; private int gameId; private int channel; private boolean debugMode = true; private UCSDK () {} public static UCSDK getInstance () {if (instance = null) {instance = new UCSDK ();} return instance;} private void parseSDKParams (SDKConfigData params) {this. gameId = params. getInt ("UCGameId"); this. cpId = params. getInt ("UCCpId"); this. channel = U8SDK. getInstance (). getCurrChannel (); if (this. channel <= 0) {this. Channel = params. getInt ("UCChannel");} this. debugMode = params. getBoolean ("UCDebugMode");} public void initSDK (Activity context, SDKConfigData params) {this. parseSDKParams (params); this. initSDK (context);} public void login (Activity context, SDKConfigData params) {this. parseSDKParams (params); this. login (context);}/*** mandatory function <br> * sdk initialization function <br> */public void initSDK (final Activity context) {this. state = SDK State. stateIniting; try {showWaitDialog (context); U8SDK. getInstance (). setActivityCallback (new ActivityCallbackAdapter () {@ Overridepublic void onBackPressed () {ucSdkExit (context) ;}@ Overridepublic void onDestroy () {callback (context) ;}}); if (loginAfterInit) {// showProgressDialog (context);} GameParamInfo gpi = new GameParamInfo (); // the following values are for reference only. setCpId (this. cpId); gpi. setGameId (this. gameId); gp I. setServerId (0); // The server ID can be set based on the game's own definition, or 0 is input. // The recharge history query and the switch Account button are displayed in the 9 game community settings, // if this parameter is not set, the "query recharge history" button is displayed in the production environment by default, and the "Switch account" button is not displayed. // the gpi is invalid in the test environment. setFeatureSwitch (new FeatureSwitch (true, false); // sets the SDK logon interface to a horizontal screen, and the personal center and recharge page are forced vertical screens by default, which cannot be modified. // UCGameSDK. defasdk SDK (). setOrientation (UCOrientation. LANDSCAPE); // set the SDK logon interface to a portrait UCGameSDK. defasdk SDK (). setOrientation (UCOrientation. LANDSCAPE); // set the logon interface: // USE_WIDGET-lite logon interface // USE _ STANDARD-STANDARD Logon interface UCGameSDK. defaultSDK (). setLoginUISwitch (UCLoginFaceType. USE_WIDGET); // setUIStyle is out of date and does not need to be called. // UCGameSDK. defasdk SDK (). setUIStyle (UCUIStyle. STANDARD); UCGameSDK. defasdk SDK (). initSDK (context, this. logLevel, this. debugMode, gpi, new UCCallbackListener <String> () {@ Overridepublic void callback (int code, String msg) {Log. e ("UCGameSDK", "returned data from the UCGameSDK initialization interface msg:" + msg + ", code:" + code + ", debug:" + debugMode + "\ n "); hideWaitDialog (context); if (code = UCGameSDKStatusCode. SUCCESS) {if (state! = SDKState. stateIniting) {U8SDK. getInstance (). onResult (U8Code. CODE_INIT_FAIL, "uc sdk init fail. not initing. curr state is: "+ state); return;} state = SDKState. stateInited; U8SDK. getInstance (). onResult (U8Code. CODE_INIT_SUCCESS, "uc sdk init success"); if (loginAfterInit) {login (context) ;}} else {hideWaitDialog (context); state = SDKState. stateDefault; U8SDK. getInstance (). onResult (U8Code. CODE_INIT_FAIL, "uc sdk Init fail. err: "+ msg) ;}});} catch (UCCallbackListenerNullException e) {e. printStackTrace ();} catch (Exception e) {e. printStackTrace () ;}} private LoginResult encodeLoginResult (String sid) {String channel = "" + getChannel (); String expansion = ""; JSONObject ext = new JSONObject (); try {ext. put ("ext", "u8"); expansion = ext. toString ();} catch (JSONException e) {e. printStackTrace ();} return new LoginResul T (sid, channel, expansion);} public void login (final Activity context) {if (state. ordinal () <SDKState. stateInited. ordinal () {loginAfterInit = true; initSDK (context); return;} if (! SDKTools. isNetworkAvailable (context) {U8SDK. getInstance (). onResult (U8Code. CODE_NO_NETWORK, "The network now is unavailable"); return;} try {state = SDKState. stateLogin; UCGameSDK. defasdk SDK (). login (context, new UCCallbackListener <String> () {@ Overridepublic void callback (int code, String msg) {Log. e ("UCGameSDK", "data returned by the UCGameSdk logon interface: code =" + code + ", msg =" + msg); // The logon is successful. You can obtain the sid. And use sid to log on to the game. // The client cannot directly obtain UCIDif (code = UCGameSDKStatusCode. SUCCESS) {state = SDKState. stateLogined; String sid = UCGameSDK. defasdk SDK (). getSid (); U8SDK. getInstance (). onResult (U8Code. CODE_LOGIN_SUCCESS, sid); LoginResult result = encodeLoginResult (sid); U8SDK. getInstance (). onLoginResult (result); // execution of the floating button creation method ucSdkCreateFloatButton (context); // execution of the floating button display method ucSdkShowFloatButton (context);} else {state = SDKState. stateInite D; U8SDK. getInstance (). onResult (U8Code. CODE_LOGIN_FAIL, msg);} // Logon Failed. You should execute initialization before logging on to the system. If (code = UCGameSDKStatusCode. NO_INIT) {// you need to call the SDK initialization method initSDK (context);} // log on and exit. This callback will be executed when the logon interface exits. If (code = UCGameSDKStatusCode. LOGIN_EXIT) {// The logon interface is closed. You need to determine whether the game has successfully logged on to the console and perform the corresponding operation. }});} catch (UCCallbackListenerNullException e) {e. printStackTrace () ;}} private PaymentInfo decodePayParams (PayParams payParams) {Log. I ("UCSDK", "The payParams is" + payParams. toString (); PaymentInfo pInfo = new PaymentInfo (); // creates a Payment object to pass the recharge information. // sets the custom parameters for recharging. this parameter is not processed, // After the recharge is complete, the sdk server will not pass the value to the game server until it notifies the game server of the result of the recharge, and the field is the call for the server callback. BackInfo field if (! SDKTools. isNullOrEmpty (payParams. getExtension () {pInfo. setCustomInfo (payParams. getExtension ();} // optional parameter. this parameter is obsolete and 0 is passed by default. // If the payment cannot be made, check whether the payment callback address of the corresponding environment has been configured on the open platform. If not, configure it. If the payment is still unavailable, contact the UC technical contact. PInfo. setServerId (0); pInfo. setRoleId (payParams. getRoleId (); // sets the ID of the user's game role. This is a required parameter. Import the real data pInfo based on the actual business data. setRoleName (payParams. getRoleName (); // set the name of the user's game role. This is a required parameter. Import the real data pInfo based on the actual business data. setGrade ("" + payParams. getRoleLevel (); // sets the game role level of the user. This is an optional parameter. // optional parameter sets the callback address of the game receiving order result after the payment is completed, it must be a URL with an http header. // PInfo. setNotifyUrl ("http: // 192.168.1.1/notifypage. do "); // when you pass in an amount as the amount value to call the payment function, the SDK will display the recharge channel based on the available payment method of this amount // if you pass in 6 yuan, the recharge card option is not displayed, because there is currently no 6 yuan recharge card on the market, we recommend that you use the amount that can display the recharge card method pInfo. setAmount (payParams. getPrice (); // set the recharge amount. This is the optional parameter return pInfo;} public void pay (Activity context, PayParams data) {try {if (! IsInited () {U8SDK. getInstance (). onResult (U8Code. CODE_INIT_FAIL, "The sdk is not inited."); return;} if (! SDKTools. isNetworkAvailable (context) {U8SDK. getInstance (). onResult (U8Code. CODE_NO_NETWORK, "The network now is unavailable"); return;} PaymentInfo pInfo = decodePayParams (data); UCGameSDK. defasdk SDK (). pay (context, pInfo, new UCCallbackListener <OrderInfo> () {@ Overridepublic void callback (int code, OrderInfo orderInfo) {if (code = UCGameSDKStatusCode. NO_INIT) {// log on to call the SDK without initialization. You need to call the game SDK initialization method U8SDK. getInst Ance (). onResult (U8Code. CODE_INIT_FAIL, "The SDK is not inited");} if (code = UCGameSDKStatusCode. SUCCESS) {// if (orderInfo! = Null) {String ordereId = orderInfo. getOrderId (); // get the order number float orderAmount = orderInfo. getOrderAmount (); // get the order amount int payWay = orderInfo. getPayWay (); String payWayName = orderInfo. getPayWayName (); System. out. print (ordereId + "," + orderAmount + "," + payWay + "," + payWayName); U8SDK. getInstance (). onResult (U8Code. CODE_PAY_SUCCESS, "uc pay success. ") ;}} else {U8SDK. getInstance (). onResult (U8Code. CODE_PAY_F AIL, "uc pay failed.");} if (code = UCGameSDKStatusCode. PAY_USER_EXIT) {// The user exits the recharge interface. U8SDK. getInstance (). onResult (U8Code. CODE_PAY_FAIL, "The user is exit. ") ;}}) ;}catch (Exception e) {e. printStackTrace ();}} /*** mandatory function <br> * Create and display the floating button <br> * The floating button must be called in the UI thread after SDK Initialization is successful. <br> br> */private void ucSdkCreateFloatButton (final Activity context) {U8SDK. getInstance (). runOnMainThread (new Runnable () {public void run () {try {// Create Floating button. The floating button will be displayed on the GameActivity page. When you click it, the floating menu will be displayed, which contains the operation entries for some functions of the // SDK. // After the creation is complete, it is not automatically displayed. You need to call the showFloatButton (Activity, // double, double, boolean) method to display or hide it. UCGameSDK. defasdk SDK (). createFloatButton (context, new UCCallbackListener <String> () {@ Overridepublic void callback (int statuscode, String data) {Log. d ("SelectServerActivity 'floatbutton Callback", "statusCode =" + statuscode + "data =" + data) ;}} catch (UCCallbackListenerNullException e) {e. printStackTrace ();} catch (UCFloatButtonCreateException e) {// TODO Auto-generated catch blocke. printStack Trace ();}}});} /*** mandatory function <br> * floating button display needs to be called in the UI thread <br> */private void ucSdkShowFloatButton (final Activity context) {U8SDK. getInstance (). runOnMainThread (new Runnable () {public void run () {// display the floating icon. You can choose to hide this icon in some scenarios to avoid affecting the game experience. try {UCGameSDK. defasdk SDK (). showFloatButton (context, 100, 50, true);} catch (UCCallbackListenerNullException e) {// TODO Auto-generated catch blocke. printStackTrace ();}} });} /*** Mandatory function <br> * suspend button destruction must be called in the UI thread <br> */private void ucSdkDestoryFloatButton (final Activity context) {U8SDK. getInstance (). runOnMainThread (new Runnable () {public void run () {// floating button destruction function UCGameSDK. defasdk SDK (). destoryFloatButton (context) ;}}) ;}/ *** mandatory function <br> * This method must be called before the game exits for cleanup. We recommend that you call this method in the game exit event. It must be executed before the game exits <br> * If the game exits directly without calling this method, an unknown error may occur, cause program crash <br> */private void ucSdkExit (final Activity context) {UCGameSDK. defasdk SDK (). exitSDK (context, new UCCallbackListener <String> () {@ Overridepublic void callback (int code, String msg) {if (UCGameSDKStatusCode. SDK_EXIT_CONTINUE = code) {// code for this addition to continue the game} else if (UCGameSDKStatusCode. SDK_EXIT = code) {// Add the code ucSdkDestoryFloatButton (c Ontext); System. exit (0) ;}}}) ;}public int getChannel () {return this. channel;} public boolean isInited () {return this. state. ordinal ()> = SDKState. stateInited. ordinal ();} public boolean isLogined () {return this. state. ordinal ()> = SDKState. stateLogined. ordinal ();} private void showWaitDialog (Activity context) {if (loadingActivity! = Null) {return;} loadingActivity = new ProgressDialog (context); loadingActivity. setIndeterminate (true); loadingActivity. setCancelable (true); loadingActivity. setMessage ("Initializing... please wait... "); loadingActivity. setOnCancelListener (new DialogInterface. onCancelListener () {@ Overridepublic void onCancel (DialogInterface arg0) {state = SDKState. stateDefault ;}}); loadingActivity. show ();} private void hideWaitDialog (Activity context) {if (loadingActivity = null) {return;} loadingActivity. dismiss (); loadingActivity = null ;}}
This class seems a little huge. However, it does not matter. We slowly peeled the wire. First, go to the call entry of our implementation class. The first is the initSDK. Let's take a look at what initSDK has done:
InitSDK first parses the parameters: In the UCUser's initSDK method, we get the parameters required by the current SDK through the U8SDK. getInstance (). getSDKParams () method. So what are these parameters. These parameters are the parameters that need to be passed in when each SDK is running. That is, the appID, appKey, and other information you applied to the channel before accessing the channel SDK. You may have doubts here that the information is different from each other. How can this be obtained through the abstraction layer? That's right. How can I get the abstract layer? This is due to the packaging tool we will talk about later. We will do this through a clever design. Here, you first know the appID and other information required for access to all channels. Here, you can directly obtain the information through the U8SDK. getInstance (). getSDKParams () method.
Then we can see that the IActivityListener interface of U8SDK is set in initSDK. This is because the uc sdk needs to complete the corresponding work in some system events of the activity.
Next, you can see that you can follow the Demo of UC to go down. The key is to call the U8SDK. getInstance (). onResult () method to throw a State information to the abstraction layer no matter whether the initialization succeeds or fails. In this way, you can add the output or Toast in the interface implemented by the game layer during debug debugging to view the status information in time for debugging and troubleshooting.
Then, let's look at the login method. The same is true for the login method. To call the login method provided by UC directly, the key is in the login callback. Besides calling the onResult method, if the login succeeds, we also need to call U8SDK. getInstance (). onLoginResult (result) method. This is because the game layer processes the successful login callback in onLoginResult and encapsulates the data returned by the SDK into the LoginResult class.
Finally, let's take a look at the pay method, which is equally simple. Only the resolution of the payment parameter is added. When talking about the implementation of the abstraction layer, we talked about the payment parameter PayParams. All the information in this class is available in the game. However, each channel may have different needs. Therefore, each channel needs to be obtained as needed based on the needs of the channel. For example, here we use the decodePayParams method to get the parameters required by UC from PayParams. Then, similarly, we call the onResult method in the callback to prompt the status information.
For other methods, hide the floating icon and show the floating icon in UCSDK. It needs to be called in the corresponding place.
Now, the uc sdk is fully integrated. After the connection, the directory structure is roughly as follows:
You may see sdk_confgi.xml and sdk_manifest.xml in the project. Here, let's leave a suspense. When we talk about packaging tools later, let's look back. As you can see here, we didn't mention the permission information and some Activity or Service data that the SDK needs to set in AndroidManifest. xml. I don't know how to use it, how to test it, and how to maintain it? All of these will be discussed later.
Author: Xiao Hei