客户端接入指南


本文档面向 Android 开发者,描述的接入方式适合运营在 4399 平台的联机游戏。

SDK版本 变更时间 变更内容
v3.2.0 2022.03.03 OperateCenterConfig 重命名为 OperateConfig
绑定手机/检查用户绑定手机接口变更:
  • 回调OpeResultListener接口
  • 状态码及其说明见接入示例
充值回调code,改成通用code,参考文档最后一部分
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 更新的原因需要:
  • 添加渠道方 GenLoginAuthActivity
  • 更新渠道方 jar, so 包,建议重新替换 libs 目录
  • 联通渠道 assets/uniaccount_core.dat 文件可删除
v3.5.0 2022.07.14 -
v3.6.0 2022.08.23 -
v3.7.0 2022.09.15 -
v3.7.1 2022.09.26 -
v3.8.0 2022.09.26 新增账号认证接口OperateCenter.authentication,见下文示例

SDK 下载

SDK和相关示例的下载地址可在游戏创建后,进入 「游戏管理-SDK服务」 页面获取。

image

SDK 说明

用户信息与隐私策略

SDK 中使用的用户信息及隐私政策参考:《4399通行证用户服务协议》《隐私政策》

功能描述

4399 运营 SDK(以下简称 SDK),为接入的游戏提供4399账户登录、充值、更新、游戏内容展示等功能。

SDK 组成

客户端 SDK

SDK 优先提供在线aar依赖方式,其 Demo 结构遵循 Android Studio(as) 规范,但仍然保留了 jar+res 的依赖方式。
SDK 支持的编译配置 android:minSdkVersion >= 16

服务端 API

需要充值功能、登录服务端校验,参考 SDK 服务端接入文档

集成流程

准备

首次接入 SDK,要在 4399 开放平台 注册应用,主要是提交APK、素材,配置游戏币、充值回调地址等信息。
完成后,开发者将得到 SDK 的基础参数:game keyGameKey,游戏在 4399 平台的运营标识

引入依赖

根据游戏需要,以下三种方式可选其一

repositories {
    maven {
        // 4399 SDK 开放仓库:正式
        url 'https://mvn.4399doc.com/repository/maven-releases'
    }
    maven {
        // 4399 SDK 开放仓库:快照
        url 'https://mvn.4399doc.com/repository/maven-snapshots'
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])

    // 运营 SDK:建议使用最新版本,可通过浏览仓库地址或向运营咨询版本
    implementation "cn.m4399.sdk:operate:3.8.0"

    // volley 和 support 是 SDK 使用的外部依赖,若接入方已有,可忽略
    implementation 'com.android.volley:volley:1.2.1'
    //noinspection GradleCompatible
    implementation "com.android.support:support-v4:28.0.0"
}

注意:若使用7.0+版本的 gradle 及 android build 插件,仓库地址应配置在settings.gradle

operate/libs/volley-v1.2.1.jar
operate/libs/support-v13-23.2.1.jar

Gradle 文件中注意添加本地依赖

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}

abi 适配与 so 库

若游戏不需要支持所有 abi ,可以按需选用。
aar依赖方式,按以下方式配置需要的abijar+res依赖方式需要手动删除不需要abi目录

android {
    defaultConfig {
        ndk {
            // 根据游戏需要选择
            abiFilters "armeabi", "armeabi-v7a", "x86", "arm64-v8a"
        }
    }
}

接口调用:初始化(必须)

SDK 初始化后才能正确调用其他接口,建议在游戏主 Activity 的开始处如 onCreate方法中进行。

private void initSDK(){
    mOpeCenter=OperateCenter.getInstance();
    OperateConfig config=new OperateConfig.Builder(MainActivity.this)
        // 设置调试模式,可选,默认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();
    mOpeCenter.setConfig(config);

    // 注意:初始化完成后,其他接口才可用        
    mOpeCenter.init(MainActivity.this,new OperateCenter.OnInitGlobalListener() {
        /*
         * 初始化互调
         * 只有在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){
            // 用户切换,游戏应回到选服页面
        }
    });
}

初始化的几点说明

页面方向

  <!-- 游戏 Activity 配置建议:
       应该使用 android:configChanges="orientation|screenSize|keyboardHidden"
       不应该使用 android:launchMode="singleTask" 启动模式,可以考虑 singleTop
  -->
方向参数 含义
SCREEN_ORIENTATION_LANDSCAPEint, 0 横屏
SCREEN_ORIENTATION_PORTRAIT, int, 1 竖屏
SCREEN_ORIENTATION_SENSOR_LANDSCAPEint, 6 横屏,可180度旋转
SCREEN_ORIENTATION_SENSOR_PORTRAITint, 7 竖屏
<!-- 
    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 ,则悬浮窗可能发生异常,建议游戏做相应调整

样式类型 图示
PopLogoStyle.POPLOGOSTYLE_ONE(默认) image
PopLogoStyle.POPLOGOSTYLE_TWO image
PopLogoStyle.POPLOGOSTYLE_THREE image
PopLogoStyle.POPLOGOSTYLE_FOUR image
样式类型 位置
PopWinPosition.POS_LEFT(默认) 屏幕左侧
PopWinPosition.POS_RIGHT 屏幕右侧
PopWinPosition.POS_TOP 屏幕上侧
PopWinPosition.POS_BOTTOM 屏幕下侧

接口调用:账号相关

账号登录(必须)

需要登录时调用此接口,如果 SDK 已存在有效登录状态,则直接回调,否则将打开登录页面登录。

if(mOpeCenter.isLogin()) {
     User user=mOpeCenter.getCurrentAccount();
} else {    
    mOpeCenter.login(MainActivity.this,new OnLoginFinishedListener() {
        @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 位整数字符串;若要转换为数值,注意溢出的可能性

User user=mOpeCenter.getCurrentAccount();

设置角色服务器 id

若游戏有区服,则应在角色进入分服时,通过以下接口设置所在服的 id。 服务器 id 为不超过10位的数字字符串

mOpeCenter.setServer(SERVER_ID);

账号切换(推荐)

当需要切换账号时调用

mOpeCenter.switchAccount(MainActivity.this,new OnLoginFinishedListener() {
    @Override
    public void onLoginFinished(boolean success,int resultCode,User userInfo) {
        //用户账号切换结束后的游戏逻辑
    }
});

有时账号切换是由于 SDK 内部发起的,切换成功后 SDK 调用OnInitGlobalListener.onSwitchUserAccountFinished()通知游戏

账号登出(推荐)

当需要登出账号时调用,SDK 立即清除本地用户状态、通知服务端,并调用OnInitGlobalListener.onUserAccountLogout()通知游戏

mOpeCenter.logout();

接口调用:充值(推荐)

关于超出金额模式(超额)
由于卡类等充值渠道有金额限制,可能出现充值金额无法匹配任何金额的情况;
如果游戏能处理超出传入金额 部分的货币,即将多余部分兑换为游戏币发放给用户,则可以设置true
否则,应设置为false或不设置,SDK将直接隐藏无匹配金额的充值渠道。

/*
 * 充值,直接传递参数,旧版接口
 *
 * money, 充值金额,整型,单位元,1 ~ 50000,必须
 * mark, 游戏方订单,必须,
 *      支持大小写字母、数字、'|'(竖线)、'-'(中划线)、'_'(下划线),最长32位,不可为空,不可重复
 * commodity, 商品名,可选,不传时认为商品名是游戏币
 */
mOpeCenter.recharge(MainActivity.this,money,mark,commodity,
        new OnRechargeFinishedListener() {
    /* 充值操作结果 */
    @Override
    public void onRechargeFinished(boolean success,int resultCode,String msg) {
        if(success) {
          // 充值操作成功,根据服务端回调决定是否道具
          // 注意:操作成功包含了订单成功、订单处理中两种情况
        } else {
            // 充值失败逻辑,resultCode查看文档结尾
        }
    }
});

/*
 * 充值,使用订单类,新版接口
 *
 * 与直接传递参数几乎一样,只是可以对单笔订单设置是否支持超出金额
 */
mOpeCenter.recharge(MainActivity.this,
    // 充值金额,整数,单位元
    new Order(money,mark)
    // 是否支持超出金额,默认不支持
    .supportExcess(false)
    // 商品名,可选,不传时认为商品名是游戏币
    .commodity(COMMODITY_NAME),
    new OperateCenter.OnRechargeFinishedListener() {
        @Override
        public void onRechargeFinished(boolean success, int resultCode, String msg) {

        }
});

接口调用:绑定手机

绑定

/*
 * 绑定手机
 */
mOpeCenter.bindPhone(this,new OpeResultListener() {
    /*
     * resultCode:0、绑定成功;1、取消绑定;2、已绑定;3、网络异常或服务器异常;
     * message:状态说明
     */
    @Override
    public void onResult(int code,@Nullable String message) {
    }
});

检查绑定状态

/*
 * 检查用户绑定手机的状态
 */
mOpeCenter.checkBindPhoneState(new OpeResultListener() {
    /*
     * resultCode: 0、未绑定手机号;2、已绑定手机号;3、网络异常或服务器异常;6 、账号被踢
     * message:状态说明
     */
    @Override
    public void onResult(int code,@Nullable String message) {
    }
});

接口调用:其他

退出游戏(必须)

当用户按“返回键”或者点击游戏内“退出游戏”时,调用,SDK 会弹出对话框挽留,并展示论坛、礼包等游戏内容

mOpeCenter.shouldQuitGame(MainActivity.this,new OnQuitGameListener(){
    @Override
    public void onQuitGame(boolean shouldQuit){
        // 点击退出对话框上的“退出游戏”时,shouldQuit为true,游戏处理退出业务逻辑
    }
});

账号认证(3.8.0+)

游戏可以对需要进行发布内容、领取福利、充值等操作的账号,进行认证,认证方式由 SDK 后台控制,可选方式为实名认证和短信认证中的任意组合

mOpeCenter.authenticate(requireActivity(),new OpeResultListener(){
    @Override
    public void onResult(int code,@Nullable String message){
        // code 提示不同类型的错误,message 提示具体信息
    }
});

查看SDK版本号

mOpeCenter.getVersion();

更新支持

此功能需要在4399后台提交新版本,并开启相关开关,详情可咨询运营。

更新功能会检查是否有新版本游戏上线,如果有,则显示更新内容、提示用户升级。 按升级内容,可为全量更新和增量更新(只需下载新旧版 APK 文件中的差异部分)。
按接入方式又可分为自动更新(无需操作,默认初始化完成)和自定义界面更新

自定义界面增量更新接入方法详见: 4399运营SDK增量升级说明

渠道支持

接入 SDK 的游戏,希望在多个渠道投放,并分别统计数据,有两种方式打入渠道标识

// 游戏 apk 工程的 build.gradle中
signingConfigs {
    release {
        v2SigningEnabled false
    }
}  

在游戏模块的 AndroidManifest.xml中,设置FTNN_CHANNEL_ID字段值,作为渠道标识


<meta-data
        android:name="FTNN_CHANNEL_ID"
        android:value="baidu"/>

API 详情

User 类方法

User类中是一系列getter方法

public final class User {
    /** uid */
    public String getUid();

    /** 用户名 */
    public String getName();

    /** 昵称 */
    public String getNick();

    /** 登录状态 */
    public String getState();

    /** 绑定的手机号,已脱敏,若已绑定则此字段非空 */
    public String getPhone();
}

接口 code 列表

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 不能在有限时间内判断订单状态,游戏应以服务端状态为准