This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,6 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMCore/UMInternalModule.h>
@interface UMReactFontManager : NSObject <UMInternalModule>
@end

View File

@ -0,0 +1,104 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMReactNativeAdapter/UMReactFontManager.h>
#import <UMFontInterface/UMFontProcessorInterface.h>
#import <React/RCTFont.h>
#import <UMFontInterface/UMFontManagerInterface.h>
#import <UMCore/UMAppLifecycleService.h>
#import <objc/runtime.h>
static dispatch_once_t initializeCurrentFontProcessorsOnce;
static NSPointerArray *currentFontProcessors;
@implementation RCTFont (UMReactFontManager)
+ (UIFont *)UMUpdateFont:(UIFont *)uiFont
withFamily:(NSString *)family
size:(NSNumber *)size
weight:(NSString *)weight
style:(NSString *)style
variant:(NSArray<NSDictionary *> *)variant
scaleMultiplier:(CGFloat)scaleMultiplier
{
UIFont *font;
for (id<UMFontProcessorInterface> fontProcessor in currentFontProcessors) {
font = [fontProcessor updateFont:uiFont withFamily:family size:size weight:weight style:style variant:variant scaleMultiplier:scaleMultiplier];
if (font) {
return font;
}
}
return [self UMUpdateFont:uiFont withFamily:family size:size weight:weight style:style variant:variant scaleMultiplier:scaleMultiplier];
}
@end
/**
* This class is responsible for allowing other modules to register as font processors in React Native.
*
* A font processor is an object conforming to UMFontProcessorInterface and is capable of
* providing an instance of UIFont for given (family, size, weight, style, variant, scaleMultiplier).
*
* To be able to hook into React Native's way of processing fonts we:
* - add a new class method to RCTFont, `UMUpdateFont:withFamily:size:weight:style:variant:scaleMultiplier`
* with UMReactFontManager category.
* - add a new static variable `currentFontProcessors` holding an array of... font processors. This variable
* is shared between the RCTFont's category and UMReactFontManager class.
* - when UMReactFontManager is initialized, we exchange implementations of RCTFont.updateFont...
* and RCTFont.UMUpdateFont... After the class initialized, which happens only once, calling `RCTFont updateFont`
* calls in fact implementation we've defined up here and calling `RCTFont UMUpdateFont` falls back
* to the default implementation. (This is why we call `[self UMUpdateFont]` at the end of that function,
* though it seems like an endless loop, in fact we dispatch to another implementation.)
* - When some module adds a font processor using UMFontManagerInterface, UMReactFontManager adds a weak pointer to it
* to currentFontProcessors array.
* - Implementation logic of `RCTFont.UMUpdateFont` uses current value of currentFontProcessors when processing arguments.
*/
@interface UMReactFontManager ()
@property (nonatomic, strong) NSMutableSet *fontProcessors;
@end
@implementation UMReactFontManager
UM_REGISTER_MODULE();
- (instancetype)init
{
if (self = [super init]) {
_fontProcessors = [NSMutableSet set];
}
return self;
}
+ (const NSArray<Protocol *> *)exportedInterfaces
{
return @[@protocol(UMFontManagerInterface)];
}
+ (void)initialize
{
dispatch_once(&initializeCurrentFontProcessorsOnce, ^{
currentFontProcessors = [NSPointerArray weakObjectsPointerArray];
});
Class rtcClass = [RCTFont class];
SEL rtcUpdate = @selector(updateFont:withFamily:size:weight:style:variant:scaleMultiplier:);
SEL exUpdate = @selector(UMUpdateFont:withFamily:size:weight:style:variant:scaleMultiplier:);
method_exchangeImplementations(class_getClassMethod(rtcClass, rtcUpdate),
class_getClassMethod(rtcClass, exUpdate));
}
# pragma mark - UMFontManager
- (void)addFontProcessor:(id<UMFontProcessorInterface>)processor
{
[_fontProcessors addObject:processor];
[currentFontProcessors compact];
[currentFontProcessors addPointer:(__bridge void * _Nullable)(processor)];
}
@end

View File

@ -0,0 +1,8 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMCore/UMSingletonModule.h>
#import <UMCore/UMLogHandler.h>
@interface UMReactLogHandler : UMSingletonModule <UMLogHandler>
@end

View File

@ -0,0 +1,27 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMReactNativeAdapter/UMReactLogHandler.h>
#import <UMCore/UMDefines.h>
#import <React/RCTLog.h>
@implementation UMReactLogHandler
UM_REGISTER_SINGLETON_MODULE(ReactLogHandler);
- (void)error:(NSString *)message {
RCTLogError(@"%@", message);
}
- (void)fatal:(NSError *)error {
RCTFatal(error);
}
- (void)info:(NSString *)message {
RCTLogInfo(@"%@", message);
}
- (void)warn:(NSString *)message {
RCTLogWarn(@"%@", message);
}
@end

View File

@ -0,0 +1,13 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMCore/UMUIManager.h>
#import <UMCore/UMInternalModule.h>
#import <UMCore/UMAppLifecycleService.h>
#import <UMCore/UMAppLifecycleListener.h>
#import <UMCore/UMModuleRegistryConsumer.h>
#import <UMCore/UMJavaScriptContextProvider.h>
#import <UMReactNativeAdapter/UMBridgeModule.h>
@interface UMReactNativeAdapter : NSObject <UMInternalModule, UMBridgeModule, UMAppLifecycleService, UMUIManager, UMJavaScriptContextProvider, UMModuleRegistryConsumer>
@end

View File

@ -0,0 +1,302 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <JavaScriptCore/JavaScriptCore.h>
#import <UMReactNativeAdapter/UMReactNativeAdapter.h>
#import <React/RCTUIManager.h>
#import <React/RCTBridge+Private.h>
#import <React/RCTAppState.h>
#import <React/RCTImageLoader.h>
@interface UMReactNativeAdapter ()
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, assign) BOOL isForegrounded;
@property (nonatomic, strong) NSPointerArray *lifecycleListeners;
@end
@interface RCTBridge ()
- (JSGlobalContextRef)jsContextRef;
- (void *)runtime;
- (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue;
@end
@implementation UMReactNativeAdapter
UM_REGISTER_MODULE();
+ (NSString *)moduleName
{
return nil;
}
+ (const NSArray<Protocol *> *)exportedInterfaces
{
return @[@protocol(UMAppLifecycleService), @protocol(UMUIManager), @protocol(UMJavaScriptContextProvider)];
}
# pragma mark - Lifecycle methods
- (instancetype)init
{
if (self = [super init]) {
_isForegrounded = false;
_lifecycleListeners = [NSPointerArray weakObjectsPointerArray];
}
return self;
}
- (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
{
if (moduleRegistry) {
[self startObserving];
}
}
- (void)dealloc
{
[self stopObserving];
}
# pragma mark - Public API
- (void)addUIBlock:(void (^)(NSDictionary<id, UIView *> *))block
{
__weak UMReactNativeAdapter *weakSelf = self;
dispatch_async(_bridge.uiManager.methodQueue, ^{
__strong UMReactNativeAdapter *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
block(viewRegistry);
}];
}
});
}
- (void)addUIBlock:(void (^)(id))block forView:(id)viewId ofClass:(Class)klass
{
[self addUIBlock:^(UIView *view) {
if (![view isKindOfClass:klass]) {
block(nil);
} else {
block(view);
}
} forView:viewId];
}
- (void)addUIBlock:(void (^)(id))block forView:(id)viewId implementingProtocol:(Protocol *)protocol
{
[self addUIBlock:^(UIView *view) {
if (![view.class conformsToProtocol:protocol]) {
block(nil);
} else {
block(view);
}
} forView:viewId];
}
- (void)dispatchOnClientThread:(dispatch_block_t)block
{
[self.bridge dispatchBlock:block queue:RCTJSThread];
}
- (void)executeUIBlock:(void (^)(NSDictionary<id,UIView *> *))block {
__weak UMReactNativeAdapter *weakSelf = self;
dispatch_async(_bridge.uiManager.methodQueue, ^{
__strong UMReactNativeAdapter *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
block(viewRegistry);
}];
[strongSelf.bridge.uiManager setNeedsLayout];
}
});
}
- (void)executeUIBlock:(void (^)(id))block forView:(id)viewId implementingProtocol:(Protocol *)protocol {
[self executeUIBlock:^(UIView *view) {
if (![view.class conformsToProtocol:protocol]) {
block(nil);
} else {
block(view);
}
} forView:viewId];
}
- (void)executeUIBlock:(void (^)(id))block forView:(id)viewId ofClass:(Class)klass {
[self executeUIBlock:^(UIView *view) {
if (![view isKindOfClass:klass]) {
block(nil);
} else {
block(view);
}
} forView:viewId];
}
- (void)setBridge:(RCTBridge *)bridge
{
_bridge = bridge;
}
- (void)registerAppLifecycleListener:(id<UMAppLifecycleListener>)listener
{
[_lifecycleListeners addPointer:(__bridge void * _Nullable)(listener)];
}
- (void)unregisterAppLifecycleListener:(id<UMAppLifecycleListener>)listener
{
for (int i = 0; i < _lifecycleListeners.count; i++) {
id pointer = [_lifecycleListeners pointerAtIndex:i];
if (pointer == (__bridge void * _Nullable)(listener) || !pointer) {
[_lifecycleListeners removePointerAtIndex:i];
i--;
}
}
// -(void)compact doesn't work, that's why we have this `|| !pointer` above
// http://www.openradar.me/15396578
[_lifecycleListeners compact];
}
# pragma mark - UMJavaScriptContextProvider
- (JSGlobalContextRef)javaScriptContextRef
{
if ([_bridge respondsToSelector:@selector(jsContextRef)]) {
return _bridge.jsContextRef;
} else if (_bridge.runtime) {
// In react-native 0.59 vm is abstracted by JSI and all JSC specific references are removed
// To access jsc context we are extracting specific offset in jsi::Runtime, JSGlobalContextRef
// is first field inside Runtime class and in memory it's preceded only by pointer to virtual method table.
// WARNING: This is temporary solution that may break with new react-native releases.
return *(((JSGlobalContextRef *)(_bridge.runtime)) + 1);
}
return nil;
}
- (void *)javaScriptRuntimePointer
{
if ([_bridge respondsToSelector:@selector(runtime)]) {
return _bridge.runtime;
} else {
return nil;
}
}
# pragma mark - App state observing
- (void)startObserving
{
for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
UIApplicationDidEnterBackgroundNotification,
UIApplicationDidFinishLaunchingNotification,
UIApplicationWillResignActiveNotification,
UIApplicationWillEnterForegroundNotification,
RCTContentDidAppearNotification,
RCTBridgeWillReloadNotification]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleAppStateDidChange:)
name:name
object:nil];
}
}
- (void)handleAppStateDidChange:(NSNotification *)notification
{
if ([notification.name isEqualToString:RCTContentDidAppearNotification]) {
[self notifyAboutContentDidAppear];
} else if ([notification.name isEqualToString:RCTBridgeWillReloadNotification]) {
[self notifyAboutContentWillReload];
} else if (
_isForegrounded && (
[notification.name isEqualToString:UIApplicationWillResignActiveNotification] ||
[notification.name isEqualToString:UIApplicationWillEnterForegroundNotification] ||
RCTSharedApplication().applicationState == UIApplicationStateBackground
)
) {
[self setAppStateToBackground];
} else if (!_isForegrounded && RCTSharedApplication().applicationState == UIApplicationStateActive) {
[self setAppStateToForeground];
}
}
- (void)setAppStateToBackground
{
if (_isForegrounded) {
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj onAppBackgrounded];
}];
_isForegrounded = false;
}
}
- (void)setAppStateToForeground
{
if (!_isForegrounded) {
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj onAppForegrounded];
}];
_isForegrounded = true;
}
}
- (void)notifyAboutContentDidAppear
{
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj respondsToSelector:@selector(onAppContentDidAppear)]) {
[obj performSelector:@selector(onAppContentDidAppear)];
}
}];
}
- (void)notifyAboutContentWillReload
{
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj respondsToSelector:@selector(onAppContentWillReload)]) {
[obj performSelector:@selector(onAppContentWillReload)];
}
}];
}
- (void)stopObserving
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
# pragma mark - Internal methods
- (void)addUIBlock:(void (^)(UIView *view))block forView:(id)viewId
{
__weak UMReactNativeAdapter *weakSelf = self;
dispatch_async(_bridge.uiManager.methodQueue, ^{
__strong UMReactNativeAdapter *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
UIView *view = viewRegistry[viewId];
block(view);
}];
}
});
}
- (void)executeUIBlock:(void (^)(UIView *view))block forView:(id)viewId
{
__weak UMReactNativeAdapter *weakSelf = self;
dispatch_async(_bridge.uiManager.methodQueue, ^{
__strong UMReactNativeAdapter *strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
UIView *view = viewRegistry[viewId];
block(view);
}];
[strongSelf.bridge.uiManager setNeedsLayout];
}
});
}
@end

View File

@ -0,0 +1,11 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMCore/UMInternalModule.h>
#import <UMCore/UMEventEmitterService.h>
#import <UMCore/UMModuleRegistryConsumer.h>
#import <UMReactNativeAdapter/UMBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface UMReactNativeEventEmitter : RCTEventEmitter <UMInternalModule, UMBridgeModule, UMModuleRegistryConsumer, UMEventEmitterService>
@end

View File

@ -0,0 +1,145 @@
// Copyright 2018-present 650 Industries. All rights reserved.
#import <UMReactNativeAdapter/UMReactNativeEventEmitter.h>
#import <UMCore/UMEventEmitter.h>
#import <UMCore/UMExportedModule.h>
#import <UMCore/UMModuleRegistry.h>
@interface UMReactNativeEventEmitter ()
@property (nonatomic, assign) int listenersCount;
@property (nonatomic, weak) UMModuleRegistry *moduleRegistry;
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *modulesListenersCounts;
@end
@implementation UMReactNativeEventEmitter
- (instancetype)init
{
if (self = [super init]) {
_listenersCount = 0;
_modulesListenersCounts = [NSMutableDictionary dictionary];
}
return self;
}
UM_REGISTER_MODULE();
+ (NSString *)moduleName
{
return @"UMReactNativeEventEmitter";
}
+ (const NSArray<Protocol *> *)exportedInterfaces
{
return @[@protocol(UMEventEmitterService)];
}
- (NSArray<NSString *> *)supportedEvents
{
NSMutableSet<NSString *> *eventsAccumulator = [NSMutableSet set];
for (UMExportedModule *exportedModule in [_moduleRegistry getAllExportedModules]) {
if ([exportedModule conformsToProtocol:@protocol(UMEventEmitter)]) {
id<UMEventEmitter> eventEmitter = (id<UMEventEmitter>)exportedModule;
[eventsAccumulator addObjectsFromArray:[eventEmitter supportedEvents]];
}
}
return [eventsAccumulator allObjects];
}
RCT_EXPORT_METHOD(addProxiedListener:(NSString *)moduleName eventName:(NSString *)eventName)
{
[self addListener:eventName];
// Validate module
UMExportedModule *module = [_moduleRegistry getExportedModuleForName:moduleName];
if (RCT_DEBUG && module == nil) {
UMLogError(@"Module for name `%@` has not been found.", moduleName);
return;
} else if (RCT_DEBUG && ![module conformsToProtocol:@protocol(UMEventEmitter)]) {
UMLogError(@"Module `%@` is not an UMEventEmitter, thus it cannot be subscribed to.", moduleName);
return;
}
// Validate eventEmitter
id<UMEventEmitter> eventEmitter = (id<UMEventEmitter>)module;
if (RCT_DEBUG && ![[eventEmitter supportedEvents] containsObject:eventName]) {
UMLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`",
eventName, moduleName, [[eventEmitter supportedEvents] componentsJoinedByString:@"`, `"]);
}
// Global observing state
_listenersCount += 1;
if (_listenersCount == 1) {
[self startObserving];
}
// Per-module observing state
int newModuleListenersCount = [self moduleListenersCountFor:moduleName] + 1;
if (newModuleListenersCount == 1) {
[eventEmitter startObserving];
}
_modulesListenersCounts[moduleName] = [NSNumber numberWithInt:newModuleListenersCount];
}
RCT_EXPORT_METHOD(removeProxiedListeners:(NSString *)moduleName count:(double)count)
{
[self removeListeners:count];
// Validate module
UMExportedModule *module = [_moduleRegistry getExportedModuleForName:moduleName];
if (RCT_DEBUG && module == nil) {
UMLogError(@"Module for name `%@` has not been found.", moduleName);
return;
} else if (RCT_DEBUG && ![module conformsToProtocol:@protocol(UMEventEmitter)]) {
UMLogError(@"Module `%@` is not an UMEventEmitter, thus it cannot be subscribed to.", moduleName);
return;
}
id<UMEventEmitter> eventEmitter = (id<UMEventEmitter>)module;
// Per-module observing state
int newModuleListenersCount = [self moduleListenersCountFor:moduleName] - count;
if (newModuleListenersCount == 0) {
[eventEmitter stopObserving];
} else if (newModuleListenersCount < 0) {
UMLogError(@"Attempted to remove more `%@` listeners than added", moduleName);
newModuleListenersCount = 0;
}
_modulesListenersCounts[moduleName] = [NSNumber numberWithInt:newModuleListenersCount];
// Global observing state
if (_listenersCount - count < 0) {
UMLogError(@"Attempted to remove more proxied event emitter listeners than added");
_listenersCount = 0;
} else {
_listenersCount -= count;
}
if (_listenersCount == 0) {
[self stopObserving];
}
}
# pragma mark Utilities
- (int)moduleListenersCountFor:(NSString *)moduleName
{
NSNumber *moduleListenersCountNumber = _modulesListenersCounts[moduleName];
int moduleListenersCount = 0;
if (moduleListenersCountNumber != nil) {
moduleListenersCount = [moduleListenersCountNumber intValue];
}
return moduleListenersCount;
}
# pragma mark - UMModuleRegistryConsumer
- (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
{
_moduleRegistry = moduleRegistry;
}
@end