接入说明

导入SDK

QYSDK 提供两种集成方式:既可以通过 CocoaPods 自动集成,也可以手动下载 SDK 并集成至您的项目中。

手动集成

动态库集成

QYSDK 在 V5.10.0 版本后已修改为动态库,集成方式相对之前静态库有所改变,若要集成动态库,只需要做以下工作:

  1. 下载 zip 文件并解压,内含两个文件夹:NIMSDKQYSDK,说明如下:
  • NIMSDK 为底层 IM SDK,主要包含:

    • NIMSDK.framework 动态库:IM 即时通讯、信令、聊天室的功能集;
    • NIMSDK.podspec:CocoaPods 配置文件,可用于本地 CocoaPods 集成。
  • QYSDK为七鱼客服 SDK,主要包含:

    • QYSDK.framework 动态库:七鱼客服功能全集,依赖 NIMSDK.framework ;
    • Resources 文件夹:内含两个资源集合 bundle 文件,QYCustomResource.bundle 用于替换 QYResource.bundle 内的同名素材;
    • QYSDK.podspec:CocoaPods 配置文件,可用于本地 CocoaPods 集成。
  1. 集成 NIMSDK.framework :将 NIMSDK.framework 文件夹拖入工程,确保文件 copy 至工程而非引用,并确保 General —> Frameworks, Libraries, and Embedded Content ( Xcode11 ) 选项中包含导入的库,同时 Embed 选择 Embed & Sign 即可。
  2. 集成 QYSDK.framework :将 QYSDK.framework 文件夹拖入工程,确保文件 copy 至工程而非引用,并确保 General —> Frameworks, Libraries, and Embedded Content ( Xcode11 ) 选项中包含导入的库,同时 Embed 选择 Embed & Sign 即可。
  3. Resources 文件夹中两个 bundle 资源文件拖入主工程,确保 mainBundle 可以访问到。

静态库集成

若需要集成 V5.10.0 之前版本静态库 SDK,步骤如下:

  1. 下载 zip 文件并解压,得到3个 .a 文件、 QYResouce 资源文件和 ExportHeaders 文件夹,将他们导入工程。

  2. 添加 QY SDK 依赖库:

    • UIKit.framework
    • AVFoundation.framework
    • SystemConfiguration.framework
    • MobileCoreService.framework
    • CoreTelephony.framework
    • CoreText.framework
    • CoreMedia.framework
    • AudioToolbox.framework
    • Photos.framework
    • AssetsLibrary.framework
    • CoreMotion.framework
    • WebKit.framework
    • libz.tbd
    • libc++.tbd
    • libsqlite3.0.tbd
    • libxml2.tbd
    • libresolv.tbd
  3. 在 Build Settings —> Other Linker Flags 中添加 -ObjC

自动集成

动态库集成

QYSDK 动态库已在 V5.11.0 版本正式上线:CocoaPods地址GitHub地址 。集成步骤如下:

  1. Podfile 文件中加入:

    pod 'QY_iOS_SDK', '~> x.x.x'
    

    "x.x.x" 代表版本号,例如需要集成 5.12.x 系列的最新版本,可加入如下代码:

    pod 'QY_iOS_SDK', '~> 5.12.0'
    
  2. Terminal 执行 pod install 即可完整集成动态库版本。

注意这里的动态库名称为:QY_iOS_SDK,之前的静态库旧版本名称为:QIYU_iOS_SDK,二者有区别。

由于 V5.10.0 版本未上线至 CocoaPods,对于使用 CocoaPods 管理第三方库的项目,若需要使用 V5.10.0 版本的动态库 SDK,可使用本地 pod 导入 NIMSDK.framework 及 QYSDK.framework 进行依赖管理,步骤如下:

  1. 项目根目录下新建文件夹 frameworks,将前面下载得到的文件夹 NIMSDK文件夹 QYSDK 拷贝至 frameworks 目录下,确保文件夹中包含有 podspec 文件。

  2. Podfile 文件中加入:

    pod 'NIMSDK', :path => './frameworks/NIMSDK'
    pod 'QYSDK', :path => './frameworks/QYSDK'
    
  3. Terminal 执行 pod install 即可完整集成 QYSDK 及其依赖的 NIMSDK。

静态库集成

若需要 CocoaPods 集成 V5.10.0 之前版本静态库 SDK,可使用如下集成步骤:

  1. Podfile 文件中加入:

    pod 'QIYU_iOS_SDK', '~> x.x.x'
    

    "x.x.x" 代表版本号,比如想要使用 5.0.0 版本,可加入如下代码:

    pod 'QIYU_iOS_SDK', '~> 5.0.0'
    
  2. Terminal 执行 pod install 即可完整集成静态库版本。

自动集成常见问题

使用 CocoaPods 过程中可能遇见的问题:

  • 无法用 CocoaPods 下载到最新的 SDK

    • 运行 pod repo update 更新本地 CocoaPods 仓库;
    • 检查网络环境,确保可以访问并下载 GitHub 相关内容。
  • 使用 CocoaPods 下载静态库版本 SDK 后编译报错

    • 需检查下载的静态库版本 SDK 中三个 .a 文件大小,若明显偏小,则需安装 Git LFS(Large File Storage)服务来下载原始 SDK。

    • 可使用 Homebrew 安装 Git LFS:

      brew install git-lfs
      
    • 启动 Git LFS 服务:

      git lfs install
      
    • 安装后请重新 pod update,若仍报错,尝试清理缓存:pod cache clean --all

解决符号冲突

针对静态库可能出现的符号冲突问题(Xcode 报错 duplicate symbol xxx in xxx.o xxx.o),建议首先升级至动态库版本尝试解决问题,如仍需使用静态库,请注意:

  1. 从 V3.1.0 版本开始,不再提供 QIYU_iOS_SDK_Exclude_Libcrypto、QIYU_iOS_SDK_Exclude_NIM 版本,统一使用 QIYU_iOS_SDK,此 SDK 中独立第三方库,提供3个静态库文件:libQYSDK.a、libcrypto.a、libevent.a。

  2. 如果您同时使用了网易云信 iOS SDK 静态库版本,请只导入 libQYSDK.a,不要导入其他两个 .a 文件。

  3. 如果您同时使用了 OpenSSL 库,或者您集成的其它静态库使用了 OpenSSL 库(比如支付宝 SDK ),请只导入 libQYSDK.a、libevent.a,不要导入 libcrypto.a:

    • 请注意,SDK 依赖的 OpenSSL 库版本为 1.0.2d,与 1.1.0 及以上版本存在兼容问题。
    • 如遇版本兼容问题,我们提供升级版本 SDK :QIYU_iOS_SDK_SSL ,依赖的 OpenSSL 库版本为 1.1.0c ,请下载后不要导入 libcrypto.a。此 SDK 跟随每次版本发布更新。
  4. 如果是其他情况的冲突,请根据实际情况有选择的导入 libevent.a、libcrypto.a。

权限设置

Info.plist 中加入以下内容:

<key>NSPhotoLibraryUsageDescription</key>
<string>需要读取相册权限</string>
<key>NSCameraUsageDescription</key>
<string>需要相机权限</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要麦克风权限</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要写入相册权限</string>

如果不加,会引发 crash。请注意,iOS11 新增写入相册数据权限 NSPhotoLibraryAddUsageDescription

https相关

V3.1.3 版本开始,SDK 已全面支持 https,但是聊天消息中可能存在链接,点击链接会用 UIWebView 打开,链接地址有可能是 http 的,为了能够正常打开,需要增加配置项。在 Info.plist 中加入以下内容:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
</dict>

加了这些配置项,在 iOS9 下,系统仅读取 NSAllowsArbitraryLoads,会放开所有 http 请求;在 iOS10 及以上系统,设置了 NSAllowsArbitraryLoadsInWebContent,就会忽略 NSAllowsArbitraryLoads,效果是只允许 WKWebView 中使用 http。SDK 消息流链接默认使用 UIWebView 打开,可通过截获链接点击事件使用自定义网页视图。

类库说明

SDK 主要提供以下类/协议/方法:

类/协议 描述 说明
QYHeaders 头文件集合 集合了非平台企业客服功能头文件
QYSDK SDK 主入口 提供初始化/注册/注销/界面及配置对象获取等方法
QYSessionViewController 聊天界面控制器 聊天主界面,同时提供各类参数设置及部分功能接口
QYCustomUIConfig UI 配置类 样式相关设置
QYCustomActionConfig 事件配置类 事件相关设置
QYConversationManager 会话管理类 负责获取会话列表及消息未读数并监听变化
QYSource 会话来源类 会话来源信息,包含标题、链接及自定义信息
QYUserInfo 用户信息类 用户信息,包含ID及详细信息
QYStaffInfo 客服信息类 人工客服信息,可替换人工客服部分信息
QYMessageInfo 消息类 包含消息类型、时间及文本信息
QYSessionInfo 会话详情类 会话列表中会话详情,包含会话状态、未读数等信息
QYCommodityInfo 商品信息类 包含商品标题、描述等信息
QYPushMessage 推送消息类 包含消息类型、头像等信息
QYAction 通用事件类 定义部分通用事件回调,例如请求客服相关事件
QYEvaluation 评价数据类 定义满意度评价数据、选项数据及结果
QYWorkOrderListViewController 工单列表页面控制器 传入工单模板 ID 即可查询访客提交工单历史记录,并提供催单功能

自定义消息相关:

类/协议 描述 说明
QYCustomSDK 自定义消息头文件集合 集合了自定义消息功能头文件
QYCustomSessionViewController 聊天界面控制器分类 提供自定义消息专用属性及接口
QYCustomMessageProtocol 自定义消息协议 事件委托/视图点击协议
QYCustomMessage 自定义消息基类 承载消息数据,可继承并扩展
QYCustomModel 数据源基类 消息列表数据源,可继承并扩展
QYCustomContentView 消息视图基类 消息对应视图,可继承并扩展
QYCustomEvent 消息事件类 消息内点击事件
QYCustomCommodityInfo 自定义商品信息类 自定义商品卡片消息,透传服务端数据

平台企业相关:

类/协议 描述 说明
QYPOPSDK 平台企业头文件集合 集合了平台企业相关功能头文件
QYPOPSessionViewController 聊天界面控制器分类 提供平台企业专用属性及接口
QYPOPConversationManager 会话管理类分类 提供平台企业会话管理专用接口及协议
QYPOPMessageInfo 消息类分类 提供平台企业专用属性及接口
QYPOPSessionInfo 会话详情类分类 提供平台企业专用属性及接口

其它说明

  • 为方便集成和后续更新,请使用 V5.10.0 以上动态库版本。

  • 为保证 SDK 在 iOS13 上效果,请使用 V5.3.0 以上版本;SDK 已针对暗黑模式下的部分显示问题、推送 DeviceToken 解析方式、页面 modalPresentationStyle 做了更新和适配。

  • SDK 支持 Bitcode。

  • 为方便开发者可同时在真机和模拟器上调试和使用,我们将 armv7、arm64、i386、x86_64 平台的 SDK 合并为一个 fat file ,导致整个 SDK 比较大。但实际编译后大约只会增加 App 4-5M 大小。

  • 对于动态库 SDK,在需要使用的地方:#import <QYSDK/QYSDK.h> ;对于静态库 SDK,在需要使用的地方: import "QYSDK.h"

  • 由于库包含模拟器版本,会导致打包失败,故需要在打包前将模拟器版本剥去,具体方法如下:

    • 创建 strip_archs.sh 脚本,并放在工程目录中,如 Resources 文件夹里;

    • 在 Build Phases 设置项中点击左上角 + 号,选择 New Run Script Phase,工程在编译过程中会自动 run script;

    • 在 script 中添加代码,执行 strip_archs.sh 脚本:

      /bin/sh "${SRCROOT}/QYSDKDemo/Resources/strip_archs.sh"
      
    • 将如下内容复制至脚本中:

      #!/bin/sh
      
      # Strip invalid architectures
      strip_invalid_archs() {
      	binary="$1"
      	echo "current binary ${binary}"
      	# Get architectures for current file
      	archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
      	stripped=""
      	for arch in $archs; do
      		if ! [[ "${ARCHS}" == *"$arch"* ]]; then
      			if [ -f "$binary" ]; then
      			# Strip non-valid architectures in-place
      			lipo -remove "$arch" -output "$binary" "$binary" || exit 1
      			stripped="$stripped $arch"
      			fi
      		fi
      	done
      	if [[ "$stripped" ]]; then
      		echo "Stripped $binary of architectures:$stripped"
      	fi
      }
      
      # Your app path
      APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
      
      # Attention: If you change framework path (not in mainBundle), please reset FRAMEWORKS_PATH with correct path
      FRAMEWORKS_PATH="${APP_PATH}/Frameworks"
      
      # This script loops through the frameworks embedded in the application and
      # removes unused architectures.
      find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
      do
      	FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
      	FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
      	echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
      	strip_invalid_archs "$FRAMEWORK_EXECUTABLE_PATH"
      done
      
    • 注意脚本中 FRAMEWORKS_PATH 应设置正确目录。

初始化SDK

在使用 SDK 任何方法之前,都应该先调用初始化方法。正常业务情况下,初始化方法有且只应调用一次,请勿重复注册。

注册方法原型

@interface QYSDK : NSObject
/**
 *  注册SDK
 *
 *  @param option 注册选项
 */
- (void)registerWithOption:(QYSDKOption *)option;
@end

选项参数列表

QYSDKOption 提供如下属性:

属性 类型 必须 说明
appKey NSString 企业的 AppKey
appName NSString App名称,即七鱼管理后台添加App时填写的App名称
pkCerName NSString PushKit推送证书名,暂不支持,无需填写
isFusion BOOL 是否为融合SDK,默认NO
调用示例

推荐在 App 启动时进行初始化操作:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    //推荐在程序启动的时候初始化 SDK    
    NSString *appKey = @"your app key";
    QYSDKOption *option = [QYSDKOption optionWithAppKey:appKey];
    option.appName = @"your App name";
    [[QYSDK sharedSDK] registerWithOption:option];
    ...
}
  1. AppKey 可在 管理端-应用-在线系统-设置-在线接入-APP-2.App Key 找到,请确保填写完整及正确,无空格,否则可能导致功能异常。
  2. AppName 对应管理端添加 App 时填写的 App名称。如需使用访客分流等功能,请及时在管理端添加 App,并填写正确的 bundleID 用于区分不同 App;如需使用推送功能,请选择相应环境上传对应推送证书,请自行确保证书有效性。
  3. 一般在application: didFinishLaunchingWithOptions:方法中调用初始化方法,如需在其他地方调用,请确保时机在启动客服功能前,且应预留一段初始化时间;尽量保证在整个软件运行期间仅调用一次。

集成聊天组件

通过[QYSDK sharedSDK]单例的sessionViewController方法可获取聊天界面控制器实例:

[[QYSDK sharedSDK] sessionViewController];
  1. 获取界面实例后,必须嵌入至导航栏控制器UINavigationController中,便可获得完整聊天窗口及所有功能。
  2. QYSessionViewController会使用到导航栏navigationItem的标题文字属性title、标题视图属性titleView、右侧按钮属性rightBarButtonItems,若使用自定义导航栏,请确保以上属性能正常设置,否则会影响部分功能。
  3. 每次调用[QYSDK sharedSDK]单例的sessionViewController方法,都会新建一个聊天页面,请确保QYSessionViewController实例同一时刻全局唯一,且退出后该界面实例能够正常释放,尽量避免循环引用导致的内存泄漏,否则会引发一系列不可预知问题。

如果调用代码所在的视图控制器在UINavigationController中,可 push 进入聊天界面:

QYSource *source = [[QYSource alloc] init];
source.title = @"七鱼客服";
source.urlString = @"https://qiyukf.com/";

QYSessionViewController *sessionViewController = [[QYSDK sharedSDK] sessionViewController];
sessionViewController.sessionTitle = @"七鱼客服";
sessionViewController.source = source;
sessionViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:sessionViewController animated:YES];

如果调用代码所在的视图控制器不在UINavigationController中,可 present 进入聊天界面:

QYSource *source = [[QYSource alloc] init];
source.title = @"七鱼客服";
source.urlString = @"https://qiyukf.com/";

QYSessionViewController *sessionViewController = [[QYSDK sharedSDK] sessionViewController];
sessionViewController.sessionTitle = @"七鱼客服";
sessionViewController.source = source;
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:sessionViewController];
[self presentViewController:nav animated:YES completion:nil];

一般来说,present 方式需要在左上角加返回按钮:

UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(onBack:)];
sessionViewController.navigationItem.leftBarButtonItem = leftItem;

onBack:的样例:

- (void)onBack:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

请根据情况选择合适的方式进入聊天界面。

常见问题

  1. 进入访客聊天界面马上 crash
  • 检查 App 工程配置-Build Phases-copy Bundle Resources 里是否添加 QYResource.bundle;一般来讲,导入时会自动添加,如果没有,必须加上。
  1. 一直显示正在连接客服

    • 可能是 AppKey 填写错误,请确保完全正确,勿带空格。
    • 可能是 App 引入或 App 使用的第三方 SDK 引入 OpenSSL 版本不兼容,导致底层数据加解密抛异常;关于 OpenSSL 版本问题请具体情况具体分析。
  2. 导航栏可以自定义吗

  • 部分自定义。聊天界面会占用导航栏navigationItem的标题文字属性title、标题视图属性titleView、右侧按钮属性rightBarButtonItemsnavigationItem的其它部分,比如leftBarButtonItems等,可以根据需要做自定义。
  1. 聊天界面可以自定义吗
  • 部分样式及事件自定义。 具体可参考QYCustomUIConfig等配置类,Demo 源码中也有相关样例代码。
  1. 键盘出现异常

    • 检查 App 中是否用到了会影响全局的键盘处理,如果是这种情况,需要对QYSessionViewController做屏蔽。典型的比如第三方键盘库IQKeyboardManager,如果用的是 V4.0.4 以前的版本(不包括 V4.0.4 ),请添加以下屏蔽代码:

      [[IQKeyboardManager sharedManager] disableDistanceHandlingInViewControllerClass:[QYSessionViewController class]];
      

      如果用的是 V4.0.4 或之后的版本,请添加以下屏蔽代码:

      [[IQKeyboardManager sharedManager].disabledDistanceHandlingClasses addObject:[QYSessionViewController class]];
      
  2. 如何强制竖屏

    • 如果您的 App 是横屏的,但希望聊天界面竖屏,可以在sessionViewController所在的UINavigationController中实现以下方法,返回UIInterfaceOrientationMaskPortrait即可:

      - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
          return UIInterfaceOrientationMaskPortrait;
      }
      
  3. 怎么知道聊天界面控制器被 pop 了

    • 请参考UINavigationControllerDelegate中提供的转场函数:

      - (id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC;