mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add NativeLogBox module on iOS
Summary: This diff adds a NativeLogBox module implementation on iOS to manage rendering LogBox the way we render RedBox, except rendering a React Native component instead of a native view. The strategy here is: - initialize: will create a hidden window (the way redbox does) and render the LogBox to it - show: will show the window - hide: will hide the window Most of this is copied from the way RedBox works, the difference here is that we eagerly initialize the window with the `initialize` function so that it's warm by the time LogBox needs to render. Changelog: [Internal] Reviewed By: RSNara Differential Revision: D18750008 fbshipit-source-id: 013e55ded55c8572bb08e0219ff4cd0060ebe0da
This commit is contained in:
@@ -1671,6 +1671,33 @@ namespace facebook {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
|
||||
static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_show(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
||||
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "show", @selector(show), args, count);
|
||||
}
|
||||
|
||||
static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_hide(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
||||
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "hide", @selector(hide), args, count);
|
||||
}
|
||||
|
||||
|
||||
NativeLogBoxSpecJSI::NativeLogBoxSpecJSI(id<RCTTurboModule> instance, std::shared_ptr<CallInvoker> jsInvoker)
|
||||
: ObjCTurboModule("LogBox", instance, jsInvoker) {
|
||||
|
||||
methodMap_["show"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_show};
|
||||
|
||||
|
||||
methodMap_["hide"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_hide};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -1771,6 +1771,25 @@ namespace facebook {
|
||||
};
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@protocol NativeLogBoxSpec <RCTBridgeModule, RCTTurboModule>
|
||||
|
||||
- (void)show;
|
||||
- (void)hide;
|
||||
|
||||
@end
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
/**
|
||||
* ObjC++ class for module 'LogBox'
|
||||
*/
|
||||
|
||||
class JSI_EXPORT NativeLogBoxSpecJSI : public ObjCTurboModule {
|
||||
public:
|
||||
NativeLogBoxSpecJSI(id<RCTTurboModule> instance, std::shared_ptr<CallInvoker> jsInvoker);
|
||||
|
||||
};
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@protocol NativeModalManagerSpec <RCTBridgeModule, RCTTurboModule>
|
||||
|
||||
- (void)addListener:(NSString *)eventName;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
|
||||
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
|
||||
|
||||
export interface Spec extends TurboModule {
|
||||
+show: () => void;
|
||||
+hide: () => void;
|
||||
}
|
||||
|
||||
export default (TurboModuleRegistry.get<Spec>('LogBox'): ?Spec);
|
||||
@@ -96,6 +96,9 @@ rn_apple_library(
|
||||
) + react_module_plugin_providers(
|
||||
name = "RedBox",
|
||||
native_class_func = "RCTRedBoxCls",
|
||||
) + react_module_plugin_providers(
|
||||
name = "LogBox",
|
||||
native_class_func = "RCTLogBoxCls",
|
||||
) + react_module_plugin_providers(
|
||||
name = "TVNavigationEventEmitter",
|
||||
native_class_func = "RCTTVNavigationEventEmitterCls",
|
||||
|
||||
@@ -48,6 +48,7 @@ Class RCTPerfMonitorCls(void) __attribute__((used));
|
||||
Class RCTDevMenuCls(void) __attribute__((used));
|
||||
Class RCTDevSettingsCls(void) __attribute__((used));
|
||||
Class RCTRedBoxCls(void) __attribute__((used));
|
||||
Class RCTLogBoxCls(void) __attribute__((used));
|
||||
Class RCTTVNavigationEventEmitterCls(void) __attribute__((used));
|
||||
Class RCTWebSocketExecutorCls(void) __attribute__((used));
|
||||
Class RCTWebSocketModuleCls(void) __attribute__((used));
|
||||
|
||||
@@ -37,6 +37,7 @@ Class RCTCoreModulesClassProvider(const char *name) {
|
||||
{"DevMenu", RCTDevMenuCls},
|
||||
{"DevSettings", RCTDevSettingsCls},
|
||||
{"RedBox", RCTRedBoxCls},
|
||||
{"LogBox", RCTLogBoxCls},
|
||||
{"TVNavigationEventEmitter", RCTTVNavigationEventEmitterCls},
|
||||
{"WebSocketExecutor", RCTWebSocketExecutorCls},
|
||||
{"WebSocketModule", RCTWebSocketModuleCls},
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
#import <React/RCTErrorCustomizer.h>
|
||||
|
||||
@class RCTJSStackFrame;
|
||||
|
||||
@interface RCTLogBox : NSObject <RCTBridgeModule>
|
||||
|
||||
- (void)show;
|
||||
- (void)hide;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#import "RCTLogBox.h"
|
||||
|
||||
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTRootView.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTErrorInfo.h>
|
||||
#import <React/RCTEventDispatcher.h>
|
||||
#import <React/RCTJSStackFrame.h>
|
||||
#import <React/RCTReloadCommand.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "CoreModulesPlugins.h"
|
||||
|
||||
#if RCT_DEV_MENU
|
||||
|
||||
@class RCTLogBoxWindow;
|
||||
|
||||
@protocol RCTLogBoxWindowActionDelegate <NSObject>
|
||||
|
||||
- (void)logBoxWindow:(RCTLogBoxWindow *)logBoxWindow openStackFrameInEditor:(RCTJSStackFrame *)stackFrame;
|
||||
- (void)reloadFromlogBoxWindow:(RCTLogBoxWindow *)logBoxWindow;
|
||||
- (void)loadExtraDataViewController;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTLogBoxWindow : UIWindow <UITableViewDelegate>
|
||||
@property (nonatomic, weak) id<RCTLogBoxWindowActionDelegate> actionDelegate;
|
||||
@end
|
||||
|
||||
@implementation RCTLogBoxWindow
|
||||
{
|
||||
UITableView *_stackTraceTableView;
|
||||
NSString *_lastErrorMessage;
|
||||
NSArray<RCTJSStackFrame *> *_lastStackTrace;
|
||||
int _lastErrorCookie;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge
|
||||
{
|
||||
_lastErrorCookie = -1;
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
#if TARGET_OS_TV
|
||||
self.windowLevel = UIWindowLevelAlert + 1000;
|
||||
#else
|
||||
self.windowLevel = UIWindowLevelStatusBar - 1;
|
||||
#endif
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.hidden = YES;
|
||||
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"LogBox" initialProperties:nil];
|
||||
|
||||
UIViewController *rootViewController = [UIViewController new];
|
||||
rootViewController.view = rootView;
|
||||
self.rootViewController = rootViewController;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)show
|
||||
{
|
||||
[self becomeFirstResponder];
|
||||
[self makeKeyAndVisible];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
self.hidden = YES;
|
||||
[self resignFirstResponder];
|
||||
[RCTSharedApplication().delegate.window makeKeyWindow];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTLogBox () <NativeLogBoxSpec>
|
||||
@end
|
||||
|
||||
@implementation RCTLogBox
|
||||
{
|
||||
RCTLogBoxWindow *_window;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self->_window = [[RCTLogBoxWindow alloc] initWithFrame:[UIScreen mainScreen].bounds bridge: self->_bridge];
|
||||
});
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(show)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self->_window show];
|
||||
});
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(hide)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self->_window dismiss];
|
||||
});
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
{
|
||||
return std::make_shared<facebook::react::NativeLogBoxSpecJSI>(self, jsInvoker);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else // Disabled
|
||||
|
||||
@interface RCTLogBox() <NativeLogBoxSpec>
|
||||
@end
|
||||
|
||||
@implementation RCTLogBox
|
||||
|
||||
+ (NSString *)moduleName
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)show {
|
||||
// noop
|
||||
}
|
||||
|
||||
- (void)hide {
|
||||
// noop
|
||||
}
|
||||
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
|
||||
{
|
||||
return std::make_shared<facebook::react::NativeLogBoxSpecJSI>(self, jsInvoker);
|
||||
}
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
Class RCTLogBoxCls(void) {
|
||||
return RCTLogBox.class;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
||||
* directory of this source tree.
|
||||
*
|
||||
* <p>Generated by an internal genrule from Flow types.
|
||||
*
|
||||
* @generated
|
||||
* @nolint
|
||||
*/
|
||||
|
||||
package com.facebook.fbreact.specs;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReactModuleWithSpec;
|
||||
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
|
||||
|
||||
public abstract class NativeLogBoxSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule {
|
||||
public NativeLogBoxSpec(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public abstract void hide();
|
||||
|
||||
@ReactMethod
|
||||
public abstract void show();
|
||||
}
|
||||
Reference in New Issue
Block a user