根据提示做出相应的活体动作，SDK 实时采集动态信息，判断用户是否为活体、真人。在黑灰产对抗激烈，“AI换脸”频发的场景下，活体检测SDK同时也集成了
**风控设备环境检测能力，能够有效拦截摄像头被外部流注入的情况，同时独有的人脸鉴伪技术也能很好的识别合成脸攻击**
> <span style="color: red;">⚠️ 接入活体SDK注意事项：</span>
>
> 1. **本地手动依赖，默认提供了活体检测、风控设备环境检测能力（推荐）**
> 2. **远程仓库依赖，仅集成了基础活体检测，不具备环境风险感知能力，如果您对SDK体积比较敏感，可以这种方式**
> 3. **如果您的产品服务的用户主要在海外，请联系技术支持提供海外专属技术方案，耗时更低**

## 平台支持（兼容性）

| 条目     | 说明       |
| -------- | ---------- |
| 适配版本 | iOS9以上   |
| 开发环境 | Xcode 11.4 |

## 环境准备

[ CocoaPods 安装教程](https://guides.cocoapods.org/using/getting-started.html)

## 资源引入/集成

### SDK模块介绍

| **模块名称**               | **功能说明**     | **支持裁剪** | **SDK包体积** | **编译后体积增量** |
| -------------------------- | ---------------- | ------------ | ------------- | ------------------ |
| NTESLiveDetect.xcframework | 活体人脸检测     | 不可裁剪     | 1.97MB        | 1.97MB             |
| RiskPerception.xcframework | 风控设备环境检测 | 可裁剪       | 1.5MB         | 2.97MB             |

### 活体检测 SDK 集成

#### 通过 CocoaPods 自动集成

podfile 里面添加以下代码：

```ruby
 source 'https://github.com/CocoaPods/Specs.git' // 指定下载源
 
# 以下两种版本选择方式示例

# 集成最新版SDK:
pod 'NTESLiveDetect'

# 集成指定SDK，具体版本号可先执行 pod search NTESLiveDetect，根据返回的版本信息自行决定:
pod 'NTESLiveDetect', '~> 3.2.2'
```

* 保存并执行 pod install 即可，若未执行 pod repo update，请执行pod install --repo-update

#### 手动集成
* 1、添加易盾SDK,将压缩包中所有资源添加到工程中(请勾选Copy items if needed选项)
* 2、添加依赖库，在项目设置target -> 选项卡General ->Linked Frameworks and Libraries添加如下依赖库，如果已存在如下的系统framework，则忽略： 
	* `AVFoundation.framework`
	* `CoreMedia.framework`
	* `AssetsLibrary.framework`
	* `CoreData.framework`
* 3、在Xcode中找到`TARGETS-->Build Setting-->Linking-->Other Linker Flags`在这个选项中需要添加 `-ObjC`
* 4、将引入SDK头文件的.m文件重命名为.mm文件 或者 在Xcode中找到`TARGETS-->Build Setting-->Apple Clang - Language-->Compile Source As`在这个选项中选择 `Objective-C++`

### 风控 SDK 集成

目前，风控 SDK 仅支持手动集成

 从易盾后台下载风控 SDK

* 1、导入 `RiskPerception.xcframework`到XCode工程，直接拖拽`RiskPerception.xcframework`文件到Xcode工程内(请勾选Copy items if needed选项)
* 2、导入 `RiskPerceptionBundle.bundle`到XCode工程，进入Build phase，在copy bundle resources选项中添加`RiskPerceptionBundle.bundle`文件（请勾选copy items if needed选项）
* 3、在Xcode中找到`TARGETS-->Build Setting-->Linking-->Other Linker Flags`在这个选项中需要添加 `-lz`、`-fprofile-instr-generate`

### 资源包介绍

| **模块名称**                | **功能说明**         | **支持裁剪** | **体积** |
| --------------------------- | -------------------- | ------------ | -------- |
| NTESLiveDetectBundle.bundle | 活体检测需要         | 不可裁剪     | 632KB    |
| RiskPerceptionBundle.bundle | 风控设备环境检测需要 | 可裁剪       | 304KB    |

#### 集成说明

- 活体检测 SDK 采用 cocoapods 方式集成，NTESLiveDetectBundle.bundle 不需要额外集成
- 风控 SDK 暂时不支持 cocoapods 方式集成，只能通过手动集成，直接拖入工程即可

#### 注意点

- RiskPerceptionBundle.bundle 资源包必须放在主项目 Target 下，不能被二次封装到 SDK 中

## 项目开发配置

* 1、在Xcode中找到`TARGETS-->Build Setting-->Linking-->Other Linker Flags`在这个选项中需要添加 `-ObjC`
* 2、将引入SDK头文件的.m文件重命名为.mm文件 或者 在Xcode中找到`TARGETS-->Build Setting-->Apple Clang - Language-->Compile Source As`在这个选项中选择 `Objective-C++`
* 3、在 info.plist 里增加相机权限
```
<!-- 相册 -->   
<key>NSPhotoLibraryUsageDescription</key>   
<string>App需要您的同意,才能访问相册</string>   
<!-- 相机 -->   
<key>NSCameraUsageDescription</key>   
<string>App需要您的同意,才能访问相机</string> 
```

## 调用示例

```
@property (nonatomic, strong) NTESLiveDetectManager *detector;

/// 初始化
self.detector = [[NTESLiveDetectManager alloc] initWithImageView:"传入放置检测活体的imageView对象，imageView宽高比需设定为3:4" withDetectSensit:NTESSensitNormal];

/// 开始活体检测
__weak __typeof(self)weakSelf = self;
[self.detector startLiveDetectWithBusinessID:BUSINESSID actionsHandler:^(NSDictionary * _Nonnull params) {
       
} checkingHandler:nil completionHandler:^(NTESLDStatus status, NSDictionary * _Nullable params) {
    /// 活体检测状态
}];
```
更多使用场景请参考 [demo](https://github.com/yidun/alive-detected-iOS-demo.git)

## SDK 方法说明

### 1 初始化

在项目需要使用 SDK 的文件中先引入 #import <NTESLiveDetect/NTESLiveDetectManager.h> 然后再初始化的 SDK，如下：

```
@property (nonatomic, strong) NTESLiveDetectManager *detector;

- (void)viewDidLoad {
    [super viewDidLoad];
    // withDetectSensit：活体检灵敏度类型
    self.detector = [[NTESLiveDetectManager alloc] initWithImageView:self.imageView withDetectSensit:NTESSensitNormal];
}
```
#### 参数说明：

|参数|类型|是否必填|默认值|描述|
|----|----|--------|------|----|
| imageView |UIImageView|是|无|传入放置检测活体的imageView对象，imageView宽高比需设定为3:4|
|  sensit |enum|是|无|NTESSensitEasy 表示动作检测容易通过<br>NTESSensitNormal 表示动作检测默认状态<br>NTESSensitHard 表示动作检测不容易通过|

### 2 开始活体检测验证

#### 代码说明：

```
[self.detector startLiveDetectWithBusinessID:<#(nonnull NSString *)#> actionsHandler:^(NSDictionary * _Nonnull params) {
    // 获取活体检测结果      
} checkingHandler:^{
    // 所有动作完成之后，活体进行云端检测。
} completionHandler:^(NTESLDStatus status, NSDictionary * _Nullable params) {
    // 获取活体检测结果   
}];
```

 * 参数说明：

    |参数|类型|是否必填|默认值|描述|
    |----|----|--------|------|----|
    | businessID |NSString|是|无|易盾分配的业务id|
	
* actionsHandler 回调参数说明

    |回调字段|类型|描述|
    |---|----|-----|
    |params|NSDictionary|action:"123"，活体检测动作。 0表示正视前方，1表示右转头，2表示左转头，3表示张张嘴，4表示眨眨眼。例如：actions = "123",表示需要做向右转头、向左转头、张张嘴三个动作|

* checkingHandler 所有动作完成之后，活体进行云端检测。可以在代码块里面加上自己的逻辑，例如正在进行云端检测的提示菊花，如果不需要传nil。

* completionHandler 回调参数说明
  
    |回调字段|类型|描述|
    |---|----|-----|
    |status|enum|NTESLDCheckPass : 活体检测通过<br> NTESLDCheckNotPass : 活体检测不通过<br>NTESLDOperationTimeout : 操作超时，用户未在规定时间内完成动作<br> NTESLDGetConfTimeout : 活体检测获取配置信息超时<br>NTESLDOnlineCheckTimeout : 云端检测结果请求超时,<br> NTESLDOnlineUploadFailure : 云端检测上传图片失败<br>NTESLDNonGateway : 网络未连接<br>NTESLDSDKError : SDK内部发生错误<br>NTESLDCameraNotAvailable : App未获取相机权限|
  |params|NSDictionary|token:"易盾分配的鉴权"|

### 3 停止活体检测

#### 代码说明：

```
[self.detector stopLiveDetect];
```

### 4 设置活体检测的超时时间

#### 代码说明：

```
[self.detector setTimeoutInterval:timeoutInterval];
```
#### 参数说明：

|类型|是否必填|默认值|描述|
|----|--------|------|----|
|NSTimeInterval|是|30|10-120秒范围内的时间值，默认30秒|

### 5 检测状态监听

#### 代码说明：

```
- (void)viewDidLoad {
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(liveDetectStatusChange:) name:@"NTESLDNotificationStatusChange" object:nil];
}
    	
// 在相应的监听方法中进行动作提示：
- (void)liveDetectStatusChange:(NSNotification *)infoNotification {
    NSDictionary *dic = infoNotification.userInfo;
    NSString *exception = [infoDict objectForKey:@"exception"];
    NSDictionary *action = [dic objectForKey:@"action"];
    NSNumber *key = [[action allKeys] firstObject];
    switch ([key intValue]) {
        case 0:
            // 正面提示
            break;
        case 1:
            // 右转头提示
            break;
        case 2:
            // 左转头提示
            break;
        case 3:
            // 张嘴提示
            break;
        case 4:
            // 眨眼提示
            break;
        default:
            break;
    }
    
    switch ([exception intValue]) {
        case 1:
            // 保持面部在框内
            break;
        case 2:
            // 环境光线过暗
            break;
        case 3:
            // 环境光线过亮
            break;
        case 4:
            // 请勿抖动手机
            break;
        case 5:
            // 检测到多张人脸
            break;
        case 6:
            // 距离屏幕过远
            break;
        case 7:
            // 距离屏幕过近
            break;
        default:
            break;
    }
}
```
*  监听回调值说明
   * 动作检测的数据结构：@{@"action"：@{1 : YES}} 或者 @{@"exception"：@"1"}  二者只可能出现其中之一。<br>
   
   |监听回调字段|类型|描述|
   |---|----|-----|
   |action|NSDictionary|  key:当前执行的动作状态， 0表示正视前方，1表示右转头，2表示左转头，3表示张张嘴，4表示眨眨眼, -1表示未检测到完整人脸<br>value:对应动作的完成状态， NO表示该动作未完成 YES表示该动作已完成|
   |exception|NSString|异常状态， 1表示保持面部在框内 2表示环境光线过暗 3表示环境光线过亮 4表示请勿抖动手机 5表示多张人脸 6 表示距离屏幕过远 7表示距离屏幕过近|
   

### 6 设置设备抖动检测的灵敏度

#### 代码说明：

```
[self.detector setShakeThreshold:shakeThreshold];
```

#### 参数说明：

| 类型    | 是否必填 | 默认值 | 描述                         |
| ------- | -------- | ------ | ---------------------------- |
| CGFloat | 是       | 0.05   | 0.01-0.1范围内的值，默认0.05 |

### 7 设置是否允许多人脸检测

#### 代码说明：      

```
[self.detector setAllowMultipleFace:allowMultipleFace];
```

#### 参数说明：

| 类型 | 是否必填 | 默认值 | 描述                    |
| ---- | -------- | ------ | ----------------------- |
| BOOL | 是       | NO     | 默认 NO，不允许多张人脸 |

### 8 设置人脸占比最小值

#### 代码说明：   

```
[self.detector setMinFacePercentage:minFacePercentage];
```

#### 参数说明：

| 类型       | 是否必填 | 默认值 | 描述                         |
| ---------- | -------- | ------ | ---------------------------- |
| NSUInteger | 是       | 7      | 人脸占比最小值：0~100，默认7 |

### 9 设置人脸占比最大值

#### 代码说明：

```
[self.detector setMaxFacePercentage:maxFacePercentage];
```

#### 参数说明：

| 类型       | 是否必填 | 默认值 | 描述                          |
| ---------- | -------- | ------ | ----------------------------- |
| NSUInteger | 是       | 60     | 人脸占比最大值：0~100，默认60 |

###