HarmonyOS SDK Guide
HarmonyOS Next SDK install, join and capability boundaries.
The HarmonyOS SDK has the ArkTS RtcEngine shape; it is isomorphic to Android (joinChannel + IRtcEngineEventHandler callbacks) but runs on the ArkTS runtime of HarmonyOS NEXT.
Prerequisites
- DevEco Studio 5.0+, HarmonyOS SDK API 12+, the
ohpmpackage manager. - Declare
ohos.permission.CAMERAandohos.permission.MICROPHONEinmodule.json5; the user grants them on first use. - An
appIdand a token service (see Enable Services and Get Credentials).
Installation
# planned ohpm coordinates (not published yet)
ohpm install @nimeet/rtc-harmonyosGet a token
Your backend issues the token; the ArkTS client only holds { appId, rtcToken, rtcUid }. Never package appCertificate or customerSecret into the HAP (a HAP can be unpacked and read).
Join a channel
import { RtcEngine, RtcEngineConfig, ChannelProfileType, ClientRoleType } from '@nimeet/rtc-harmonyos';
const engine: RtcEngine = createRtcEngine();
engine.initialize(new RtcEngineConfig(appId));
engine.registerEventHandler({
onJoinChannelSuccess: (connection, elapsed) => console.info('joined'),
onUserJoined: (connection, uid, elapsed) => console.info('remote', uid),
onUserOffline: (connection, uid, reason) => console.info('left', uid),
onTokenPrivilegeWillExpire: (token) => refreshToken(),
onError: (err, msg) => console.error(`rtc ${err}: ${msg}`),
});
engine.setChannelProfile(ChannelProfileType.ChannelProfileLiveBroadcasting);
engine.enableVideo();
engine.startPreview();
engine.joinChannelWithOptions(token, 'weekly-sync', 10001, {
clientRoleType: ClientRoleType.ClientRoleBroadcaster,
autoSubscribeAudio: true,
autoSubscribeVideo: true,
});Publishing and subscribing
engine.muteLocalAudioStream(true);
engine.muteLocalVideoStream(true);
engine.enableLocalVideo(false);
engine.updateChannelMediaOptions(options);Screen sharing: startScreenCapture(parameters) / stopScreenCapture() / updateScreenCaptureParameters(parameters); it needs the screen-recording permission (granted through a system dialog).
Events
IRtcEngineEventHandler exposes 51 on* methods: onJoinChannelSuccess, onUserJoined, onUserOffline, onFirstRemoteVideoDecoded, onTokenPrivilegeWillExpire, onError, onConnectionStateChanged.
Error handling
- Synchronous methods return a numeric error code;
0means success and a negative value is an Agora error number; - Asynchronous errors arrive through
onError; - Unimplemented capabilities return
-4(ERR_NOT_SUPPORTED).
Troubleshooting
| Symptom | Cause | Handling |
|---|---|---|
| Module not found at compile time | ohpm is not installed / not synced | Sync the project in DevEco |
| Crash on capture because of permissions | CAMERA/MICROPHONE were not requested | Add the permissions to module.json5 and handle the user's refusal |
| Screen sharing fails | Screen recording was not authorized by the system | Send the user to the system settings to grant it |
| Callbacks never fire | The handler was never registered or has been collected | Register in the page's aboutToAppear and unregister in aboutToDisappear |
| The app is frozen in the background | Application lifecycle limits | Use a long-running task / foreground service capability |
Next steps
- Full interfaces and overloads: API reference for this platform
- Error codes and troubleshooting: Error code table, FAQ
- Issue tokens on your server: Token authentication
Platform information
| Item | value |
|---|---|
| Platform | HarmonyOS(ArkTS) |
| Language | ArkTS |
| SDK package | @nimeet/rtc-harmonyos |
| Interface version | 4.6.3 |
| Compatible Agora API | Agora harmonyos API |
The public interfaces are aligned with the Agora harmonyos API; installation and runtime requirements are listed under Prerequisites above.
Availability
This platform's SDK: Generally available. The examples use the public API; runtime capability follows the published SDK package.
join-channel flow
The method names, parameter types and return values match the API reference for the same platform. Where a method has several overloads, the most common one is shown here; see the API reference for all overloads.
| Step | Interface | Method | Overload count |
|---|---|---|---|
| Create instance / initialize | __unattributed__ | create | 1 |
| Renew the Token | IAgoraMusicContentCenter | renewToken | 1 |
| enable video and local preview | RtcEngine | enableVideo | 1 |
| Join a channel | RtcEngine | joinChannel | 1 |
| Leave a channel | RtcEngine | leaveChannel | 1 |
| subscribe to remote media | RtcEngine | muteRemoteAudioStream | 1 |
| Channel scenarios | RtcEngine | setChannelProfile | 1 |
| switch roles | RtcEngine | setClientRole | 1 |
| bind the local video | RtcEngine | setupLocalVideo | 1 |
create(config: RtcEngineConfig): RtcEngine
renewToken(token: string): number
enableVideo(): number
joinChannel(key: string, channel: string, optionalInfo: string, uid: number): number
leaveChannel(options?: LeaveChannelOptions): number
muteRemoteAudioStream(uid: number, muted: boolean): number
setChannelProfile(profile: number): number
setClientRole(role: number, options?: ClientRoleOptions): number
setupLocalVideo(canvas: VideoCanvas): numberEvents and callbacks
Callbacks are registered on IRtcEngineEventHandler; naming differs by platform, and the full list is in the API reference for the same platform.
| Callbacks | Signature | Purpose |
|---|---|---|
onConnectionStateChanged | onConnectionStateChanged(state: Constants.ConnectionState, reason: Constants.ConnectionChangedReason): void | join result / connection-state changes:update the UI accordingly and decide whether to reconnect. |
onUserJoined | onUserJoined(uid: number, elapse: number): void | Remote user joined:allocate the frame container. |
onRemoteVideoStateChanged | onRemoteVideoStateChanged(uid: number, state: Constants.RemoteVideoStreamState, reason: Constants.RemoteVideoStreamReason, elapsed: number): void | Remote video status:it can render once the first frame is decoded. |
onUserOffline | onUserOffline(uid: number, reason: number): void | Remote user left:release the container and subscription. |
onRequestToken | onRequestToken(): void | Token expiring soon:call the server to renew, then `renewToken`. |
onError | onError(err: Constants.ErrorCode, message: string): void | Runtime errors:`err` is an Agora error number, route by the error-code table. |
onNetworkQuality | onNetworkQuality(uid: number, txQuality: Constants.NetworkQuality, rxQuality: Constants.NetworkQuality): void | Network quality:report to Analytics or prompt the user. |
| Interface | event name | listener parameters |
|---|---|---|
IMediaPlayerObserver | onPlayerCacheStats | onPlayerCacheStats?:(stats:CacheStatistics |
Error codes
| Constant | value |
|---|---|
ERR_ABORTED | 20 |
ERR_ADM_GENERAL_ERROR | 1005 |
ERR_ADM_INIT_PLAYOUT | 1008 |
ERR_ADM_INIT_RECORDING | 1011 |
ERR_ADM_START_PLAYOUT | 1009 |
ERR_ADM_START_RECORDING | 1012 |
ERR_ADM_STOP_PLAYOUT | 1010 |
ERR_ADM_STOP_RECORDING | 1013 |
ERR_ALREADY_IN_USE | 19 |
ERR_BITRATE_LIMIT | 115 |
ERR_BUFFER_TOO_SMALL | 6 |
ERR_CONNECTION_INTERRUPTED | 111 |
ERR_CONNECTION_LOST | 112 |
ERR_DATASTREAM_DECRYPTION_FAILED | 122 |
ERR_DECRYPTION_FAILED | 120 |
ERR_ENCRYPTED_STREAM_NOT_ALLOWED_PUBLISH | 130 |
ERR_FAILED | 1 |
ERR_INIT_NET_ENGINE | 21 |
ERR_INVALID_APP_ID | 101 |
ERR_INVALID_ARGUMENT | 2 |
ERR_INVALID_CHANNEL_NAME | 102 |
ERR_INVALID_TOKEN | 110 |
ERR_INVALID_USER_ACCOUNT | 134 |
ERR_JOIN_CHANNEL_REJECTED | 17 |
ERR_LEAVE_CHANNEL_REJECTED | 18 |
ERR_LOAD_MEDIA_ENGINE | 1001 |
ERR_NOT_INITIALIZED | 7 |
ERR_NOT_IN_CHANNEL | 113 |
ERR_NOT_READY | 3 |
ERR_NOT_SUPPORTED | 4 |
ERR_NO_PERMISSION | 9 |
ERR_OK | 0 |
ERR_REFUSED | 5 |
ERR_RESOURCE_LIMITED | 22 |
ERR_SIZE_TOO_LARGE | 114 |
ERR_TIMEDOUT | 10 |
ERR_TOKEN_EXPIRED | 109 |
ERR_TOO_MANY_DATA_STREAMS | 116 |
ERR_VDM_CAMERA_NOT_AUTHORIZED | 1501 |
RtcEngine | null |
the platform REST layer uses REST error codes;the SDK layer maps connection/authentication failures to Agora error numbers, for the mapping table see SDK error identifiers per platform。