# 客户端接入指南  

---

本文档面向 Android 开发者，描述的接入方式适合运营在 4399 平台、只需要防沉迷功能的游戏。

## SDK 下载

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

<img src="https://f.abd001.com//common/show?f=cm2741857&s=1bed1769b126f33300" alt="image" width="auto" height="auto">

## SDK 说明

### 用户信息与隐私策略

<div class="v-md-plugin-tip warning">
    <p class="v-md-plugin-tip-title">注意</p>
    <p>如果您是开发者，在为用户提供服务前请阅读<a href="https://ptlogin.4399.com/resource/protocol.html?type=1&aids=1,3,6,7" target="_blank"> 《4399通行证用户服务协议》</a>与<a href="https://ptlogin.4399.com/resource/protocol.html?type=2&aids=4,10" target="_blank">《隐私政策》</a>，了解SDK对个人信息收集范围、处理目的以及权限使用情况。请您向用户提供服务时，告知相关信息并取得用户同意。</p>
    <p>如果您是用户，请在使用我们的服务前阅读<a href="https://ptlogin.4399.com/resource/protocol.html?type=1&aids=1,3,6,7" target="_blank"> 《4399通行证用户服务协议》</a>与<a href="https://ptlogin.4399.com/resource/protocol.html?type=2&aids=4,10" target="_blank">《隐私政策》</a>，了解SDK对个人信息收集范围、处理目的以及权限使用情况。充分理解后再开始使用我们的服务。</p>
</div>

### 功能描述
为接入4399平台的游戏提供防沉迷支持

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

## 集成流程
### 准备

首次接入 SDK，要在 [4399 开放平台](https://open.4399.cn/) 注册应用，主要是提交APK、素材等信息。  
完成后，开发者将得到 SDK 的基础参数：`game key`或`GameKey`，游戏在 4399 平台的运营标识（开发者平台的游戏信息页面显示为“游戏ID”）

### 引入依赖  
根据游戏需要，以下三种方式可选其一

- *在线aar*  
若使用*在线aar*，开发者只要在使用 SDK 的 module 的 `build.gradle`中引入以下内容即可  

```groovy
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：建议使用最新正式版本（release仓库中的版本），可通过浏览仓库地址或向运营咨询版本
  implementation "cn.m4399.sdk:operate:3.20.1"

  // volley、support v4、okhttp3、kotlin 是 SDK 使用的外部依赖，若接入方已有，可忽略
  implementation 'com.android.volley:volley:1.2.1'
  //noinspection GradleCompatible
  implementation "com.android.support:support-v4:28.0.0"
  implementation 'com.squareup.okhttp3:okhttp:3.12.8'
  implementation 'com.squareup.okio:okio:1.15.0'
  implementation 'com.squareup.okhttp3:logging-interceptor:3.12.8'
  // kotlin 库支持 1.6.0 以上版本
  implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.0'
  implementation 'org.jetbrains.kotlin:kotlin-stdlib:2.2.0'
  implementation 'org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.2.0'
}
```

*注意：若使用`7.0+`版本的 gradle 及 android build 插件，仓库地址应配置在`settings.gradle`中*

- *本地aar*  
  若使用*本地aar*，则要下载 [在线aar](https://mvn.4399doc.com/repository/maven-releases/cn/m4399/sdk/operate/3.20.1/operate-3.20.1.aar) 和 [jar+res](https://sdkftp.4399doc.com/external/operate/3.20.1/operate-3.20.1+727.zip) 到本地，并将`aar`整体和`jar`包中的以下文件  
  拷贝到游戏模块的`libs`目录下（若游戏已有类似版本的外部依赖，可忽略）

```
operate/libs/volley-v1.2.1.jar
operate/libs/support-v13-23.2.1.jar
operate/libs/kotlin-android-extensions-runtime-2.2.0.jar  
operate/libs/kotlin-stdlib-2.2.0.jar  
operate/libs/kotlin-stdlib-jdk7-2.2.0.jar  
operate/libs/logging-interceptor-3.12.8.jar  
operate/libs/okhttp-3.12.8.jar  
operate/libs/okio-1.15.0.jar
```

Gradle 文件中注意添加本地依赖
```groovy
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
}
```

- *jar+res*  
  [jar+res 依赖引入](https://sdkftp.4399doc.com/external/operate/3.20.1/jar_res_import.html) 比较繁琐，但是完成后，后续接口调用仍然是一样的。

#### abi 适配与 so 库
若游戏不需要支持所有 [abi](https://developer.android.google.cn/ndk/guides/abis?hl=zh-cn) ，可以按需选用。  
`aar`依赖方式，按以下方式配置需要的`abi`；`jar+res`依赖方式需要手动删除**不需要**的`abi`目录
```
android {
    defaultConfig {
        ndk {
            // 根据游戏需要选择
            abiFilters "armeabi-v7a", "x86", "arm64-v8a"
        }
    }
}
```

### 接口调用：初始化（必须）
**功能简介：** 此接口初始化 SDK 内部状态，并完成“更新、激活、防沉迷”等流程。
<span style="color:red">**SDK 初始化后才能正确调用其他接口**</span>   
**调用时机：** 建议在游戏 `Activity` 的开始处如 `onCreate` 方法中进行

```java
// 初始化选项，传入游戏配置，更多说明见接入文档
OperateConfig config = new OperateConfig.Builder(this)
        // 设置游戏运营 key，此参数需要在原创开放平台注册应用后得到
        .setGameKey(GAME_KEY)
        // 设置SDK页面方向，应与游戏方向一致，部分第三方页面需要在AndroidManifest中设置
        .setOrientation(GAME_ORIENTATION)
        // 设置游戏是否兼容 Android 9.0 及以上全面屏，true兼容，默认false
        .compatNotch(GAME_COMPACT_NOTCH)
        .build();

// 初始化SDK
AdGame.init(this, config, new OpeInitedListener() {
    @Override
    public void onInitFinished() {
        // 验证通过，可以进入游戏
    }
});
```

初始化的几点说明
#### 页面方向

- *游戏页面* 应如下配置`android:configChanges`等，否则系统强制方向变化（一般发生是打开外部应用，如支付宝、微信）或系统设置变化时，可能会发生异常

```xml
<!-- 游戏 Activity：
     若覆盖了 android:resizeableActivity="false"，则必须如下设置 android:configChanges
     android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|navigation|smallestScreenSize|fontScale"
     
     不应该使用 android:launchMode="singleTask" 启动模式，可以考虑 singleTop
 -->
```

其中`android:configChanges` 新增的配置项，是为适配 Android 分屏模式而添加的，更多内容参考[多窗口支持](https://developer.android.google.cn/guide/topics/ui/multi-window?hl=zh-cn#config)


**分屏（画中画）兼容**：游戏进入分屏再点击桌面图标启动，会重启游戏页面，而并没有完整的启动应用，这会导致部分功能异常，  
为了兼容这种情况，SDK 为应用默认设置了`android:resizeableActivity="false"`，即不支持分屏模式，  
<span style="color:red;font-weight:700">若游戏出于某些原因必须要覆盖此项，则务必按最低标准设置入口 Activity 和主 Activity的`android:configChanges`</span>，即
```xml
<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize|keyboardHidden|screenLayout|navigation|smallestScreenSize|fontScale"
/>
```

- *SDK 页面*，**方向支持横屏或竖屏，但不支持横竖屏切换**  
  通过`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 | 竖屏 |

- *第三方页面*，其方向一般使用 SDK 默认设置即可，需要锁定可设置`android:screenOrientation`，如下所示

```xml
<!-- 
    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" />
```