本文档面向 Android 开发者,描述的接入方式适合运营在 4399 平台的联机游戏。
版本列表 | 变更时间 | 变更内容 |
---|---|---|
v3.2.0 |
2022.03.03 | OperateCenterConfig 重命名为
OperateConfig 绑定手机/检查用户绑定手机接口变更:
|
v3.3.0 |
2022.03.29 | -(表示接口、接入方式不变,以下省略说明,但跳版本接入时应注意中间版本的变更) |
v3.3.2 |
2022.04.20 | - |
v3.3.3 |
2022.05.25 | - |
v3.3.4 |
2022.06.06 | - |
v3.4.0 |
2022.07.01 | 接口不变,aar 接入方式不变jar+res
接入方式,由于第三方SDK 更新的原因需要:
|
v3.5.0 |
2022.07.14 | - |
v3.6.0 |
2022.08.23 | - |
v3.7.0 |
2022.09.15 | - |
v3.7.1 |
2023.01.09 | - |
v3.10.0 |
2023.02.16 | 接口不变,若打包出现资源错误,compileSdkVersion 需要提升到29或更高 |
v3.12.1 |
2023.05.15 | 接口不变,但游戏 Activity 的 android:configChanges
要增加配置以支持分屏,具体内容见初始化部分 |
v3.12.2 |
2023.06.14 | 接口不变,优化充值页面折叠屏兼容性 |
v3.13.0 |
2023.07.10 | 新增好友、排行、成就接口 |
SDK和相关示例的下载地址可在游戏创建后,进入 「游戏管理-SDK服务」 页面获取。
注意
如果您是开发者,在为用户提供服务前请阅读 《4399通行证用户服务协议》与《隐私政策》,了解SDK对个人信息收集范围、处理目的以及权限使用情况。请您向用户提供服务时,告知相关信息并取得用户同意。
如果您是用户,请在使用我们的服务前阅读 《4399通行证用户服务协议》与《隐私政策》,了解SDK对个人信息收集范围、处理目的以及权限使用情况。充分理解后再开始使用我们的服务。
4399 运营 SDK(以下简称 SDK),为接入的游戏提供4399账户登录、充值、更新、游戏内容展示等功能。
SDK 优先提供在线aar
依赖方式,其 Demo 结构遵循 Android
Studio(as) 规范,但仍然保留了 jar+res
的依赖方式。
SDK 支持的编译配置 android:minSdkVersion >= 16。
需要充值功能、登录服务端校验,参考 SDK 服务端接入文档
首次接入 SDK,要在 4399 开放平台
注册应用,主要是提交APK、素材,配置游戏币、充值回调地址等信息。
完成后,开发者将得到 SDK
的基础参数:game key
或GameKey
,游戏在 4399
平台的运营标识(开发者平台的游戏信息页面显示为“游戏ID”)
根据游戏需要,以下三种方式可选其一
build.gradle
中引入以下内容即可{
repositories {
maven // 4399 SDK 开放仓库:正式
'https://mvn.4399doc.com/repository/maven-releases'
url }
{
maven // 4399 SDK 开放仓库:快照
'https://mvn.4399doc.com/repository/maven-snapshots'
url }
}
{
dependencies fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation
// 运营 SDK:建议使用最新版本,可通过浏览仓库地址或向运营咨询版本
"cn.m4399.sdk:operate:3.13.0"
implementation
// volley 和 support 是 SDK 使用的外部依赖,若接入方已有,可忽略
'com.android.volley:volley:1.2.1'
implementation //noinspection GradleCompatible
"com.android.support:support-v4:28.0.0"
implementation }
注意:若使用7.0+
版本的 gradle 及 android build
插件,仓库地址应配置在settings.gradle
中
operate/libs/volley-v1.2.1.jar
operate/libs/support-v13-23.2.1.jar
Gradle 文件中注意添加本地依赖
{
dependencies fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation }
若游戏不需要支持所有 abi
,可以按需选用。
aar
依赖方式,按以下方式配置需要的abi
;jar+res
依赖方式需要手动删除不需要的abi
目录
android {
defaultConfig {
ndk {
// 根据游戏需要选择
abiFilters "armeabi", "armeabi-v7a", "x86", "arm64-v8a"
}
}
}
SDK
初始化后才能正确调用其他接口,建议在游戏主 Activity
的开始处如 onCreate
方法中进行。
private void initSDK(){
= OperateCenter.getInstance();
mOpeCenter = new OperateConfig.Builder(MainActivity.this)
OperateConfig config // 设置调试模式,可选,默认false, 发布前应设置为false或删除调用
.setDebugEnabled(false)
// 设置游戏运营 key,必须
.setGameKey(GAME_KEY)
// 设置 SDK 页面方向,必须,应与游戏方向一致,可取值见下文说明
.setOrientation(GAME_ORIENTATION)
// 设置悬浮窗风格,可选,悬浮窗更多信息参考下文
.setPopLogoStyle(PopLogoStyle.POPLOGOSTYLE_FOUR)
// 设置悬浮窗初始位置,可选,有四种,分别在屏幕上下左右
.setPopWinPosition(PopWinPosition.POS_LEFT)
// 设置游戏充值是否支持超出金额,可选,true支持,默认false
.setSupportExcess(GAME_SUPPORT_EXCESS)
// 设置是否在 Android 9.+系统上兼容全面屏,true兼容,默认false
.compatNotch(GAME_COMPACT_NOTCH)
.build();
.setConfig(config);
mOpeCenter
// 注意:初始化完成后,其他接口才可用
.init(MainActivity.this,new OperateCenter.OnInitGlobalListener(){
mOpeCenter/*
* 初始化回调
* 只有在init之后, isLogin()返回的状态才可靠
*/
@Override
public void onInitFinished(boolean isLogin,User userInfo) {
// 初始化后处理
}
/*
* 登出帐号的回调
* @param fromUserCenter 标识区分是否从个人中心中登出的,若是则为true,不是为false
*/
@Override
public void onUserAccountLogout(boolean fromUserCenter) {
// 用户登出,游戏应回到自身登录页面
}
/*
* 切换账号回调
*/
@Override
public void onSwitchUserAccountFinished(boolean fromUserCenter,User userInfo) {
// 用户切换,游戏应回到选服页面
}
});
}
初始化的几点说明
android:configChanges
等,否则系统强制方向变化(一般发生是打开外部应用,如支付宝、微信)或系统设置变化时,可能会发生异常<!-- 游戏 Activity 配置:
应该使用 android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|navigation|smallestScreenSize|fontScale"
若游戏覆盖了 `android:resizeableActivity="true"` ,则必须按上面配置
不应该使用 android:launchMode="singleTask" 启动模式,可以考虑 singleTop
-->
其中android:configChanges
新增的配置项,这是为适配
Android 分屏模式而添加的,更多内容参考多窗口支持
分屏(画中画)兼容:游戏进入分屏再点击桌面图标启动,会重启游戏页面,而并没有完整的启动应用,这会导致部分功能异常,
为了兼容这种情况,SDK
为应用默认设置了android:resizeableActivity="false"
,即不支持分屏模式,
若游戏出于某些原因必须要覆盖此项,则务必按最低标准设置入口
Activity 和主
Activity的android:configChanges
,即
activity
< android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|navigation|smallestScreenSize|fontScale"
/>
OperateConfig.setOrientation()
设置 SDK
页面方向,值是系统类android.content.pm.ActivityInfo
定义的常量方向参数 | 含义 |
---|---|
SCREEN_ORIENTATION_LANDSCAPE ,int , 0 |
横屏 |
SCREEN_ORIENTATION_PORTRAIT , int , 1 |
竖屏 |
SCREEN_ORIENTATION_SENSOR_LANDSCAPE ,int ,
6 |
横屏,可180度旋转 |
SCREEN_ORIENTATION_SENSOR_PORTRAIT ,int ,
7 |
竖屏 |
android:screenOrientation
,如下所示<!--
4399 SDK:SDK 中除了以'cn.m4399.'开头的 Activity 都是第三方页面,
假设游戏为横屏,需要锁定它们的方向为横屏,可以设置 android:screenOrientation,
此设置应与初始化接口中设置的值保持对应,且若编译有错误,可以进一步设置‘tools:replace’
-->
activity android:name="com.cmic.gen.sdk.view.GenLoginAuthActivity"
< android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop"
android:screenOrientation="landscape"
android:theme="@style/AppTheme.NoActionBar"
tools:replace="android:theme, android:screenOrientation" />
悬浮窗会在用户登录后附着在游戏页面上层,点击后打开对页面展示个人信息、设置,和游戏论坛、官网等入口。
极少数游戏登录 Activity 并不是游戏主 Activity ,则悬浮窗可能发生异常,建议游戏做相应调整
OperateConfig.setPopLogoStyle()
设置。样式类型 | 图示 |
---|---|
PopLogoStyle.POPLOGOSTYLE_ONE (默认) |
|
PopLogoStyle.POPLOGOSTYLE_TWO |
|
PopLogoStyle.POPLOGOSTYLE_THREE |
|
PopLogoStyle.POPLOGOSTYLE_FOUR |
OperateConfig.setPopWinPosition()
设置。样式类型 | 位置 |
---|---|
PopWinPosition.POS_LEFT (默认) |
屏幕左侧 |
PopWinPosition.POS_RIGHT |
屏幕右侧 |
PopWinPosition.POS_TOP |
屏幕上侧 |
PopWinPosition.POS_BOTTOM |
屏幕下侧 |
需要登录时调用此接口,如果 SDK 已存在有效登录状态,则直接回调,否则将打开登录页面登录。
if(mOpeCenter.isLogin()) {
= mOpeCenter.getCurrentAccount();
User user } else {
.login(MainActivity.this,new OnLoginFinishedListener() {
mOpeCenter@Override
public void onLoginFinished(boolean success,int resultCode,User user) {
// 登录结束后的游戏逻辑
}
});
}
最佳实践:SDK
初始化时会检查已有登录状态有效,若有效OperateCenter.isLogin()
会返回true
,
游戏直接通过OperateCenter.getCurrentAccount()
获取用户信息接口即可,而不需要调用登录接口
在登录成功回调的用户信息,即User
对象(参考 API
详情),包含state
字段,此值可用于游戏服务端进行 用户信息二次验证
boolean isLogin = mOpeCenter.isLogin();
在 SDK 处于登录状态时,可通过该接口获取当前用户的信息。 注意:User 中的uid是 32 位整数字符串;若要转换为数值,注意溢出的可能性
= mOpeCenter.getCurrentAccount(); User user
若游戏有区服,则应在角色进入分服时,通过以下接口设置所在服的 id。 服务器 id 为不超过10位的数字字符串
.setServer(SERVER_ID); mOpeCenter
当需要切换账号时调用
.switchAccount(MainActivity.this,new OnLoginFinishedListener() {
mOpeCenter@Override
public void onLoginFinished(boolean success,int resultCode,User userInfo){
// 用户账号切换结束后的游戏逻辑
}
});
有时账号切换是由于 SDK 内部发起的,切换成功后 SDK
调用OnInitGlobalListener.onSwitchUserAccountFinished()
通知游戏
当需要登出账号时调用,SDK
立即清除本地用户状态、通知服务端,并调用OnInitGlobalListener.onUserAccountLogout()
通知游戏
.logout(); mOpeCenter
mOpeCenter.setSupportExcess(SUPPORT_EXPRESS)
接口关于超出金额模式(超额)
由于卡类等充值渠道有金额限制,可能出现充值金额无法匹配任何金额的情况;
如果游戏能处理超出传入金额 部分的货币,即将多余部分兑换为游戏币发放给用户,则可以设置true
;
否则,应设置为false
或不设置,SDK将直接隐藏无匹配金额的充值渠道。
/*
* 充值,直接传递参数,旧版接口
*
* money, 充值金额,整型,单位元,1 ~ 50000,必须
* mark, 游戏方订单,必须,
* 支持大小写字母、数字、'|'(竖线)、'-'(中划线)、'_'(下划线),最长32位,不可为空,不可重复
* commodity, 商品名,可选,不传时认为商品名是游戏币
*/
.recharge(MainActivity.this,money,mark,commodity, new OnRechargeFinishedListener() {
mOpeCenter/* 充值操作结果 */
@Override
public void onRechargeFinished(boolean success,int resultCode,String msg) {
if(success) {
// 充值操作成功,根据服务端回调决定是否道具
// 注意:操作成功包含了订单成功、订单处理中两种情况
} else {
// 充值失败逻辑,resultCode查看文档结尾
}
}
});
/*
* 充值,使用订单类,新版接口
*
* 与直接传递参数几乎一样,只是可以对单笔订单设置是否支持超出金额
*/
.recharge(MainActivity.this,
mOpeCenter// 充值金额,整数,单位元
new Order(money, mark)
// 是否支持超出金额,默认不支持
.supportExcess(false)
// 商品名,可选,不传时认为商品名是游戏币
.commodity(COMMODITY_NAME),
new OperateCenter.OnRechargeFinishedListener() {
@Override
public void onRechargeFinished(boolean success,int resultCode,String msg){
}
});
/*
* 绑定手机
*/
.bindPhone(this,new OpeResultListener() {
mOpeCenter/*
* resultCode:0、绑定成功;1、取消绑定;2、已绑定;3、网络异常或服务器异常;
* message:状态说明
*/
@Override
public void onResult(int code,@Nullable String message){
}
});
/*
* 检查用户绑定手机的状态
*/
.checkBindPhoneState(new OpeResultListener() {
mOpeCenter/*
* resultCode: 0、未绑定手机号;2、已绑定手机号;3、网络异常或服务器异常;6 、账号被踢
* message:状态说明
*/
@Override
public void onResult(int code,@Nullable String message){
}
});
当用户按“返回键”或者点击游戏内“退出游戏”时,调用,SDK 会弹出对话框挽留,并展示论坛、礼包等游戏内容
.shouldQuitGame(MainActivity.this,new OnQuitGameListener() {
mOpeCenter@Override
public void onQuitGame(boolean shouldQuit){
// 点击退出对话框上的“退出游戏”时,shouldQuit为true,游戏处理退出业务逻辑
}
});
游戏可以对需要进行发布内容、领取福利、充值等操作的账号,进行认证,认证方式由 SDK 后台控制,可选方式为实名认证和短信认证中的任意组合
.authenticate(requireActivity(),new OpeResultListener() {
mOpeCenter@Override
public void onResult(int code,@Nullable String message){
// code 提示不同类型的错误,message 提示具体信息
}
});
.getVersion(); mOpeCenter
此功能需要在4399后台提交新版本,并开启相关开关,详情可咨询运营。
更新功能会检查是否有新版本游戏上线,如果有,则显示更新内容、提示用户升级。
按升级内容,可为全量更新和增量更新(只需下载新旧版 APK
文件中的差异部分)。
按接入方式又可分为自动更新(无需操作,默认初始化完成)和自定义界面更新
自定义界面增量更新接入方法详见: 4399运营SDK增量升级说明
接入 SDK 的游戏,希望在多个渠道投放,并分别统计数据,有两种方式打入渠道标识
v2SigningEnabled
校验// 游戏 apk 工程的 build.gradle中
{
signingConfigs {
release false
v2SigningEnabled }
}
meta-data
字段:需要运营与开发人员配合完成,但不会有兼容问题在游戏模块的
AndroidManifest.xml
中,设置FTNN_CHANNEL_ID
字段值,作为渠道标识
meta-data android:name="FTNN_CHANNEL_ID" android:value="baidu" /> <
User
类中是一系列getter
方法
public final class User {
/** uid */
public String getUid();
/** 用户名 */
public String getName();
/** 昵称 */
public String getNick();
/** 登录状态 */
public String getState();
/** 绑定的手机号,已脱敏,若已绑定则此字段非空 */
public String getPhone();
}
code | 含义 |
---|---|
0 |
成功,通用code |
1 |
取消,通用code |
2 |
处理中,通用code |
3 |
失败,通用code |
4 |
超时,通用code |
5 |
中止,通用code |
16 |
登录成功 |
17 |
不能取得游戏盒认证(一般是号被封了) |
18 |
登录取消 |
19 |
游戏不存在,GameKey问题 |
20 |
已登录 |
21 |
没有初始化 |
22 |
一键登录失败 |
24 |
拒绝用户协议与隐私政策 |
25 |
网络问题,或者服务端问题 |
50 |
认证通过 |
51 |
待认证 |
52 |
拒绝认证 |
53 |
跳过认证,此时后台配置允许取消 |
54 |
认证审核中 |
55 |
取消认证 |
56 |
认证中断,一般由于账号被顶,或踢出 |
57 |
认证错误,具体消息看对应message |
6001 |
充值取消 |
0 , 9000 |
充值成功 |
2 , 9001 |
订单处理中,游戏应等待服务端的充值回调状态 |
9002 |
订单已提交,SDK 不能在有限时间内判断订单状态,游戏应以服务端状态为准 |