小米微信WAP支付SDK接入指南
一、接入前準(zhǔn)備
1、下載小米微信wap支付sdk_v1.3.1版本
2、準(zhǔn)備小米手機(jī)、平板設(shè)備。設(shè)備規(guī)格:http://dev.xiaomi.com/doc/?p=246
3、注冊(cè)開(kāi)發(fā)者站帳號(hào)。流程:http://dev.xiaomi.com/doc/?p=90
4、在開(kāi)發(fā)者站創(chuàng)建應(yīng)用并申請(qǐng)AppId、AppKey、AppSecret
5、配置應(yīng)用內(nèi)支付,計(jì)費(fèi)方式分為兩種“金額購(gòu)買(mǎi)”和“計(jì)費(fèi)點(diǎn)購(gòu)買(mǎi)”,下面以計(jì)費(fèi)點(diǎn)購(gòu)買(mǎi)為例:
6、添加自己服務(wù)器的回調(diào)地址和計(jì)費(fèi)單位,并保存
二、程序接入
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:
//購(gòu)買(mǎi)可消耗計(jì)費(fèi)點(diǎn) 請(qǐng)一定確認(rèn)是可消耗計(jì)費(fèi)點(diǎn)
/**
* 整個(gè)調(diào)用必須在主線程中進(jìn)行,回調(diào)默認(rèn)也在主線程中
* 調(diào)用前請(qǐng)確認(rèn)自己的游戲申請(qǐng)的時(shí)候是 “計(jì)費(fèi)點(diǎn)計(jì)費(fèi)方式”,還是“金額計(jì)費(fèi)方式”
* 金額方式只能以第三種方式調(diào)用,計(jì)費(fèi)點(diǎn)方式只能以前兩種方式調(diào)用,不然“創(chuàng)建訂單失敗”
* **/
WxRepeatPurchase purchase =new WxRepeatPurchase();
purchase.setCpOrderId(System.currentTimeMillis()+"");//設(shè)置訂單號(hào)
purchase.setChargeCode("a1");//計(jì)費(fèi)點(diǎn)名稱設(shè)置
//purchase.setAmout("2");//購(gòu)買(mǎi)數(shù)量,不設(shè)置的話默認(rèn)為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:
//購(gòu)買(mǎi)不可消耗計(jì)費(fèi)點(diǎn),請(qǐng)一定確保是不可消耗計(jì)費(fèi)點(diǎn)
WxUnrepeatPurchase purchase1 =new WxUnrepeatPurchase();
purchase1.setCpOrderId(System.currentTimeMillis()+"");
purchase1.setChargeCode("a2");//設(shè)置計(jì)費(fèi)點(diǎn)
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:
//購(gòu)買(mǎi)金額 最小值100,必須是100倍數(shù),整形值,請(qǐng)不要加小數(shù)點(diǎn),不然創(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;
}
}
三、常見(jiàn)問(wèn)題:
1、忘記在application中初始化,或者忘了寫(xiě)application:name
2、計(jì)費(fèi)代碼填寫(xiě)錯(cuò)誤,比如創(chuàng)建了可消耗計(jì)費(fèi)代碼類(lèi),卻填寫(xiě)不可消耗的計(jì)費(fèi)代碼
四、服務(wù)器接口:
1)按金額付費(fèi),以小米應(yīng)用支付服務(wù)器通知的結(jié)果為準(zhǔn)為用戶進(jìn)行虛擬幣充值。所以必須提供接收訂單支付結(jié)果通知的地址(必選)。2)按計(jì)費(fèi)代碼計(jì)費(fèi),也可以提供接收訂單支付結(jié)果通知的地址(可選)。3)服務(wù)器代碼示例下載地址。包含簽名實(shí)現(xiàn),登錄驗(yàn)證,訂單查詢,回調(diào)接口,有php和java的示例。
4.1訂單支付結(jié)果通知接口
4.1.1流程說(shuō)明
此接口由開(kāi)發(fā)者負(fù)責(zé)開(kāi)發(fā)并在開(kāi)發(fā)者后臺(tái)進(jìn)行配置。在訂單支付成功后,小米應(yīng)用支付服務(wù)器會(huì)將支付結(jié)果通知給開(kāi)發(fā)者預(yù)先提供的服務(wù)器上。若開(kāi)發(fā)者所提供的服務(wù)器地址不可用,在一定時(shí)間段內(nèi)游戲平臺(tái)服務(wù)器會(huì)按照周期進(jìn)行輪詢(前10次,每分鐘通知1次;10次后每小時(shí)通知1次)。
注:由于是異步通知模型,(3)和(4)不一定是按序號(hào)產(chǎn)生。因此(4)和(5)需要進(jìn)行輪詢處理或者使用接口進(jìn)行支付結(jié)果查詢。相比后面提到的開(kāi)發(fā)者主動(dòng)查詢訂單的模式,我們推薦使用此模式。
4.1.2接口及參數(shù)說(shuō)明
1)接口地址:各開(kāi)發(fā)者服務(wù)器的通知地址(提前申請(qǐng),在小米開(kāi)發(fā)者站進(jìn)行配置)2)請(qǐng)求方法:GET請(qǐng)求參數(shù)說(shuō)明:
注意:如果開(kāi)發(fā)者允許使用游戲禮券則必須使用partnerGiftConsume參數(shù),否則使用游戲禮券的消費(fèi)訂單會(huì)出現(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ù)說(shuō)明:
例如:
{“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)
請(qǐng)開(kāi)發(fā)商服務(wù)器開(kāi)發(fā)人員加到ip白名單內(nèi),以免因?yàn)閕p限制造成回調(diào)不成功。
4.2主動(dòng)查詢訂單支付狀態(tài)接口
此接口由小米為開(kāi)發(fā)者提供。
4.2.1接口及參數(shù)說(shuō)明:
1)接口地址:http://mis.migc.xiaomi.com/api/biz/service/queryOrder.do 2)請(qǐng)求方法:GET請(qǐng)求參數(shù)說(shuō)明:
例如:
http://mis.migc.xiaomi.com/api/biz/service/queryOrder.do?appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&uid=100010&signature=e91d68b864b272b6ec03f35ee5a640423d01a0a1
正確返回參數(shù)說(shuō)明:
{
"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"
}
錯(cuò)誤返回參數(shù)說(shuō)明:
4.3用戶session驗(yàn)證接口
此接口由小米應(yīng)用支付為開(kāi)發(fā)者提供,用于驗(yàn)證登錄賬戶的有效性。注意:用戶的唯一標(biāo)識(shí)是通過(guò)SDK獲得的uid,而不是Session,Session用于校驗(yàn)登錄驗(yàn)證的有效性,必須經(jīng)過(guò)SDK、游戲中心服務(wù)器、開(kāi)發(fā)者服務(wù)器進(jìn)行三方驗(yàn)證,如果Session失效,需要重新調(diào)用miLogin()進(jìn)行登錄。
4.3.1接口及參數(shù)說(shuō)明
1)接口地址:http://mis.migc.xiaomi.com/api/biz/service/verifySession.do 2)請(qǐng)求方法:GET請(qǐng)求參數(shù)說(shuō)明:
http://mis.migc.xiaomi.com/api/biz/service/verifySession.do?appId=2882303761517239138&session=1nlfxuAGmZk9IR2L&uid=100010&signature=b560b14efb18ee2eb8f85e51c5f7c11f697abcfc
返回參數(shù)說(shuō)明:
{
“errcode”:200
}
4.4接口格式說(shuō)明
輸入?yún)?shù):?參數(shù)1=值1&參數(shù)2=值2&….&參數(shù)n=值n,如果遇到文本參數(shù)值,需要根據(jù)情況對(duì)參數(shù)值做UrlEncode。返回參數(shù):在回調(diào)的時(shí)候,是http get方式發(fā)送請(qǐng)求,參數(shù)拼接在url后面,你們的服務(wù)器返回的數(shù)據(jù)要求是json格式的,如:{“errcode”:200}這種格式
4.5 signature簽名方法說(shuō)明
1、生成帶簽名字符串表中各參數(shù)按字母順序排序(不包含signature),如果第一個(gè)字母相同,按第二個(gè)字母排序,依次類(lèi)推。排序后拼接成par1=val1&par2=val2&par3=val3的格式,所生成的字符串即為待簽名的字符串。沒(méi)有值的參數(shù)請(qǐng)不要參與簽名。由于有些數(shù)據(jù)根據(jù)HTTP協(xié)議需求,需要進(jìn)行URLencoding,這樣接收方才可以接收到正確的參數(shù),但如果這個(gè)參數(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í)候需要對(duì)每個(gè)參數(shù)的值進(jìn)行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
而需要進(jìn)行簽名的字符串為:
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)的哈希算法對(duì)代簽字符串進(jìn)行簽名計(jì)算。簽名的結(jié)果由16進(jìn)制表示。hmac-sha1帶密鑰(secret)哈希算法的實(shí)現(xiàn)請(qǐng)參考6.2服務(wù)器簽名函數(shù)。
五、常見(jiàn)問(wèn)題*
5.1 APK打包及發(fā)布
需要注意,SDK包是以jar包提供給開(kāi)發(fā)者,此jar包本身已為混淆狀態(tài),您在混淆自己游戲的APK包時(shí),需要在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實(shí)現(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 簽名方法對(duì)對(duì)encryptText進(jìn)行簽名
* @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)造一個(gè)密鑰,第二參數(shù)指定一個(gè)密鑰算法的名稱
SecretKey secretKey = new SecretKeySpec( data, MAC_NAME );
// 生成一個(gè)指定 Mac 算法 的 Mac 對(duì)象
Mac mac = Mac.getInstance( MAC_NAME );
// 用給定密鑰初始化 Mac 對(duì)象
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 簽名方法對(duì)對(duì)encryptText進(jìn)行簽名
*
* @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)造一個(gè)密鑰,第二參數(shù)指定一個(gè)密鑰算法的名稱
SecretKey secretKey = new SecretKeySpec( data, MAC_NAME );
// 生成一個(gè)指定 Mac 算法 的 Mac 對(duì)象
Mac mac = Mac.getInstance( MAC_NAME );
// 用給定密鑰初始化 Mac 對(duì)象
mac.init( secretKey );
// 完成 Mac 操作
byte[] digest = mac.doFinal( encryptData );
StringBuilder sBuilder = bytesToHexString( digest );
return sBuilder.toString();
}
}