Skip to content

Commit 2ae43e5

Browse files
Emily Janzerfacebook-github-bot
authored andcommitted
Replace UIManager with stub for bridgeless RN
Summary: Replacing UIManager.js with a shim that redirects to either PaperUIManager (containing old impl) or DummyUIManager, if `global.RN$Bridgeless` is set. The UIManager native module doesn't exist in bridgeless mode, which means requiring UIManager.js currently fatals. This is a bit hacky, but it's a lot easier than implementing a dummy native module to make it happy. I did have to stub out all the properties in UIManagerJSInterface to appease flow, though... Reviewed By: yungsters Differential Revision: D15775582 fbshipit-source-id: 8e2628f75b2242971895583696122760acdad7af
1 parent c2824dd commit 2ae43e5

File tree

3 files changed

+305
-169
lines changed

3 files changed

+305
-169
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
* @format
9+
*/
10+
'use strict';
11+
12+
module.exports = {
13+
getViewManagerConfig: (viewManagerName: string) => {
14+
throw new Error(
15+
'Attempting to get config for view manager ' + viewManagerName,
16+
);
17+
},
18+
getConstants: () => ({}),
19+
getConstantsForViewManager: (viewManagerName: string) => {},
20+
getDefaultEventTypes: () => [],
21+
playTouchSound: () => {},
22+
lazilyLoadView: (name: string) => {},
23+
createView: (
24+
reactTag: ?number,
25+
viewName: string,
26+
rootTag: number,
27+
props: Object,
28+
) => {},
29+
updateView: (reactTag: number, viewName: string, props: Object) => {},
30+
focus: (reactTag: ?number) => {},
31+
blur: (reactTag: ?number) => {},
32+
findSubviewIn: (
33+
reactTag: ?number,
34+
point: Array<number>,
35+
callback: (
36+
nativeViewTag: number,
37+
left: number,
38+
top: number,
39+
width: number,
40+
height: number,
41+
) => void,
42+
) => {},
43+
dispatchViewManagerCommand: (
44+
reactTag: ?number,
45+
commandID: number,
46+
commandArgs: ?Array<string | number | boolean>,
47+
) => {},
48+
measure: (
49+
reactTag: ?number,
50+
callback: (
51+
left: number,
52+
top: number,
53+
width: number,
54+
height: number,
55+
pageX: number,
56+
pageY: number,
57+
) => void,
58+
) => {},
59+
measureInWindow: (
60+
reactTag: ?number,
61+
callback: (x: number, y: number, width: number, height: number) => void,
62+
) => {},
63+
viewIsDescendantOf: (
64+
reactTag: ?number,
65+
ancestorReactTag: ?number,
66+
callback: (result: Array<boolean>) => void,
67+
) => {},
68+
measureLayout: (
69+
reactTag: ?number,
70+
ancestorReactTag: ?number,
71+
errorCallback: (error: Object) => void,
72+
callback: (
73+
left: number,
74+
top: number,
75+
width: number,
76+
height: number,
77+
) => void,
78+
) => {},
79+
measureLayoutRelativeToParent: (
80+
reactTag: ?number,
81+
errorCallback: (error: Object) => void,
82+
callback: (
83+
left: number,
84+
top: number,
85+
width: number,
86+
height: number,
87+
) => void,
88+
) => {},
89+
setJSResponder: (reactTag: ?number, blockNativeResponder: boolean) => {},
90+
clearJSResponder: () => {},
91+
configureNextLayoutAnimation: (
92+
config: Object,
93+
callback: () => void,
94+
errorCallback: (error: Object) => void,
95+
) => {},
96+
removeSubviewsFromContainerWithID: (containerID: number) => {},
97+
replaceExistingNonRootView: (reactTag: ?number, newReactTag: ?number) => {},
98+
setChildren: (containerTag: ?number, reactTags: Array<number>) => {},
99+
manageChildren: (
100+
containerTag: ?number,
101+
moveFromIndices: Array<number>,
102+
moveToIndices: Array<number>,
103+
addChildReactTags: Array<number>,
104+
addAtIndices: Array<number>,
105+
removeAtIndices: Array<number>,
106+
) => {},
107+
108+
// Android only
109+
setLayoutAnimationEnabledExperimental: (enabled: boolean) => {},
110+
sendAccessibilityEvent: (reactTag: ?number, eventType: number) => {},
111+
showPopupMenu: (
112+
reactTag: ?number,
113+
items: Array<string>,
114+
error: (error: Object) => void,
115+
success: (event: string, selected?: number) => void,
116+
) => {},
117+
dismissPopupMenu: () => {},
118+
};
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
* @format
9+
*/
10+
'use strict';
11+
12+
const NativeModules = require('../BatchedBridge/NativeModules');
13+
const Platform = require('../Utilities/Platform');
14+
const UIManagerProperties = require('./UIManagerProperties');
15+
16+
const defineLazyObjectProperty = require('../Utilities/defineLazyObjectProperty');
17+
18+
import NativeUIManager from './NativeUIManager';
19+
20+
const viewManagerConfigs = {};
21+
22+
const triedLoadingConfig = new Set();
23+
24+
let NativeUIManagerConstants = {};
25+
let isNativeUIManagerConstantsSet = false;
26+
function getConstants(): Object {
27+
if (!isNativeUIManagerConstantsSet) {
28+
NativeUIManagerConstants = NativeUIManager.getConstants();
29+
isNativeUIManagerConstantsSet = true;
30+
}
31+
return NativeUIManagerConstants;
32+
}
33+
34+
const UIManagerJS = {
35+
...NativeUIManager,
36+
getConstants(): Object {
37+
return getConstants();
38+
},
39+
getViewManagerConfig: function(viewManagerName: string) {
40+
if (
41+
viewManagerConfigs[viewManagerName] === undefined &&
42+
NativeUIManager.getConstantsForViewManager
43+
) {
44+
try {
45+
viewManagerConfigs[
46+
viewManagerName
47+
] = NativeUIManager.getConstantsForViewManager(viewManagerName);
48+
} catch (e) {
49+
viewManagerConfigs[viewManagerName] = null;
50+
}
51+
}
52+
53+
const config = viewManagerConfigs[viewManagerName];
54+
if (config) {
55+
return config;
56+
}
57+
58+
// If we're in the Chrome Debugger, let's not even try calling the sync
59+
// method.
60+
if (!global.nativeCallSyncHook) {
61+
return config;
62+
}
63+
64+
if (
65+
NativeUIManager.lazilyLoadView &&
66+
!triedLoadingConfig.has(viewManagerName)
67+
) {
68+
const result = NativeUIManager.lazilyLoadView(viewManagerName);
69+
triedLoadingConfig.add(viewManagerName);
70+
if (result.viewConfig) {
71+
getConstants()[viewManagerName] = result.viewConfig;
72+
lazifyViewManagerConfig(viewManagerName);
73+
}
74+
}
75+
76+
return viewManagerConfigs[viewManagerName];
77+
},
78+
};
79+
80+
// TODO (T45220498): Remove this.
81+
// 3rd party libs may be calling `NativeModules.UIManager.getViewManagerConfig()`
82+
// instead of `UIManager.getViewManagerConfig()` off UIManager.js.
83+
// This is a workaround for now.
84+
// $FlowFixMe
85+
NativeUIManager.getViewManagerConfig = UIManagerJS.getViewManagerConfig;
86+
87+
function lazifyViewManagerConfig(viewName) {
88+
const viewConfig = getConstants()[viewName];
89+
if (viewConfig.Manager) {
90+
viewManagerConfigs[viewName] = viewConfig;
91+
defineLazyObjectProperty(viewConfig, 'Constants', {
92+
get: () => {
93+
const viewManager = NativeModules[viewConfig.Manager];
94+
const constants = {};
95+
viewManager &&
96+
Object.keys(viewManager).forEach(key => {
97+
const value = viewManager[key];
98+
if (typeof value !== 'function') {
99+
constants[key] = value;
100+
}
101+
});
102+
return constants;
103+
},
104+
});
105+
defineLazyObjectProperty(viewConfig, 'Commands', {
106+
get: () => {
107+
const viewManager = NativeModules[viewConfig.Manager];
108+
const commands = {};
109+
let index = 0;
110+
viewManager &&
111+
Object.keys(viewManager).forEach(key => {
112+
const value = viewManager[key];
113+
if (typeof value === 'function') {
114+
commands[key] = index++;
115+
}
116+
});
117+
return commands;
118+
},
119+
});
120+
}
121+
}
122+
123+
/**
124+
* Copies the ViewManager constants and commands into UIManager. This is
125+
* only needed for iOS, which puts the constants in the ViewManager
126+
* namespace instead of UIManager, unlike Android.
127+
*/
128+
if (Platform.OS === 'ios') {
129+
Object.keys(getConstants()).forEach(viewName => {
130+
lazifyViewManagerConfig(viewName);
131+
});
132+
} else if (getConstants().ViewManagerNames) {
133+
// We want to add all the view managers to the UIManager.
134+
// However, the way things are set up, the list of view managers is not known at compile time.
135+
// As Prepack runs at compile it, it cannot process this loop.
136+
// So we wrap it in a special __residual call, which basically tells Prepack to ignore it.
137+
let residual = global.__residual
138+
? global.__residual
139+
: (_, f, ...args) => f.apply(undefined, args);
140+
residual(
141+
'void',
142+
(UIManager, defineLazyObjectProperty) => {
143+
UIManager.getConstants().ViewManagerNames.forEach(viewManagerName => {
144+
defineLazyObjectProperty(UIManager, viewManagerName, {
145+
get: () => UIManager.getConstantsForViewManager(viewManagerName),
146+
});
147+
});
148+
},
149+
NativeUIManager,
150+
defineLazyObjectProperty,
151+
);
152+
153+
// As Prepack now no longer knows which properties exactly the UIManager has,
154+
// we also tell Prepack that it has only partial knowledge of the UIManager,
155+
// so that any accesses to unknown properties along the global code will fail
156+
// when Prepack encounters them.
157+
if (global.__makePartial) {
158+
global.__makePartial(NativeUIManager);
159+
}
160+
}
161+
162+
if (!global.nativeCallSyncHook) {
163+
Object.keys(getConstants()).forEach(viewManagerName => {
164+
if (!UIManagerProperties.includes(viewManagerName)) {
165+
if (!viewManagerConfigs[viewManagerName]) {
166+
viewManagerConfigs[viewManagerName] = getConstants()[viewManagerName];
167+
}
168+
defineLazyObjectProperty(NativeUIManager, viewManagerName, {
169+
get: () => {
170+
console.warn(
171+
`Accessing view manager configs directly off UIManager via UIManager['${viewManagerName}'] ` +
172+
`is no longer supported. Use UIManager.getViewManagerConfig('${viewManagerName}') instead.`,
173+
);
174+
175+
return UIManagerJS.getViewManagerConfig(viewManagerName);
176+
},
177+
});
178+
}
179+
});
180+
}
181+
182+
module.exports = UIManagerJS;

0 commit comments

Comments
 (0)