Skip to main content

React Native

By the end of this page your app shows the editor on a video, lets users add their own media through your picker, and exports the result.

Requirements​

  • React Native with the New Architecture (the default since 0.76) and react-native-nitro-modules.
  • iOS 16 or later; Android 8.0 or later (minSdkVersion 26).

Install​

The package is @nitrakit/react-native; it includes the native code for iOS and Android.

Beta access
During the beta, the SDK is shared with teams that have an invite, together with install instructions. Ask for access if you don't have it yet.
  • iOS: run pod install. If users pick from their photo library, add NSPhotoLibraryUsageDescription to your Info.plist.
  • Android: raise minSdkVersion to 26 if it's lower.

1. Install your license key Stable​

The key unlocks full-length, watermark-free exports for your app. Install it once when your app starts, outside any component. Without a key everything still works, so you can skip this while trying the SDK.

import { setLicense } from '@nitrakit/react-native'

const status = setLicense('nk1.…')
if (status.problems.length) console.warn('Nitrakit:', status.problems)

See License key.

2. Create a project Stable​

An editor holds one project and its undo history. Create it with your output size and frame rate, then add media: adding a file makes it a source; placing the source on a track makes it a clip the user sees in the timeline.

import { createEditor, importFile } from '@nitrakit/react-native'

const editor = createEditor(1080, 1920, 30)

const media = editor.addMedia(assetId, importFile(pickedUri, 'clip.mp4'), 'clip.mp4')
const track = editor.addTrack('visual', true)
editor.insertMedia(track, media.source, 0, 0, media.durationUs)
  • assetId is your app's id for the file, for example its key in your storage: the project refers to media only by these ids.
  • importFile turns what a picker gives you (content://, file://) into a path the SDK can read. The SDK keeps its own copy, so editing starts right away.
  • Times are microseconds.

3. Tell the SDK where media lives Stable​

When a project is opened on a device that doesn't have its media yet, the SDK asks your app where each media id lives. Return a URL (it can be signed) and the SDK downloads it, showing the progress on the clips:

import { setMediaResolver } from '@nitrakit/react-native'

setMediaResolver(async (id) => (await api.signedUrl(id)).url) // or a local path

Set it once, at start-up. Skip it if your projects never leave the device. See Projects and media.

4. Show the editor Stable​

Two components make up the editor: NitrakitPreview plays the project and lets the user move and resize layers; NitrakitEditor has the timeline, tools and panels. Give both the same editor; they stay in sync with each other and with your code.

import { NitrakitEditor, NitrakitPreview } from '@nitrakit/react-native'

export function EditorScreen({ editor }: { editor: Editor }) {
return (
<View style={{ flex: 1, backgroundColor: '#000' }}>
<NitrakitPreview editor={editor} style={{ flex: 1 }} />
<NitrakitEditor editor={editor} style={{ height: 400 }} onRequest={onRequest} />
</View>
)
}

Create the editor once per project (for example in a useMemo or your state store), not on every render.

5. Connect your pickers Stable​

The editor never opens the photo library or a file browser itself. When the user taps Add media, picks a font or a colour, it asks your app through onRequest, so these screens look like the rest of your app and media can come from wherever you keep it.

Return the answer, or a promise of it. Return null if the user backed out, or undefined (nothing) to let the SDK show its built-in picker:

async function onRequest(request: EditorRequest) {
switch (request.kind) {
case 'addMedia':
case 'addOverlay':
case 'addAudio':
case 'addSticker': {
const picked = await pickFromLibrary() // your picker
if (!picked) return null
const path = importFile(picked.uri, picked.fileName)
const media = editor.addMedia(startUpload(path), path, picked.fileName) // your storage's id
return { source: media.source }
}
}
// anything else: the built-in picker
}

The built-in pickers cover fonts, colours, text, text styles and filters; adding media always needs yours. See Your pickers for every request and its answer.

6. Save the project Stable​

Projects save as JSON, with media referred to by your ids. Store it on the device or sync it to your backend, and reopen it anywhere:

import { openEditor } from '@nitrakit/react-native'

const json = editor.toJson()

const reopened = openEditor(json)
reopened.loadMedia() // from the device, else through your resolver

editor.setListener(() => scheduleSave(editor.toJson())) // after every change

While your app uploads a file, show the progress on its clips with editor.setMediaProgress(id, fraction).

7. Export Stable​

Export renders the project to an MP4 in the background while the user keeps editing:

import { filesDir } from '@nitrakit/react-native'

const path = `${filesDir()}/export-${Date.now()}.mp4`
try {
await editor.exportVideo(path, editor.exportSettings(1080), (f) => setProgress(f))
// the file at `path` is ready to save, share or upload
} catch (e) {
// failed, or cancelled with editor.cancelExport()
}

See Export.

Playback​

Control playback from your own buttons through a ref:

const preview = useRef<PreviewHandle>(null)

<NitrakitPreview ref={preview} editor={editor} onPosition={(us) => setTime(us)} />

preview.current?.play()
preview.current?.seek(2_000_000)

Next​