iStation iOS SDK 开发指南
简介
iStation iOS SDK 是客服系统访客端的解决方案,包含客服聊天逻辑管理和聊天界面,开发者可以方便地将客服功能集成到自己的 APP 中。iOS SDK 支持 iOS 8 以上版本,同时支持 iPhone、iPad 以及横竖屏 UI。在 iOS 9.2 以上版本中支持 IPv6,能通过苹果审核。
SDK 目录讲解
下载 iStation SDK 后,可以得到以下两部分:
- IStationSDK.framework:静态库 Framework,包含静态库文件和 SDK 的头文件
- IStationResource.bundle:SDK 的资源文件包
由于 SDK 是静态库,且为了方便开发者使用,我们将 i386、x86_64、armv7、arm64 平台的静态库合并成一个 Fat Library,导致整个 SDK 比较大。但实际编译后大约只会增加 app 1-2M 大小
系统要求以及依赖第三方框架
-
系统要求
该项目最低支持 iOS 8.0 和 Xcode 9.0。 -
依赖第三方框架
iStation SDK 依赖于 Socket.IO-Client-Swift 库。如果选择手动集成 iStation SDK,则需要使用 CocoaPods 引入 Socket.IO 库;如果选择 CocoaPods 集成,则无需手动添加依赖处理。
SDK集成和配置
CocoaPods集成
在 Podfile 文件中加入 pod 'IStation_iOS_SDK'
platform :ios, '8.0'
use_frameworks! #必须加入这一句,因为有依赖swift库
target 'YourApp' do
pod 'IStation_iOS_SDK'
end
推荐使用CocoaPods集成,在Podfile中加入IStation_iOS_SDK的引用即可
手动集成
-
下载iStation SDK,得到一个IStationSDK.framework文件、IStationResource.bundle文件夹,将它们导入工程
-
添加iStation SDK依赖库
- UIKit.framework
- MobileCoreService.framework
- SystemConfiguration.framework
- AVFoundation.framwork
- CoreGraphics.framework
- ImageIO.framework
- CoreFoundation.framework
- UserNotifications.framework
- libstdc++.6.0.9.tbd
-
添加第三方库:在Podfile中添加Socket.IO的依赖,pod 'Socket.IO-Client-Swift', '~> 13.2.1'
-
在Build Settings -> Other Linker Flags 中添加-ObjC
配置工程
- iOS10权限设置,在Info.plist中加入以下内容:
<key>NSCameraUsageDescription</key>
<string>App需要您的同意,才能访问相机</string>
<key>NSMicrophoneUsageDescription</key>
<string>App需要您的同意,才能访问麦克风</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>App需要您的同意,才能访问相册</string>
- SDK不支持bitcode
向Build Settings → Linking → Enable Bitcode中设置NO。
FAQ
集成遇到问题,请参考使用详解
使用简介
- 在需要使用 SDK 的地方 #import <IStationSDK/IStationSDK.h>。IStationSDK 类是整个 SDK 的唯一主入口,是一个单例。各个函数简介:
初始化:
- (void)registerAppKey:(NSString *)appKey appName:(NSString *)appName;
集成客户聊天组件:
- (IStationChatViewController *)chatViewController;
自定义客户端聊天组件UI效果:
- (IStationUIConfig *)customUIConfig;
APNs推送:
- (void)updateApnsToken:(NSData *)token;
注销:
- (void)logout:(IStationCompletionBlock)completion;
设置用户信息:
- (void)setUserInfo:(IStationUserVo *)userVo;
设置调试模式获取更多的Log信息,发布应用时建议不开启,用于节省性能开销:
- (void)setDebugMode;
初始化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
......
[[IStationSDK sharedSDK] registerAppKey:appKey appName:App名称];
......
return YES;
}
appKey 可以通过公司管理员账号登录 “iStation Web端” -> “配置” -> “App Sdk设置” -> “App Key:渠道appKey” 找到, appName对应添加一个 app 时填写的 App 名称, 详细步骤请参见 新建App和上传推送证书
设置用户信息
设置个人信息,用户帐号登录成功之后,调用设置用户信息函数(userID必填,建议同时设置用户昵称(userName))。如果不设置用户信息,则使用匿名用户的方式进行客服咨询。应该在进入聊天咨询界面之前设置用户信息。
IStationUserVo *userVo = [[IStationUserVo alloc]init];
userVo.userID = @"45471429666"; //用户标识,必填
userVo.userName = @"iOS_SDK_用户1"; //用户昵称
userVo.headerImageURL = @"http://visionet.findest.com/letsdesk/assets/img/logo-1.png"; //用户头像
userVo.gender = 1; //性别,1:男、2:女
userVo.phoneNumber = @"18611111111"; //手机
userVo.telephone = @"021-12345678"; //固定电话
userVo.email = @"[email protected]"; //邮箱
userVo.address = @"上海市长宁区"; //地址
userVo.position = @"人事经理"; //职位
userVo.department = @"人事部"; //单位
userVo.birthday = @"1988-12-12"; //生日(yyyy-MM-dd)
userVo.remark = @"备注SDK"; //备注
// 传递自定义客户信息
userVo.customData = @"[{\"label_cn\":\"订单号\", \"label_en\":\"orderNo\", \"value\":\"1111111\"},"
"{\"label_cn\":\"员工号\", \"label_en\":\"empNo\", \"value\":\"2222222\"}]";
[[IStationSDK sharedSDK] setUserInfo:userVo];
#####自定义客户信息使用注意:
| 字段 | 类型 | 说明 | |---|---|---| | label_cn | String | 该项数据显示的中文名称 | | label_en | String | 该项数据显示的英文名称 | | value | String | 该数据显示的值,类型不做限定,根据实际需要进行设定 |
集成客户聊天组件
[[IStationSDK sharedSDK] chatViewController];
应用层获取此 chatViewController 之后,必须嵌入到 UINavigationcontroller 中,就可以获得聊天窗口的 UI 以及所有功能。 chatViewController 只会使用到导航栏的 self.navigationItem.title。 self.navigationItem.title 放置标题栏;必须注意,不能在 chatViewController 外层套其他 viewController 之后再嵌入到 UINavigationcontroller。
如果调用代码所在的 viewController 在 UINavigationcontroller 中,可以如下方式集成(第一种集成方式):
IStationChatViewController *chatViewController = [[IStationSDK sharedSDK] chatViewController];
chatViewController.chatTitle = @"iStation SDK测试";
chatViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController: chatViewController animated:YES];
如果调用代码所在的 viewController 不在 UINavigationcontroller 中,可如下方式集成(第二种集成方式):
IStationChatViewController *chatViewController = [[IStationSDK sharedSDK] chatViewController];
chatViewController.chatTitle = @"iStation SDK测试";
chatViewController.hidesBottomBarWhenPushed = YES;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:chatViewController];
[self presentViewController:navController animated:YES completion:nil];
一般来说,第二种方式会需要在左上角加一个返回按钮,在 “initWithRootViewController:chatViewController” 之前加上:
chatViewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleBordered target:self action:@selector(onBack:)];
“onBack” 的样例:
- (void)onBack:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
如果您的代码要求所有 viewController 继承某个公共基类,并且公共基类对 UINavigationController 统一做了某些处理;或者其他原因导致使用第一种方式集成会有问题;这些情况下,建议您使用第二种方式集成。
监控SDK内的链接跳转动作
在 IStationChatViewController 控制器中设置链接跳转的监听 block 即可
如果 block 返回为 NO,则不执行 SDK 默认处理。如果 block 返回为 YES,则执行 SDK 默认跳转处理:
/**
* 提供了监控SDK内消息跳转行为的block;
* 如果设置了block回调,则在链接点击之后执行该block
* 如果block返回为NO,则不执行SDK默认处理.如果block返回为YES则执行SDK默认跳转处理
*/
typedef BOOL (^IStationLinkClickBlock)(NSString *linkAddress);
@interface IStationChatViewController : UIViewController
...
/**
* 监控SDK内消息跳转行为的block
*
* @return 是否执行SDK默认的跳转行为
*/
@property (nonatomic, copy) IStationLinkClickBlock linkClickBlock;
...
@end
参考代码:
//启动聊天界面
IStationChatViewController *chatViewController = [[IStationSDK sharedSDK] chatViewController];
chatViewController.chatTitle = @"iStation SDK测试";
//设置回调
chatViewController.linkClickBlock = ^(NSString *urlString) {
ViewController2 *viewController2 = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"ViewController2"];
[self.navigationController pushViewController:viewController2 animated:YES];
return NO;
};
集成热点引导问题
在IStationChatViewController控制器中设置需要显示的热点引导问题ID,热点引导问题ID获取参考:如何获取热点引导问题ID
@interface IStationChatViewController : UIViewController
...
/**
* 热点引导问题ID
*/
@property (nonatomic, strong) NSString *faqId;
...
@end
参考代码:
//启动聊天界面
IStationChatViewController *chatViewController = [[IStationSDK sharedSDK] chatViewController];
chatViewController.chatTitle = @"iStation SDK测试";
chatViewController.faqId = @"27"; //跳转时指定热点引导问题ID
chatViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController: chatViewController animated:YES];
效果图如下:
自定义客户端聊天组件UI效果
获取自定义UI类对象
[[IStationSDK sharedSDK] customUIConfig];
IStationUIConfig是负责自定义UI的类;目前主要是定义聊天界面中的字体颜色、气泡图片、头像等。相关设置必须在集成客户聊天组件之前进行。 IStationUIConfig 只负责替换部分皮肤相关内容,不包含所有的图片素材的替换,调整UI样例代码:
/**
* 访客文本消息字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].customMessageTextColor = [UIColor blackColor];
/**
* 客服文本消息字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].serviceMessageTextColor = [UIColor blackColor];
/**
* 客户文本消息内嵌链接字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].customMessageLinkTextColor = [UIColor colorWithRed:128.0/255.0 green:233.0/255.0 blue:255.0/255.0 alpha:1.0];
/**
* 客服文本消息内嵌链接字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].serviceMessageLinkTextColor = [UIColor colorWithRed:0.0/255.0 green:165.0/255.0 blue:224.0/255.0 alpha:1.0];
/**
* 提示文本消息字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].tipMessageTextColor = [UIColor grayColor];
/**
* 提示文本消息背景颜色
*/
[[IStationSDK sharedSDK] customUIConfig].tipMessageBackgroundColor = [UIColor whiteColor];
/**
* 输入框文本消息字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].inputTextColor = [UIColor blackColor];
/**
* 消息时间颜色
*/
[[IStationSDK sharedSDK] customUIConfig].messageTimeColor = [UIColor grayColor];
/**
* 消息tableview的背景图片
*/
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"chat_bg"]];
imageView.contentMode = UIViewContentModeScaleToFill;
[[IStationSDK sharedSDK] customUIConfig].chatBackground = imageView;
/**
* 客户头像URL,优先使用URL加载图片
*/
[[IStationSDK sharedSDK] customUIConfig].customerHeadURL = [NSURL URLWithString:@"http://visionet.findest.com/letsdesk/assets/img/logo-1.png"];
/**
* 客户头像
*/
[[IStationSDK sharedSDK] customUIConfig].customerHeadImage = [UIImage imageNamed:@"customer_avatar"];
/**
* 客户消息气泡normal图片
*/
[[IStationSDK sharedSDK] customUIConfig].customerMessageBubbleNormalImage =
[[UIImage imageNamed:@"chat_send_text_bk"]
resizableImageWithCapInsets:UIEdgeInsetsMake(26,26,26,26)
resizingMode:UIImageResizingModeStretch];
/**
* 客户消息气泡pressed图片
*/
[[IStationSDK sharedSDK] customUIConfig].customerMessageBubblePressedImage =
[[UIImage imageNamed:@"chat_send_text_press_bk"]
resizableImageWithCapInsets:UIEdgeInsetsMake(26,26,26,26)
resizingMode:UIImageResizingModeStretch];
/**
* 客服消息气泡normal图片
*/
[[IStationSDK sharedSDK] customUIConfig].serviceMessageBubbleNormalImage =
[[UIImage imageNamed:@"chat_receive_text_bk"]
resizableImageWithCapInsets:UIEdgeInsetsMake(26,26,26,26)
resizingMode:UIImageResizingModeStretch];
/**
* 客服消息气泡pressed图片
*/
[[IStationSDK sharedSDK] customUIConfig].serviceMessageBubblePressedImage =
[[UIImage imageNamed:@"chat_receive_text_press_bk"]
resizableImageWithCapInsets:UIEdgeInsetsMake(26,26,26,26)
resizingMode:UIImageResizingModeStretch];
/**
* 默认是YES,默认进入聊天界面,是文本输入模式的话,会弹出键盘,设置为NO,可以修改为不弹出
*/
[IStationUIConfig sharedInstance].isShowKeyboard = YES;
/**
* 常见问题简介字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].faqDescriptionTextColor = [UIColor blackColor];
/**
* 常见问题项字体颜色
*/
[[IStationSDK sharedSDK] customUIConfig].faqItemTextColor = [UIColor colorWithRed:35.0/255.0 green:150.0/255.0 blue:255.0/255.0 alpha:1.0];
APNs推送
-
请开启Application Target的Capabilities->Push Notifications选项,如图:
-
请开启Application Target的Capabilities->Background Modes->Remote notifications选项:
-
注册APNs推送
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
......
//传入正确的App名称
[[IStationSDK sharedSDK] registerAppKey:appKey appName:App名称];
//注册APNs推送
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(@"request authorization succeeded!");
}
}];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
//小于 iOS 10.0
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
......
return YES;
}
- 把 APNs Token 传给 SDK
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
......
[[IStationSDK sharedSDK] updateApnsToken:deviceToken];
......
}
- 接收APNs推送消息
// iOS8、iOS9 接收APNs推送的方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler {
NSLog(@"收到APNs通知消息:%@", userInfo);
//Required
completionHandler(UIBackgroundFetchResultNewData);
}
// iOS10以及之后的版本接收APNs推送的方法
// 前台收到推送
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
NSLog(@"收到APNs通知消息:%@", notification.request.content.userInfo);
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
//远程通知
} else {
//判断为本地通知
}
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge);
}
// 点击通知栏触发的推送
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler {
NSLog(@"收到APNs通知消息:%@", response.notification.request.content.userInfo);
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
//远程通知
} else {
//判断为本地通知
}
completionHandler();
}
注销
[[IStationSDK sharedSDK] logout:^{
NSLog(@"注销成功!");
}];
应用层退出自己的账号时需要调用 SDK 的注销操作,该操作会通知服务器进行 APNs 推送信息的解绑操作,避免用户已退出但推送依然发送到当前设备的情况发生。
常见问题
如果集成过程中遇到任何问题,可查看 FAQ
补充说明
如果您在阅读完此文档后还有关于集成的任何疑问,可以参考以下iOS SDK Demo源码:https://github.com/sykesiStation/IStation_iOS_SDK_Demo.git。
源码充分展示了iOS SDK的功能,并为集成iOS SDK提供了示例代码。