HarmonyOS 6.0 Call Service Kit for Wearables: How to Extend VoIP Calling from Phone to Smartwatch

[AI Readability Summary] HarmonyOS 6.0 extends Call Service Kit’s VoIP capabilities to Wearable devices, allowing developers to use the same voipCall API across phones, tablets, and smartwatches. It addresses wearable-side incoming call handling, outgoing call reporting, state synchronization, and foreground/background activation. Keywords: HarmonyOS 6.0, voipCall, Wearable.

Technical specifications are easy to verify at a glance

Parameter Description
Platform language ArkTS / TypeScript
Core protocols VoIP, Push-based wake-up, system call UI event callbacks
Version baseline HarmonyOS 6.0.0(20) / API 21
Supported devices Phone, Tablet, Wearable
Calling capabilities Incoming calls, outgoing calls, state changes, UI interaction events
Core dependencies @kit.CallServiceKit, @kit.ImageKit, @kit.PerformanceAnalysisKit
Regional availability Currently supported in mainland China
Concurrency limits Up to 3 incoming calls and 1 outgoing call

Illustration AI Visual Insight: The image shows the HarmonyOS Call Service Kit calling interface in a multi-device scenario, highlighting system-level incoming call presentation, wearable notification layouts, and a consistent cross-device experience powered by a unified API.

Wearable support brings VoIP into true full-scenario collaboration

The key change in HarmonyOS 6.0 is not the introduction of a separate watch-specific API. Instead, it extends the existing voipCall capability to Wearable devices. For developers, this means you do not need to rewrite the business-layer call model. You only need to add device capability checks, UI constraints, and lifecycle handling.

For users, the value is even more direct: when the phone is not nearby, the smartwatch can still receive or initiate a VoIP call. This capability moves the smartwatch beyond being a simple notification mirror and turns it into a device that can independently carry the communication flow.

You must confirm version and capability boundaries first

Full Wearable support starts with HarmonyOS 6.0.0(20), which corresponds to API 21. If the device version or SDK version is below this baseline, the code may still compile, but the system incoming call banner or UI event callbacks may not work correctly.

Capability scenario Supported devices
Incoming call reporting Phone, Tablet, Wearable
Outgoing call reporting Phone, Tablet, Wearable
Enterprise contact display Phone, Tablet, PC/2in1, Wearable

This matrix makes two points clear. First, smartwatch support is not a reduced or limited implementation. Second, enterprise communication apps can reuse the same capability to display contact identity information.

The voipCall module is the core entry point for Wearable calling

voipCall connects in-app VoIP sessions to the system call interaction layer. Its core responsibilities include reporting incoming calls, reporting outgoing calls, synchronizing call state, and listening for answer, reject, hang-up, and mute actions from the system UI.

Core enums define the state machine design

export enum VoipCallType {
  VOIP_CALL_VOICE = 0, // Voice call
  VOIP_CALL_VIDEO = 1  // Video call
}

export enum VoipCallState {
  VOIP_CALL_STATE_IDLE = 0,          // Idle
  VOIP_CALL_STATE_RINGING = 1,       // Ringing
  VOIP_CALL_STATE_ACTIVE = 2,        // Active
  VOIP_CALL_STATE_HOLDING = 3,       // On hold
  VOIP_CALL_STATE_DISCONNECTED = 4,  // Disconnected
  VOIP_CALL_STATE_DIALING = 5,       // Dialing
  VOIP_CALL_STATE_ANSWERED = 6,      // Answering
  VOIP_CALL_STATE_DISCONNECTING = 7  // Disconnecting
}

These enums define the standard state machine for a VoIP session from setup to termination. They form the foundation for call synchronization and failure recovery.

The timing of UI event subscription matters more than reporting itself

The most common pitfall is not reportIncomingCall(), but the subscription order for voipCallUiEvent. If the app reports an incoming call before subscribing to events, the user’s answer or reject action on the system banner may be lost.

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

function subscribeVoipEvent() {
  voipCall.on('voipCallUiEvent', (eventInfo) => {
    // Subscribe early to ensure user actions on the system banner are not lost
    hilog.info(0x0000, 'CallDemo', `event=${eventInfo.event}, callId=${eventInfo.callId}`);
  });
}

This code subscribes to system UI events in advance so user actions can reliably flow back to the business layer.

Incoming and outgoing call flows still follow a unified model on smartwatches

The incoming call flow usually has four steps: subscribe to events, report the incoming call, handle the user action, and continuously report call state. The outgoing call flow is simpler. The main difference is that it calls reportOutgoingCall(), and the system displays a call capsule instead of an incoming call banner.

Incoming call reporting requires complete call attributes

import { voipCall } from '@kit.CallServiceKit';

async function reportIncomingCall(callId: string, callerName: string, avatar: PixelMap) {
  const attr: voipCall.VoipCallAttribute = {
    callId,
    voipCallType: voipCall.VoipCallType.VOIP_CALL_VOICE,
    userName: callerName,
    userProfile: avatar,
    abilityName: 'EntryAbility' // Page entry launched after the user answers
  };

  // Report the incoming call to the system so it can display the incoming call banner
  return await voipCall.reportIncomingCall(attr);
}

This code connects an app-side incoming call session to the system call entry point and specifies which UIAbility should be opened after the user answers.

State synchronization determines whether the system UI is trustworthy

System display does not mean the call is actually established. After the user taps Answer, the app still needs to establish the media channel itself and then call the state reporting API to synchronize with the system. Otherwise, the system UI and the real session state will drift apart.

async function reportCallState(callId: string, state: voipCall.VoipCallState) {
  // Sync immediately after a call state change to avoid inconsistency between system UI and app state
  await voipCall.reportCallStateChange(callId, state);
}

This code continuously maps the business-layer state machine to the system layer so the smartwatch UI remains accurate.

You must actively restore the app to the foreground after answering in the background

The voipCallUiEvent callback does not automatically bring the app back to the foreground. This is especially important on Wearable devices. After the user answers from the banner, the app UI may still remain in the background unless you explicitly restore the window.

private async handleVoiceAnswer(callId: string): Promise
<void> {
  await this.establishVoipConnection(callId); // Establish the audio/video channel
  await voipCall.reportCallStateChange(
    callId,
    voipCall.VoipCallState.VOIP_CALL_STATE_ACTIVE
  );

  const windowStage = AppStorage.get<window.WindowStage>('windowStage');
  if (windowStage) {
    const mainWindow = await windowStage.getMainWindow();
    await windowStage.restoreWindow(mainWindow); // Actively restore the foreground window
  }
}

This code fixes a common issue where the call is successfully answered but the app does not become visible. It is a critical step in closing the wearable experience loop.

Smartwatch adaptation is more about constraints than APIs

The main challenge on Wearable devices is not API differences, but resource limits, screen size, and system behavior. Smartwatch screens are smaller, batteries are more sensitive, and foreground/background switching happens more frequently. You should treat these constraints as first-class concerns during development.

You should narrow device capabilities and image sizes early

import { bundleManager, common } from '@kit.AbilityKit';

async function checkVoipSupport(context: common.Context): Promise
<boolean> {
  // Confirm at runtime whether the system exposes VoIP calling capability
  return await bundleManager.canIUse('SystemCapability.Telephony.VoipCallManager');
}

This code checks whether the target device exposes the required system capability before runtime execution, which helps you avoid direct failures on unsupported devices.

These limitations directly affect production implementation

  • The system supports up to 3 simultaneous incoming calls and 1 outgoing call.
  • The capability currently supports only mainland China.
  • Background incoming calls depend on Push Kit to wake the main process first.
  • On smartwatches, the incoming call banner and call capsule UI must adapt to round screens or small square displays.

If your app targets enterprise IM, customer service, or meeting scenarios, you should add these constraints to the test matrix early instead of waiting until the final integration phase.

Developers should treat Wearable calling as a state-driven system

From an architectural perspective, HarmonyOS 6.0 does not change the essence of VoIP. The system provides a unified entry point and interaction layer, while the app remains responsible for real session establishment, audio routing, failure recovery, and lifecycle management. Wearable support simply extends this mechanism to a lighter class of device.

Therefore, the best practice is not to copy phone code directly to a smartwatch. Instead, abstract a unified call state machine and then layer UI and resource strategies by device form factor. This approach gives you both high code reuse and strong stability.

FAQ: The 3 questions developers ask most often

Q1: Why can I see the incoming call banner on the watch, but the app never receives the answer event?

A: In most cases, voipCallUiEvent was subscribed too late. You must call voipCall.on() before the business flow starts. Do not wait until after the incoming call has been reported.

Q2: Why doesn’t the app open automatically after the user taps Answer on the watch?

A: The event callback does not automatically bring the app to the foreground. You need to explicitly call windowStage.restoreWindow() inside the callback to restore the window.

Q3: Why do background incoming calls sometimes not appear at all?

A: Background scenarios depend on Push Kit to wake the main process first, so the app can continue and call reportIncomingCall(). If the push delivery chain is not working, the system cannot display the complete incoming call flow.

Core Summary: This article systematically reconstructs HarmonyOS 6.0 Call Service Kit support for Wearable VoIP, focusing on the API 21 baseline, the voipCall event model, incoming and outgoing call reporting flows, smartwatch UI and lifecycle adaptation, and key engineering constraints such as Push Kit, regional availability, and concurrency limits.