Mi Game Center Developer Guide(for Single Player Game)

UsingMi Game Center paymentincludes access server and client in two parts, in which the server-side access is optional (depending on whether there is a single player game server).

Before reading the below, it is highly recommended that you install the two Demo programs(SDK_Demo_OfflineGame.apk and SDK_Demo_OnlineGame.apk) distributed with this document into cell phones. Because the two programs demonstrate the whole work flow of mi game SDK, and it is helpful to understand our SDK payment flow.

Revision History:

  • v3.3.7 Interface unchanged

1 Flow of single player game

The developers of single player games need to call miLogin () function before payment. after the successfullylogin you can call miUniPayOffline () function to make payments.The SDK will deal with user login, registration, insufficient balance, has bought it self.As for developers, only need to add the following code to realize the single player game payment.

Note: 1)Make sure to apply for and bind with valid APPid and APPkey generated on your Developer Console; 2) configure in-app purchase module, before calling miLogin()function.

2.SDK invoke methods

2.1 Initialization

Please obtain AppId and AppKey first, then invoke the following SDK initialization code to initialize the operation.

Put MiGameCenterSDKService.apk of SDK package into the 'assets' directory of application, and SDK's jar the 'libs', referenced in buildpath, then initialize SDK.

Note: You need to check the consistency of the following, it would be failed when invoke login and other SDK interfaces

1 whether the package name of the game is the same with the package name of xiaomi server configuration;

2. whether the Appid and Appkey are consistent with the applied

MiAppInfo appInfo = new MiAppInfo ();

appInfo.setAppId ("Developer applied ");

appInfo.setAppKey ("Developer applied ");

appInfo.setAppType (MiGameType.offline); // single player game

MiCommplatform.Init (this, appInfo);

The permission that SDK needs to add

<uses-permission android:name="android.permission.GET_TASKS" />

<uses-permission android:name="com.xiaomi.sdk.permission.PAYMENT" />

2.2 Invoke payment

  • 2.2.1 Code of Mi account login

MiCommplatform.getInstance (). MiLogin (context, new OnLoginProcessListener (){

@Override

public void finishLoginProcess (int code, MiAccountInfo arg1){

switch (code) {

case MiErrorCode.MI_XIAOMI_GAMECENTER_SUCCESS:

// Login success

// Get the user's UID after landing (ie, the user's unique

//identifier)

String uid = arg1.getUid ();//Returns null if not logged in

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_LOGIN_FAIL:

// Login failed

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_CANCEL:

// Unregister

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_ACTION_EXECUTED:

// Login operation is in progress

break;

default:

// Login failed break;

}

}

});

  • 2.2.2 Consumable production(Production that can be re-purchased, such as blood bottle and magic bottle)

MiBuyInfoOffline offline = new MiBuyInfoOffline ();

offline.setCpOrderId (UUID.randomUUID ().toString());//unique order ID (not null)

offline.setProductCode("productCode");//commodity code, developers applyed (not null)

offline.setCount(3);//purchased quantity(max9999,min1) (not null)

MiCommplatform.getInstance ().MiUniPayOffline (activiy, offline,

new OnPayProcessListener() {

@Override

public void finishPayProcess (int code) {

switch (code) {

case MiErrorCode.MI_XIAOMI_GAMECENTER_SUCCESS:

//purchased successfully, please process delivering

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_PAY_CANCEL:

// Cancel purchase

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_PAY_FAILURE:

// purchase failed

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_ACTION_EXECUTED:

// processing

break;

default:

// purchase failed

break;

}

}

});

  • 2.2.3 Non-consumable production(Production that cannot be re-purchased, such as game level)

MiBuyInfoOffline offline = new MiBuyInfoOffline ();

offline.setCpOrderId (UUID.randomUUID ().toString());//unique order ID (not null)

offline.setProductCode("productCode");//commodity code, developers applyed (not null)

offline.setCount(1);//purchased quantity(only can be 1)(not null)MiCommplatform.getInstance ().MiUniPayOffline (activiy, offline,

new OnPayProcessListener() {

@Override

public void finishPayProcess (int code) {

switch (code) {

case MiErrorCode.MI_XIAOMI_GAMECENTER_SUCCESS:

//purchased successfully, please process delivering

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_PAY_CANCEL:

// Cancel purchase

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_PAY_FAILURE:

// purchase failed

break;

case MiErrorCode.MI_XIAOMI_GAMECENTER_ERROR_ACTION_EXECUTED:

// processing

break;

default:

// purchase failed

break;

}

}

});

  • Parameter Description

Parameter name / Use / Remark
cpOrderId / Developer's order ID / 20~100 characters, generated by developers,uniquely, can be auto generated based on developer rules.
productCode / Product code / Rules:
Composed of 0-9,a-zA-Z and ”_”,”.”,”-”, 8~40characters, uniquely within one game, case sensitive. Recommendation: com.xiaomi.migc.xxx.
Please do not confuse the productCode of non-consumable production and consumable production when invoking
count / Purchased quantity / Non-consumable production,count=1
Consumable production,count>=1

3 Server Interface

If needed, it could also provide the notification address of receiving order payment result for single player games.(Optional)

3.1 Order notification interface

This interface is developed by developer and should be configured in xiaomi game center before releasing.After successful payment of the order, xiaomi game center will notify the developer's server provided in advance with the payment result. If the developer's server cannot be accessed, within a certain period of time, game center server would do the checking cycle(The former 10 times, notifying once a minute; then once an hour).Specific procedures are as follows:

Note: Due to the asynchronous notification model,(3) and (4) may not follow the sequence, so (4) and (5) need to be checked cyclically, or use the interface to query the payment result.

3.2 interfaces and parameters Description:

Interface address: each developer's server's notification address(Applied in advance, configured in xiaomi game center)

Request parameters:

Parameter name / Optional / Explanation
appId / Required / ID of the application
cpOrderId / Required / Developer’s order ID
cpUserInfo / Optional / Developer’s information
uid / Required / User ID
orderId / Required / Order ID
orderStatus / Required / Order status, TRADE_SUCCESS for success
payFee / Required / Payment amount, the unit is cent, which is 0.01Mi.
productCode / Required / Product Code
productName / Required / Product Name
productCount / Required / Quantity
payTime / Required / Time of payment, the format yyyy-MM-dd HH: mm: ss
orderConsumeType / Optional / Order type:
10: Common order
11: Direct charge and consumable order
signature / Required / Signature. Signature method description is in below.

Return parameters:

Parameter name / Optional / Explanation
errcode / Required / Status code:
200 success
1506cpOrderId error
1515appId error
1516 uid error
1525 signature error
errMsg / Optional / Error Messages

Note: Developers must guarantee that product be delivered only once for the same order's multiple notifications.

3.3 Interface format:

Request method: HTTP GET

input parameters:?parameter1=value1&parameter2=value2&...& parameterN=valueN, values required to do UrlEncode under the circumstances.
Return: use json format, for example:{“Response parameters1”:”Response value1”,“Response parameters2”:”Response value2”,...“Response parametersN”:”Response valueN”}

3.4 Signature Method Description:

3.4.1 Generate the string with signature

All parameters in the table are in alphabetical sequence(Excluding signature), if the first letters are same, then sort by the second letters, and so on. The generated string, which needs to be signed, is in the format like this: par1=val1&par2=val2&par3=val3. The parameter with no value will not be involved in the signature. Because some data are based on the HTTP protocol, the receiver needs URLencoding to get the right parameter, but if this parameter is involved in the signature, the generated string, which needs to be signed, must be the original value, not the URLencoding value.

3.4.2 Signature Algorithm

Use appKey as key, and the hash algorithm of hmac-sha1 with secret to make the signature calculation of the generated string. The result is showed in hexadecimal. About the hash algorithm of hmac-sha1 with secret, please refer to appendix.

4.FAQ

4.1APK packaged and released

Note: SDK package is provided to developers in jar package, which is already in code obfuscation status, please add the following codes to your own 'proguard.cfg' to avoid a second code obfuscation when you obfuscate your own APK package.

-Keep public class

com.xiaomi.gamecenter.sdk.ui.actlayout.ViewAliPayWeb $ PayObject {*;}

-keepclasseswithmembers class * {

public (...);

}

-Keepclassmembers enum * {

public static ** [] values ​​();

public static ** valueOf (java.lang.String);

}

-Keep class * implements android.os.Parcelable {

public static final android.os.Parcelable $ Creator *;

}

4.2 server signing function

Hmac-SHA1 algorithm in java:

import javax.crypto.Mac;

import javax.crypto.SecretKey;

import javax.crypto.spec.SecretKeySpec;

public class HmacSHA1Encryption {

private static final String MAC_NAME = "HmacSHA1";

private static final String ENCODING = "UTF-8";

/ **

* Use HMAC-SHA1 signature method tosign encryptText

* @ param encryptText be signed string

* @ param encryptKey key

* @ return Returns the encrypted string

* @ throws Exception

* /

public static String HmacSHA1Encrypt (String encryptText, String encryptKey)

throws Exception {

byte [] data = encryptKey.getBytes (ENCODING);

SecretKey secretKey = new SecretKeySpec (data, MAC_NAME);

Mac mac = Mac.getInstance (MAC_NAME);

mac.init (secretKey);

byte [] text = encryptText.getBytes (ENCODING);

byte [] digest = mac.doFinal (text);

StringBuilder sBuilder = bytesToHexString (digest);

return sBuilder.toString ();

}

/ **

* Convert to Hex

* @ Param bytesArray

* /

public static StringBuilder bytesToHexString (byte [] bytesArray) {

if (bytesArray == null) {

return null;

}

StringBuilder sBuilder = new StringBuilder ();

for (byte b: bytesArray) {

String hv = String.format ("% 02x", b);

sBuilder.append (hv);

} return sBuilder;

}

/ **

* Use HMAC-SHA1 signature method to sign encryptText

* @ param encryptData be signed string

* @ param encryptKey key

* @ return Returns the encrypted string

* @ throws Exception

* /

public static String HmacSHA1Encrypt (byte [] encryptData, String encryptKey)

throws Exception {

byte [] data = encryptKey.getBytes (ENCODING);

SecretKey secretKey = new SecretKeySpec (data, MAC_NAME); 

Mac mac = Mac.getInstance (MAC_NAME);

mac.init (secretKey);

byte [] digest = mac.doFinal (encryptData);

StringBuilder sBuilder = bytesToHexString (digest);

return sBuilder.toString ();

}

}