Fabic Component
- Run
npx create-react-native-library@latest react-native-fast-pdf-viewer2. Run
cd react-native-fast-pdf-viewer && yarn install
cd example && yarn install
cd ios && pod install && cd ..
yarn ios 3. At root-project/src/FastPdfViewerViewNativeComponent.ts
import { codegenNativeComponent, type ViewProps } from 'react-native';
interface NativeProps extends ViewProps {
color?: string;
}
export default codegenNativeComponent<NativeProps>('FastPdfViewerView');3. At root-project/src/index.tsx
export { default as FastPdfViewerView } from './FastPdfViewerViewNativeComponent';
export * from './FastPdfViewerViewNativeComponent';Fabic Component for IOS
4. In root Project at FastPdfViewer.podspec add swift in s.source_files to support for Swift File
5. Open Xcode and select path root-project/example/ios
Get John Luong’s stories in your inbox
Join Medium for free to get updates from this writer.
6. Go to Pods/Development Pods/FastPdfViewer -> click right -> New File from Template -> Swift File (not SwiftUI) -> Save file in root-project/ios (not in example/ios) -> Put name FastPdfViewerViewUI -> create
if the message “want you create brigde-header” -> choose Dont’t Create
7. FastPdfViewerViewUI.swift
import Foundation
import UIKit
import PDFKit
@objc public class FastPdfViewerViewUI: UIView {
private var pdfView: PDFView?
@objc public override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .lightGray
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
// MARK: - Load PDF from URI (local or remote)
@objc public func loadPdf(from uri: NSString?) {
guard let uri = uri as String? else { return }
// Remove old pdfView if exists
pdfView?.removeFromSuperview()
pdfView = PDFView(frame: bounds)
guard let pdfView = pdfView else { return }
pdfView.autoScales = true
pdfView.backgroundColor = .white
addSubview(pdfView)
pdfView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pdfView.leadingAnchor.constraint(equalTo: leadingAnchor),
pdfView.trailingAnchor.constraint(equalTo: trailingAnchor),
pdfView.topAnchor.constraint(equalTo: topAnchor),
pdfView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
if uri.lowercased().hasPrefix("http") {
// Remote PDF
loadRemotePdf(urlString: uri, into: pdfView)
} else {
// Local PDF
let fileURL = URL(fileURLWithPath: uri)
pdfView.document = PDFDocument(url: fileURL)
}
}
private func loadRemotePdf(urlString: String, into pdfView: PDFView) {
guard let url = URL(string: urlString) else { return }
let session = URLSession.shared
let task = session.dataTask(with: url) { [weak self] data, _, error in
guard let self = self, let data = data, error == nil else { return }
DispatchQueue.main.async {
if let document = PDFDocument(data: data) {
pdfView.document = document
} else {
self.showErrorLabel("Failed to open PDF")
}
}
}
task.resume()
}
private func showErrorLabel(_ text: String) {
let label = UILabel()
label.text = text
label.textColor = .red
label.textAlignment = .center
label.frame = bounds
addSubview(label)
}
// MARK: - Background Color
@objc public func updateBackgroundColor(_ hex: NSString?) {
guard let hex = hex as String? else { return }
backgroundColor = UIColor(hex: hex)
}
}
private extension UIColor {
convenience init?(hex: String) {
var cString = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
if cString.hasPrefix("#") { cString.removeFirst() }
guard cString.count == 6 else { return nil }
var rgbValue: UInt64 = 0
Scanner(string: cString).scanHexInt64(&rgbValue)
self.init(
red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
alpha: 1.0
)
}
}8. FastPdfViewerView.mm
#import "FastPdfViewerView.h"
#import <react/renderer/components/FastPdfViewerViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/FastPdfViewerViewSpec/EventEmitters.h>
#import <react/renderer/components/FastPdfViewerViewSpec/Props.h>
#import <react/renderer/components/FastPdfViewerViewSpec/RCTComponentViewHelpers.h>
#import "RCTFabricComponentsPlugins.h"
#import "FastPdfViewer-Swift.h"
using namespace facebook::react;
@interface FastPdfViewerView () <RCTFastPdfViewerViewViewProtocol>
@end
@implementation FastPdfViewerView {
FastPdfViewerViewUI *_pdfView; // ✅ Swift UIView
}
+ (ComponentDescriptorProvider)componentDescriptorProvider {
return concreteComponentDescriptorProvider<FastPdfViewerViewComponentDescriptor>();
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const FastPdfViewerViewProps>();
_props = defaultProps;
// ✅ Dùng UIView Swift thay vì UIView thuần
_pdfView = [FastPdfViewerViewUI new];
self.contentView = _pdfView;
}
return self;
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
const auto &oldViewProps = *std::static_pointer_cast<FastPdfViewerViewProps const>(_props);
const auto &newViewProps = *std::static_pointer_cast<FastPdfViewerViewProps const>(props);
// ✅ Cập nhật PDF URI
if (oldViewProps.uri != newViewProps.uri) {
NSString *uriString = [[NSString alloc] initWithUTF8String:newViewProps.uri.c_str()];
[_pdfView loadPdfFrom:uriString];
}
[super updateProps:props oldProps:oldProps];
}
Class<RCTComponentViewProtocol> FastPdfViewerViewCls(void) {
return FastPdfViewerView.class;
}
@end9. Run
cd example/ios && pod install
yarn install







