website/versioned_docs/version-0.81/fabric-native-components-ios.md
import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import constants from '@site/core/TabsConstants';
Now it's time to write some iOS platform code to be able to render the web view. The steps you need to follow are:
RCTWebViewRCTWebView in the applicationYou can manually run the Codegen, however it's simpler to use the application you're going to demo the component in to do this for you.
cd ios
bundle install
bundle exec pod install
Importantly you will see logging output from Codegen, which we're going to use in Xcode to build our WebView native component.
:::warning You should be careful about committing generated code to your repository. Generated code is specific to each version of React Native. Use npm peerDependencies to restrict compatibility with version of React Native. :::
RCTWebViewWe need to prepare your iOS project using Xcode by completing these 5 steps:
cd ios
open Demo.xcworkspace
Right click on app and select <code>New Group</code>, call the new group WebView.
In the WebView group, create <code>New</code>→<code>File from Template</code>.
Use the <code>Objective-C File</code> template, and name it <code>RCTWebView</code>.
Repeat step 4 and create a header file named RCTWebView.h.
Rename <code>RCTWebView.m</code> → <code>RCTWebView.mm</code> making it an Objective-C++ file.
Podfile
...
Demo
├── AppDelegate.swift
...
// highlight-start
├── RCTWebView.h
└── RCTWebView.mm
// highlight-end
After creating the header file and the implementation file, you can start implementing them.
This is the code for the RCTWebView.h file, which declares the component interface.
#import <React/RCTViewComponentView.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTWebView : RCTViewComponentView
// You would declare native methods you'd want to access from the view here
@end
NS_ASSUME_NONNULL_END
This class defines an RCTWebView which extends the RCTViewComponentView class. This is the base class for all the native components and it is provided by React Native.
The code for the implementation file (RCTWebView.mm) is the following:
#import "RCTWebView.h"
#import <react/renderer/components/AppSpec/ComponentDescriptors.h>
#import <react/renderer/components/AppSpec/EventEmitters.h>
#import <react/renderer/components/AppSpec/Props.h>
#import <react/renderer/components/AppSpec/RCTComponentViewHelpers.h>
// highlight-next-line
#import <WebKit/WebKit.h>
using namespace facebook::react;
@interface RCTWebView () <RCTCustomWebViewViewProtocol, WKNavigationDelegate>
@end
@implementation RCTWebView {
NSURL * _sourceURL;
WKWebView * _webView;
}
-(instancetype)init
{
if(self = [super init]) {
// highlight-start
_webView = [WKWebView new];
_webView.navigationDelegate = self;
[self addSubview:_webView];
// highlight-end
}
return self;
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
const auto &oldViewProps = *std::static_pointer_cast<CustomWebViewProps const>(_props);
const auto &newViewProps = *std::static_pointer_cast<CustomWebViewProps const>(props);
// Handle your props here
if (oldViewProps.sourceURL != newViewProps.sourceURL) {
NSString *urlString = [NSString stringWithCString:newViewProps.sourceURL.c_str() encoding:NSUTF8StringEncoding];
_sourceURL = [NSURL URLWithString:urlString];
// highlight-start
if ([self urlIsValid:newViewProps.sourceURL]) {
[_webView loadRequest:[NSURLRequest requestWithURL:_sourceURL]];
}
// highlight-end
}
[super updateProps:props oldProps:oldProps];
}
-(void)layoutSubviews
{
[super layoutSubviews];
_webView.frame = self.bounds;
}
#pragma mark - WKNavigationDelegate
// highlight-start
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
CustomWebViewEventEmitter::OnScriptLoaded result = CustomWebViewEventEmitter::OnScriptLoaded{CustomWebViewEventEmitter::OnScriptLoadedResult::Success};
self.eventEmitter.onScriptLoaded(result);
}
- (BOOL)urlIsValid:(std::string)propString
{
if (propString.length() > 0 && !_sourceURL) {
CustomWebViewEventEmitter::OnScriptLoaded result = CustomWebViewEventEmitter::OnScriptLoaded{CustomWebViewEventEmitter::OnScriptLoadedResult::Error};
self.eventEmitter.onScriptLoaded(result);
return NO;
}
return YES;
}
// Event emitter convenience method
- (const CustomWebViewEventEmitter &)eventEmitter
{
return static_cast<const CustomWebViewEventEmitter &>(*_eventEmitter);
}
// highlight-end
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<CustomWebViewComponentDescriptor>();
}
@end
This code is written in Objective-C++ and contains various details:
@interface implements two protocols:
RCTCustomWebViewViewProtocol, generated by Codegen;WKNavigationDelegate, provided by the WebKit framework to handle the web view navigation events;init method that instantiates the WKWebView, adds it to the subviews and that sets the navigationDelegate;updateProps method that is called by React Native when the component's props change;layoutSubviews method that describes how the custom view needs to be laid out;webView:didFinishNavigation: method that lets you handle what to do when the WKWebView finishes loading the page;urlIsValid:(std::string)propString method that checks whether the URL received as prop is valid;eventEmitter method which is a utility to retrieve a strongly typed eventEmitter instancecomponentDescriptorProvider which returns the ComponentDescriptor generated by Codegen;:::note This step is only required because we are creating a Web view. Web components on iOS needs to be linked against the WebKit framework provided by Apple. If your component doesn't need to access web-specific features, you can skip this step. :::
A web view requires access to some features that Apple provides through one of the frameworks shipped with Xcode and the devices: WebKit.
You can see it in the native code by the #import <WebKit/WebKit.h> line added in the RCTWebView.mm.
To link the WebKit framework in your app, follow these steps:
In Xcode, Click on your project
Select the app target
Select the General tab
Scroll down until you find the "Frameworks, Libraries, and Embedded Contents" section, and press the + button
In the search bar, filter for WebKit
Select the WebKit framework
Click on Add.