文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
指南与API参考指南媒体AVSession Kit(音视频播控服务)本地媒体会话媒体会话提供方(ArkTS)

媒体会话提供方(ArkTS)

音视频应用在实现音视频功能的同时,需要作为媒体会话提供方接入媒体会话,在媒体会话控制方(例如播控中心)中展示媒体相关信息,并响应媒体会话控制方下发的播控命令。

基本概念

  • 媒体会话元数据(AVMetadata):用于描述媒体数据相关属性,包含标识当前媒体的ID(assetId)、上一首媒体的ID(previousAssetId)、下一首媒体的ID(nextAssetId)、标题(title)、艺术家(artist)、专辑作者(author)、专辑名称(album)、词作者(writer)和媒体时长(duration)等属性。

  • 媒体播放状态(AVPlaybackState):用于描述媒体播放状态的相关属性,包含当前媒体的播放状态(state)、播放位置(position)、播放倍速(speed)、缓冲时间(bufferedTime)、循环模式(loopMode)、是否收藏(isFavorite)、正在播放的媒体ID(activeItemId)和自定义媒体数据(extras)等属性。

接口说明

媒体会话提供方使用的关键接口如下表所示。接口返回值有两种返回形式:callback和promise,下表中为callback形式接口,promise和callback只是返回值方式不一样,功能相同。

更多API说明请参考文档:模块描述。

展开
接口名 说明
createAVSession(context: Context, tag: string, type: AVSessionType, callback: AsyncCallback<AVSession>): void10+

创建媒体会话。

一个UIAbility只能存在一个媒体会话,重复创建会失败。

setAVMetadata(data: AVMetadata, callback: AsyncCallback<void>): void10+ 设置媒体会话元数据。
setAVPlaybackState(state: AVPlaybackState, callback: AsyncCallback<void>): void10+ 设置媒体会话播放状态。
setLaunchAbility(ability: WantAgent, callback: AsyncCallback<void>): void10+ 设置启动UIAbility。
getController(callback: AsyncCallback<AVSessionController>): void10+ 获取当前会话自身控制器。
getOutputDevice(callback: AsyncCallback<OutputDeviceInfo>): void10+ 获取输出设备相关信息。
activate(callback: AsyncCallback<void>): void10+ 激活媒体会话。
deactivate(callback: AsyncCallback<void>): void10+ 禁用当前会话。
destroy(callback: AsyncCallback<void>): void10+ 销毁媒体会话。
setAVQueueItems(items: Array<AVQueueItem>, callback: AsyncCallback<void>): void 10+ 设置媒体播放列表。
setAVQueueTitle(title: string, callback: AsyncCallback<void>): void10+ 设置媒体播放列表名称。
dispatchSessionEvent(event: string, args: {[key: string]: Object}, callback: AsyncCallback<void>): void10+ 设置会话内自定义事件。
setExtras(extras: {[key: string]: Object}, callback: AsyncCallback<void>): void10+ 设置键值对形式的自定义媒体数据包。
getOutputDeviceSync(): OutputDeviceInfo10+ 使用同步方法获取当前输出设备信息。

开发步骤

音视频应用作为媒体会话提供方接入媒体会话的基本步骤如下所示:

  1. 通过AVSessionManager的方法创建并激活媒体会话。

    说明

    以下示例代码仅展示创建AVSession对象的接口调用,应用在真正使用时,需要确保AVSession对象实例在应用后台播放业务活动期间一直存在,避免被系统回收、释放,导致后台发声时被系统管控。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. // ...
    3. @Entry
    4. @Component
    5. struct Index {
    6. @State message: string = 'hello world';
    7. // ...
    8. build() {
    9. Column() {
    10. // ...
    11. Text(this.message)
    12. .onClick(async () => {
    13. try {
    14. // 开始创建并激活媒体会话。
    15. // 创建session。
    16. let context = this.getUIContext().getHostContext() as Context;
    17. let type: AVSessionManager.AVSessionType = 'audio';
    18. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    19. await session.activate();
    20. console.info(`session create done : sessionId : ${session.sessionId}`);
    21. // ...
    22. } catch (err) {
    23. if (err) {
    24. console.error(`AVSession create Error: Code: ${err.code}, message: ${err.message}`);
    25. // ...
    26. }
    27. }
    28. })
    29. }
    30. .width('100%')
    31. .height('100%')
    32. }
    33. }
  2. 跟随媒体信息的变化,及时设置媒体会话信息。需要设置的媒体会话信息主要包括:

    • 媒体会话元数据AVMetadata。
    • 媒体播放状态AVPlaybackState。

    音视频应用设置的媒体会话信息,会被媒体会话控制方通过AVSessionController相关方法获取后进行显示或处理。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. import { BusinessError } from '@kit.BasicServicesKit';
    3. // ...
    4. @Entry
    5. @Component
    6. struct Index {
    7. @State message: string = 'hello world';
    8. // ...
    9. build() {
    10. Column() {
    11. // ...
    12. Text(this.message)
    13. .onClick(async () => {
    14. let context = this.getUIContext().getHostContext() as Context;
    15. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    16. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
    17. // 播放器逻辑··· 引发媒体信息与播放状态的变更。
    18. // 设置必要的媒体信息。
    19. let metadata: AVSessionManager.AVMetadata = {
    20. assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体。
    21. title: 'TITLE',
    22. mediaImage: 'IMAGE',
    23. artist: 'ARTIST'
    24. };
    25. session.setAVMetadata(metadata).then(() => {
    26. console.info(`setAVMetadata successfully`);
    27. // ...
    28. }).catch((err: BusinessError) => {
    29. console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
    30. // ...
    31. });
    32. // 简单设置一个播放状态 - 暂停 未收藏。
    33. let playbackState: AVSessionManager.AVPlaybackState = {
    34. state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE,
    35. isFavorite: false
    36. };
    37. session.setAVPlaybackState(playbackState, (err) => {
    38. if (err) {
    39. console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
    40. // ...
    41. } else {
    42. console.info(`setAVPlaybackState successfully`);
    43. // ...
    44. }
    45. });
    46. // 设置一个播放列表。
    47. let queueItemDescription1: AVSessionManager.AVMediaDescription = {
    48. assetId: '001',
    49. title: 'music_name',
    50. subtitle: 'music_sub_name',
    51. description: 'music_description',
    52. mediaImage: 'PIXELMAP_OBJECT',
    53. extras: { 'extras': 'any' }
    54. };
    55. let queueItem1: AVSessionManager.AVQueueItem = {
    56. itemId: 1,
    57. description: queueItemDescription1
    58. };
    59. let queueItemDescription2: AVSessionManager.AVMediaDescription = {
    60. assetId: '002',
    61. title: 'music_name',
    62. subtitle: 'music_sub_name',
    63. description: 'music_description',
    64. mediaImage: 'PIXELMAP_OBJECT',
    65. extras: { 'extras': 'any' }
    66. };
    67. let queueItem2: AVSessionManager.AVQueueItem = {
    68. itemId: 2,
    69. description: queueItemDescription2
    70. };
    71. let queueItemsArray = [queueItem1, queueItem2];
    72. session.setAVQueueItems(queueItemsArray).then(() => {
    73. console.info(`SetAVQueueItems successfully`);
    74. // ...
    75. }).catch((err: BusinessError) => {
    76. console.error(`Failed to set AVQueueItem, error code: ${err.code}, error message: ${err.message}`);
    77. // ...
    78. });
    79. // 设置媒体播放列表名称。
    80. let queueTitle = 'QUEUE_TITLE';
    81. session.setAVQueueTitle(queueTitle).then(() => {
    82. console.info(`SetAVQueueTitle successfully`);
    83. // ...
    84. }).catch((err: BusinessError) => {
    85. console.error(`Failed to set AVQueueTitle, error code: ${err.code}, error message: ${err.message}`);
    86. // ...
    87. });
    88. // ...
    89. })
    90. }
    91. .width('100%')
    92. .height('100%')
    93. }
    94. }
  3. 设置用于被媒体会话控制方拉起的UIAbility。当用户操作媒体会话控制方的界面时,例如点击播控中心的卡片,可以拉起此处配置的UIAbility。

    设置UIAbility时通过WantAgent接口实现,更多关于WantAgent的信息请参考WantAgent。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. import { wantAgent } from '@kit.AbilityKit';
    3. import { BusinessError } from '@kit.BasicServicesKit';
    4. @Entry
    5. @Component
    6. struct Index {
    7. @State message: string = 'hello world';
    8. build() {
    9. Column() {
    10. Text(this.message)
    11. .onClick(async () => {
    12. let context = this.getUIContext().getHostContext() as Context;
    13. let type: AVSessionManager.AVSessionType = 'audio';
    14. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    15. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    16. let wantAgentInfo: wantAgent.WantAgentInfo = {
    17. wants: [
    18. {
    19. bundleName: 'com.example.musicdemo',
    20. abilityName: 'MainAbility'
    21. }
    22. ],
    23. // OperationType.START_ABILITIES
    24. operationType: 2,
    25. requestCode: 0,
    26. wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
    27. }
    28. wantAgent.getWantAgent(wantAgentInfo).then((agent) => {
    29. session.setLaunchAbility(agent);
    30. }).catch((err: BusinessError) => {
    31. console.error(`Failed to getWantAgent. Code: ${err.code}, message: ${err.message}`);
    32. })
    33. // ...
    34. })
    35. }
    36. .width('100%')
    37. .height('100%')
    38. }
    39. }
  4. 发送一个即时的自定义会话事件,以供媒体控制方接收到事件后进行相应的操作。

    说明

    通过dispatchSessionEvent方法发送的数据不会保存在会话对象或AVSession服务中。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. import { BusinessError } from '@kit.BasicServicesKit';
    3. // ...
    4. @Entry
    5. @Component
    6. struct Index {
    7. @State message: string = 'hello world';
    8. // ...
    9. build() {
    10. Column() {
    11. // ...
    12. Text(this.message)
    13. .onClick(async () => {
    14. let context = this.getUIContext().getHostContext() as Context;
    15. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    16. let type: AVSessionManager.AVSessionType = 'audio';
    17. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    18. let eventName = 'dynamic_lyric';
    19. await session.dispatchSessionEvent(eventName, { lyric: 'This is my lyric' }).then(() => {
    20. console.info(`Dispatch session event successfully`);
    21. // ...
    22. }).catch((err: BusinessError) => {
    23. console.error(`Failed to dispatch session event. Code: ${err.code}, message: ${err.message}`);
    24. // ...
    25. })
    26. // ...
    27. })
    28. }
    29. .width('100%')
    30. .height('100%')
    31. }
    32. }
  5. 设置与当前会话相关的自定义媒体数据包,以供媒体控制方接收到事件后进行相应的操作。

    说明

    通过setExtras方法设置的数据包会被存储在AVSession服务中,数据的生命周期与会话一致;会话对应的Controller可以使用getExtras来获取该数据。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. import { BusinessError } from '@kit.BasicServicesKit';
    3. // ...
    4. @Entry
    5. @Component
    6. struct Index {
    7. @State message: string = 'hello world';
    8. // ...
    9. build() {
    10. Column() {
    11. // ...
    12. Text(this.message)
    13. .onClick(async () => {
    14. let context = this.getUIContext().getHostContext() as Context;
    15. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    16. let type: AVSessionManager.AVSessionType = 'audio';
    17. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    18. await session.setExtras({ extra: 'This is my custom media packet' }).then(() => {
    19. console.info(`Set extras successfully`);
    20. // ...
    21. }).catch((err: BusinessError) => {
    22. console.error(`Failed to set extras. Code: ${err.code}, message: ${err.message}`);
    23. // ...
    24. })
    25. // ...
    26. })
    27. }
    28. .width('100%')
    29. .height('100%')
    30. }
    31. }
  6. 注册播控命令事件监听,便于响应用户通过媒体会话控制方,例如播控中心,下发的播控命令。

    在Session侧注册的监听分为固定播控命令和高级播控事件两种。

    6.1 固定控制命令的监听。

    说明

    媒体会话提供方在注册相关固定播控命令事件监听时,监听的事件会在媒体会话控制方的getValidCommands()方法中体现,即媒体会话控制方会认为对应的方法有效,进而根据需要触发相应的事件。为了保证媒体会话控制方下发的播控命令可以被正常执行,媒体会话提供方请勿进行无逻辑的空实现监听。

    Session侧的固定播控命令主要包括播放、暂停、上一首、下一首等基础操作命令,详细介绍请参见AVControlCommand。

    控制场景包括:播控中心点击、播控中心通知栏移除、蓝牙耳机佩戴、蓝牙耳机/有线耳机按键、语音助手控制等。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. // ...
    3. @Entry
    4. @Component
    5. struct Index {
    6. @State message: string = 'hello world';
    7. // ...
    8. build() {
    9. Column() {
    10. // ...
    11. Text(this.message)
    12. .onClick(async () => {
    13. let context = this.getUIContext().getHostContext() as Context;
    14. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    15. let type: AVSessionManager.AVSessionType = 'audio';
    16. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    17. // ...
    18. // 一般在监听器中会对播放器做相应逻辑处理。
    19. // 不要忘记处理完后需要通过set接口同步播放相关信息,参考上面的用例。
    20. session.on('play', () => {
    21. console.info(`on play , do play task`);
    22. // ...
    23. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('play')取消监听。
    24. // 处理完毕后,请使用setAVPlaybackState上报播放状态。
    25. });
    26. session.on('pause', () => {
    27. console.info(`on pause , do pause task`);
    28. // ...
    29. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('pause')取消监听。
    30. // 处理完毕后,请使用setAVPlaybackState上报播放状态。
    31. });
    32. session.on('stop', () => {
    33. console.info(`on stop , do stop task`);
    34. // ...
    35. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('stop')取消监听。
    36. // 处理完毕后,请使用setAVPlaybackState上报播放状态。
    37. });
    38. session.on('playNext', () => {
    39. console.info(`on playNext , do playNext task`);
    40. // ...
    41. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('playNext')取消监听。
    42. // 处理完毕后,请使用setAVPlaybackState上报播放状态,使用setAVMetadata上报媒体信息。
    43. });
    44. session.on('playPrevious', () => {
    45. console.info(`on playPrevious , do playPrevious task`);
    46. // ...
    47. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('playPrevious')取消监听。
    48. // 处理完毕后,请使用setAVPlaybackState上报播放状态,使用setAVMetadata上报媒体信息。
    49. });
    50. session.on('fastForward', () => {
    51. console.info(`on fastForward , do fastForward task`);
    52. // ...
    53. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('fastForward')取消监听。
    54. // 处理完毕后,请使用setAVPlaybackState上报播放状态和播放position。
    55. });
    56. session.on('rewind', () => {
    57. console.info(`on rewind , do rewind task`);
    58. // ...
    59. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('rewind')取消监听。
    60. // 处理完毕后,请使用setAVPlaybackState上报播放状态和播放position。
    61. });
    62. session.on('seek', (time: number) => {
    63. console.info(`on seek , the time is ${time}`);
    64. // ...
    65. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('seek')取消监听。
    66. // 处理完毕后,请使用setAVPlaybackState上报播放状态和播放position。
    67. });
    68. session.on('setSpeed', (speed) => {
    69. console.info(`on setSpeed , the speed is ${speed}`);
    70. // ...
    71. // 实现具体功能。
    72. });
    73. session.on('setLoopMode', (mode) => {
    74. console.info(`on setLoopMode , the loop mode is ${mode}`);
    75. // ...
    76. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('setLoopMode')取消监听。
    77. // 应用自定义下一个模式,处理完毕后,请使用setAVPlaybackState上报切换后的LoopMode。
    78. });
    79. session.on('toggleFavorite', (assetId) => {
    80. console.info(`on toggleFavorite , the target asset Id is ${assetId}`);
    81. // ...
    82. // 如暂不支持该指令,请勿注册;或在注册后但暂不使用时,通过session.off('toggleFavorite')取消监听。
    83. // 处理完毕后,请使用setAVPlaybackState上报收藏结果isFavorite。
    84. });
    85. // ...
    86. })
    87. }
    88. .width('100%')
    89. .height('100%')
    90. }
    91. }

    6.2 高级播控事件的监听。

    Session侧可注册的高级播控事件主要包括:

    • skipToQueueItem: 播放列表其中某项被选中的事件。
    • handleKeyEvent: 按键事件。
    • outputDeviceChange: 输出设备变化的事件。
    • commonCommand: 自定义控制命令变化的事件。
    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. // ...
    3. @Entry
    4. @Component
    5. struct Index {
    6. @State message: string = 'hello world';
    7. // ...
    8. build() {
    9. Column() {
    10. // ...
    11. Text(this.message)
    12. .onClick(async () => {
    13. try {
    14. let context = this.getUIContext().getHostContext() as Context;
    15. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    16. let type: AVSessionManager.AVSessionType = 'audio';
    17. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    18. // ...
    19. // 一般在监听器中会对播放器做相应逻辑处理。
    20. // 不要忘记处理完后需要通过set接口同步播放相关信息,参考上面的用例。
    21. session.on('skipToQueueItem', (itemId) => {
    22. console.info(`on skipToQueueItem , do skip task`);
    23. // ...
    24. // 实现具体功能。
    25. });
    26. session.on('handleKeyEvent', (event) => {
    27. console.info(`on handleKeyEvent , the event is ${JSON.stringify(event)}`);
    28. // ...
    29. // 实现具体功能。
    30. });
    31. session.on('outputDeviceChange', (state: AVSessionManager.ConnectionState, device: AVSessionManager.OutputDeviceInfo) => {
    32. console.info(`on outputDeviceChange , the state is ${JSON.stringify(state)} and device info is ${JSON.stringify(device)}`);
    33. // ...
    34. // 实现具体功能。
    35. });
    36. session.on('commonCommand', (commandString, args) => {
    37. console.info(`on commonCommand , command is ${commandString}, args are ${JSON.stringify(args)}`);
    38. // ...
    39. // 实现具体功能。
    40. });
    41. // ...
    42. } catch (err) {
    43. if (err) {
    44. console.error(`AVSession create Error: Code: ${err.code}, message: ${err.message}`);
    45. // ...
    46. }
    47. }
    48. })
    49. }
    50. .width('100%')
    51. .height('100%')
    52. }
    53. }
  7. 获取当前媒体会话自身的控制器,与媒体会话对应进行通信交互。

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. // ...
    3. @Entry
    4. @Component
    5. struct Index {
    6. @State message: string = 'hello world';
    7. // ...
    8. build() {
    9. Column() {
    10. // ...
    11. Text(this.message)
    12. .onClick(async () => {
    13. try {
    14. let context = this.getUIContext().getHostContext() as Context;
    15. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    16. let type: AVSessionManager.AVSessionType = 'audio';
    17. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    18. // 通过已有session获取一个controller对象。
    19. let controller = await session.getController();
    20. // ...
    21. // controller可以与原session对象进行基本的通信交互,比如下发播放命令。
    22. let avCommand: AVSessionManager.AVControlCommand = { command: 'play' };
    23. controller.sendControlCommand(avCommand);
    24. // 或者做状态变更监听。
    25. controller.on('playbackStateChange', 'all', (state) => {
    26. // do some things.
    27. });
    28. // ...
    29. } catch (err) {
    30. if (err) {
    31. console.error(`AVSession create or getController Error: Code: ${err.code}, message: ${err.message}`);
    32. // ...
    33. }
    34. }
    35. })
    36. }
    37. .width('100%')
    38. .height('100%')
    39. }
    40. }
  8. 音视频应用在退出,并且不需要继续播放时,及时取消监听以及销毁媒体会话释放资源。

    取消播控命令监听的示例代码如下所示:

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. @Entry
    3. @Component
    4. struct Index {
    5. @State message: string = 'hello world';
    6. build() {
    7. Column() {
    8. Text(this.message)
    9. .onClick(async () => {
    10. let context = this.getUIContext().getHostContext() as Context;
    11. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    12. let type: AVSessionManager.AVSessionType = 'audio';
    13. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    14. // 取消指定session下的相关监听。
    15. session.off('play');
    16. session.off('pause');
    17. session.off('stop');
    18. session.off('playNext');
    19. session.off('playPrevious');
    20. session.off('skipToQueueItem');
    21. session.off('handleKeyEvent');
    22. session.off('outputDeviceChange');
    23. session.off('commonCommand');
    24. // ...
    25. })
    26. }
    27. .width('100%')
    28. .height('100%')
    29. }
    30. }

    销毁媒体会话示例代码如下所示:

    收起
    自动换行
    深色代码主题
    复制
    1. import { avSession as AVSessionManager } from '@kit.AVSessionKit';
    2. // ...
    3. @Entry
    4. @Component
    5. struct Index {
    6. @State message: string = 'hello world';
    7. // ...
    8. build() {
    9. Column() {
    10. // ...
    11. Text(this.message)
    12. .onClick(async () => {
    13. let context = this.getUIContext().getHostContext() as Context;
    14. // 假设已经创建了一个session,如何创建session可以参考之前的案例。
    15. let type: AVSessionManager.AVSessionType = 'audio';
    16. let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
    17. // 主动销毁已创建的session。
    18. session.destroy((err) => {
    19. if (err) {
    20. console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
    21. // ...
    22. } else {
    23. console.info(`Destroy : SUCCESS `);
    24. // ...
    25. }
    26. });
    27. })
    28. }
    29. .width('100%')
    30. .height('100%')
    31. }
    32. }