概述

Call Service Kit(通话服务)是 HarmonyOS 为开发者提供的应用内通话管理服务。开发者通过集成 Call Service Kit,可以实现便捷的来电一键接听、横幅通知、静音与取消静音等功能,提升用户体验。

场景分类

应用内通话主要分为来电场景和去电场景两类。

  • 来电场景:应用接收到来自网络的音/视频通话,称为来电场景。在来电场景中,应用需要将来电信息上报给 Call Service Kit,系统会为用户展示来电横幅通知。用户可以在横幅上执行接听或拒接来电、静音与解除静音、挂断通话等操作。此外,Call Service Kit 还支持锁屏来电通知、多路来电通知等。
  • 去电场景:应用主动发起音/视频通话,称为去电场景。去电场景与来电场景大部分功能相似,但有以下几点区别:
    • 去电时,由于应用在前台,不需要展示横幅通知,只在屏幕左上角展示通话胶囊。
    • 去电不支持多路共存,即同一时间只能有 1 路去电存在。

与相关 Kit 的关系

当应用在后台时,如果有来电,需要 Push Kit(推送服务)先拉起应用主进程,应用才能给 Call Service Kit 上报来电。因此,Push Kit 是 Call Service Kit 实现后台来电通知的重要前置依赖。

约束和限制

设备限制

本 Kit 仅支持标准系统上运行,不支持模拟器。

能力支持设备
来电场景Phone、Tablet、PC/2in1、Wearable
去电场景Phone、Tablet、PC/2in1、Wearable
企业联系人信息来去电页面显示Phone、Tablet、PC/2in1、Wearable
企业服务信息来去电页面显示Phone、Tablet、PC/2in1、Wearable
应用跳转陌生号码和信息识别页面Phone、Tablet、PC/2in1、Wearable

不同设备形态对版本有不同要求:来电场景和去电场景从 6.0.0(20) 版本开始支持 Wearable 设备,6.1.1(24) 版本开始支持 PC/2in1 设备。

通话数量

  • 同一时间,最多支持 3 路应用内来电。
  • 同一时间,最多支持 1 路应用内去电。

这一限制要求开发者在设计通话逻辑时,必须考虑多路来电的并发处理,而去电则必须保证同一时间只有一路,避免冲突。

支持的国家/地区

Call Service Kit 提供的能力当前只支持中国境内(香港特别行政区、澳门特别行政区、中国台湾除外)。开发者需要根据应用发布区域判断是否可以使用该能力。

相关 Kit 的约束和限制

由于 Call Service Kit 依赖 Push Kit,还需要参考 Push Kit 的约束和限制。例如 Push Kit 的推送通道可用性、消息格式限制等都会影响来电通知的可靠送达。

模拟器支持情况

本 Kit 暂不支持模拟器,所有开发和调试必须在真机上进行,这要求开发者准备符合要求的 HarmonyOS 设备。

开发准备

在开通应用内通话服务之前,需要先参考“应用开发准备”完成基本准备工作,再继续进行以下开发活动。

开通 Push Kit(推送服务)

如与相关 Kit 的关系所述,开发者在开通 Call Service Kit 之前,需要开通 Push Kit(推送服务)。Push Kit 负责在应用处于后台时推送来电事件,从而唤醒应用进程并完成后续的上报流程。开通方法详见开通推送服务。

申请权限

开发者需要根据实际场景申请对应权限,具体申请方式请参见声明权限。

权限使用场景备注
ohos.permission.MICROPHONE用于在语音通话中,使用麦克风。必须申请。
ohos.permission.CAMERA用于在视频通话中,使用相机。如果应用支持视频通话业务,则需要申请。

权限申请需要在应用的配置文件中声明,并在运行时向用户请求授权,否则通话过程中无法正常采集音视频数据。

示例代码

该指南涉及到的示例代码均为片段,全量示例代码请参考:Samplecode。开发者可以在官方示例代码仓库中找到完整的集成案例,便于快速上手。

来电场景适配

场景介绍

应用接收到来自网络的音/视频通话,称为来电场景。来电场景的效果图展示如下:

  • 语音来电
  • 视频来电
  • 视频来电(不支持语音接听)
  • 通话中
  • 锁屏语音来电
  • 锁屏视频来电

来电场景下,即使应用处于后台,系统也能展示横幅通知,用户可直接在横幅上进行接听、拒接、静音等操作,无需进入应用。

约束与限制

来电场景支持 Phone、Tablet 设备,并从 6.0.0(20) 版本开始支持 Wearable 设备,6.1.1(24) 版本开始支持 PC/2in1 设备。同一时间最多支持 3 路来电,开发者需要处理好多路来电的排队与展示逻辑。

业务流程

来电场景包含接听流程图和拒接流程图。接听流程涉及用户点击接听、应用内建立通话连接、上报状态等步骤;拒接流程则相对简单,用户点击拒接后应用内终止通话并上报断开状态。

接口说明

来电场景的接口由 voipCall 提供。更多接口信息详见接口文档。

接口名描述
on(type: 'voipCallUiEvent', callback: Callback<VoipCallUiEventInfo>): void订阅 voipCallUiEvent 事件。
off(type: 'voipCallUiEvent', callback?: Callback<VoipCallUiEventInfo>): void取消订阅 voipCallUiEvent 事件。
reportIncomingCall(voipCallAttribute: VoipCallAttribute): Promise<ErrorReason>上报来电。
reportCallAudioEventChange(callId: string, callAudioEvent: CallAudioEvent): Promise<void>上报音频事件。
reportCallStateChange(callId: string, callState: VoipCallState): Promise<void>上报通话状态改变。
reportCallStateChange(callId: string, callState: VoipCallState, callType: VoipCallType): Promise<void>上报通话状态改变,并指定通话类型。

开发步骤

导入相关依赖

import { voipCall } from '@kit.CallServiceKit';
import { image } from '@kit.ImageKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

这些依赖分别提供通话服务接口、图像处理能力和日志能力,是开发的基础。

注册 voipCallUiEvent 事件

为了感知到用户在横幅通知上做的接听、挂断、静音与解除静音等操作,应用需要注册 voipCallUiEvent 事件。建议在上报来电之前注册,以确保事件不会遗漏。

voipCall.on('voipCallUiEvent', callback => {
  hilog.info(0x0000, 'CallDemo', 'Succeeded in registering voipCallUiEvent');
});

回调中会携带 VoipCallUiEventInfo 对象,包含 callIdvoipCallUiEvent 等字段,应用通过判断事件类型执行相应逻辑。

上报来电

应用内部建立通话连接之后,需要向 Call Service Kit 上报来电,并携带通话信息,详见 VoipCallAttribute。如果当时应用在后台,系统会展示来电横幅。

let voipCallAttribute: voipCall.VoipCallAttribute = {
  callId: 'callId123',
  voipCallType: voipCall.VoipCallType.VOIP_CALL_VOICE,
  userName: 'Callman',
  userProfile: image.createPixelMapSync(new ArrayBuffer(100), { size: { width: 90, height: 90 } }),
  abilityName: 'VoipCallAbility',
  voipCallState: voipCall.VoipCallState.VOIP_CALL_STATE_RINGING,
  showBannerForIncomingCall: true
};

voipCall.reportIncomingCall(voipCallAttribute).then(errorReason => {
  if (errorReason == voipCall.ErrorReason.ERROR_NONE) {
    hilog.info(0x0000, 'CallDemo', 'Succeeded in reporting the incoming call');
  } else {
    hilog.error(0x0000, 'CallDemo', 'Failed to report the incoming call: %{public}d', errorReason);
  }
});

VoipCallAttribute 中的各个字段含义:callId 为应用内通话唯一标识,需要保证与其他接口一致;voipCallType 指定语音或视频;userName 为来电人名称;userProfile 为头像图片;abilityName 为接听电话后需要拉起的 Ability 名称;voipCallState 来电时必须为 VOIP_CALL_STATE_RINGINGshowBannerForIncomingCall 控制是否展示来电横幅。

对于视频通话,可以通过参数 isVoiceAnswerSupported 指定是否允许语音接听,示例代码如下:

let voipCallAttribute: voipCall.VoipCallAttribute = {
  callId: 'callId123',
  voipCallType: voipCall.VoipCallType.VOIP_CALL_VIDEO,
  userName: 'Jack',
  userProfile: image.createPixelMapSync(new ArrayBuffer(100), { size: { width: 90, height: 90 } }),
  abilityName: 'VoipCallAbility',
  voipCallState: voipCall.VoipCallState.VOIP_CALL_STATE_RINGING,
  showBannerForIncomingCall: true,
  isVoiceAnswerSupported: false  // 视频通话不支持语音接听
};

用户接听

接收到来电之后,用户可以选择接听。接听有两种开发方式:上报两次状态、只上报一次状态。

上报两次状态(推荐)

以语音通话为例,应用在接收到 VOIP_CALL_EVENT_VOICE_ANSWER 事件回调之后,立即向 Call Service Kit 上报 VOIP_CALL_STATE_ANSWERED 状态,并同时执行应用内接听。在完成应用内接听之后,再向 Call Service Kit 上报 VOIP_CALL_STATE_ACTIVE 状态,系统会更新通话横幅。

voipCall.on('voipCallUiEvent', callback => {
  if (callback?.voipCallUiEvent == voipCall.VoipCallUiEvent.VOIP_CALL_EVENT_VOICE_ANSWER) {
    // 立即向 Call Service Kit 上报 answered 状态
    voipCall.reportCallStateChange(callback.callId, voipCall.VoipCallState.VOIP_CALL_STATE_ANSWERED);

    // ...在应用内完成接听

    // 应用内接听后,向 Call Service Kit 上报 active 状态
    voipCall.reportCallStateChange(callback.callId, voipCall.VoipCallState.VOIP_CALL_STATE_ACTIVE);
  }
});

上报两次状态的好处是:因为网络等原因,从用户点击接听到通话真正被接通的时间间隔可能比较长(比如 1s 左右)。如果横幅通知的样式不变,一直停留在来电状态,用户可能认为点击接听无响应,体验不好。上报两次状态可以在接听的过程中,在界面上给用户以反馈,提升交互流畅度。

只上报一次状态

以语音通话为例,应用在接收到 VOIP_CALL_EVENT_VOICE_ANSWER 事件回调之后,执行应用内接听。一直到完成应用内接听后,再向 Call Service Kit 上报 VOIP_CALL_STATE_ACTIVE 状态。

voipCall.on('voipCallUiEvent', callback => {
  if (callback?.voipCallUiEvent == voipCall.VoipCallUiEvent.VOIP_CALL_EVENT_VOICE_ANSWER) {
    // ...在应用内完成接听

    // 应用内接听后,向 Call Service Kit 上报通话状态
    voipCall.reportCallStateChange(callback.callId, voipCall.VoipCallState.VOIP_CALL_STATE_ACTIVE);
  }
});

这种方式实现简单,但在网络延迟较大时可能让用户感觉响应不及时。

用户拒接

如果用户在横幅通知上点击拒接,则应用在接收到 VOIP_CALL_EVENT_REJECT 事件回调之后,在应用内完成拒接,然后向 Call Service Kit 上报 VOIP_CALL_STATE_DISCONNECTED 状态,系统会取消横幅通知。

voipCall.on('voipCallUiEvent', callback => {
  if (callback?.voipCallUiEvent == voipCall.VoipCallUiEvent.VOIP_CALL_EVENT_REJECT) {
    // ...应用内完成拒接

    // 向 Call Service Kit 上报通话状态
    voipCall.reportCallStateChange(callback.callId, voipCall.VoipCallState.VOIP_CALL_STATE_DISCONNECTED);
  }
});

拒接之后,应用可跳过静音/挂断等后续步骤。

静音与解除静音

在通话过程中,用户可以根据需要静音或解除静音。以静音为例,用户在横幅上点击静音,Call Service Kit 会给应用回调 VOIP_CALL_EVENT_MUTED 事件。应用在完成静音后,应向 Call Service Kit 上报 AUDIO_EVENT_MUTED 音频状态。

voipCall.on('voipCallUiEvent', callback => {
  if (callback?.voipCallUiEvent == voipCall.VoipCallUiEvent.VOIP_CALL_EVENT_MUTED) {
    // 向 Call Service Kit 上报静音
    voipCall.reportCallAudioEventChange(callback.callId, voipCall.CallAudioEvent.AUDIO_EVENT_MUTED);
  } else if (callback?.voipCallUiEvent == voipCall.VoipCallUiEvent.VOIP_CALL_EVENT_UNMUTED) {
    // 向 Call Service Kit 上报解除静音
    voipCall.reportCallAudioEventChange(callback.callId, voipCall.CallAudioEvent.AUDIO_EVENT_UNMUTED);
  }
});

音频事件上报后,系统会更新横幅上的静音状态图标,用户可直观看到当前麦克风状态。

用户挂断

用户在横幅点击挂断,Call Service Kit 会给应用回调 VOIP_CALL_EVENT_HANGUP 事件。应用收到该事件后,应在应用内完成挂断,然后向 Call Service Kit 上报 VOIP_CALL_STATE_DISCONNECTED 状态,系统会取消横幅通知。

voipCall.on('voipCallUiEvent', callback => {
  if (callback?.voipCallUiEvent == voipCall.VoipCallUiEvent.VOIP_CALL_EVENT_HANGUP) {
    // ...应用内完成挂断

    // 向 Call Service Kit 上报通话状态
    voipCall.reportCallStateChange(callback.callId, voipCall.VoipCallState.VOIP_CALL_STATE_DISCONNECTED);
  }
});

解除事件注册

通话结束后,应用不再需要感知到用户在通话横幅上的操作,可以解除 voipCallUiEvent 事件。

voipCall.off('voipCallUiEvent', callback => {
  hilog.info(0x0000, 'CallDemo', `Succeeded in unRegistering voipCallUiEvent, callId: ${callback.callId}`);
});

及时解除事件监听可以避免内存泄漏和不必要的回调处理。

去电场景适配

场景介绍

应用主动发起音/视频通话,称为去电场景。去电场景由于应用在前台,不需要横幅通知,只在屏幕左上角展示通话胶囊。去电场景的效果图展示如下:

  • 语音去电(正在呼叫)
  • 语音去电(通话中)
  • 视频去电(正在呼叫)
  • 视频去电(通话中)

去电场景中,用户也可以拉起通知中心面板,在实况窗横幅上做静音与解除静音、挂断通话等操作。去电实况窗通知展示:

  • 去电实况窗通知(正在呼叫)
  • 去电实况窗通知(通话中)

约束与限制

去电场景支持 Phone、Tablet 设备,并从 6.0.0(20) 版本开始支持 Wearable 设备,6.1.1(24) 版本开始支持 PC/2in1 设备。同一时间仅支持 1 路去电,应用需确保不重复发起去电。

业务流程

去电场景的业务流程与来电场景类似,包括上报去电、等待对端接听、通话中状态管理、静音与挂断处理等环节。

接口说明

去电场景的接口由 voipCall 提供。更多接口信息详见接口文档。

接口名描述
on(type: 'voipCallUiEvent', callback: Callback<VoipCallUiEventInfo>): void订阅 voipCallUiEvent 事件。
off(type: 'voipCallUiEvent', callback?: Callback<VoipCallUiEventInfo>): void取消订阅 voipCallUiEvent 事件。
reportOutgoingCall(voipCallAttribute: VoipCallAttribute): Promise<ErrorReason>上报去电。
reportCallAudioEventChange(callId: string, callAudioEvent: CallAudioEvent): Promise<void>上报音频事件。
reportCallStateChange(callId: string, callState: VoipCallState): Promise<void>上报通话状态改变。
reportCallStateChange(callId: string, callState: VoipCallState, callType: VoipCallType): Promise<void>上报通话状态改变,并指定通话类型。

开发步骤

导入相关依赖

import { voipCall } from '@kit.CallServiceKit';
import { image } from '@kit.ImageKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

注册 voipCallUiEvent 事件

为了感知到用户在实况窗上做的静音与解除静音、挂断通话等操作,应用需要注册 voipCallUiEvent 事件。建议在上报去电之前注册。

voipCall.on('voipCallUiEvent', callback => {
  hilog.info(0x0000, 'CallDemo', 'Succeeded in registering voipCallUiEvent');
});

上报去电

应用内部建立通话连接之后,需要向 Call Service Kit 上报去电,并携带通话信息,详见 VoipCallAttribute。系统会在屏幕左上角展示通话胶囊。

以语音去电为例:

let voipCallAttribute: voipCall.VoipCallAttribute = {
  callId: 'callId123',
  voipCallType: voipCall.VoipCallType.VOIP_CALL_VOICE,
  userName: 'Jack',
  userProfile: image.createPixelMapSync(new ArrayBuffer(100), { size: { width: 90, height: 90 } }),
  abilityName: 'VoipCallAbility',
  voipCallState: voipCall.VoipCallState.VOIP_CALL_STATE_DIALING,  // 去电的状态必须是 DIALING
  showBannerForIncomingCall: true
};

voipCall.reportOutgoingCall(voipCallAttribute).then(errorReason => {
  if (errorReason == voipCall.ErrorReason.ERROR_NONE) {
    hilog.info(0x0000, 'CallDemo', 'Succeeded in reporting the outgoing call');
  } else {
    hilog.error(0x0000, 'CallDemo', 'Failed to report the outgoing call: %{public}d', errorReason);
  }
});

注意:上报去电时,通话状态必须是 VOIP_CALL_STATE_DIALING,否则 Call Service Kit 会认为参数不合法而返回 1007200001 错误码。

对端接听

如果对端接听,应用需要向 Call Service Kit 上报通话状态 VOIP_CALL_STATE_ACTIVE。系统会更新通话胶囊,开始展示通话计时。

// ...应用服务器收到对端接听的消息
let answeredCallId = '123456'; // 与 reportOutgoingCall 携带 callId 一致,应用内通话唯一 ID。

voipCall.reportCallStateChange(answeredCallId, voipCall.VoipCallState.VOIP_CALL_STATE_ACTIVE);

静音与解除静音

去电场景中,用户也可以拉起通知中心面板,在实况窗通知上执行静音或解除静音。开发方法与来电场景相同,详见来电场景:静音与解除静音。

用户挂断

去电场景中,用户也可以拉起通知中心面板,在实况窗通知上点击挂断。开发方式与来电场景相同,详见来电场景:用户点击挂断。

解除事件注册

通话结束后,可以解除 voipCallUiEvent 事件。

voipCall.off('voipCallUiEvent', callback => {
  hilog.info(0x0000, 'CallDemo', `Succeeded in unRegistering voipCallUiEvent, callId: ${callback.callId}`);
});

企业联系人信息来去电页面显示适配

本功能仅供企业应用开发者接入。

场景介绍

来去电时,页面显示已安装企业应用的联系人信息,方便用户识别来去电人信息,快速回应,增强企业内部沟通效率。

说明:来去电页面或横幅仅展示一个联系人信息,对于多个应用里存在相同联系人的情况,按照应用包名的字典序排序,展示首个查询结果。

接口说明

接口名描述
onQueryCallerInfo(phoneNumber: string): Promise<CallerInfo>查询联系人信息接口。
queryNumberIdentifySwitchState(context: Context): SwitchState查询陌生号码与信息识别总开关状态以及调用该接口的应用号码识别开关状态。
isSupportEnterpriseNumberIdentify(context: Context): Promise<boolean>查询是否已开通企业来电显示权限。

申请接入

企业来电显示能力使用受限,如需接入,需要在 AGC 网站申请对应权限。

  1. 登录 AGC 网站,选择“开发与服务”。
  2. 在项目列表选择项目,并在应用列表下选择需要申请企业来电显示的应用。
  3. 进入“项目设置 > 开放能力管理”页面,点击“企业来电显示”对应的“申请”。
  4. 根据实际业务需求在弹框中填写对应信息,完成后点击右上角“提交”,提交后将在 3 个工作日内回复。

替换调试 Profile

当企业来电显示能力申请成功后,需要重新申请调试 Profile,并且在 DevEco Studio 中替换新申请的调试 Profile。

开发步骤

创建 ExtensionAbility 并复写 onQueryCallerInfo

在工程内创建一个 ExtensionAbility 类型的自定义组件并继承 CallerInfoQueryExtensionAbility,完成 onQueryCallerInfo 方法的复写。

说明:由于调用 onQueryCallerInfo 方法时,系统先创建应用的 AbilityStage 实例,请勿在 AbilityStage 中添加过于复杂耗时的逻辑,避免调用超时。

import { CallerInfoQueryExtensionAbility, CallerInfo } from '@kit.CallServiceKit';

export default class EntryCallerInfoQueryExtAbility extends CallerInfoQueryExtensionAbility {
  // 来去电时由系统通话应用主动调用该接口查询企业联系人信息
  async onQueryCallerInfo(phoneNumber: string): Promise<CallerInfo> {
    return new Promise<CallerInfo>((resolve, reject) => {
      let isSuccess = true;
      // 在此处实现根据号码查询企业联系人的业务逻辑
      if (isSuccess) {
        // 查询成功,返回结果
        resolve({
          contactName:'xxxx',
          employeeId:'xxxx',
          department:'xxxx',
          position:'xxxx'
        });
      } else {
        // 查询失败,返回错误原因
        reject('error reason');
      }
    });
  }
}

CallerInfo 对象包含联系人姓名、员工 ID、部门和职位等信息,可根据企业实际数据结构灵活返回。

在 module.json5 中注册 extensionAbilities

{
  "extensionAbilities": [
    {
      "name": "EntryCallerInfoQueryExtAbility",
      "srcEntry": "./ets/callerinfoquery/EntryCallerInfoQueryExtAbility.ets",
      "type": "callerInfoQuery"
    }
  ]
}
  • type 标签需设为 "callerInfoQuery",表示该拓展类型为 CallerInfoQueryExtensionAbility
  • srcEntry 标签表示上述 ExtensionAbility 组件所对应的代码路径。

调试

在调试设备上,前往“电话”,点击右上角的“更多”图标,前往“设置”>“陌生号码和信息识别”,或者通过应用跳转陌生号码和信息识别页面,打开对应企业应用的号码识别功能开关,进行调试。

企业服务信息来去电页面显示适配

从 6.1.1(24) 版本开始,新增支持企业服务信息来去电页面显示。本功能仅供企业应用开发者接入。

场景介绍

来去电时,通过对端手机号,查询获取对应的企业服务信息,方便企业员工快速了解通话号码相关的服务数据。例如快递员在给客户打电话或者接电话时可以显示客户的快递信息,包括单号、地址等。

说明:来去电页面仅展示第一条企业服务信息数据,对于多个应用里同时存在数据时,按照应用包名的字典序排序,展示首个查询结果。

接口说明

接口名描述
queryNumberIdentifySwitchState(context: Context): SwitchState查询陌生号码与信息识别总开关状态以及调用该接口的应用号码识别开关状态。
onQueryBusinessServiceData(phoneNumber: string): Promise<Array<BusinessServiceData>>查询企业服务信息。

申请接入

企业服务信息展示能力使用受限,如需接入,需要在 AGC 网站申请对应权限。

  1. 登录 AGC 网站,选择“开发与服务”。
  2. 在项目列表选择项目,并在应用列表下选择需要申请企业服务信息展示的应用。
  3. 进入“项目设置 > 开放能力管理”页面,点击“企业服务信息展示”对应的“申请”。
  4. 根据实际业务需求在弹框中填写对应信息,完成后点击右上角“提交”,提交后将在 3 个工作日内完成审核,审核结果请在互动中心查看。

替换调试 Profile

当企业服务信息展示能力申请成功后,需要重新申请 Profile,并且在 DevEco Studio 中替换新申请的调试 Profile。

说明:在应用正式发布前,需要替换成发布 Profile。

开发步骤

创建 ExtensionAbility 并复写 onQueryBusinessServiceData

在工程内创建一个 ExtensionAbility 类型的自定义组件并继承 CallerInfoQueryExtensionAbility,完成 onQueryBusinessServiceData 方法的复写。

说明:由于调用 onQueryBusinessServiceData 方法时,系统先创建应用的 AbilityStage 实例,请勿在 AbilityStage 中添加过于复杂耗时的逻辑,避免调用超时。

import { CallerInfoQueryExtensionAbility, numberIdentify } from '@kit.CallServiceKit';

export default class EntryBusinessServiceDataQueryExtAbility extends CallerInfoQueryExtensionAbility {
  // 来去电时由系统通话应用主动调用该接口查询企业联系人信息
  async onQueryBusinessServiceData(phoneNumber: string): Promise<Array<numberIdentify.BusinessServiceData>> {
    return new Promise<Array<numberIdentify.BusinessServiceData>>((resolve, reject) => {
      let isSuccess = true;
      // 在此处实现根据号码查询企业服务信息的业务逻辑
      if (isSuccess) {
        // 查询成功,返回结果
        resolve([{
          type: numberIdentify.BusinessServiceType.DELIVERY,
          delivery: {
            customerName: "xxxx",
            deliveryNumber: "xxxx",
            deliveryStatus: "xxxx",
            deliveryAddress: "xxxx",
            deliveryTimeout: "xxxx",
            deliveryStatusColor: numberIdentify.DeliveryStatusColor.GREEN
          }
        }]);
      } else {
        // 查询失败,返回错误原因
        reject("error reason");
      }
    });
  }
}

BusinessServiceData 支持多种业务类型(如快递),每种类型包含对应的数据字段,可根据企业业务需求返回相应的服务信息。

在 module.json5 中注册 extensionAbilities

{
  "extensionAbilities": [
    {
      "name": "EntryBusinessServiceDataQueryExtAbility",
      "srcEntry": "./ets/businessservicedataquery/EntryBusinessServiceDataQueryExtAbility.ets",
      "type": "callerInfoQuery"
    }
  ]
}
  • type 标签需设为 "callerInfoQuery",表示该拓展类型为 CallerInfoQueryExtensionAbility
  • srcEntry 标签表示上述 ExtensionAbility 组件所对应的代码路径。

调试

在调试设备上,前往“电话”,点击右上角的“更多”图标,前往“设置”>“陌生号码和信息识别”,或者通过应用跳转陌生号码和信息识别页面,打开对应陌生号码信息识别功能开关,再根据需要打开企业服务信息展示对应企业的开关,进行调试。

应用跳转陌生号码和信息识别页面

从 6.1.0(23) 版本开始,新增支持从应用直接跳转到“电话 > 更多 > 设置 > 陌生号码和信息识别”。

通过 Deep Linking 方式应用可以直接跳转“陌生号码和信息识别”页面。

以使用 openLink 实现应用跳转举例,在 openLink 接口的 link 字段中传入目标应用的 URL 信息,并将 options 字段中的 appLinkingOnly 配置为 false,跳转的 URL 固定为 "callsetting://number_identity"

其他跳转方式参考使用 Deep Linking 实现应用间跳转拉起方应用实现应用跳转章节。

import { common, OpenLinkOptions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Entry
@Component
struct Index {
  build() {
    Button('start link', { type: ButtonType.Capsule, stateEffect: true })
      .width('87%')
      .height('5%')
      .margin({ bottom: '12vp' })
      .onClick(() => {
        let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
        let link: string = 'callsetting://number_identity';
        let openLinkOptions: OpenLinkOptions = {
          appLinkingOnly: false
        };
        try {
          context.openLink(link, openLinkOptions)
            .then(() => {
              hilog.info(0, 'TAG','Successed in opening link.');
            }).catch((err: BusinessError) => {
              hilog.error(0, 'TAG',`Failed to open link. Code is ${err.code}, message is ${err.message}`);
            });
        } catch (paramError) {
          hilog.error(0, 'TAG',`Failed to start link. Code is ${paramError.code}, message is ${paramError.message}`);
        }
      })
  }
}

常见问题与解决

来电横幅无法拉起

问题现象:调用 voipCall.reportIncomingCall 上报来电信息,但来电横幅无法显示。

解决措施

  1. 检查应用是否已开启通知权限。通知权限是横幅展示的前提,未授权时系统不会显示任何通知。
  2. 检查是否继承 UIAbility,调用 pushService.receiveMessage 并在接收后调用上报接口。后台来电依赖 Push Kit 唤醒应用,如果未正确处理推送消息,来电上报可能不会执行。
  3. 来电信息中获取的 callId,上报给通话服务接口的 callId,二者应该保持一致。不一致会导致系统无法关联通话记录,横幅可能不展示。
  4. 检查构造的 callInfo 信息是否有参数错误,参考开发步骤。例如 voipCallState 必须为 VOIP_CALL_STATE_RINGINGabilityName 必须为有效的 Ability 名称。
  5. 如还未解决,请通过在线提单提交问题,华为支持人员会及时处理。

来电横幅通知头像无法显示

问题现象:来电过程中,横幅通知展示,但头像无法正常显示。

解决措施

  1. 保证头像图片大小在 196608 bit 以内。过大图片可能被系统拒绝或裁剪。
  2. 支持传入的最大图片大小为 221 x 221 像素,推荐传入的图片大小为 112 x 112 像素。建议使用推荐尺寸以获得最佳显示效果。
  3. 如还未解决,请通过在线提单提交问题,华为支持人员会及时处理。

总结

Call Service Kit 为 HarmonyOS 应用提供了完整的应用内通话管理能力,覆盖来电、去电两大核心场景,并支持企业联系人信息展示、企业服务信息展示以及跳转陌生号码识别页面等扩展能力。开发者在适配过程中需要完成 Push Kit 开通、权限申请、事件订阅、通话状态上报等步骤,并注意设备限制、通话数量限制、地区限制以及企业能力的申请流程。通过合理使用 Call Service Kit,可以显著提升应用内通话的用户体验,实现系统级的通话交互界面,减少开发工作量。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐