Provide a Minimal PlatformConstants Implementation (#4075)

* Provide a Minimal PlatformConstants Implementation

Partially addresses #2077

During the upgrade to 0.61, we needed to patch out checks for React Native version since we did not have an implementation of PlatformConstants. This change adds a very minimal implementation of one. The provided constants already vary between platforms, so we have a bit of leeway here in what we decide to provide. The only currently shared API we don't provide is for checking OS version.

Update Platform JS with caching, tpying, and turbomodule changes made upstream. Move modules to a consitent folder. Fix a potential async memory safety issue adjacent to the change,

Tested using ReactUWP Playground RNTester.

* Change files

* Fix Format

* Update Header Paths

* Update a comment

* Fixup vcxproj files

* Add Missing Override

* Change Name to uppercase
This commit is contained in:
Nick Gerleman 2020-02-12 03:11:37 -08:00 коммит произвёл GitHub
Родитель dba0a480f2
Коммит 6162b1f97f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 251 добавлений и 115 удалений

Просмотреть файл

@ -0,0 +1,9 @@
{
"type": "prerelease",
"comment": "Provide a Minimal PlatformConstants Implementation",
"packageName": "@office-iss/react-native-win32",
"email": "ngerlem@microsoft.com",
"commit": "cae1620822a386c4a52fb7351e922485d4f81ac1",
"dependentChangeType": "patch",
"date": "2020-02-11T07:09:14.058Z"
}

Просмотреть файл

@ -0,0 +1,9 @@
{
"type": "prerelease",
"comment": "Provide a Minimal PlatformConstants Implementation",
"packageName": "react-native-windows",
"email": "ngerlem@microsoft.com",
"commit": "cae1620822a386c4a52fb7351e922485d4f81ac1",
"dependentChangeType": "patch",
"date": "2020-02-11T07:09:16.192Z"
}

Просмотреть файл

@ -0,0 +1,28 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*
* @format
* @flow
*/
'use strict';
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
isTesting: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
|};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'PlatformConstants',
): Spec);

Просмотреть файл

@ -8,23 +8,41 @@
'use strict';
const NativeModules = require('../BatchedBridge/NativeModules');
import NativePlatformConstantsWin from './NativePlatformConstantsWin';
export type PlatformSelectSpec<D, I> = {
default?: D,
win32?: I,
};
const Platform = {
__constants: null,
OS: 'win32',
get Version() {
const constants = NativeModules.PlatformConstants;
return constants && constants.Version;
get constants(): {|
isTesting: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
|} {
if (this.__constants == null) {
this.__constants = NativePlatformConstantsWin.getConstants();
}
return this.__constants;
},
get isTesting(): boolean {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
if (__DEV__) {
return this.constants.isTesting;
}
return false;
},
select: (obj: Object) => ('win32' in obj ? obj.win32 : obj.default),
get isTV() {
const constants = NativeModules.PlatformConstants;
return constants ? constants.interfaceIdiom === 'tv' : false;
return false;
},
select: <D, I>(spec: PlatformSelectSpec<D, I>): D | I =>
'win32' in spec ? spec.win32 : spec.default,
};
module.exports = Platform;

Просмотреть файл

@ -23,7 +23,7 @@ const ReactNativeVersion = require('./ReactNativeVersion');
*/
exports.checkVersions = function checkVersions(): void {
// [Windows
// $FlowFixMe constants doesn't exist yet
// This can be removed once devmain adopts 0.61
if (!Platform.constants) {
return;
}

Просмотреть файл

@ -13,7 +13,6 @@
<PROJECT_ROOT>/Libraries/AppTheme/AppTheme.js
<PROJECT_ROOT>/Libraries/Color/normalizeColor.js
<PROJECT_ROOT>/Libraries/Core/setUpDeveloperTools.js
<PROJECT_ROOT>/Libraries/Core/ReactNativeVersionCheck.js
<PROJECT_ROOT>/Libraries/Components/ActivityIndicator/RCTActivityIndicatorViewNativeComponent.js
<PROJECT_ROOT>/Libraries/Components/Button.js
<PROJECT_ROOT>/Libraries/Components/DatePicker/DatePicker.js

Просмотреть файл

@ -7,8 +7,8 @@
#include <IUIManager.h>
#include <Modules/AppStateModule.h>
#include <Modules/NetworkingModule.h>
#include <Modules/WebSocketModule.h>
#include <NativeModuleFactories.h>
#include <WebSocketModule.h>
#include "ChakraRuntimeHolder.h"
#include "DesktopTestInstance.h"
#include "TestMessageQueueThread.h"

Просмотреть файл

@ -3,7 +3,7 @@
#include <CppUnitTest.h>
#include <WebSocketModule.h>
#include <Modules/WebSocketModule.h>
using namespace facebook::react;
using namespace folly;

Просмотреть файл

@ -2,7 +2,7 @@
// Licensed under the MIT License.
#include <CppUnitTest.h>
#include <WebSocketModule.h>
#include <Modules/WebSocketModule.h>
using namespace facebook::react;
using namespace facebook::xplat::module;

Просмотреть файл

@ -3,7 +3,7 @@
#include "pch.h"
#include <WebSocketModule.h>
#include <Modules/WebSocketModule.h>
#include <cxxreact/Instance.h>
#include <cxxreact/JsArgumentHelpers.h>

Просмотреть файл

@ -93,9 +93,9 @@
<ClCompile Include="DevSupportManager.cpp" />
<ClCompile Include="Executors\WebSocketJSExecutor.cpp" />
<ClCompile Include="Executors\WebSocketJSExecutorFactory.cpp" />
<ClCompile Include="JSBigStringResourceDll.cpp" />
<ClCompile Include="LazyDevSupportManager.cpp" />
<ClCompile Include="Modules\NetworkingModule.cpp" />
<ClCompile Include="JSBigStringResourceDll.cpp" />
<ClCompile Include="Modules\TimingModule.cpp" />
<ClCompile Include="Modules\WebSocketModule.cpp" />
<ClCompile Include="pch.cpp">

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "PlatformConstantsModule.h"
#include <VersionHelpers.h>
using Method = facebook::xplat::module::CxxModule::Method;
namespace facebook::react {
const char *PlatformConstantsModule::Name = "PlatformConstants";
std::string PlatformConstantsModule::getName() {
return PlatformConstantsModule::Name;
}
std::vector<Method> PlatformConstantsModule::getMethods() {
return {};
}
std::map<std::string, folly::dynamic> PlatformConstantsModule::getConstants() {
return {
// We don't currently treat Native code differently in a test environment
{"isTesting", false},
// Since we're out-of-tree, we don't know the exact version of React Native
// we're paired with. Provide something sane for now, and try to provide a
// better source of truth later. Tracked by Issue #4073
{"reactNativeVersion", folly::dynamic::object("major", 0)("minor", 61)("patch", 0)}
// We don't provide the typical OS version here. Windows make it hard to
// get an exact version by-design. In the future we should consider
// exposing something here like a facility to check Universal API
// Contract.
};
}
} // namespace facebook::react

Просмотреть файл

@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
#include <cxxreact/CxxModule.h>
namespace facebook::react {
class PlatformConstantsModule : public facebook::xplat::module::CxxModule {
public:
static const char *Name;
std::string getName() override;
std::map<std::string, folly::dynamic> getConstants() override;
std::vector<Method> getMethods() override;
};
} // namespace facebook::react

Просмотреть файл

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include <ReactWindowsCore/SourceCodeModule.h>
#include "SourceCodeModule.h"
using namespace folly;
using namespace facebook::xplat;
@ -9,12 +9,12 @@ using namespace facebook::xplat;
namespace facebook {
namespace react {
const char *SourceCodeModule::name = "SourceCode";
const char *SourceCodeModule::Name = "SourceCode";
SourceCodeModule::SourceCodeModule(const std::string &bundleUrl) : m_bundleUrl(bundleUrl) {}
std::string SourceCodeModule::getName() {
return name;
return Name;
}
auto SourceCodeModule::getConstants() -> std::map<std::string, dynamic> {

Просмотреть файл

@ -20,7 +20,7 @@ class SourceCodeModule : public facebook::xplat::module::CxxModule {
virtual auto getConstants() -> std::map<std::string, folly::dynamic>;
virtual auto getMethods() -> std::vector<Method>;
static const char *name;
static const char *Name;
private:
std::string m_bundleUrl;

Просмотреть файл

@ -127,7 +127,10 @@
<ClInclude Include="Modules\AppThemeModule.h" />
<ClInclude Include="Modules\ExceptionsManagerModule.h" />
<ClInclude Include="Modules\I18nModule.h" />
<ClInclude Include="Modules\PlatformConstantsModule.h" />
<ClInclude Include="Modules\SourceCodeModule.h" />
<ClInclude Include="Modules\UIManagerModule.h" />
<ClInclude Include="Modules\WebSocketModule.h" />
<ClInclude Include="NativeModuleProvider.h" />
<ClInclude Include="OInstance.h" />
<ClInclude Include="pch.h" />
@ -139,7 +142,6 @@
<ClInclude Include="Tracing.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="WebSocketJSExecutorFactory.h" />
<ClInclude Include="WebSocketModule.h" />
<ClInclude Include="ChakraRuntimeHolder.h" Condition="'$(PATCH_RN)' == 'true'" />
<ClInclude Include="HermesRuntimeHolder.h" Condition="'$(PATCH_RN)' == 'true' AND '$(USE_HERMES)' == 'true'" />
<ClInclude Include="V8JSIRuntimeHolder.h" Condition="'$(PATCH_RN)' == 'true' AND '$(USE_V8)' == 'true'" />
@ -158,6 +160,7 @@
<ClCompile Include="Modules\AsyncStorageModule.cpp" />
<ClCompile Include="Modules\ExceptionsManagerModule.cpp" />
<ClCompile Include="Modules\I18nModule.cpp" />
<ClCompile Include="Modules\PlatformConstantsModule.cpp" />
<ClCompile Include="Modules\SourceCodeModule.cpp" />
<ClCompile Include="Modules\UIManagerModule.cpp" />
<ClCompile Include="pch.cpp">

Просмотреть файл

@ -72,6 +72,9 @@
<ClCompile Include="Modules\I18nModule.cpp">
<Filter>Source Files\Modules</Filter>
</ClCompile>
<ClCompile Include="Modules\PlatformConstantsModule.cpp">
<Filter>Source Files\Modules</Filter>
</ClCompile>
<ClCompile Include="Modules\SourceCodeModule.cpp">
<Filter>Source Files\Modules</Filter>
</ClCompile>
@ -191,9 +194,15 @@
<ClInclude Include="Modules\I18nModule.h">
<Filter>Header Files\Modules</Filter>
</ClInclude>
<ClInclude Include="Modules\PlatformConstantsModule.h">
<Filter>Header Files\Modules</Filter>
</ClInclude>
<ClInclude Include="Modules\UIManagerModule.h">
<Filter>Header Files\Modules</Filter>
</ClInclude>
<ClInclude Include="Modules\WebSocketModule.h">
<Filter>Header Files\Modules</Filter>
</ClInclude>
<ClInclude Include="NativeModuleProvider.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -227,9 +236,7 @@
<ClInclude Include="WebSocketJSExecutorFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="WebSocketModule.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Modules\SourceCodeModule.h" />
</ItemGroup>
<ItemGroup>
<None Include="etw\react_native_windows.man">

Просмотреть файл

@ -27,10 +27,11 @@
#include <cxxreact/ModuleRegistry.h>
#if (defined(_MSC_VER) && !defined(WINRT))
#include <WebSocketModule.h>
#include <Modules/WebSocketModule.h>
#endif
#include <Modules/ExceptionsManagerModule.h>
#include <SourceCodeModule.h>
#include <Modules/PlatformConstantsModule.h>
#include <Modules/SourceCodeModule.h>
#if (defined(_MSC_VER) && (defined(WINRT)))
#include <Utils/LocalBundleReader.h>
@ -738,7 +739,7 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
: std::string();
modules.push_back(std::make_unique<CxxNativeModule>(
m_innerInstance,
facebook::react::SourceCodeModule::name,
facebook::react::SourceCodeModule::Name,
[bundleUrl]() -> std::unique_ptr<xplat::module::CxxModule> {
return std::make_unique<SourceCodeModule>(bundleUrl);
},
@ -747,12 +748,17 @@ std::vector<std::unique_ptr<NativeModule>> InstanceImpl::GetDefaultNativeModules
modules.push_back(std::make_unique<CxxNativeModule>(
m_innerInstance,
"ExceptionsManager",
[&]() -> std::unique_ptr<xplat::module::CxxModule> {
return std::make_unique<facebook::react::ExceptionsManagerModule>(
std::move(m_devSettings->jsExceptionCallback));
[callback{std::move(m_devSettings->jsExceptionCallback)}]() mutable {
return std::make_unique<ExceptionsManagerModule>(std::move(callback));
},
nativeQueue));
modules.push_back(std::make_unique<CxxNativeModule>(
m_innerInstance,
PlatformConstantsModule::Name,
[]() { return std::make_unique<PlatformConstantsModule>(); },
nativeQueue));
return modules;
}

Просмотреть файл

@ -0,0 +1,28 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*
* @format
* @flow
*/
'use strict';
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|
isTesting: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
|};
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'PlatformConstants',
): Spec);

Просмотреть файл

@ -1,24 +1,48 @@
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*
* @format
* @flow
*/
'use strict';
const NativeModules = require('../BatchedBridge/NativeModules');
import NativePlatformConstantsWin from './NativePlatformConstantsWin';
export type PlatformSelectSpec<D, I> = {
default?: D,
windesktop?: I,
};
const Platform = {
__constants: null,
OS: 'windesktop',
get Version() {
const constants = NativeModules.PlatformConstants;
return constants && constants.Version;
get constants(): {|
isTesting: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
|} {
if (this.__constants == null) {
this.__constants = NativePlatformConstantsWin.getConstants();
}
return this.__constants;
},
get isTesting(): boolean {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
if (__DEV__) {
return this.constants.isTesting;
}
return false;
},
select: (obj: Object) => ('windesktop' in obj ? obj.windesktop : obj.default),
get isTV() {
return false;
},
select: <D, I>(spec: PlatformSelectSpec<D, I>): D | I =>
'windesktop' in spec ? spec.windesktop : spec.default,
};
module.exports = Platform;

Просмотреть файл

@ -8,23 +8,41 @@
'use strict';
const NativeModules = require('../BatchedBridge/NativeModules');
import NativePlatformConstantsWin from './NativePlatformConstantsWin';
export type PlatformSelectSpec<D, I> = {
default?: D,
windows?: I,
};
const Platform = {
__constants: null,
OS: 'windows',
get Version() {
const constants = NativeModules.PlatformConstants;
return constants && constants.Version;
get constants(): {|
isTesting: boolean,
reactNativeVersion: {|
major: number,
minor: number,
patch: number,
prerelease: ?number,
|},
|} {
if (this.__constants == null) {
this.__constants = NativePlatformConstantsWin.getConstants();
}
return this.__constants;
},
get isTesting(): boolean {
const constants = NativeModules.PlatformConstants;
return constants && constants.isTesting;
if (__DEV__) {
return this.constants.isTesting;
}
return false;
},
select: (obj: Object) => ('windows' in obj ? obj.windows : obj.default),
get isTV() {
const constants = NativeModules.PlatformConstants;
return constants ? constants.interfaceIdiom === 'tv' : false;
return false;
},
select: <D, I>(spec: PlatformSelectSpec<D, I>): D | I =>
'windows' in spec ? spec.windows : spec.default,
};
module.exports = Platform;

Просмотреть файл

@ -1,14 +0,0 @@
/**
* 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 strict-local
* @format
*/
'use strict';
exports.checkVersions = function checkVersions(): void {
return;
};

Просмотреть файл

@ -1,55 +0,0 @@
/**
* 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 strict-local
* @format
*/
'use strict';
import Platform from '../Utilities/Platform';
const ReactNativeVersion = require('./ReactNativeVersion');
/**
* Checks that the version of this React Native JS is compatible with the native
* code, throwing an error if it isn't.
*
* The existence of this module is part of the public interface of React Native
* even though it is used only internally within React Native. React Native
* implementations for other platforms (ex: Windows) may override this module
* and rely on its existence as a separate module.
*/
exports.checkVersions = function checkVersions(): void {
// [Windows
// $FlowFixMe Platform.contstants doesn't exist yet
if (!Platform.constants) {
return;
}
// Windows]
const nativeVersion = Platform.constants.reactNativeVersion;
if (
ReactNativeVersion.version.major !== nativeVersion.major ||
ReactNativeVersion.version.minor !== nativeVersion.minor
) {
console.error(
`React Native version mismatch.\n\nJavaScript version: ${_formatVersion(
ReactNativeVersion.version,
)}\n` +
`Native version: ${_formatVersion(nativeVersion)}\n\n` +
'Make sure that you have rebuilt the native code. If the problem ' +
'persists try clearing the Watchman and packager caches with ' +
'`watchman watch-del-all && react-native start --reset-cache`.',
);
}
};
function _formatVersion(version): string {
return (
`${version.major}.${version.minor}.${version.patch}` +
// eslint-disable-next-line eqeqeq
(version.prerelease != undefined ? `-${version.prerelease}` : '')
);
}