小米微信WAP支付SDK接入指南
一、接入前準備
1、下載小米微信wap支付sdk_v1.3.1版本
2、準備小米手機、平板設(shè)備。設(shè)備規(guī)格:http://dev.xiaomi.com/doc/?p=246
3、注冊開發(fā)者站帳號。流程:http://dev.xiaomi.com/doc/?p=90
4、在開發(fā)者站創(chuàng)建應(yīng)用并申請AppId、AppKey、AppSecret
5、配置應(yīng)用內(nèi)支付,計費方式分為兩種“金額購買”和“計費點購買”,下面以計費點購買為例:
6、添加自己服務(wù)器的回調(diào)地址和計費單位,并保存
二、程序接入
1、添加jar包
將libs中的jar包添加至自己的工程中。
2、AndroidManifest.xml清單文件修改
清單中添加如下:
<activity android:name="com.xiaomi.gamecenter.wxwap.HyWxWappayActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:configChanges="orientation|screenSize" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name=“android.permission.READ_PHONE_STATE”/>
3、調(diào)用方法:在Application中初始化,傳入appid和appkey:
public class HyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//appid和appkey
HyWxWapPay.init(this,"2882303761517****35","5151740****35");
}
}
4、調(diào)用方式:
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_wap:
//購買可消耗計費點 請一定確認是可消耗計費點
/**
* 整個調(diào)用必須在主線程中進行,回調(diào)默認也在主線程中
* 調(diào)用前請確認自己的游戲申請的時候是 “計費點計費方式”,還是“金額計費方式”
* 金額方式只能以第三種方式調(diào)用,計費點方式只能以前兩種方式調(diào)用,不然“創(chuàng)建訂單失敗”
* **/
WxRepeatPurchase purchase =new WxRepeatPurchase();
purchase.setCpOrderId(System.currentTimeMillis()+"");//設(shè)置訂單號
purchase.setChargeCode("a1");//計費點名稱設(shè)置
//purchase.setAmout("2");//購買數(shù)量,不設(shè)置的話默認為1
HyWxWapPay.getInstance().pay(this, purchase, new PayResultCallback() {
@Override
public void onError(int code, String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}
@Override
public void onSuccess(String cpOrderId) {
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_LONG).show();
}
});
break;
case R.id.btn_wap2:
//購買不可消耗計費點,請一定確保是不可消耗計費點
WxUnrepeatPurchase purchase1 =new WxUnrepeatPurchase();
purchase1.setCpOrderId(System.currentTimeMillis()+"");
purchase1.setChargeCode("a2");//設(shè)置計費點
HyWxWapPay.getInstance().pay(this,purchase1, new PayResultCallback() {
@Override
public void onError(int code, String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}
@Override
public void onSuccess(String cpOrderId) {
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_LONG).show();
}
});
break;
case R.id.btn_wap3:
//購買金額 最小值100,必須是100倍數(shù),整形值,請不要加小數(shù)點,不然創(chuàng)建訂單失敗
WxFeePurchase purchase3 =new WxFeePurchase();
purchase3.setCpOrderId(System.currentTimeMillis()+"");
purchase3.setFeeValue("100");//設(shè)置金額
HyWxWapPay.getInstance().pay(this,purchase3, new PayResultCallback() {
@Override
public void onError(int code, String msg) {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
}
@Override
public void onSuccess(String cpOrderId) {
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_LONG).show();
}
});
break;
}
}
三、常見問題:
1、忘記在application中初始化,或者忘了寫application:name
2、計費代碼填寫錯誤,比如創(chuàng)建了可消耗計費代碼類,卻填寫不可消耗的計費代碼
四、服務(wù)器接口:
1)按金額付費,以小米應(yīng)用支付服務(wù)器通知的結(jié)果為準為用戶進行虛擬幣充值。所以必須提供接收訂單支付結(jié)果通知的地址(必選)。2)按計費代碼計費,也可以提供接收訂單支付結(jié)果通知的地址(可選)。3)服務(wù)器代碼示例下載地址。包含簽名實現(xiàn),登錄驗證,訂單查詢,回調(diào)接口,有php和java的示例。
4.1訂單支付結(jié)果通知接口
4.1.1流程說明
此接口由開發(fā)者負責(zé)開發(fā)并在開發(fā)者后臺進行配置。在訂單支付成功后,小米應(yīng)用支付服務(wù)器會將支付結(jié)果通知給開發(fā)者預(yù)先提供的服務(wù)器上。若開發(fā)者所提供的服務(wù)器地址不可用,在一定時間段內(nèi)游戲平臺服務(wù)器會按照周期進行輪詢(前10次,每分鐘通知1次;10次后每小時通知1次)。
注:由于是異步通知模型,(3)和(4)不一定是按序號產(chǎn)生。因此(4)和(5)需要進行輪詢處理或者使用接口進行支付結(jié)果查詢。相比后面提到的開發(fā)者主動查詢訂單的模式,我們推薦使用此模式。
4.1.2接口及參數(shù)說明
1)接口地址:各開發(fā)者服務(wù)器的通知地址(提前申請,在小米開發(fā)者站進行配置)2)請求方法:GET請求參數(shù)說明:
注意:如果開發(fā)者允許使用游戲禮券則必須使用partnerGiftConsume參數(shù),否則使用游戲禮券的消費訂單會出現(xiàn)掉單情況。
例如:
http://ccc.com/notify.do?appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&orderConsumeType=10&orderId=21140990160359583390&orderStatus=TRADE_SUCCESS&payFee=1&payTime=2014-09-05%2015:20:27&productCode=com.demo_1&productCount=1&productName=%E9%93%B6%E5%AD%901%E4%B8%A4&uid=100010&signature=1388720d978021c20aa885d9b3e1b70cec751496
返回參數(shù)說明:
例如:
{“errcode”:200}
服務(wù)器IP地址 42.62.48.246 223.202.68.237 42.62.103.0/26(42.62.103.1~42.62.103.62)120.134.34.0/26(120.134.34.1~120.134.34.62)
請開發(fā)商服務(wù)器開發(fā)人員加到ip白名單內(nèi),以免因為ip限制造成回調(diào)不成功。
4.2主動查詢訂單支付狀態(tài)接口
此接口由小米為開發(fā)者提供。
4.2.1接口及參數(shù)說明:
1)接口地址:http://mis.migc.xiaomi.com/api/biz/service/queryOrder.do 2)請求方法:GET請求參數(shù)說明:
例如:
http://mis.migc.xiaomi.com/api/biz/service/queryOrder.do?appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&uid=100010&signature=e91d68b864b272b6ec03f35ee5a640423d01a0a1
正確返回參數(shù)說明:
{
"signature":"eb30240cff8c66f856ec0e48354aa670b8cf037f",
"uid":"100010",
"appId":2882303761517239300,
"cpOrderId":"9786bffc-996d-4553-aa33-f7e92c0b29d5",
"productCode":"com.demo_1",
"orderStatus":"TRADE_SUCCESS",
"productName":"%E9%93%B6%E5%AD%901%E4%B8%A4",
"productCount":1,
"orderConsumeType":"10",
"orderId":"21140990160359583390",
"payFee":1,
"payTime":"2014-09-05 15:20:27"
}
錯誤返回參數(shù)說明:
4.3用戶session驗證接口
此接口由小米應(yīng)用支付為開發(fā)者提供,用于驗證登錄賬戶的有效性。注意:用戶的唯一標(biāo)識是通過SDK獲得的uid,而不是Session,Session用于校驗登錄驗證的有效性,必須經(jīng)過SDK、游戲中心服務(wù)器、開發(fā)者服務(wù)器進行三方驗證,如果Session失效,需要重新調(diào)用miLogin()進行登錄。
4.3.1接口及參數(shù)說明
1)接口地址:http://mis.migc.xiaomi.com/api/biz/service/verifySession.do 2)請求方法:GET請求參數(shù)說明:
http://mis.migc.xiaomi.com/api/biz/service/verifySession.do?appId=2882303761517239138&session=1nlfxuAGmZk9IR2L&uid=100010&signature=b560b14efb18ee2eb8f85e51c5f7c11f697abcfc
返回參數(shù)說明:
{
“errcode”:200
}
4.4接口格式說明
輸入?yún)?shù):?參數(shù)1=值1&參數(shù)2=值2&….&參數(shù)n=值n,如果遇到文本參數(shù)值,需要根據(jù)情況對參數(shù)值做UrlEncode。返回參數(shù):在回調(diào)的時候,是http get方式發(fā)送請求,參數(shù)拼接在url后面,你們的服務(wù)器返回的數(shù)據(jù)要求是json格式的,如:{“errcode”:200}這種格式
4.5 signature簽名方法說明
1、生成帶簽名字符串表中各參數(shù)按字母順序排序(不包含signature),如果第一個字母相同,按第二個字母排序,依次類推。排序后拼接成par1=val1&par2=val2&par3=val3的格式,所生成的字符串即為待簽名的字符串。沒有值的參數(shù)請不要參與簽名。由于有些數(shù)據(jù)根據(jù)HTTP協(xié)議需求,需要進行URLencoding,這樣接收方才可以接收到正確的參數(shù),但如果這個參數(shù)參與簽名,那么待簽名字符串必須是字符串原值而非URLencoding的值。例如:在訂單通知接口收到的回調(diào)信息如下:
appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&orderConsumeType=10&orderId=21140990160359583390&orderStatus=TRADE_SUCCESS&payFee=1&payTime=2014-09-05%2015:20:27&productCode=com.demo_1&productCount=1&productName=%E9%93%B6%E5%AD%901%E4%B8%A4&uid=100010&signature=1388720d978021c20aa885d9b3e1b70cec751496
這時候需要對每個參數(shù)的值進行URLdecode,decode后的字符如下:
appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&orderConsumeType=10&orderId=21140990160359583390&orderStatus=TRADE_SUCCESS&payFee=1&payTime=2014-09-05 15:20:27&productCode=com.demo_1&productCount=1&productName=銀子1兩&uid=100010&signature=1388720d978021c20aa885d9b3e1b70cec751496
而需要進行簽名的字符串為:
appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&orderConsumeType=10&orderId=21140990160359583390&orderStatus=TRADE_SUCCESS&payFee=1&payTime=2014-09-05 15:20:27&productCode=com.demo_1&productCount=1&productName=銀子1兩&uid=100010
2、簽名算法以AppSecret作為key,使用hmac-sha1帶密鑰(secret)的哈希算法對代簽字符串進行簽名計算。簽名的結(jié)果由16進制表示。hmac-sha1帶密鑰(secret)哈希算法的實現(xiàn)請參考6.2服務(wù)器簽名函數(shù)。
五、常見問題*
5.1 APK打包及發(fā)布
需要注意,SDK包是以jar包提供給開發(fā)者,此jar包本身已為混淆狀態(tài),您在混淆自己游戲的APK包時,需要在proguard.cfg里加入,以避免二次混淆。
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*;
}
5.2服務(wù)器簽名函數(shù)
Hmac-SHA1算法java實現(xiàn)參考:
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";
/**
* 使用 HMAC-SHA1 簽名方法對對encryptText進行簽名
* @param encryptText 被簽名的字符串
* @param encryptKey 密鑰
* @return 返回被加密后的字符串
* @throws Exception
*/
public static String HmacSHA1Encrypt( String encryptText,
String encryptKey ) throws Exception{
byte[] data = encryptKey.getBytes( ENCODING );
// 根據(jù)給定的字節(jié)數(shù)組構(gòu)造一個密鑰,第二參數(shù)指定一個密鑰算法的名稱
SecretKey secretKey = new SecretKeySpec( data, MAC_NAME );
// 生成一個指定 Mac 算法 的 Mac 對象
Mac mac = Mac.getInstance( MAC_NAME );
// 用給定密鑰初始化 Mac 對象
mac.init( secretKey );
byte[] text = encryptText.getBytes( ENCODING );
// 完成 Mac 操作
byte[] digest = mac.doFinal( text );
StringBuilder sBuilder = bytesToHexString( digest );
return sBuilder.toString();
}
/**
* 轉(zhuǎn)換成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;
}
/**
* 使用 HMAC-SHA1 簽名方法對對encryptText進行簽名
*
* @param encryptData 被簽名的字符串
* @param encryptKey 密鑰
* @return 返回被加密后的字符串
* @throws Exception
*/
public static String hmacSHA1Encrypt( byte[] encryptData, String encryptKey ) throws Exception{
byte[] data = encryptKey.getBytes( ENCODING );
// 根據(jù)給定的字節(jié)數(shù)組構(gòu)造一個密鑰,第二參數(shù)指定一個密鑰算法的名稱
SecretKey secretKey = new SecretKeySpec( data, MAC_NAME );
// 生成一個指定 Mac 算法 的 Mac 對象
Mac mac = Mac.getInstance( MAC_NAME );
// 用給定密鑰初始化 Mac 對象
mac.init( secretKey );
// 完成 Mac 操作
byte[] digest = mac.doFinal( encryptData );
StringBuilder sBuilder = bytesToHexString( digest );
return sBuilder.toString();
}
}