# 会话消息

# 未读消息

企业可以使用ysf('onunread')来监听未读消息通知,也可以使用ysf('getUnreadMsg')获取当前的未读消息。七鱼提供的未读消息内容包括未读消息的总数、最后一条消息的类型和内容

    // 监听
    ysf('onunread',  function(result){
        // todo
        console.log(result.total, result.type, result.message);
    });

    // 获取
    var result = ysf('getUnreadMsg');
    console.log(result.total, result.type, result.message);

七鱼只是暴露了unread事件读取未读消息,之后的处理逻辑由开发者自己定义。

# 设置机器人常见问题

访客进入咨询时,如果进入了机器人会话,企业可以通过设置常见问题,将一些用户可能需要问的问题首先发送给用户。通过高级自定义配置,可以给不同页面中的不同咨询入口设置不同的常见问题。

你可以在管理后台 -> 服务中心 -> 在线机器人 -> 设置 -> 导航菜单 -> 常见问题 -> 常见问题模板,可以查找到企业的常见问题模板及其id。

接入代码

    ysf('config', {
       uid:"201609051809",
       name:'接入',
       email:'test@163.com',
       mobile:'13888888888',
       qtype: 1056         //常见问题模板id
    });

# 设置机器人欢迎语

访客进入咨询时,如果进入了机器人会话,机器人会发送一句欢迎语给访客,通过高级自定义配置,可以给不同页面中的不同咨询入口设置不同的欢迎语。

你可以在管理后台 -> 服务中心 -> 在线机器人 -> 设置 -> 基础设置 -> 引导语设置 -> 欢迎语 中,查看和配置机器人的的欢迎语模板及其id。

接入代码

    ysf('config', {
       uid:"201609051809",
       name:'接入',
       email:'test@163.com',
       mobile:'13888888888',
       welcomeTemplateId: 1024         //欢迎语模板id
    });

# 卡片消息

# 商品卡片

发起会话前,企业可以将用户正在查看的商品信息发送给客服,以便客服在后台及时预判访客需要咨询的内容。

注意,如果你在sdk初始化完成之前调用本接口,它将等待sdk初始化完成后执行

    ysf('product', {
        show : 1, // 1为打开, 其他参数为隐藏(包括非零元素)
        title : '标题',
        desc : '商品描述',
        picture : '商品图片地址',
        note : '备注',
        url : '跳转链接'
    })

ysf('product')支持传入成功和失败回调函数(success、error)。当在ios的h5页面使用七鱼sdk时,设置商品链接是一个异步的过程;如果需要保证商品链接设置成功,则应该在成功回调中进行后续操作(如进行页面跳转、打开聊天窗口等)

示例代码:

	ysf('product', {
	    show : 1, // 1为打开, 其他参数为隐藏(包括非零元素)
	    title : '标题',
	    desc : '商品描述',
	    picture : '商品图片地址',
	    note : '备注',
	    url : '跳转链接',
        success: function(){     // 成功回调
			ysf('open');
    	},
    	error: function(){       // 错误回调
    		// handle error
    	}
	})

注: show 参数用于控制访客端商品链接是否显示;对于客服端,只要接入就一定会显示商品链接信息

ysf('config')ysf('product')接口都提供了回调方法,所以在同时使用config和product方法是需要注意回调逻辑。可以在config的success回调中调用product方法,之后再在product的success中处理开发者自己想要实现的逻辑;或者可以使用变量标记的方法。

默认情况下,配置的商品链接会在接入人工会话后自动发送给客服;如果需要控制发送的时机,可以传入sendByUser参数。当设置该参数为1时,七鱼访客端不会自动发送商品链接,而是提供对应的引导卡片,访客可根据自己的需要点击引导卡片,手动发送商品链接给客服。

示例代码:

    ysf('product', {
        sendByUser: 1, // 是否由访客手动发送,1为是,其他参数为否
        actionText: '发送链接', // 发送按钮文案
        actionTextColor: '#000000', // 发送按钮文案颜色(16进制格式)
        title : '标题',
        desc : '商品描述',
        picture : '商品图片地址',
        note : '备注',
        url : '跳转链接'
    })

当sendByUser设置为1时,show参数将失效(取默认值1);同样的,actionText和actionTextColor参数仅在sendByUser为1时有效

# 自定义卡片

为支持不同场景下商品信息的展示,七鱼访客端根据传入的template字段来确定具体的解析方式,当前支持pictureLink(图片链接)模板和默认模板

    ysf('product', {
        show : 1, // 1为打开,其他参数为隐藏(包括非零元素)
        template: 'pictureLink', // 模板类型,不传为默认类型
        title : '标题',
        picture : '商品图片地址',
        url : '跳转链接'
    })

当使用pictureLink模板时,只有title、picture、url字段生效

# 卡片按钮点击效果

商品链接消息提供了可配置的功能性按钮,可以实现两个功能:1、支持主动定位到客服工作台的iframe页面,并通过postMessage的方式向iframe页面中发送配置的信息,2、支持浏览器用新标签的方式打开配置的url。

示例代码:

    ysf('product', {
        show : 1, // 1为打开, 其他参数为隐藏(包括非零元素)
        title : '标题',
        desc : '商品描述',
        picture : '商品图片地址',
        note : '备注',
        url : '跳转链接',
        tags: [{
                "label": "打开七鱼官网",  // 按钮名字
                "url": "https://qi.163.com", // 非必填,如果没有focusIframe字段,或者没有匹配到iframe,就以新窗口打开这个链接
                "focusIframe": "iframe名称", // 定位到iframe的标识,以iframe的名称匹配
                "data": {"name": "ss","sex": "男"}  // 以postMessage形式发送的数据,数据格式不限
            },{
                "label": "查询订单",
                "focusIframe": "订单",
                "data": {"orderId": "10000012","userName": "xxx"}
        }]
    });

注: 使用此接口,移动端SDK也得更新到4.1版本。

# 工作台iframe发送卡片消息

网易七鱼对于已经接入客服工作台iframe的客户提供了可以发送自定义商品或者订单类、自定义模板类消息的功能。 用户可以通过在接入的iframe页面中将数据对象按找下面规则组装好后通过postMessage的方式发送到网易七鱼的系统。

基本实现代码如下:

    var data = {
        // 要发送到七鱼的商品或者订单的数据对象
    }
    window.parent.postMessage(data, '*'); // 将数据用postMessage的方式发送到七鱼

商品类消息的字段规则如下:

字段 类型 必须 描述
cardType String 卡片类型,共三种类型。商品: 0,订单: 1,自定义: 2,推荐填写
picture String 商品的缩略图地址
title String 商品的展示标题
desc String 商品展示的简要描述
price String 商品的价格
goodsCId String 商品类目ID,长度限制为 100 字符,填写后有助于机器人识别商品和后续业务
goodsCName String 商品类目名称,长度限制为 10 字,如生鲜食品
goodsId String 商品ID, 长度限制为 100 字符,商品唯一标识符,填写后有助于机器人识别商品和后续业务,当卡片类型为商品时,推荐填写
url String 点击商品跳转到的链接地址
activity String 活动展示标题
activityHref String 点击活动跳转到的地址
showCustomMsg String 此字段为向七鱼发送自定义信息的标识,为1展示并接收此消息,为0则不接收此消息(此字段为必填项,没有七鱼则不会接收)
sendProToRobot number 此字段为机器人会话是否发送商品卡片,为1展示机器人阶段发送商品卡片,为0则机器人阶段不发送商品卡片
intent String 意图名称

订单类消息字段规则如下:

字段 类型 必须 描述
cardType String 卡片类型,共三种类型。商品: 0,订单: 1,自定义: 2,推荐填写
picture String 商品的缩略图地址
title String 商品的展示标题
desc String 商品展示的简要描述
payMoney String 商品支付的价格
orderId String 订单的id
orderTime String 下单时间
orderSku String 订单的sku描述信息
orderCount String 订单中商品数量
orderStatus String 订单交易状态
tags Array 订单类消息展示的功能按钮,tag每一项为{"label": "打开七鱼网址","url": "https://qi.163.com"},label为按钮的名称,url为打开的链接
url String 点击商品跳转到的链接地址
activity String 活动展示标题
activityHref String 点击活动跳转到的地址
showCustomMsg String 此字段为向七鱼发送自定义信息的标识,为1展示并接收此消息,为0则不接收此消息(此字段为必填项,没有七鱼则不会接收)

自定义模板类消息字段规则如下:

字段 类型 必须 描述
template String 模板类型(当前支持"pictureLink"即图片链接模板)
picture String 图片地址
url String 点击图片跳转到的链接地址
showCustomMsg String 此字段为向七鱼发送自定义信息的标识,为1展示并接收此消息,为0则不接收此消息(此字段为必填项,没有七鱼则不会接收)

# 自定义卡片消息(new)

通过开放的模板,可以在七鱼原有的访客端&客服端的页面上,展示半自定义的消息体样式。(不支持平台版企业)

目前只有新版访客端支持发送卡片消息,老版访客端不支持卡片消息

仅在线专业版及以上坐席支持

若访客端界面视觉UI需要自定义样式,请前往七鱼管理端-在线客服设置-访客端-样式设置中可自由配置

# 卡片类型定义

卡片消息【cards】支持所有的9种类型卡片,分别是:标题类型、富文本类型、副标题类型、图片类型、节点流程类型、商品类型、订单类型、按钮类型、跳转链接类型。一条卡片消息可以包含多种类型的模板组合。

浮动卡片消息【floatCards】只支持商品类型和按钮类型。

【建议内容长度在4000个字符以内,超过可能会有非预期表现】

type ICard =
  | TitleOptions
  | RichOptions
  | SubTitleOptions
  | ImageOptions
  | ProductOptions
  | OrderOptions
  | FlowOptions
  | ButtonOptions
  | LinkOptions;

type IFloatCard = ProductOptions | ButtonOptions;

enum MoudleType {
  TITLE = 'title',
  RICH = 'rich',
  SUBTITLE = 'subtitle',
  IMAGE = 'image',
  PRODUCT = 'product',
  ORDER = 'order',
  FLOW = 'flow',
  BUTTON = 'button',
  LINK = 'link',
}

interface TitleOptions {
  type: MoudleType.TITLE;
  content: string; //内容
  url?: string; // 超链接
  img?: string; // 图片加文本的图片url
  style?: {
    fontSize?: string | number; // 文字大小,默认14px
    fontColor?: string; // 字体颜色
    divider?: 0 | 1; // 是否添加分割线默认有分割线,最后一个元素没有
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 富文本模版的配置
 */
interface RichOptions {
  type: MoudleType.RICH; // 富文本
  content: string; // 内容
  style?: {
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
    divider?: 0 | 1; // 分割线
  };
}

/**
 * 副标题模版的配置
 */
interface SubTitleOptions {
  type: MoudleType.SUBTITLE;
  img?: string; // 图片url
  content: string;
  subContent?: string; // 显示在右侧的
  url?: string; // 跳转 url
  style?: {
    backgroundColor?: string; // 背景色
    divider?: 0 | 1; // 分割线
    fontSize?: number;
    fontColor?: string;
    subFontSize?: number;
    subFontColor?: string;
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 图片模版的配置
 */
interface ImageOptions {
  type: MoudleType.IMAGE; // 图片
  img: string; // 图片url
  url?: string; // 跳转 url
  style?: {
    divider?: 0 | 1; // 分割线
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 商品模版的配置
 */
export interface ProductOptions {
  type: MoudleType.PRODUCT; // 商品
  data: {
    id: string | number; // 商品id
    picture: string; // 商品图片
    desc: string; // 描述
    title: string; 标题
    price: string; // 价格
    url?: string; // actions 0的情况 跳转链接
    action?: 0 | 1; // 0 点击跳转【默认】, 1 点击发送对应的商品卡片 (只试用于访客端)
  }[];
  style?: {
    divider?: 0 | 1; // 分割线
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 订单模版的配置
 */
export interface OrderOptions {
  type: MoudleType.ORDER; // 订单
  orderId: string | number; // 订单id
  orderTime: string; // 下单时间
  data: {
    picture: string; // 商品图片
    desc: string; // 描述
    title: string; // 商品标题
    payMoney?: string; // 价格
    url?: string; // 跳转链接
    count?: string; // 订单商品数量 x 100
    sku?: string; // 商品sku描述
    status: string; // 交易状态
    action?: 0 | 1; // 0 点击跳转, 1 点击发送对应的订单卡片 (只试用于访客端)
  }[];
  style?: {
    divider?: 0 | 1; // 分割线
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 节点流程的配置
 */
export interface FlowOptions {
  type: MoudleType.FLOW; // 流程
  data: {
    id: string | number; // 流程id
    title: string; // 标题
    subtitle?: string; // 副标题
    current?: 1 | 0; // 当前步骤
  }[];
  style?: {
    fontSize?: number; // 主标题大小
    fontColor?: string; // 主标题颜色 有默认
    subFontSize?: number; // 副标题大小
    sunFontColor?: string; // 副标题颜色 有默认值
    divider?: 0 | 1; // 分割线
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 按钮模版的配置 TODO
 */
export interface ButtonOptions {
  type: MoudleType.BUTTON; // 按钮
  numInRow?: number; // 一行显示几个按钮 默认1个【浮动组件不生效】
  data: {
    title: string; // 标题
    action?: 0 | 1; // 0 点击跳转链接, 1 点击发送配置的文字(仅限访客)
    url?: string; // 跳转链接
    content?: string; // 发送的文字 action === 1 需要配置此内容
  }[];
  style?: {
    backgroundColor?: string; // 背景色
    fontColor?: string; // 文字颜色
    fontSize?: number; // 文字大小
    divider?: 0 | 1; // 分割线
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

/**
 * 卡片消息的配置
 */
export interface LinkOptions {
  type: MoudleType.LINK; // 链接
  content: string; // 标题
  url: string; // 跳转链接
  style?: {
    fontSize?: number; // 文字大小
    fontColor?: string; // 文字颜色
    divider?: 0 | 1; // 分割线
    pt?: number; // 上边距
    pb?: number; // 下边距
    pl?: number; // 左边距
    pr?: number; // 右边距
  };
}

# 各模板类型&参数说明

所有模板类型支持上下左右边距调整&分割线,在具体参数说明当中不再重复

参数 是否必须 参数说明
cards 卡片消息内容
floatCards 浮动卡片消息内容

# 标题文本:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,title
content string 标题
img string 左侧图片URL
url string 链接跳转地址
style object 样式

style字段object结构

参数 是否必须 参数类型 参数说明
fontSize number 文字大小,默认14px
fontColor string 字体颜色,有默认值
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 副标题文本:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,subtitle
content string 左侧文字内容
subContent string 右侧文字内容
img string 图片url地址,默认与文字等高
url string 跳转超链接
style object 样式

style字段object结构

参数 是否必须 参数类型 参数说明
backgroundColor string 背景色
fontSize number 左侧文字大小,有默认值
fontColor string 左侧文字字体颜色,有默认值
subFontSize number 右侧文字大小,有默认值
subFontColor string 右侧文字字体颜色,有默认值
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 富文本:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,rich
content string 内容
style object 样式

style字段object结构

参数 是否必须 参数类型 参数说明
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 图片:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,image
img string 图片地址
url string 跳转超链接
style object 样式

style字段object结构

参数 是否必须 参数类型 参数说明
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 商品:

图片 图片

参数 是否必须 参数类型 参数说明
type string 固定值,product
data array 商品数据节点
style object 样式

data字段object结构

参数 是否必须 参数类型 参数说明
id string 商品id
picture string 商品图片
desc string 描述
title string 标题
price string 价格
url string 跳转超链接,action为0的情况下的跳转链接
action number 2种类型,默认为0 (0 :点击跳转url, 1 :点击发送对应的商品卡片 (只适用于访客端))

style字段object结构

参数 是否必须 参数类型 参数说明
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 订单:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,order
orderId string 订单ID
orderTime string 下单时间
data array 订单数据节点
style object 样式

data字段object结构

参数 是否必须 参数类型 参数说明
picture string 商品图片
desc string 描述
title string 商品标题
status string 交易状态
payMoney string 价格
url string 跳转超链接,action为0的情况下的跳转链接
count string 订单商品数量 x 100
sku string 商品sku描述
action number 2种类型,默认为0 (0 :点击跳转url, 1 :点击发送对应的订单卡片 (只适用于访客端))

style字段object结构

参数 是否必须 参数类型 参数说明
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 节点流程:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,flow
data array 流程数据节点
style object 样式

data字段object结构

参数 是否必须 参数类型 参数说明
id string 流程id
title string 标题
subtitle string 副标题
current number 2种状态 (0 :非当前步骤,1 :当前步骤)

style字段object结构

参数 是否必须 参数类型 参数说明
fontSize number 主标题文字大小,有默认值
fontColor string 主标题文字字体颜色,有默认值
subFontSize number 副标题文字大小,有默认值
subFontColor string 副标题文字字体颜色,有默认值
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 操作按钮:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,button
numInRow number 一行显示几个按钮 默认1个(悬浮组件不生效)
data array 按钮数据节点
style object 样式

data字段object结构

参数 是否必须 参数类型 参数说明
title string 商品标题
action number 2种类型,默认为0 (0 点击跳转链接, 1 点击发送配置的文字 (只适用于访客端))
url string 跳转超链接,action为0的情况下的跳转链接
content string 发送内容,action为1的情况下的发送内容

style字段object结构

参数 是否必须 参数类型 参数说明
backgroundColor string 背景色
fontSize number 文字大小,有默认值
fontColor string 文字字体颜色,有默认值
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 跳转链接:

图片

参数 是否必须 参数类型 参数说明
type string 固定值,link
content string 标题
url string 跳转链接
style object 样式

style字段object结构

参数 是否必须 参数类型 参数说明
fontSize number 文字大小,有默认值
fontColor string 文字字体颜色,有默认值
pt number 上边距
pb number 下边距
pl number 左边距
pr number 右边距
divider number 是否需要分割线,0:不需要;1:需要

# 组合效果展示

可以通过以上开放的模板进行自由组合,生成半自定义的消息体样式,一条卡片消息可以包含多种类型的卡片。 以下为部分举例示意:

图片

# 支持发送的场景

目前仅支持人工会话过程中发送响应自定义卡片

# 访客端进线直接发送

接入代码:

    ysf('cardMessage', options: {
      sendByUser?: 0, // 0 进线自动发送,1 手动发送  默认0
      actionText? :string // 发送按钮文案
      actionTextColor?: string // 发送按钮颜色
      hideAction?: number; // 是否展示action按钮 默认0;用于sendByUser=1隐藏发送按钮
      cards: ICard[]; // 这里是消息的配置,至少一个 ,看卡片类型定义
      floatCards?: IFloatCard[] // 这里是消息的配置,看卡片类型定义
      succsess?: () => {}
      error?: () => {}
    }
  })

# 工作台iframe发送卡片消息

网易七鱼对于已经接入客服工作台iframe的客户提供了可以发送自定义卡片消息的功能。 用户可以通过在接入的iframe页面中将数据对象按找下面规则组装好后通过postMessage的方式发送到网易七鱼的系统。

    var data = {
        msgtype: 'cardMessage',
        cards: ICard[]; // 这里是消息的配置,至少一条,具体配置看卡片类型定义
        floatCards?: IFloatCard[] // 这里是消息的配置,具体配置看卡片类型定义
    }
    // 将数据用postMessage的方式发送到七鱼
    window.parent.postMessage(JSON.stringify(data), '*');

# 通过接口开发者服务器替用户向客服发送消息

接口对接请见 - 给七鱼发送消息 (opens new window)

# 通过接口开发者服务器替客服向访客发送消息

接口对接请见 - 给访客发送消息 (opens new window)

# 会话管理

# 分配客服&客服组

网易七鱼客服系统默认会按照智能方式分配客服, 如果想让访客分配给指定的客服组或者客服,则需要使用访客分流功能

你可以在管理后台 -> 服务中心-> 在线系统-> 设置 -> 会话流程 -> 会话分配 ->分配规则-> ID查询, 可以查找到相应的客服id和客服组id。

你可以在管理后台 -> 服务中心 -> 在线系统-> 设置 -> 会话流程 -> 会话分配 -> 分配规则 -> 高级自定义分配(WEB端)-> Web端自定义链接分配,可以直接复制链接地址接入

接入代码:


    ysf('config', {
        uid:"1442286211167",
        name:'test',
        email:'test@163.com',
        mobile:'13888888888',
        staffid:'123', // 客服id
        groupid: '123' // 客服组id
    });

代码优先级高于后台配置,所以当代码中指定了staffid或者groupid后,后台的web端访客分流配置将无效。staffid和groupid只要传一个就可以了,没必要两个参数都传(同时传了staffid和groupid,忽略groupid)。

# 分配机器人

在3.1版本中,增加了robotShuntSwitch参数,该参数取值为0或1,在指定了访客分流时有效;如果robotShuntSwitch为1,访客会先由机器人接待,当转人工咨询时再分配给设置的分流客服

接入代码:

    ysf('config', {
        uid:"1442286211167",
        name:'test',
        email:'test@163.com',
        mobile:'13888888888',
        staffid:'123',
        robotShuntSwitch: 1 // 机器人优先开关
    });

对于开通了多机器人的企业,对于不指定robotId的访客入口,网易七鱼系统会在机器人开关打开的情况下自动匹配当前的默认机器人,如果想让指定的机器人服务访客,则需要使用多机器人接入功能指定robotId。

开通了多个机器人的企业,在管理后台-> 服务中心 -> 在线机器人 -> 机器人列表中找到对应的机器人ID。 在管理后台 -> 服务中心 -> 在线系统 -> 设置 -> 会话流程 -> 会话分配 ->分配规则->高级自定义分配(WEB端)-> Web端自定义链接分配,可以直接复制链接地址接入

接入代码:

    ysf('config', {
        uid:"usr18398492039",
        name:'mixRobotTestUser',
        email:'test@163.com',
        mobile:'13888888888',
        robotId: '12345'  // 机器人ID
    });

# 关闭挽留邀评

app webview嵌入H5访客端,点击app自己的返回时,可以配置关闭挽留邀请评价

# 接入说明

字段 类型 必须 描述
APPbackPop Number APP点击返回的时候是否弹出 关闭挽留弹窗(同时需要APP调用JS window.checkCloseQyClient(data))
0:不弹起 1:只弹起关闭挽留弹窗 2: 弹起关闭挽留弹窗和满意度评价弹窗

接入代码:

    ysf('config', {
        APPbackPop: 2  // 0不弹起挽留弹窗 1:弹关闭挽留弹窗 2: 关闭挽留弹窗和评价挽留弹窗
    });

提供APP调用H5方法

方法名称 类型 描述
checkCloseYSFClient (data:JSONString) => Void APP点击返回的时候需要调用H5的方法,通知H5去处理挽留弹窗和挽留评价操作

# H5和webview通信

# Android示例

APP调用H5的方法


    // 在需要关闭七鱼访客端界面的地方,加入下面的代码
    String js = "javascript:" + "checkCloseYSFClient" + "()";
    WebView.loadUrl(js);

H5操作完数据,需要通知APP进行返回,我们通过postMessage的方式发送消息通知到APP

定义receiveYSFMessage方法


// 自定义addJavascriptInterface接口
public class JavaScriptInterface {
    @JavascriptInterface
    public void receiveYSFMessage(String message) {
        // 在这里处理从H5页面传来的消息
        Log.e("receiveYSFMessage: ", "从js--> " + message);
    }
}

需要定义postmessage为postH5Message防止重写了H5自己的postmessage


    //webView 然后设置 setJavaScriptEnabled 为 true
    WebView.setJavaScriptEnabled(true);
    //添加 addJavascriptInterface 监听,设置全局的 JavaScript 方法处理 postH5Message 。
    WebView.addJavascriptInterface(new JavaScriptInterface(), "postH5Message");

# IOS示例代码

IOS示例地址


#import "TestViewController.h"
#import <WebKit/WebKit.h>

@interface TestViewController ()<WKScriptMessageHandler,WKNavigationDelegate,WKUIDelegate>
@property (nonatomic, strong) WKWebView *webView;
@end

@implementation TestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    CGRect rect = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.preferences = [[WKPreferences alloc] init];
    config.preferences.minimumFontSize = 10;
    config.preferences.javaScriptEnabled = YES;
    config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
    config.userContentController = [[WKUserContentController alloc] init];
    config.processPool = [[WKProcessPool alloc] init];
    config.userContentController = [WKUserContentController new];
    //在创建wkWebView时,需要将被js调用的方法注册进去,oc与js端对应实现
    [config.userContentController addScriptMessageHandler:self name:@"receiveYSFMessage"];
    WKWebView *wkWebView = [[WKWebView alloc]initWithFrame:rect configuration:config];
    self.webView = wkWebView;
    wkWebView.navigationDelegate = self;
    wkWebView.UIDelegate = self;
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"http://6669.qytest.netease.com/sdk/r/demo-debug.html"]];
    [wkWebView loadRequest:request];
    [self.view addSubview:wkWebView];
    UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    backBtn.frame = CGRectMake(100, 100, 100, 100);
    [backBtn setTitle:@"返回" forState:UIControlStateNormal];
    [self.view addSubview:backBtn];
    [backBtn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
    [backBtn addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];

}
- (void)onBack {
    [self nativeCallJS];
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"receiveYSFMessage"]) {
        NSLog(@"JS调用原生,参数:%@",message.body);
        [self.navigationController popViewControllerAnimated:YES];
    }
}
- (void)nativeCallJS {
    [self.webView evaluateJavaScript:@"checkCloseYSFClient()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
      //TODO
        NSLog(@"");
     }];
}

@end

# 相册、视频、文件权限通信

app webview嵌入H5访客端,点击相册、视频、文件获取APP权限(浮层模式不支持,不能跨域访问访客端方法),仅支持IOS

注意:android以标准的WebView接入方式来完成权限调用,在WebChromeClient的onShowFileChooser方法中判断权限有没有调用,视频客服则需要通过onPermissionRequest方法来判断

# 接入说明

字段 类型 必须 描述
APPBridgePermission Number 1: 获取app相机、文件权限 0: 不获取权限(浮层模式不支持)

接入代码:

    ysf('config', {
        APPBridgePermission: 1  // 0:不获取权限 1:获取app权限,需要app客户端配合开发
    });

提供APP调用H5方法

方法名称 类型 描述
ysfBridge (data:{ seq: 1, type: 'imagePermission' }) => Void APP主动调用H5的方法,通知H5获取权限问题
(传会的参数,就是H5请求带的参数,即下面H5和webview通信中讲到的参数)

# H5和webview通信

receiveYSFMessage h5主动传递给客户端的类型

type 类型 描述
imagePermission string 获取图片权限
videoPermission string 获取视频权限
filePermission string 获取文件权限
requestImagePermission string 请求图片权限(让APP去请求相册权限,弹出对应的权限弹窗)
requestVideoPermission string 请求视频权限(让APP去请求视频权限,弹出对应的权限弹窗)
requestFilePermission string 请求文件权限(让APP去请求文件权限,弹出对应的权限弹窗)

# IOS示例代码

IOS示例地址(仅提供了获取相册权限demo)

//
//  TestViewController.m
//  QYSDKDemo
//
//  Created by zhongzhida on 2023/4/19.
//  Copyright © 2023 Netease. All rights reserved.
//

#import "TestViewController.h"
#import <WebKit/WebKit.h>
#import <Photos/Photos.h>

@interface TestViewController ()<WKScriptMessageHandler,WKNavigationDelegate,WKUIDelegate>
@property (nonatomic, strong) WKWebView *webView;
@end

@implementation TestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    CGRect rect = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.preferences = [[WKPreferences alloc] init];
    config.preferences.minimumFontSize = 10;
    config.preferences.javaScriptEnabled = YES;
    config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
    config.userContentController = [[WKUserContentController alloc] init];
    config.processPool = [[WKProcessPool alloc] init];
    config.userContentController = [WKUserContentController new];
    //在创建wkWebView时,需要将被js调用的方法注册进去,oc与js端对应实现
    [config.userContentController addScriptMessageHandler:self name:@"receiveYSFMessage"];
    WKWebView *wkWebView = [[WKWebView alloc]initWithFrame:rect configuration:config];
    self.webView = wkWebView;
    wkWebView.navigationDelegate = self;
    wkWebView.UIDelegate = self;
    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:@"http://10.221.149.18:8002/src/html/demo-debug.html"] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10];
    [wkWebView loadRequest:request];
    [self.view addSubview:wkWebView];
    
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if ([message.name isEqualToString:@"receiveYSFMessage"]) {
        NSLog(@"JS调用原生,参数:%@",message.body);
        NSString *body = message.body;
        NSData *jsonData = [message.body dataUsingEncoding:NSUTF8StringEncoding];

        NSError *error = nil;
        NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
        NSString *type = jsonDictionary[@"type"];
        NSInteger result = 0;
        if ([type isEqualToString:@"imagePermission"] || [type isEqualToString:@"videoPermission"]) {
            // 获取相册权限状态
            PHAuthorizationStatus photoLibraryAuthorizationStatus = [PHPhotoLibrary authorizationStatus];
            [self nativeCallJS:@{@"seq":jsonDictionary[@"seq"],@"type":type,@"result":@(photoLibraryAuthorizationStatus)}];
        } else if ([type isEqualToString:@"filePermission"]) {
            [self nativeCallJS:@{@"seq":jsonDictionary[@"seq"],@"type":type,@"result":@(1)}];
        } else if ([type isEqualToString:@"requestImagePermission"] || [type isEqualToString:@"requestVideoPermission"]) {
            // 获取相册权限状态
            PHAuthorizationStatus photoLibraryAuthorizationStatus = [PHPhotoLibrary authorizationStatus];
            if (photoLibraryAuthorizationStatus == PHAuthorizationStatusDenied ) {
                [[[UIAlertView alloc] initWithTitle:@"没有相册权限"
                                            message:@"请在iPhone的“设置-隐私-相册”选项中,允许访问你的相册。"
                                           delegate:nil
                                  cancelButtonTitle:@"确定"
                                  otherButtonTitles:nil] show];
            } else if (photoLibraryAuthorizationStatus == PHAuthorizationStatusNotDetermined) {
                // 请求访问相册的权限
                [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self nativeCallJS:@{@"seq":jsonDictionary[@"seq"],@"type":type,@"result":@(status)}];
                    });
                }];
            }
            
        }
        
    }
}
- (void)nativeCallJS:(NSDictionary *)param {
    NSData *data = [NSJSONSerialization dataWithJSONObject:param
                                                   options:0
                                                     error:nil];
    NSString *str  = [[NSString alloc] initWithData:data
                                           encoding:NSUTF8StringEncoding];
    NSString *js = [NSString stringWithFormat:@"ysfAppBridge(%@)",str];
    [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
      //TODO
        NSLog(@"");
     }];
}

@end