- Installation
- Methods
- Callbacks (New arch)
- Events (Old arch)
- Audio support
- Cancel trimming
- Fail to load media
- Use FFMPEG HTTPS version
- Android: update SDK version
- Thanks
- âś… Support video and audio
- âś… Support local files and remote files (remote files need
https
version, see below) - âś… Save to Photos, Documents and Share to other apps
- âś… Check if file is valid video/audio
- âś… File operations: list, clean up, delete specific file
- âś… Support React Native New + Old Arch
# new arch
npm install react-native-video-trim react-native-nitro-modules
# old arch
npm install react-native-video-trim@^3.0.0
# or with yarn
# new arch
yarn add react-native-video-trim react-native-nitro-modules
# old arch
yarn add react-native-video-trim@^3.0.0
react-native-nitro-modules
is required in New Arch as this library relies on Nitro Modules.
Run the following command to setup for iOS:
npx pod-install ios
You need to run prebuild
in order for native code takes effect:
npx expo prebuild
Then you need to restart to make the changes take effect
Note that on iOS you'll need to run on real device, Expo Go may not work because of library linking
import { showEditor } from 'react-native-video-trim';
// ...
showEditor(videoUrl);
// or with output length limit
showEditor(videoUrl, {
maxDuration: 20,
});
Usually this library will be used along with other library to select video file, Eg. react-native-image-picker. Below is real world example:
import * as React from 'react';
import {
StyleSheet,
View,
Text,
TouchableOpacity,
NativeEventEmitter,
NativeModules,
} from 'react-native';
import { isValidFile, showEditor } from 'react-native-video-trim';
import { launchImageLibrary } from 'react-native-image-picker';
export default function App() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={async () => {
const result = await launchImageLibrary({
mediaType: 'video',
assetRepresentationMode: 'current',
});
isValidFile(result.assets![0]?.uri || '').then((res) =>
console.log(res)
);
showEditor(result.assets![0]?.uri || '', {
maxDuration: 20,
},
(eventName, payload) => {
console.log('Event:', eventName, 'Payload:', payload);
}
);
}}
style={{ padding: 10, backgroundColor: 'red' }}
>
<Text>Launch Library</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
isValidFile('invalid file path').then((res) => console.log(res));
}}
style={{
padding: 10,
backgroundColor: 'blue',
marginTop: 20,
}}
>
<Text>Check Video Valid</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
showEditor(videoPath: string, config?: EditorConfig, onEvent?: (eventName: string, payload: Record<string, string>) => void)
Main method to show Video Editor UI.
Params:
-
videoPath
: Path to video file, if this is an invalid path,onError
event will be fired -
config
(optional, every sub props ofconfig
is optional):type
(default = video
): which player to use,video
oraudio
outputExt
(default = mp4
): output file extensionenableHapticFeedback
(default = true
): whether to enable haptic feedbacksaveToPhoto
(Video-only,default = false
): whether to save video to photo/gallery after editingopenDocumentsOnFinish
(default = false
): open Document Picker on done trimmingopenShareSheetOnFinish
(default = false
): open Share Sheet on done trimmingremoveAfterSavedToPhoto
(default = false
): whether to remove output file from storage after saved to Photo successfullyremoveAfterFailedToSavePhoto
(default = false
): whether to remove output file if fail to save to PhotoremoveAfterSavedToDocuments
(default = false
): whether to remove output file from storage after saved Documents successfullyremoveAfterFailedToSaveDocuments
(default = false
): whether to remove output file from storage after fail to save to DocumentsremoveAfterShared
(default = false
): whether to remove output file from storage after saved Share successfully. iOS only, on Android you'll have to manually remove the file (this is because on Android there's no way to detect when sharing is successful)removeAfterFailedToShare
(default = false
): whether to remove output file from storage after fail to Share. iOS only, on Android you'll have to manually remove the filemaxDuration
(optional): maximum duration for the trimmed videominDuration
(default = 1000
): minimum duration for the trimmed videocancelButtonText
(default= "Cancel"
): text of left button in Editor dialogsaveButtonText
(default= "Save"
): text of right button in Editor dialogenableCancelDialog
(default = true
): whether to show alert dialog on press CancelcancelDialogTitle
(default = "Warning!"
)cancelDialogMessage
(default = "Are you sure want to cancel?"
)cancelDialogCancelText
(default = "Close"
)cancelDialogConfirmText
(default = "Proceed"
)enableSaveDialog
(default = true
): whether to show alert dialog on press SavesaveDialogTitle
(default = "Confirmation!"
)saveDialogMessage
(default = "Are you sure want to save?"
)saveDialogCancelText
(default = "Close"
)saveDialogConfirmText
(default = "Proceed"
)fullScreenModalIOS
(default = false
): whether to open editor in fullscreen modaltrimmingText
(default = "Trimming video..."
): trimming text on the progress dialogautoplay
(default = false
): whether to autoplay media on loadjumpToPositionOnLoad
(optional): which time position should jump on media loaded (millisecond)closeWhenFinish
(default = true
): should editor close on finish trimmingenableCancelTrimming
(default = true
): enable cancel trimmingcancelTrimmingButtonText
(default = "Cancel"
)enableCancelTrimmingDialog
(default = true
)cancelTrimmingDialogTitle
(default = "Warning!"
)cancelTrimmingDialogMessage
(default = "Are you sure want to cancel trimming?"
)cancelTrimmingDialogCancelText
(default = "Close"
)cancelTrimmingDialogConfirmText
(default = "Proceed"
)headerText
(optional)headerTextSize
(default = 16
)headerTextColor
(default = white
)alertOnFailToLoad
(default = true
)alertOnFailTitle
(default = "Error"
)alertOnFailMessage
(default = "Fail to load media. Possibly invalid file or no network connection"
)alertOnFailCloseText
(default = "Close"
)enableRotation
(default = false
)rotationAngle
(default = 0
)
If saveToPhoto = true
, you must ensure that you have request permission to write to photo/gallery
- For Android: you need to have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
in AndroidManifest.xml - For iOS: you need
NSPhotoLibraryUsageDescription
in Info.plist
If openShareSheetOnFinish=true
, on Android you'll need to update AndroidManifest.xml
like below:
</application>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
If you face issue when building Android app related to file_paths
, then you may need to create res/xml/file_paths.xml
: with the following content:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="internal_files" path="." />
<external-path name="external_files" path="." />
</paths>
Directly trim a file without showing editor
This method is to check if a path is a valid video/audio
Close Editor
Return array of generated output files in app storage. (Promise<string[]>
)
Clean all generated output files in app storage. Return number of successfully deleted files (Promise<number>
)
Delete a file in app storage. Return true
if success
showEditor('file', config, (eventName, payload) => {
console.log(eventName, payload)
})
closeEditor(() => {
console.log('Editor closed')
})
To listen for events you interest, do the following:
useEffect(() => {
const eventEmitter = new NativeEventEmitter(NativeModules.VideoTrim);
const subscription = eventEmitter.addListener('VideoTrim', (event) => {
switch (event.name) {
case 'onLoad': {
console.log('onLoadListener', event);
break;
}
case 'onShow': {
console.log('onShowListener', event);
break;
}
case 'onHide': {
console.log('onHide', event);
break;
}
case 'onStartTrimming': {
console.log('onStartTrimming', event);
break;
}
case 'onFinishTrimming': {
console.log('onFinishTrimming', event);
break;
}
case 'onCancelTrimming': {
console.log('onCancelTrimming', event);
break;
}
case 'onCancel': {
console.log('onCancel', event);
break;
}
case 'onError': {
console.log('onError', event);
break;
}
case 'onLog': {
console.log('onLog', event);
break;
}
case 'onStatistics': {
console.log('onStatistics', event);
break;
}
}
});
return () => {
subscription.remove();
};
}, []);
For audio only you have to pass type=audio
and outputExt
:
showEditor(url, {
type: 'audio', // important
outputExt: 'wav', // important: any audio type for output file extension
})
While trimming, you can press Cancel to terminate the process.
Related props: enableCancelTrimming, cancelTrimmingButtonText, enableCancelTrimmingDialog, cancelTrimmingDialogTitle, cancelTrimmingDialogMessage, cancelTrimmingDialogCancelText, cancelTrimmingDialogConfirmText
If there's error while loading media, there'll be a prompt
Related props: alertOnFailToLoad, alertOnFailTitle, alertOnFailMessage, alertOnFailCloseText
To trim & rotate video you can pass enableRotation
and rotationAngle
to showEditor
/trim
. But note that it doesn't re-encode the video, instead the lib uses display_rotation
metadata from ffmpeg, and some players/platforms may show differently.
If you want to trim a remote file, you need to use https
version (default is min
which does not support remote file).
Do the following:
// android/build.gradle
buildscript {
ext {
VideoTrim_ffmpeg_package=https
// optional: VideoTrim_ffmpeg_version=6.0.1
}
}
// ios
FFMPEGKIT_PACKAGE=https FFMPEG_KIT_PACKAGE_VERSION=6.0 pod install
You can override sdk version to use any version in your android/build.gradle
> buildscript
> ext
buildscript {
ext {
VideoTrim_kotlinVersion=2.0.21
VideoTrim_minSdkVersion=24
VideoTrim_targetSdkVersion=34
VideoTrim_compileSdkVersion=35
VideoTrim_ndkVersion=27.1.12297006
}
}
- Android part is created by modified + fix bugs from: https://github.com/iknow4/Android-Video-Trimmer
- iOS UI is created from: https://github.com/AndreasVerhoeven/VideoTrimmerControl