How to display native view in React Native (iOS)
- General
How to display native view in React Native (iOS)
While working in react native, Many times, we needed to display native view in React Native.
In this post, I’d like to show you an example of both how to do it and how to pass data from React Native to this native view.
Let’s get into it. As a native view, we’ll use VideoPlayer View from Player pod. It’s a great video player library with various built-in features.
Note:- In This post, we won’t talk about things like to init project and how to setup. We are hoping that you are already familiar with it.
So how it works on the iOS side?
firstly, we prepare our VideoPlayerView.swift that we’d like to display:
Defining out custom view in iOS
Create a new file: File -> New -> File… -> Cocoa Touch Class
Note:-When asked, choose Create Bridge Header.
Select the file ProjectName-Bridging-Header.h and add this content:
1 2 3 4 5 6 7 |
#import "React/RCTBridgeModule.h" #import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> #import <React/RCTComponent.h> #import <React/RCTBridgeModule.h> #import <React/RCTViewManager.h> #import <React/RCTDevLoadingView.h> |
Define our custom view:-
Open VideoPlayerView.swift and paste the following code to define our view:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import UIKit class VideoPlayerView: UIView { weak var videoPlayerVC: VideoPlayerVC?//1 @objc var stringULValue: String = "" { didSet { setNeedsLayout() } } override init(frame: CGRect) { super.init(frame: frame) } required init?(coder aDecoder: NSCoder) { fatalError("nope") } override func layoutSubviews() {//2 super.layoutSubviews() if videoPlayerVC == nil { embed() } else { videoPlayerVC?.view.frame = bounds } } private func embed() {//3 guard let parentVC = parentViewController else {//4 return } let vc = VideoPlayerVC.instantiate(fromAppStoryboard: .first) parentVC.addChild(vc) addSubview(vc.view) vc.view.frame = bounds vc.onClick = { params in guard let onClick = self.onClick else { return } onClick(params as? [AnyHashable : Any]) } vc.didMove(toParent: parentVC) vc.strURL = self.stringULValue self.videoPlayerVC = vc } } |
But wait
//1 for what,
We will define a separate controller for our video player.
And what about //2,
This layout method will be called every time whenever my view will be rendered or the layout gets changed.
Ok, but we have //3 too,
This method will be responsible for adding videoplayre’s viewcontroller view inside this view.
I have never seen//4, where did ParentViewController come from,
We introduced it so we can access the current view controller to set this view in that
So we will define an iOS swift extension .
1 2 3 4 5 6 7 8 9 10 11 12 |
extension UIView { var parentViewController: UIViewController? { var parentResponder: UIResponder? = self while parentResponder != nil { parentResponder = parentResponder!.next if let viewController = parentResponder as? UIViewController { return viewController } } return nil } } |
OK enough!, Talk about how to manipulate this view.
Well to use this view, we will have to consume RCTViewManager subclass that will be the one creating and manipulating this view.
Create a new file of type objective c:- VideoPlayerViewManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#import <Foundation/Foundation.h> #import <React/RCTViewManager.h> #import "VidePlayer-Swift.h" @interface VideoPlayerViewManager: RCTViewManager @end @implementation VideoPlayerViewManager RCT_EXPORT_MODULE()//1 - (UIView *) view { VideoPlayerView *view = [[VideoPlayerView alloc] init]; return view; } RCT_EXPORT_VIEW_PROPERTY(stringULValue, NSString)//2 @end |
In above code, Lines
- Here RCT_EXPORT_MODULE() macro is used so we have access to this class from RN and return our VideoPlayerView.swift in view function. This function decides which view will be displayed for this class in RN.
- we use RCT_EXPORT_VIEW_PROPERTY where the first parameter is a name of the prop that we will send from RN and the second parameter is a type. This macro will also set values for us of those RN props to our VideoPlayerView.swift variables that we’d like to use in there.
Ok enough from the iOS side, we want to implement it in react native so let’s move toward there,
And how it will work on the React Native side?
JavaScript:-
Define our custom view in Javascript
Let’s create a simple wrapper for our custom view:
VideoPlayer.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React from 'react'; import PropTypes from 'prop-types'; import {requireNativeComponent, StyleSheet} from 'react-native'; const MODULE_NAME = 'VideoPlayerView'; const Player = requireNativeComponent(MODULE_NAME, 'VideoPlayer'); type Props = { stringULValue: string, style?: Object, }; const VideoPlayer = (Props) => { return <Player style={Props.style} {...Props}></Player>; }; Player.propTypes = { stringULValue: PropTypes.string.isRequired, }; const styles = StyleSheet.create({}); export default VideoPlayer; |
BUT How to use it
To use it you can do the following
1 2 3 4 5 6 7 8 |
<VideoPlayer stringULValue={ 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4' } style={{ height: '50%', width: '100%',backgroundColor: 'yellow', }}> </VideoPlayer> |
But What if we will have to notify ours react-native side code when the video player is a pause, stop, finish the video in the iOS Native component?
Well, No worries if you have no idea about it for now because luckily we do have a solution for that, RN was not planning to abandon us so they have RCTBubblingEventBlock for us, this works as the callback.
To have the benefit of this call back we need to add the following code in the following files.
- In VideoPlayerView :-
- @objc var onClick: RCTBubblingEventBlock? // To declare variable of predefined event type
- onClick(params as? [AnyHashable : Any]) // To call js onclick(Like call back)
- In VideoPlayerViewManager
- RCT_EXPORT_VIEW_PROPERTY(onClick, RCTBubblingEventBlock) // To export to RN
- In VideoPlayer.js // To access in RN
- onClick = (event: Object) => {
console.log(‘Received params: ‘ + JSON.stringify(event), event); };
woooho! that’s it. wasn’t simple?
Git repository address: – Bitbucket Code
In addition:- This repository also demonstrate that how to call iOS Native View controller From RN
Happy to hear feedbacks.
References:-
- https://github.com/andreipitis/ASPVideoPlayer
- https://reactnative.dev/docs/native-components-ios
- https://reactnative.dev/docs/native-modules-ios
Related content
Auriga: Leveling Up for Enterprise Growth!
Auriga’s journey began in 2010 crafting products for India’s