Added stubs for some native modules

Reviewed By: javache

Differential Revision: D5111649

fbshipit-source-id: eef2f84556611dec01978d845b89fa145ec5d4db
This commit is contained in:
Alex Dvornikov 2017-06-01 08:20:57 -07:00 committed by Facebook Github Bot
parent bd5051adeb
commit a93b7a2da0
7 changed files with 170 additions and 63 deletions

View File

@ -11,7 +11,7 @@
*/ */
'use strict'; 'use strict';
const EventEmitter = require('EventEmitter'); const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim');
const NativeEventEmitter = require('NativeEventEmitter'); const NativeEventEmitter = require('NativeEventEmitter');
const NativeModules = require('NativeModules'); const NativeModules = require('NativeModules');
const RCTAppState = NativeModules.AppState; const RCTAppState = NativeModules.AppState;
@ -32,8 +32,8 @@ const invariant = require('fbjs/lib/invariant');
* - `background` - The app is running in the background. The user is either * - `background` - The app is running in the background. The user is either
* in another app or on the home screen * in another app or on the home screen
* - `inactive` - This is a state that occurs when transitioning between * - `inactive` - This is a state that occurs when transitioning between
* foreground & background, and during periods of inactivity such as * foreground & background, and during periods of inactivity such as
* entering the Multitasking view or in the event of an incoming call * entering the Multitasking view or in the event of an incoming call
* *
* For more information, see * For more information, see
* [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html) * [Apple's documentation](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html)
@ -87,7 +87,7 @@ class AppState extends NativeEventEmitter {
_eventHandlers: Object; _eventHandlers: Object;
currentState: ?string; currentState: ?string;
isAvailable: boolean; isAvailable: boolean = true;
constructor() { constructor() {
super(RCTAppState); super(RCTAppState);
@ -176,48 +176,31 @@ class AppState extends NativeEventEmitter {
} }
} }
function throwMissingNativeModule() { if (__DEV__ && !RCTAppState) {
invariant( class MissingNativeAppStateShim extends MissingNativeEventEmitterShim {
false, constructor() {
'Cannot use AppState module when native RCTAppState is not included in the build.\n' + super('RCTAppState', 'AppState');
'Either include it, or check AppState.isAvailable before calling any methods.' }
);
}
class MissingNativeAppStateShim extends EventEmitter { get currentState(): ?string {
// AppState this.throwMissingNativeModule();
isAvailable: boolean = false; }
currentState: ?string = null;
addEventListener() { addEventListener(...args: Array<any>) {
throwMissingNativeModule(); this.throwMissingNativeModule();
}
removeEventListener(...args: Array<any>) {
this.throwMissingNativeModule();
}
} }
removeEventListener() { // This module depends on the native `RCTAppState` module. If you don't include it,
throwMissingNativeModule(); // `AppState.isAvailable` will return `false`, and any method calls will throw.
} // We reassign the class variable to keep the autodoc generator happy.
// EventEmitter
addListener() {
throwMissingNativeModule();
}
removeAllListeners() {
throwMissingNativeModule();
}
removeSubscription() {
throwMissingNativeModule();
}
}
// This module depends on the native `RCTAppState` module. If you don't include it,
// `AppState.isAvailable` will return `false`, and any method calls will throw.
// We reassign the class variable to keep the autodoc generator happy.
if (RCTAppState) {
AppState = new AppState();
} else {
AppState = new MissingNativeAppStateShim(); AppState = new MissingNativeAppStateShim();
} else {
AppState = new AppState();
} }
module.exports = AppState; module.exports = AppState;

View File

@ -13,24 +13,28 @@
if (__DEV__) { if (__DEV__) {
const AppState = require('AppState'); const AppState = require('AppState');
const WebSocket = require('WebSocket');
const {PlatformConstants} = require('NativeModules'); const {PlatformConstants} = require('NativeModules');
const {connectToDevTools} = require('react-devtools-core'); const {connectToDevTools} = require('react-devtools-core');
connectToDevTools({ // Initialize dev tools only if the native module for WebSocket is available
isAppActive() { if (WebSocket.isAvailable) {
// Don't steal the DevTools from currently active app. connectToDevTools({
// Note: if you add any AppState subscriptions to this file, isAppActive() {
// you will also need to guard against `AppState.isAvailable`, // Don't steal the DevTools from currently active app.
// or the code will throw for bundles that don't have it. // Note: if you add any AppState subscriptions to this file,
return AppState.currentState !== 'background'; // you will also need to guard against `AppState.isAvailable`,
}, // or the code will throw for bundles that don't have it.
// Special case: Genymotion is running on a different host. return AppState.currentState !== 'background';
host: PlatformConstants && PlatformConstants.ServerHost ? },
PlatformConstants.ServerHost.split(':')[0] : // Special case: Genymotion is running on a different host.
'localhost', host: PlatformConstants && PlatformConstants.ServerHost ?
// Read the optional global variable for backward compatibility. PlatformConstants.ServerHost.split(':')[0] :
// It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0. 'localhost',
port: window.__REACT_DEVTOOLS_PORT__, // Read the optional global variable for backward compatibility.
resolveRNStyle: require('flattenStyle'), // It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0.
}); port: window.__REACT_DEVTOOLS_PORT__,
resolveRNStyle: require('flattenStyle'),
});
}
} }

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule MissingNativeEventEmitterShim
* @flow
*/
'use strict';
const EmitterSubscription = require('EmitterSubscription');
const EventEmitter = require('EventEmitter');
const invariant = require('fbjs/lib/invariant');
class MissingNativeEventEmitterShim extends EventEmitter {
isAvailable: boolean = false;
_nativeModuleName: string;
_nativeEventEmitterName: string;
constructor(nativeModuleName: string, nativeEventEmitterName: string) {
super(null);
this._nativeModuleName = nativeModuleName;
this._nativeEventEmitterName = nativeEventEmitterName;
}
throwMissingNativeModule() {
invariant(
false,
`Cannot use '${this._nativeEventEmitterName}' module when ` +
`native '${this._nativeModuleName}' is not included in the build. ` +
`Either include it, or check '${this._nativeEventEmitterName}'.isAvailable ` +
'before calling any methods.'
);
}
// EventEmitter
addListener(eventType: string, listener: Function, context: ?Object): EmitterSubscription {
this.throwMissingNativeModule();
}
removeAllListeners(eventType: string) {
this.throwMissingNativeModule();
}
removeSubscription(subscription: EmitterSubscription) {
this.throwMissingNativeModule();
}
}
module.exports = MissingNativeEventEmitterShim;

View File

@ -23,7 +23,6 @@ import type EmitterSubscription from 'EmitterSubscription';
* a subset of the standard EventEmitter node module API. * a subset of the standard EventEmitter node module API.
*/ */
class NativeEventEmitter extends EventEmitter { class NativeEventEmitter extends EventEmitter {
_nativeModule: Object; _nativeModule: Object;
constructor(nativeModule: Object) { constructor(nativeModule: Object) {

View File

@ -13,7 +13,7 @@
// Do not require the native RCTNetworking module directly! Use this wrapper module instead. // Do not require the native RCTNetworking module directly! Use this wrapper module instead.
// It will add the necessary requestId, so that you don't have to generate it yourself. // It will add the necessary requestId, so that you don't have to generate it yourself.
const FormData = require('FormData'); const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim');
const NativeEventEmitter = require('NativeEventEmitter'); const NativeEventEmitter = require('NativeEventEmitter');
const RCTNetworkingNative = require('NativeModules').Networking; const RCTNetworkingNative = require('NativeModules').Networking;
const convertRequestBody = require('convertRequestBody'); const convertRequestBody = require('convertRequestBody');
@ -43,6 +43,8 @@ function generateRequestId(): number {
*/ */
class RCTNetworking extends NativeEventEmitter { class RCTNetworking extends NativeEventEmitter {
isAvailable: boolean = true;
constructor() { constructor() {
super(RCTNetworkingNative); super(RCTNetworkingNative);
} }
@ -90,4 +92,31 @@ class RCTNetworking extends NativeEventEmitter {
} }
} }
module.exports = new RCTNetworking(); if (__DEV__ && !RCTNetworkingNative) {
class MissingNativeRCTNetworkingShim extends MissingNativeEventEmitterShim {
constructor() {
super('RCTAppState', 'AppState');
}
sendRequest(...args: Array<any>) {
this.throwMissingNativeModule();
}
abortRequest(...args: Array<any>) {
this.throwMissingNativeModule();
}
clearCookies(...args: Array<any>) {
this.throwMissingNativeModule();
}
}
// This module depends on the native `RCTNetworkingNative` module. If you don't include it,
// `RCTNetworking.isAvailable` will return `false`, and any method calls will throw.
// We reassign the class variable to keep the autodoc generator happy.
RCTNetworking = new MissingNativeRCTNetworkingShim();
} else {
RCTNetworking = new RCTNetworking();
}
module.exports = RCTNetworking;

View File

@ -11,7 +11,7 @@
*/ */
'use strict'; 'use strict';
const FormData = require('FormData'); const MissingNativeEventEmitterShim = require('MissingNativeEventEmitterShim');
const NativeEventEmitter = require('NativeEventEmitter'); const NativeEventEmitter = require('NativeEventEmitter');
const RCTNetworkingNative = require('NativeModules').Networking; const RCTNetworkingNative = require('NativeModules').Networking;
const convertRequestBody = require('convertRequestBody'); const convertRequestBody = require('convertRequestBody');
@ -20,6 +20,8 @@ import type {RequestBody} from 'convertRequestBody';
class RCTNetworking extends NativeEventEmitter { class RCTNetworking extends NativeEventEmitter {
isAvailable: boolean = true;
constructor() { constructor() {
super(RCTNetworkingNative); super(RCTNetworkingNative);
} }
@ -58,4 +60,31 @@ class RCTNetworking extends NativeEventEmitter {
} }
} }
module.exports = new RCTNetworking(); if (__DEV__ && !RCTNetworkingNative) {
class MissingNativeRCTNetworkingShim extends MissingNativeEventEmitterShim {
constructor() {
super('RCTAppState', 'AppState');
}
sendRequest(...args: Array<any>) {
this.throwMissingNativeModule();
}
abortRequest(...args: Array<any>) {
this.throwMissingNativeModule();
}
clearCookies(...args: Array<any>) {
this.throwMissingNativeModule();
}
}
// This module depends on the native `RCTNetworkingNative` module. If you don't include it,
// `RCTNetworking.isAvailable` will return `false`, and any method calls will throw.
// We reassign the class variable to keep the autodoc generator happy.
RCTNetworking = new MissingNativeRCTNetworkingShim();
} else {
RCTNetworking = new RCTNetworking();
}
module.exports = RCTNetworking;

View File

@ -71,6 +71,10 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
readyState: number = CONNECTING; readyState: number = CONNECTING;
url: ?string; url: ?string;
// This module depends on the native `RCTWebSocketModule` module. If you don't include it,
// `WebSocket.isAvailable` will return `false`, and WebSocket constructor will throw an error
static isAvailable: boolean = !!RCTWebSocketModule;
constructor(url: string, protocols: ?string | ?Array<string>, options: ?{origin?: string}) { constructor(url: string, protocols: ?string | ?Array<string>, options: ?{origin?: string}) {
super(); super();
if (typeof protocols === 'string') { if (typeof protocols === 'string') {
@ -81,6 +85,11 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) {
protocols = null; protocols = null;
} }
if (!WebSocket.isAvailable) {
throw new Error('Cannot initialize WebSocket module. ' +
'Native module RCTWebSocketModule is missing.');
}
this._eventEmitter = new NativeEventEmitter(RCTWebSocketModule); this._eventEmitter = new NativeEventEmitter(RCTWebSocketModule);
this._socketId = nextWebSocketId++; this._socketId = nextWebSocketId++;
this._registerEvents(); this._registerEvents();