OHOS Rive Project

This project has two parts:

  1. Native build backend — Used to compile the Rive engine native libraries
  2. Rive Integration with HarmonyOS ArkTS — A guide to integrating the Rive into HarmonyOS ArkTS applications

Part 1: Native build guide

Clone the repository

git clone git@gitcode.com:openharmony-tpc/openharmony_tpc_samples.git
git submodule update --init --recursive ohos_rive/submodules/rive-runtime
git submodule update --init --recursive ohos_rive/library/src/main/cpp/boundscheck/third_party_bounds_checking_function

Prerequisites

1. Set the OHOS_NDK environment variable

  • Install the OpenHarmony SDK.

  • Locate the native directory inside the SDK, typically similar to D:\OpenHarmonySDK\api_version\native.

  • Configure the variable:

    1. Open System variablesNew
    2. Name: OHOS_NDK
    3. Value: full path to the SDK native directory
    4. Click OK to save
  • Verify:

    1. Open a new Command Prompt
    2. Run echo %OHOS_NDK% and verify the path matches your SDK location

If your SDK is not in the default location, use your actual path.

After this, you can build the OHOS Rive native project.

2. Install MSYS2 and configure PATH

  • Download and install MSYS2 (default path recommended: C:\msys64)

  • In MSYS2, install the required tools:

    pacman -S mingw-w64-x86_64-ninja mingw-w64-x86_64-premake mingw-w64-x86_64-python-ply make --noconfirm
    
  • Add to Path (example for default install):

    • C:\msys64\mingw64\bin
    • C:\msys64\usr\bin
  • Verify in a new Command Prompt:

    premake5 --version, python3 --version, sh --version, ninja --version, make --version


Part 2: Rive animation library for HarmonyOS

Overview

This is the HarmonyOS-native Rive engine. It enables HarmonyOS to utilize Rive vector animations with interactive playback and control.

What is Rive?

Rive is a modern vector animation runtime. Compared with traditional formats, it offers:

  • Small file sizes (often much smaller than GIF or Lottie)
  • Runtime rendering at full resolution
  • Rich interactive animations
  • Runtime state and parameter control
  • Multiple platforms (Web, iOS, Android, HMS, etc.)

Installation

Requirements

  • DevEco Studio 5.1.1 Release or newer
  • HarmonyOS SDK API 12 or newer

Steps

  1. Install from OHPM

    ohpm install @ohos/rive
    
  2. Initialize in the entry ability onCreate

    // EntryAbility.ets
    import { initializeRive } from '@ohos/rive';
    
    onCreate() {
      try {
        initializeRive();
      } catch (error) {
        console.error("Failed to initialize Rive library:", error);
      }
    }
    

Basic usage

Show a Rive animation on a page

import { RiveAnimationView } from 'library';

@Entry
@Component
struct AnimationPage {
  build() {
    Column() {
      RiveAnimationView({
        riveResource: '@rawfile/example_animation.riv', // .riv under rawfile
        riveFit: 'cover',
        riveAutoPlay: false                             // default true
      })
      .width('100%')
      .height('30%')
    }
  }
}

Advanced usage

Switch artboard

RiveAnimationView({
  riveResource: '@rawfile/multi_artboard.riv',
  riveArtboard: 'Circle',
})

Control playback from code

@State riveView: RiveAnimationView | null = null;

RiveAnimationView({
  riveResource: '@rawfile/button.riv',
  riveAutoPlay: false,
  onReady: (view) => {
    this.riveView = view;
  }
})

this.riveView?.play()
this.riveView?.pause()
this.riveView?.reset()

Load from network

Option A: direct URL
RiveAnimationView({
  riveUrl: 'https://cdn.rive.app/animations/vehicles.riv',
})
.width('100%')
.height('100%')
Option B: HTTP then bytes
// Add network permission in module.json5
"requestPermissions": [{
  "name": "ohos.permission.INTERNET",
}],

// Page code
private riveUrl = "https://cdn.rive.app/animations/juice_v7.riv"
@State riveView: RiveAnimationView | null = null;

RiveAnimationView({
  onReady: (view) => {
    this.riveView = view
  }
})
.width('100%')
.height('100%')

const httpRequest = http.createHttp();
httpRequest.request(this.riveUrl, {
  method: http.RequestMethod.GET,
  connectTimeout: 30000,
  readTimeout: 30000
}).then((response) => {
  if (response.responseCode === 200) {
    const arrayBuffer = response.result as ArrayBuffer;
    this.riveView?.setRiveBytes(arrayBuffer)
  } else {
    console.error(`HttpPage: Network request failed: ${response.responseCode}`);
  }
}).catch((error: Error) => {
  console.error(`HttpPage: Network request error: ${error}`);
}).finally(() => {
  httpRequest.destroy();
});

Directory layout

ohos_rive/
├── entry/                     # Entry module
│   ├── src/main/
│   │   ├── ets/               # ArkTS
│   │   │   ├── common/
│   │   │   ├── entryability/
│   │   │   └── pages/
│   │   └── resources/
│   │       └── rawfile/       # .riv assets
├── library/                   # Rive library module
│   ├── src/main/
│   │   ├── ets/
│   │   ├── cpp/               # Native C++
│   │   └── resources/
├── README.md                  # This file (English)
└── README_zh.md               # Chinese readme

API reference

RiveAnimationView

Primary element for rendering and managing Rive animations within the HarmonyOS framework.

Properties
Name Type Required Description
riveResource string No Local resource path (mutually exclusive with riveUrl)
riveUrl string No Remote URL (mutually exclusive with riveResource)
riveLoop number No Loop mode
rendererType RendererType No Renderer type
riveArtboard string No Artboard name; default is first artboard
riveStateMachine string No State machine name
riveAnimation string No Animation name
riveFit string No Fit: contain, cover, fill, fitWidth, fitHeight, none, scaleDown
alignmentIndex number No Alignment
riveAutoPlay boolean No Auto-play (default true)
onReady (view: RiveAnimationView) => void No Called when the view is ready
Methods
Method Description
play(animationName?: string, loop?: Loop, direction?: Direction, isStateMachine?: boolean, settleInitialState?: boolean) Play; optional animation name and options
pause() Pause
stop() Stop
reset() Reset to initial state
isPlaying() Returns whether playing
setRiveFile(file: File, artboardName?, animationName?, stateMachineName?, autoplay?, autoBind?, fit?, alignment?, loop?) Load from File
setRiveBytes(bytes: ArrayBuffer, artboardName?, animationName?, stateMachineName?, autoplay?, autoBind?, fit?, alignment?, loop?) Load from bytes
setNumberState(stateMachineName: string, inputName: string, value: number) Set numeric SM input
pauseAnimation(animationName: string, isStateMachine?: boolean) Pause named animation
stopAnimation(animationName: string, isStateMachine?: boolean) Stop named animation
setBooleanState(stateMachineName: string, inputName: string, value: boolean) Set boolean SM input
setBooleanStateAtPath(inputName: string, value: boolean, path: string) Set boolean at path
setTextRunValue(textRunName: string, textValue: string, path?: string) Set text run
setRiveResource(resId: number|string, artboardName?, animationName?, stateMachineName?, autoplay?, autoBind?, fit?, alignment?, loop?) Load by resource id
setArtboardName(name: string) Set active artboard
getFit() Get Fit
setFit(value: Fit) Set Fit
setAlignment(value: Alignment) Set alignment
getLayoutScaleFactor() Get layout scale
setLayoutScaleFactor(value: number) Set layout scale
registerListener(listener: RiveFileControllerListener) Register controller listener
unregisterListener(listener: RiveFileControllerListener) Unregister listener
addEventListener(listener: RiveEventListener) Add event listener
removeEventListener(listener: RiveEventListener) Remove event listener
getRenderer() Get Renderer
getArtboard() Get active Artboard
Alignment.fromIndex(index: number) Alignment from index
Fit.fromString(fitString: string) Fit from string
RiveManager.getInstance() Singleton RiveManager
RiveManager.getInstance().init(context: Context, defaultRenderer?: RendererType) Init manager
RiveManager.getInstance().setFallbackFont(context: Context, byteArray?: Uint8Array, opts?: FontOpts) Set fallback font
RiveRenderImage.fromEncoded(encodedBytes: Uint8Array, rendererType?, premultiplied?) Decode to image
RiveRenderImage.fromARGBInts(pixels: Uint32Array, width, height, rendererType?, premultiplied?) From ARGB
RiveRenderImage.fromRGBABytes(pixelBytes: Uint8Array, width, height, rendererType?, premultiplied?) From RGBA bytes
artboardByName(name: string) Artboard by name from file
animationIndex(index: number) LinearAnimationInstance by index
restoreControllerState(state: ControllerState) Restore controller state
saveControllerState() Save controller state
release() Decrement ref count
RiveFont.make(bytes: Uint8Array, rendererType?: RendererType) Create RiveFont

initializeRive

One-time library initialization; call at app startup.

import { initializeRive } from '@ohos/rive';

initializeRive();

Notes

  1. Place .riv files under resources/rawfile.
  2. Very large animations can hurt performance; optimize assets when possible.
  3. State machine and input names must match the .riv file exactly (case-sensitive).
  4. Call initializeRive() only once at startup.

Code obfuscation

-keep
./oh_modules/@ohos/rive

License

This project is licensed under the MIT License.

Contributing

Please open Issues or submit Pull Requests — contributions are welcome.