本文档介绍了应用联运sdk接入操作指南,您可在了解文档内容后,自行接入应用联运sdk。
本SDK只服务于应用类型,不适用于游戏,游戏联运SDK请前往《小米游戏SDK接入指南》。
一、应用商店介绍
应用商店是小米公司推出的面向所有小米手机、MIUI用户的应用平台,整个应用平台整合了MIUI系统、开发SDK、互联网网站、小米论坛等各方面优质资源,力求打造一个良好的安卓应用生态系统。 小米应用平台提供应用下载、应用搜索、应用计费等多种平台支撑能力,接入简单快捷,是众多应用开发商最优的选择。
二、联运SDK介绍
SDK名称:应用联运支付SDK
开发者:美卓软件设计(北京)有限公司
版本号:3.6.1
主要功能:应用联运支付SDK是小米官方开发的功能插件,用于为用户在应用内提供支付安全,账号服务等功能。
应用联运SDK隐私政策:《应用联运SDK隐私政策》
应用联运SDK使用合规规范:《应用联运SDK使用合规规范》
三、联运SDK接入须知
应用联运SDK的目前最新版本是mio_sdk_app_3.6.1.aar
Demo(含sdk)下载地址:https://kpan.mioffice.cn/webfolder/ext/ck8jDkuEHzo%40
Demo(含sdk)下载地址密码:9N5L
有效期限:2035-04-23 14:30:11
版本 | v3.6.1 |
Md5值 | 02d5d7941bba50071d86e97f2feffa1f |
请特别注意:
1、请开发者在与我们商务人员(mayue9@xiaomi.com、 gechunyu@xiaomi.com)达成合作意向后再接入本SDK。
2、请在上架后签署联运协议,方可进行分成结算。
当前为联运SDK接入指南3.6.1文档。
在开发者后台配置计费的步骤为:
1、配置计费时需要点击应用的空白处进入,如下图红色方框处。
2、点击红框内的商品管理,进入配置页。
3、点击问号可查看详细描述信息。
具体配置方式可见:商品管理配置说明
修订记录
3.3.1版本
1. 支持联运活动
2. 订阅模式补充微信支付渠道
3.3.2版本
1. 图片库修改(废弃Picasso引入)
2. 支付宝sdk更新到最新版本
3. 修复部分bug
3.4.0版本
1. 个保法整改
2. 活动弹窗下发时机优化
3.4.1版本
1. 修复遗留登陆问题
3.5.0版本
1. 使用onetrack打点代替自打点
3.5.1版本
1. 修复打点遗留问题
3.5.2版本
1. 补充onetrack研发侧打点
2. 服务端下发单笔订单付款上限、单日订单付款上限的限制
3.5.3版本
1. 恢复老数据打点,保证新旧打点共存
3.5.4版本
1. 修复个保法整改遗留问题
3.5.5版本
1. 移除imei、imsi的调用
3.5.8版本
1. 隐私合规
3.5.9版本
1. 修改编译依赖仓库配置
3.6.0版本
1. 隐私整改
2. 质量建设
3.6.1版本
1. 隐私整改
2. targetVersion适配33
3.修复遗留支付问题
开发环境
- JDK 1.8及以上
- 安装AndroidStudio 3.6.3及以上
- minSdkVersion 19及以上
- targetSdkVersion 33(推荐)
- compileSdkVersion 33(推荐)
- Gradle 5.6.4及以上(推荐)
四、操作方法/路径
1、申请接入
请按以下格式发送邮件至mayue9@xiaomi.com、gechunyu@xiaomi.com申请联运。
邮件标题: 【应用联运合作申请】【应用类型】【应用名称】【公司主体名称】
邮件内容:
1. 应用名称及包名
2. 请将demo(可以不含计费)、ppt介绍(不是必须)放至*腾讯微云网盘*(公司邮箱无法接收附件)
3. 预签约主体全称
4. 应用类型(如教育、视频、工具等)
5. 开发者对接人联系方式:姓名、电话、微信。
6. ICP证、视听许可证、文网文证,软件著作权登记证。(请尽量提供完整,如部分证件暂无法提供,请提供已有资质和正在办理中的相关查询截图证明。)
注:不提供资质,一律不回复!
收到邮件后,小米商务会在5个工作日内回复并沟通具体合作事宜,信息不完整一律不予回复,如没有及时回复请电话催促或者QQ催促避免造成合作延误,感谢理解。
2、接入前准备
开发者可根据以下项做好接入前的准备工作:
1. 准备小米手机、平板设备。设备规格:小米手机&平板设备规格。
2. 注册开发者站帐号。流程:开发者账号注册流程。
3. 在开发者站创建应用并申请AppId、AppKey、AppSecret,其中AppId、AppKey用来初始化SDK、AppSecret在服务器与服务器通信签名生成signature时使用。申请新应用时,选择应用类型时一定要选择软件应用。申请参数后切记要配置应用相关计费信息(点击已创建的应用--商品管理界面)。流程:应用提交流程。
4. 在开发者站配置应用内商品管理界面,配置商品代码,如果是按金额付费必须配置回调地址,按计费代码付费可选。
3、接入流程与实现
3.1 接入声明
如果您的应用是分包联运,请务必注意以下内容:
1. 应用名称更改为:应用名**版(比如懒人听书尊享版等,其中**为替换项)
2. Icon需增加区分(例如在icon下方增加极速版标识)
3. applicationID:在原applicationID加后缀.appunion
*主包联运无须做以上修改。
*主包和分包是两个单独的app。
如您在接入期间有任何技术问题请直接邮件至mayue9@xiaomi.com, 邮件标题务必注明应用名称,技术同事会在1~3个工作日内回复。也可以直接在对接的讨论群中直接咨询。
3.2 快速开始
在继续看文档之前,建议您先把随本文档一起分发的Demo程序安装到手机或安卓平板上,这个程序完整演示了小米应用支付的工作流程,有助于您快速理解我们SDK支付的整个流程。
请参考AppSDKDemo项目。
应用内支付SDK核心是mio_sdk_app_xxx.aar(位于libs目录下,根据不同版本,名称会有所变化,但开头会是"mio_sdk_app_",以实际名称为准),需要将此jar包放入应用App的工程中,我们已将要使用的接口封装好。内部含有2个so文件,提供armeabi-v7a/armeabi/x86版本,请注意这是否与您现有的结构冲突。
应用内支付SDK还需要一系列第三方支持的库,一些以jar包形式在libs目录里,一些在gradle里直接依赖。
请确保调用的activity的launchmode为默认(standard),否则会出现按home键后返回 界面消失流程强制中断,订单状态异常的问题。
3.3 产品设计及实现说明
3.3.1 登录及支付
请确保已经配置应用相关的计费信息(按金额付费/按计费代码付费/订阅),否则登录和支付都会失败。
注:需在用户每次启动应用时,调用登录接口。如果在支付界面调用登录接口,有可能造成后续联运活动不能正常进行,导致用户不能参与到活动中,从而影响用户付费,造成用户付费率降低,影响联运收入。
登录流程概述
用户每次启动应用时,必须调用miLogin()来判断用户会话是否超时,在应用运行过程中,如果需要充值可以调用miUniPay()。 登录实现请参考:3.3.2sdk调用方法-小米账号登录调用代码。
注意:调取miLogin()登录前需要:
1. 在开发者站申请并绑定有效的appId/appKey。
2. 配置商品管理模块,否则会报告 -102 错误。
用户登录时序图
注意:
1. UID不是小米ID,但与小米ID有对照关系。
2. 请开发者一定要使用这个UID作为用户标识,不要使用本机的IMEI、IMSI或Mac地址,我们的审核团队会严格测试
支付流程概述
计费方式:
1. 按金额付费(3.3.2sdk调用方法-按金额付费调用代码):回调地址必须配置,可自行传入付费金额(单位:分,整型,2.0之前的版本为元 请一定注意此项变动) 。
2. 按计费代码付费(含订阅)(3.3.2sdk调用方法-按计费代码付费调用代码):回调地址。配置可选,支持可消耗类商品代码与不可消耗类商品代码,可在开发者后台调整计费代码的价格。
如需接入订阅,请先阅读订阅注意点:订阅接入注意点
按金额付费流程
3.3.2 SDK调用方法
对于开发者来说只需要引入以下代码即可完成应用内支付
初始化
在小米开发者创建应用并获取 AppId 、AppKey和AppSecret(注意AppSecret是用于服务器端签名,不要在客户端里使用)。
将 SDK 包中libs目录下的文件放在你的项目的libs目录下,并配置denpendencies和AndroidManifest.(可能会有变动,以SDK包中实际内容为准)。
SampleMiAppSdk-20240619包内:
注意: 需要检查下面的一致性,如果不一致会导致调用登录和其它 SDK 接口失败。
1. 在小米开发者站后台配置好AppId/AppKey和包名。
2. 检查AndroidManifest.xml里面所设置的package必须与开发者站配置的一致。
3. 必须配置应用内消费,否则无法成功登录(会返回1515) 。
4. 上传对应签名的apk到小米开发者站后台(可不申请审核) 。
SDK所需要的权限
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="com.xiaomi.sdk.permission.APP" /
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.xiaomi.permission.AUTH_SERVICE" />
包可见性适配
<!-- 安卓11包可见性适配 -->
<queries>
<!-- 微信 -->
<package android:name="com.tencent.mm" />
<!-- 支付宝 -->
<package android:name="com.eg.android.AlipayGphone" />
</queries>
SDK所需要的清单配置
<activity android:name="com.xiaomi.account.openauth.AuthorizeActivity" />
build.gradle 配置
dependencies {
implementation 'androidx.multidex:multidex:2.0.0'
implementation fileTree(include: '*.jar', dir: 'libs')
implementation 'androidx.annotation:annotation:1.0.0'
implementation 'com.android.support:support-annotations:28.0.0'
implementation 'com.xiaomi.account:passportsdk-account-oauth:5.0.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.android.volley:volley:1.1.0'
implementation (name:'mio_sdk_app_3.6.1', ext:'aar')
implementation (name:'alipaysdk-android-15.8.17', ext:'aar')
implementation 'com.xiaomi.gamevenus:milink-compat:4.0.34'
}
repositories {
jcenter()
google()
maven { url "https://jitpack.io" }
maven { url 'https://maven.aliyun.com/repository/public' }
maven {
credentials {
username '5f45c9022d5925c55bc00c6f'
password 'NQwPJAa42nlV'
}
url 'https://packages.aliyun.com/maven/repository/2028284-release-awMPKn/'
}
maven {
credentials {
username '5f45c9022d5925c55bc00c6f'
password 'NQwPJAa42nlV'
}
url 'https://packages.aliyun.com/maven/repository/2028284-snapshot-gw4bH1/'
}
maven {
url "https://repos.xiaomi.com/maven"
credentials {
username 'mi-gamesdk'
password 'AKCp8mYeLuhuaGj6bK1XK7t2w4CsPuGwg6GpQdZ9cat7K59y5sD7Tx3dHjJcFrBGj3TQ4vi7g'
}
}
}
注册应用生命周期
注册ActivityLifecycleCallbacks,感知应用内activity的生命周期的变化,用于展示活动弹窗。请确保在Application的onCreate方法内调用
public class MiAppApplication extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
MiCommplatform.setApplication(this);
}
}
初始化调用代码
MiAppInfo appInfo = new MiAppInfo();
appInfo.setAppId("请申请获得");
appInfo.setAppKey("请申请获得");
MiCommplatform.Init(this, appInfo, new OnInitProcessListener() {
@Override
public void finishInitProcess(@MiCode int code, @Nullable String msg) {
switch (returnCode) {
case MiCode.MI_INIT_SUCCESS:
Toast.makeText(getApplicationContext(), "初始化成功", Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(getApplicationContext(), "初始化失败(请检查是否已配计费):" + msg, Toast.LENGTH_LONG).show();
break;
}
}
});
若接入活动弹窗则需调用以下代码:
1.页面级别:在预期想要弹出弹窗的界面中调用初始化,初始化代码如上(预期界面如:首页等),如果页面销毁则调取MiCommplatform.getInstance().removeAllListener(); 。
adb shell touch /sdcard/Android/data/{应用包名}/files/sdk_switch_test.config
登录调用代码
登录是支付的前置步骤,一个应用生命周期内没有登录是无法进行支付的。
请确保登录/更换非小米账号后及时调用自有账号登录同步账号信息给我们,否则会导致订单信息错误。
请确保在每次应用开启时:
1.如果用户已登录小米账号,通过调用自动登录(MiLoginType.AUTO_ONLY)模式登录来检查登录状态,如果失败则此账号信息已过期,需要尽快合理的通过调用手动登录
(MiLoginType.MANUAL_ONLY)重新登录
2.如果用户已登录非小米账号,需要通过调用自有账号登陆的方式通知我们登录状态
小米账号自动登录(MiLoginType.AUTO_ONLY)和自有账号登录没有界面。
小米账号和自有账号是平级的,即若您在自有账号传入的id是您获得的小米账号的id,我们返回的id和您传入的小米账号的id也无任何关联。
所以请不要将获得的小米账号id作为自有账号id再次传入。
参数说明:
参数名称 | 用途 | 备注 |
context | 上下文 | 必填参数。 |
onLoginProcessListener | 登录结果监听接口 | 必填参数。用于获取登录结果 |
miLoginType | 登录方式 | 必填参数。MiLoginType.AUTO_FIRST(自动登录优先,自有账号仅支持此方法), MiLoginType.AUTO_ONLY(仅自动登录), MiLoginType.MANUAL_ONLY(仅手动登录) |
miAccountType | 账号类型 | 必填参数。MiAccountType.APP(自有账号), MiAccountType.MI_SDK(小米账号) |
extra | 补充信息 | 必填参数。自有账号填入您的账号系统的用户id,小米账号传null即可. |
MiCommplatform.getInstance().miLogin( context,
new OnLoginProcessListener()
{
@Override
public void finishLoginProcess(@MiCode intcode, @Nullable MiAccountInfo account)
{
switch( code )
{
// 登录成功
case MiCode.MI_LOGIN_SUCCESS:
//获取用户的登录后的UID(即用户唯一标识)
String uid = account.getUid();
//以下为获取session并校验流程,可选,12小时过期
//获取用户的登陆的Session(请参考5.3.3流程校验Session有效性)
String session = account.getSessionId();
//请开发者完成将uid和session提交给开发者自己服务器进行session验证
String unionID = account. getUnionId();
//unionID 用于验证在不同应用中 是否为同一用户
//如果为空 则代表没有开启unionID权限
break;
// 登录失败,详细错误码见5.4 返回码
default:
break;
}
}
}, MiLoginType.AUTO_FIRST, MiAccountType.MI_SDK,null);
按金额付费调用代码
请确保调用时有登录态,如果没有可以先采用无界面的登录方式登录,若仍然失败再考虑有界面的手动登录。
参数说明:
参数名称 | 用途 | 备注 |
cpOrderId | 开发方订单号 | 必填参数。20~100字符以内,要求必须由开发者的业务服务器生成,因订单支付成功后应用平台服务器会直接将支付结果通知给开发者的业务服务器,通知参数的cpOrderId是重要信息。 |
cpUserInfo | 给网游透传参数 | 必填参数。用于透传用户信息,当用户支付成功后我们会将此参数透传给开发者业务服务器(不能为null或“”) |
feeValue | 金额 | 必填参数。且数量是int型,即最少只能购买1分. |
MiBuyInfo miBuyInfo= new MiBuyInfo();
miBuyInfo.setCpOrderId(UUID.randomUUID().toString());//订单号唯一(不为空)
miBuyInfo.setCpUserInfo("cpUserInfo"); //此参数在用户支付成功后会透传给CP的服务器
miBuyInfo.setFeeValue( 100 ); //必须是大于0的整数,100代表1元人民币(不为空)
MiCommplatform.getInstance().miUniPay(activity, miBuyInfo,
new OnPayProcessListener()
{
@Override
public void finishPayProcess(@MiCode int code, @Nullable String msg) {
switch( code ) {
//购买成功,建议先通过自家服务器校验后再处理发货
case MiCode.MI_PAY_SUCCESS:
break;
//购买失败,详细错误码见5.4 返回码
default:
break
}
}
});
按计费代码付费调用代码(含订阅)
请确保调用时有登录态,如果没有可以先采用无界面的登录方式登录,若仍然失败再考虑有界面的手动登录。
计费代码有3种类型:
1. 可消耗:可以重复购买
2. 不可消耗:不可以重复购买
3. 订阅:依据订阅规则
参数名 | 用途 | 备注 |
cpOrderId | 开发方订单号 | 20~100字符以内,开发方生成,要求不能重复,可根据开发方规则自行生成。 |
productCode | 商品编号 | 规则要求:可由数字 0-9,字母 a-zA-Z 以及特殊字符”_”,”.”,”-”组成, 长度8~40位,同一款应用内 productCode要求唯一,区分字母大小写。建议使用com.companyname.appname.productname 的格式命名。调用时请不要弄混非消耗类商品和可消耗类商品的productCode。 |
quantity | 购买数量 | 非消耗类商品,取值=1 可消耗类商品,取值≥1 |
按计费代码
MiBuyInfo miBuyInfo = new MiBuyInfo();
miBuyInfo.setCpOrderId( UUID.randomUUID().toString() );//订单号唯一(不为空)
miBuyInfo.setProductCode( "productCode" );//商品代码,开发者申请获得(不为空)
miBuyInfo.setQuantity( 1 );//购买数量(商品数量最大9999,最小1)(不为空)
MiCommplatform.getInstance().miUniPay( activiy, miBuyInfo,new OnPayProcessListener()
{
@Override
public void finishPayProcess(@MiCode int code, @Nullable String msg) {
switch( code ) {
/**
* 支付成功
*/
case MiCode.MI_PAY_SUCCESS:
Toast.makeText(PaymentActivity.this, "支付成功!", Toast.LENGTH_SHORT).show();
break;
//购买失败,详细错误码见5.4 返回码
default:
break;
}
}
});
订阅
MiBuyInfo miBuyInfo = new MiBuyInfo();
miBuyInfo.setCpOrderId( UUID.randomUUID().toString() );//订单号唯一(不为空)
miBuyInfo.setProductCode( "productCode" );//商品代码,开发者申请获得(不为空)
miBuyInfo.setQuantity( 1 );//购买数量(商品数量最大9999,最小1)(不为空)
MiCommplatform.getInstance().miSubscribe( activiy, miBuyInfo,new OnPayProcessListener()
{
@Override
public void finishPayProcess(@MiCode int code, @Nullable String msg) {
switch( code ) {
/**
* 订阅成功
*/
case MiCode.MI_SUB_SUCCESS:
Toast.makeText(PaymentActivity.this, "订阅成功!", Toast.LENGTH_SHORT).show();
break;
//购买失败,详细错误码见5.4 返回码
default:
break;
}
}
});
其余可选功能性接口调用代码
以下接口请在初始化后调用
获取本次登录过的最近的账号信息,此账号信息会和订单的账号信息一致,为空则无账号信息也无法进行支付。
MiCommplatform.getInstance().getLoginInfo();
设置是否显示错误对话框,默认显示
MiCommplatform.getInstance().setAlertDialogDisplay(true);
设置是否显示错误Toast,默认显示
MiCommplatform.getInstance().setToastDisplay(true);
设置错误监听,设置后可以通过此接口获取错误信息
MiCommplatform.getInstance().setOnAlertListener(onAlertListener);
3.4 服务器接口
1. 按金额付费,以小米应用支付服务器通知的结果为准为用户进行虚拟币充值。所以必须提供接收订单支付结果通知的地址(必选) 。
2. 按计费代码计费,也可以提供接收订单支付结果通知的地址(可选) 。
3. 服务器代码示例下载地址。 包含签名实现,登录验证,订单查询,回调接口,有php和java的示例。
3.4.1 订单支付结果通知接口
服务端只会回调支付成功的结果,失败或者没有收到回调,请参考3.4.2主动查询订单支付状态,主动查询订单状态。
3.4.1.2 流程说明
此接口由开发者负责开发并在开发者后台进行配置。在订单支付成功后,小米应用支付服务器会将支付结果通知给开发者预先提供的服务器上。若开发者所提供的服务器地址不可用,在一定时间段内应用商店服务器会按照周期进行轮询(前10次,每分钟通知1次;10次后每小时通知1次)。 具体流程如下:
注:由于是异步通知模型,(3)和(4)不一定是按序号产生。因此(4)和(5)需要进行轮询处理或者使用接口进行支付结果查询。 相比后面提到的开发者主动查询订单的模式,我们推荐使用此模式。
3.4.1.2 接口及参数说明
1. 接口地址:各开发者服务器的通知地址(提前申请,在小米开发者站进行配置,请使用https)
2. 请求方法:GET
3. 订阅:对于订阅商品,首次签约并支付成功会有签约回调和支付回调,之后自动扣款只有支付回调,如果签约状态发送改变,会有签约回调;这两个回调通知的地址只能设置为同一个,不可以分别设置。
支付回调参数说明:
参数 | 是否必传 | 说明 | |
appId | 是 | 应用id | |
cpOrderId | 是 | 开发商订单ID | 对于订阅商品,此参数只有首次签约的时候会有,之后自动扣款不会有; 同一用户取消订阅后再次购买,此参数会发生改变 |
cpUserInfo | 否 | 开发商透传信息 | |
uid | 是 | 用户ID | |
orderId | 是 | 订单号 | |
orderStatus | 是 | 订单状态 TRADE_SUCCESS 代表成功 WAIT_BUYER_PAY 代表未支付 REPEAT_PURCHASE 订购关系已经存在 | |
payFee | 是 | 支付金额,单位为分,即0.01 米币。 | 请务必使用(payFee)和游戏发起订单金额做校验,确保订单金额一致性(曾出现为校验被篡改金额被盗刷风险) |
productCode | 是 | 商品代码 | |
productName | 是 | 商品名称 | |
productCount | 是 | 商品数量 | |
payTime | 是 | 支付时间,格式 yyyy-MM-dd HH:mm:ss | |
orderConsumeType | 否 | 订单类型: 10 普通订单 11 直充直消订单 | |
signature | 是 | 签名 | |
deductType | int | 订阅支付或者扣款必传 新增参数 | 0:用户主动支付 1:服务端代扣 |
uid + productCode可以确定哪个用户订阅的哪个商品,deductType可以确定是用户首次订阅还是后续服务端自动扣款。
签约回调参数说明:
参数 | 类型 | 是否必传 | 说明 |
subStatus | String | 是 | 签约状态 SUBSCRIBE_PERIOD:订阅中 SUBSCRIBE_TERMINATE:订阅终止状态 SUBSCRIBE_ONLY_CONTRACT_TERMINATE:与第三方支付解约免密支付,订阅权益到期后终止 |
appId | long | 是 | 应用ID |
uid | String | 是 | 用户id |
productCode | String | 是 | 订阅商品id |
signature | String | 是 | 签名,签名方法见后面说明 |
返回参数说明:
参数名称 | 重要性 | 说明 |
errcode | 必须 | 状态码: 200 成功 1506 cpOrderId 错误 1515 appId 错误 1516 uid 错误 1525 signature 错误 3515 订单信息不一致,用于和 CP 的订单校验 3525 订阅错误 |
errMsg | 可选 | 错误信息 |
注意:对于同一个订单号的多次通知,开发商要自己保证只处理一次发货。 例如: {"errcode":200}
再次提醒:处理errcode需仔细检查格式和拼写,否则会出现服务器反复回调的情况。(格式拼写错误小米服务器都认为回调失败)
服务器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)
124.251.57.0/24 (124.251.57.0 ~ 124.251.57.255)
183.84.4.0/26 (183.84.4.1 ~ 183.84.4.62)
118.26.209.0/24 (118.26.209.0 ~ 118.26.209.255)
请开发商服务器开发人员加到ip白名单内,以免因为ip限制造成回调不成功。
3.4.2 主动查询订单支付状态接口
此接口由小米为开发者提供。
流程说明
接口及参数说明
1. 接口地址:https://mis.migc.xiaomi.com/api/biz/service/queryOrder.do
2. 请求方法:GET
请求参数说明:
参数名称 | 重要性 | 说明 |
appId | 必须 | 应用ID |
cpOrderId | 必须 | 开发商订单ID |
uid | 必须 | 用户ID |
signature | 必须 | 签名,签名方法见后面说明 |
例如:
https://mis.migc.xiaomi.com/api/biz/service/queryOrder.do?appId=2882303761517239138&cpOrderId=9786bffc-996d-4553-aa33-f7e92c0b29d5&uid=100010&signature=e91d68b864b272b6ec03f35ee5a640423d01a0a1
正确返回参数说明:
参数名称 | 重要性 | 说明 |
appId | 必须 | 应用ID |
cpOrderId | 必须 | 开发商订单ID |
cpUserInfo | 可选 | 开发商透传信息 |
uid | 必须 | 用户ID |
orderId | 必须 | 应用商店订单ID |
orderStatus | 必须 | 订单状态,TRADE_SUCCESS 代表成功WAIT_BUYER_PAY 代表未支付REPEAT_PURCHASE 订购关系已经存在 |
payFee | 必须 | 支付金额,单位为分,即0.01 米币。(请务必使用payFee字段值与游戏发起订单金额做校验,确保订单金额一致性) |
productCode | 必须 | 商品代码 |
productName | 必须 | 商品名称 |
productCount | 必须 | 商品数量 |
payTime | 必须 | 支付时间,格式 yyyy-MM-dd HH:mm:ss |
orderConsumeType | 可选 | 订单类型: 10 普通订单 11 直充直消订单 |
signature | 必须 | 签名。签名方法见后面说明 |
例如:
{
"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"
}
错误返回参数说明:
参数名称 | 重要性 | 说明 |
errcode | 必须 | 状态码: 1506 cpOrderId 错误 1515 appId 错误 1516 uid 错误 1525 signature 错误 |
errMsg | 可选 | 错误信息 |
3.4.3 用户session验证接口
此接口由小米应用支付为开发者提供,用于验证登录账户的有效性。
注意:用户的唯一标识是通过SDK获得的uid,而不是Session,Session用于校验登录验证的有效性,必须经过SDK、应用商店服务器、开发者服务器进行三方验证,如果Session失效,需要重新调用miLogin()进行登录。
流程说明
接口及参数说明
1. 接口地址:https://mis.migc.xiaomi.com/api/biz/service/loginvalidate
2. 请求方法:POST
3. Headers:Content-Type: application/x-www-form-urlencoded
请求参数说明:
参数名称 | 重要性 | 说明 |
appId | 必须 | 应用ID |
session | 必须 | 用户sessionID,12小时过期 |
uid | 必须 | 用户ID |
signature | 必须 | 签名,签名方法见后面说明 |
例如:
POST https://mis.migc.xiaomi.com/api/biz/service/loginvalidate
appId=2882303761517239138&session=1nlfxuAGmZk9IR2L&uid=100010&signature=b560b14efb18ee2eb8f85e51c5f7c11f697abcfc
参数名称 | 重要性 | 说明 |
errcode | 必须 | 状态码: 200 验证正确 1515 appId 错误 1516 uid 错误 1520 session 错误 1525 signature 错误 4002 appid, uid, session 不匹配(常见为session过期) |
errMsg | 可选 | 错误信息 |
adult | 可选 | 用户实名标识。 407 实名认证通过,年龄大于18岁 408 实名认证通过,年龄小于18岁 409 未进行实名认证 |
age | 可选 | 用户年龄 |
例如:
{ "errcode": 200,"adult":409 }
接口及参数说明
1. 接口地址:https://mis.migc.xiaomi.com/api/biz/service/queryTrade.do
2. 请求方法:GET
请求参数说明:
参数名称 | 重要性 | 说明 |
appId | 必须 | 应用ID |
tradeId | 必须 | 商家订单号(支付宝,微信账单处有,见下图) |
uid | 必须 | 用户ID |
signature | 必须 | 签名,签名方法见后面说明 |
返回参数说明:
参数名称 | 重要性 | 说明 |
appId | 必须 | 应用ID |
cpOrderId | 必须 | 开发商订单ID |
cpUserInfo | 可选 | 开发商透传信息 |
uid | 必须 | 用户ID |
orderId | 必须 | 应用商店订单ID |
orderStatus | 必须 | 订单状态 TRADE_SUCCESS 代表成功 WAIT_BUYER_PAY 代表未支付 REPEAT_PURCHASE 订购关系已经存在 |
payFee | 必须 | 支付金额,单位为分,即0.01 米币。(请务必使用payFee字段值与游戏发起订单金额做校验,确保订单金额一致性) |
productCode | 必须 | 商品代码 |
productName | 必须 | 商品名称 |
productCount | 必须 | 商品数量 |
payTime | 必须 | 支付时间,格式 yyyy-MM-dd HH:mm:ss |
orderConsumeType | 可选 | 订单类型: 10 普通订单 11 直充直消订单 |
signature | 必须 | 签名。签名方法见后面说明 |
tradeId | 必须 | 商家订单号 |
tradeFee | 必须 | 用户实际支付金额 |
payType | 必须 | 用户支付类型(中文:支付宝/微信) |
3.4.4 订阅状态查询接口
1. 接口地址:https://mis.migc.xiaomi.com/api/biz/service/querySubscribe.do
2. 请求方法:GET/POST
请求参数说明:
参数 | 类型 | 是否必传 | 说明 |
appId | long | 是 | 应用ID |
uid | String | 是 | 用户id |
productCode | String | 是 | 订阅商品id |
signature | String | 是 | 签名,签名方法见后面说明 |
返回参数说明:
参数 | 类型 | 是否必传 | 说明 |
appId | long | 是 | 应用ID |
uid | String | 是 | 用户id(openid) |
productCode | String | 是 | 订阅商品id |
subStatus | String | 是 | 订阅状态: NOT_SUBSCRIBE:未订阅 SUBSCRIBE_PERIOD:订阅中 SUBSCRIBE_PERIOD_GRACE:处于宽限期内 SUBSCRIBE_PERIOD_GRACE_EXPIRY:失效期状态 SUBSCRIBE_TERMINATE:订阅终止状态 SUBSCRIBE_ONLY_CONTRACT_TERMINATE:与第三方支付解约免密支付,订阅权益到期后终止 |
3.4.5 解除订阅关系接口
1. 接口地址:https://mis.migc.xiaomi.com/api/biz/service/unSubscribe.do
2. 请求方法:GET/POST
请求参数说明:
参数 | 类型 | 是否必传 | 说明 |
appId | long | 是 | 应用ID |
uid | String | 是 | 用户id |
productCode | String | 是 | 订阅商品id |
signature | String | 是 | 签名 |
返回参数说明:
参数 | 类型 | 是否必传 | 说明 |
errcode | int | 是 | 发起扣款调用结果 200:调用成功(不一定解约成功,以异步签约回调为准) 1000:参数错误 1001:系统错误 1002:订阅信息有误 1003:与第三方支付签约信息有误 1005: 用户没有与第三方支付签约 40004:支付宝解约失败 |
errMsg | String | 是 | 错误信息 |
3.4.6 接口格式说明
输入参数:?参数1=值1&参数2=值2&....&参数n=值n,如果遇到文本参数值,需要根据情况对参数值做 UrlEncode。
返回参数:在回调的时候,是 http get方式发送请求,参数拼接在url后面,你们的服务器返回的数据 要求是json格式的,如:{"errcode":200}这种格式。
3.4.7 signature签名方法说明
1.生成带签名字符串表中各参数按字母顺序排序(不包含signature),如果第一个字母相同,按第二个字母排序,依次类推。排序后拼接成par1=val1&par2=val2&par3=val3的格式,所生成的字符串即为待签名的字符串。没有值的参数请不要参与签名。由于有些数据根据HTTP协议需求,需要进行URLencoding,这样接收方才可以接收到正确的参数,但如果这个参数参与签名,那么待签名字符串必须是字符串原值而非URLencoding的值。 例如(具体参数请以收到的为准,不要依据此示例修改参数):
在订单通知接口收到的回调信息如下:
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
这时候需要对每个参数的值进行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)的哈希算法对代签字符串进行签名计算。签名的结果由16进制表示。hmac-sha1 带密钥(secret)哈希算法的实现请参考5.2服务器签名函数。
4、小米账号介绍
功能介绍
小米账户是小米公司为所有小米网、MIUI、米聊而开发的小米通行证账户系统,小米账户主要通过绑定手机号码的方式进行注册和登录,用户注册小米账户的同时将会享受小米云服务、小米社区、米聊、应用商店等多项优质免费服务。 小米账户既可使用小米ID登录,也可使用手机号码作为用户名登录,十分方便快捷。 若没有小米账号,可以访问https://account.xiaomi.com/进行注册。
登录介绍
提供小米帐号登录和游客登录(第三方登录,也就是现有多种登录模式)选择界面,小米账号要优先展示,具体展示风格与效果由开发者自行设置;
注:需在用户每次启动应用时,调用登录接口。如果在支付界面调用登录接口,有可能造成后续联运活动不能正常进行,导致用户不能参与到活动中,从而影响用户付费,造成用户付费率降低,影响联运收入。
账号切换(含更换手机):
切换帐号带来的账号ID、操作记录、进度等的对应关系同步,需要开发者自行处理,部分场景参考如下:
1、游客模式切换小米帐号登录:按新用户处理;
2、小米手机更换:已登录小米帐号用户,使用小米手机登录原有帐号;未登录小米帐号用户,按新用户处理;
3、手机更换(其它品牌切换小米手机):有小米账号,登录小米账号即可同步账号数据;无小米账号,按新用户处理;
UnionID 功能
如果开发者拥有多个移动应用,可通过 UnionID 来区分用户的唯一性,因为只要是同一个小米帐号下的移动应用,用户的 UnionID 是唯一的,开发者可以通过UnionID实现跨程序的用户区分。也就是说,同一用户,对同一个小米开放平台下的不同应用,UnionID是相同的。
此功能需要联系对应商务申请开通相应的权限。通过提供包名+开发者账号去申请。
5、常见问题
5.1 APK打包及发布
需要注意,SDK 包是以 jar 包提供给开发者,此jar包本身已为混淆状态,您在混淆自己应用的 APK包时,需要在proguard.cfg 里加入,以避免二次混淆。
-keepattributes InnerClasses,Signature,Exceptions,Deprecated,*Annotation*
-dontwarn android.**
-keep class android.** {*;}
-keep class com.google.** {*;}
-keep class com.android.** {*;}
-dontwarn org.apache.**
-keep class org.apache.** { *; }
-keep class sun.misc.Unsafe { *; }
-keep class com.google.zxing.** {*;}
-dontwarn com.alipay.**
-keep class com.alipay.** {*;}
-keep class com.ut.device.** {*;}
-keep class com.ta.utdid2.** {*;}
-keep class org.greenrobot.eventbus.** { *; }
-keep class de.greenrobot.event.** { *; }
-keep class de.greenrobot.dao.** {*;}
-keepclassmembers class ** {
public void onEvent*(**);
void onEvent*(**);
}
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable);
}
-keep class com.tencent.** {*;}
-dontwarn com.xiaomi.**
-keep class com.xiaomi.** {*;}
-keep class com.mi.** {*;}
-keep class com.wali.** {*;}
-keep class cn.com.wali.** {*;}
-keep class miui.net.**{*;}
-keep class org.xiaomi.** {*;}
-keep class com.mi.*** {*;}
-keep class demo.csm.*** {*;}
#保留位于View类中的get和set方法
-keepclassmembers public class * extends android.view.View{
void set*(***);
*** get*();
}
#保留在Activity中以View为参数的方法不变
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#保留实现了Parcelable的类名不变,
-keep class * implements android.os.Parcelable{
public static final android.os.Parcelable$Creator *;
}
#保留R$*类中静态成员的变量名
-keep class **.R$* {*;}
-dontwarn android.support.**
-keep class **.R$styleable{*;}
5.2 服务器签名函数
Hmac-SHA1算法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";
/**
* 使用 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 );
// 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
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();
}
/**
* 转换成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 );
// 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
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();
}
}
5.3 SDK接入完毕
完成SDK接入的应用包请参考《CP内嵌SDK自测用例》进行测试,自测通过以后请到小米开发者站上传,上传成功后请按照要求发送邮件至mayue9@xiaomi.com申请审核。
5.4 返回码
返回码 | MiCode | 含义 |
通用返回码 | ||
MI_SUCCESS | 0 | 成功(2.5废弃) |
MI_ERROR_CANCEL | -1000 | 操作取消(2.5废弃) |
MI_ERROR_ACTION_EXECUTED | -1001 | 动作正在执行 |
MI_ERROR_NETWORK_ERROR | -1002 | 网络错误 |
初始化返回码 | ||
MI_ERROR_INIT_FAILURE | -2000 | 初始化失败 |
MI_INIT_SUCCESS | -2001 | 初始化成功 |
MI_ERROR_NOT_PASS_INIT | -2002 | 初始化未通过(出现在登录和支付/订阅返回内) |
登录错误码 | ||
MI_ERROR_LOGIN_FAILURE | -3000 | 登录失败 |
MI_ERROR_LOGIN_INVALID_PARAMETER | -3003 | 参数错误 |
MI_ERROR_LOGIN_APPINFO_IS_NULL | -3004 | appinfo为空 |
MI_ERROR_AUTO_LOGIN_FAILURE | -3005 | 自动登录失败 |
MI_ERROR_LOGIN_CANCEL | -3006 | 登录取消 |
MI_LOGIN_SUCCESS | -3007 | 登陆成功 |
绑定错误码 | ||
MI_ERROR_BIND_FAILURE | -3200 | 绑定失败 |
MI_ERROR_BIND_CANCEL | -3201 | 绑定取消 |
MI_ERROR_BIND_ACCOUNT_TYPE_INVALID | -3203 | 绑定账号类型错误 |
MI_BIND_SUCCESS | -3204 | 绑定成功 |
支付返回码 | ||
MI_ERROR_PAY_FAILURE | -4000 | 支付失败 |
MI_ERROR_PAY_MISSING_LOGIN_STATE | -4001 | 缺失登录态 |
MI_ERROR_PAY_INVALID_PARAMETER | -4002 | 参数错误 |
MI_ERROR_PAY_REPEAT | -4004 | 重复支付 |
MI_ERROR_PAY_CANCEL | -4005 | 支付取消 |
MI_PAY_SUCCESS | -4006 | 支付成功 |
订阅返回码 | ||
MI_ERROR_SUB_FAILURE | -4200 | 订阅失败 |
MI_ERROR_SUB_MISSING_LOGIN_STATE | -4201 | 订阅缺失登录态 |
MI_ERROR_SUB_INVALID_PARAMETER | -4202 | 订阅参数无效 |
MI_ERROR_SUB_HAS_BEEN_BOUGHT | -4203 | 已订阅 |
MI_ERROR_SUB_CANCEL | -4205 | 订阅取消 |
MI_SUB_SUCCESS | -4206 | 订阅成功 |
5.5 提示码
提示码 | MiAlertCode | 含义 |
通用提示码 | ||
MI_ALERT_UNKNOWN_ERROR | 1000 | 未知错误 |
MI_ALERT_NETWORK_ERROR | 1001 | 网络错误 |
MI_ALERT_UNSUPPORTED_LINK | 1002 | 不支持的跳转链接 |
MI_ALERT_UNSUPPORTED_APP | 1003 | 未安装该应用 |
初始化提示码 | ||
MI_ALERT_INIT_FAILURE | 2000 | 初始化失败 |
登录提示码 | ||
MI_ALERT_LOGIN_FAILURE | 3000 | 登录失败 |
MI_ALERT_AUTO_LOGIN_FAILURE | 3001 | 自动登录失败 |
MI_ALERT_SHOW_DIALOG | 3002 | 显示对话框 |
支付提示码 | ||
MI_ALERT_PAY_FAILURE | 4000 | 支付失败 |
参数名称 | 用途 | 备注 |
context | 上下文 | 必填参数。 |
onLoginProcessListener | 登录结果监听接口 | 必填参数。用于获取登录结果 |
miLoginType | 登录方式 | 必填参数。MiLoginType.AUTO_FIRST(自动登录优先,自有账号仅支持此方法), MiLoginType.AUTO_ONLY(仅自动登录), MiLoginType.MANUAL_ONLY(仅手动登录) |
miAccountType | 账号类型 | 必填参数。MiAccountType.APP(自有账号), MiAccountType.MI_SDK(小米账号) |
extra | 补充信息 | 必填参数。自有账号填入您的账号系统的用户id,小米账号传null即可. |
6、隐私合规相关
开发者需要在开发者的隐私政策中补充以下内容:
1、用户权利反馈流程:
a.用户向应用提交反馈。通过用户权利中心、客服等方式。
b.应用收集用户反馈并整理,如果反馈问题中有涉及需要联运方配合处理的问题,及时反馈给联运侧。
c.联运接到应用提供的问题反馈,3-5个工作日内及时处理并同步应用侧信息。
d.应用侧将处理结果统一反馈给用户。
2、【隐私政策嵌入】在一些法律允许的情况下,为了向您提供相关服务,第三方联运方可能处理您的个人信息,以下为联运方隐私政策+链接:https://dev.mi.com/xiaomihyperos/documentation/detail?pId=1327。
如您仍有疑问,请联系客服,与我们取得联系。