mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a3cad4d89 | ||
|
|
48f29a74c5 | ||
|
|
8e03ced500 | ||
|
|
ac55ffd777 | ||
|
|
8bdd98ea48 | ||
|
|
2d57335fa7 | ||
|
|
2f8446319a | ||
|
|
815a07c77b | ||
|
|
53c1a4cc7b | ||
|
|
67e67ec83c | ||
|
|
0f96ebd93b | ||
|
|
f4fde9d84a | ||
|
|
4194bb242d | ||
|
|
675f14257a | ||
|
|
21dd3dd296 | ||
|
|
03d7b2aa0e | ||
|
|
2c5fbd79a2 | ||
|
|
49e35bd939 | ||
|
|
829f675b8b | ||
|
|
b58d848d9c | ||
|
|
294d95a236 |
@@ -383,6 +383,9 @@ jobs:
|
||||
publish_npm_package:
|
||||
<<: *android_defaults
|
||||
steps:
|
||||
# Checkout code so that we can work with `git` in publish.js
|
||||
- checkout
|
||||
|
||||
- attach_workspace:
|
||||
at: ~/react-native
|
||||
|
||||
@@ -606,6 +609,7 @@ workflows:
|
||||
- approve_publish_npm_package:
|
||||
filters: *filter-only-stable
|
||||
type: approval
|
||||
|
||||
- publish_npm_package:
|
||||
requires:
|
||||
- checkout_code
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
exports.version = {
|
||||
major: 0,
|
||||
minor: 0,
|
||||
patch: 0,
|
||||
minor: 54,
|
||||
patch: 2,
|
||||
prerelease: null,
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
const ReactFeatureFlags = {
|
||||
debugRenderPhaseSideEffects: false,
|
||||
debugRenderPhaseSideEffectsForStrictMode: false,
|
||||
warnAboutDeprecatedLifecycles: true,
|
||||
warnAboutDeprecatedLifecycles: false,
|
||||
};
|
||||
|
||||
module.exports = ReactFeatureFlags;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#define RCT_REACT_NATIVE_VERSION @{ \
|
||||
@"major": @(0), \
|
||||
@"minor": @(0), \
|
||||
@"patch": @(0), \
|
||||
@"minor": @(54), \
|
||||
@"patch": @(2), \
|
||||
@"prerelease": [NSNull null], \
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VERSION_NAME=1000.0.0-master
|
||||
VERSION_NAME=0.54.2
|
||||
GROUP=com.facebook.react
|
||||
|
||||
POM_NAME=ReactNative
|
||||
|
||||
@@ -146,13 +146,13 @@ public class BundleDownloader {
|
||||
if (match.find()) {
|
||||
String boundary = match.group(1);
|
||||
MultipartStreamReader bodyReader = new MultipartStreamReader(response.body().source(), boundary);
|
||||
boolean completed = bodyReader.readAllParts(new MultipartStreamReader.ChunkCallback() {
|
||||
boolean completed = bodyReader.readAllParts(new MultipartStreamReader.ChunkListener() {
|
||||
@Override
|
||||
public void execute(Map<String, String> headers, Buffer body, boolean finished) throws IOException {
|
||||
public void onChunkComplete(Map<String, String> headers, Buffer body, boolean isLastChunk) throws IOException {
|
||||
// This will get executed for every chunk of the multipart response. The last chunk
|
||||
// (finished = true) will be the JS bundle, the other ones will be progress events
|
||||
// (isLastChunk = true) will be the JS bundle, the other ones will be progress events
|
||||
// encoded as JSON.
|
||||
if (finished) {
|
||||
if (isLastChunk) {
|
||||
// The http status code for each separate chunk is in the X-Http-Status header.
|
||||
int status = response.code();
|
||||
if (headers.containsKey("X-Http-Status")) {
|
||||
@@ -184,6 +184,15 @@ public class BundleDownloader {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onChunkProgress(Map<String, String> headers, long loaded, long total) throws IOException {
|
||||
if ("application/javascript".equals(headers.get("Content-Type"))) {
|
||||
callback.onProgress(
|
||||
"Downloading JavaScript bundle",
|
||||
(int) (loaded / 1024),
|
||||
(int) (total / 1024));
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!completed) {
|
||||
callback.onFailure(new DebugServerException(
|
||||
|
||||
+51
-9
@@ -26,9 +26,18 @@ public class MultipartStreamReader {
|
||||
|
||||
private final BufferedSource mSource;
|
||||
private final String mBoundary;
|
||||
private long mLastProgressEvent;
|
||||
|
||||
public interface ChunkCallback {
|
||||
void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException;
|
||||
public interface ChunkListener {
|
||||
/**
|
||||
* Invoked when a chunk of a multipart response is fully downloaded.
|
||||
*/
|
||||
void onChunkComplete(Map<String, String> headers, Buffer body, boolean isLastChunk) throws IOException;
|
||||
|
||||
/**
|
||||
* Invoked as bytes of the current chunk are read.
|
||||
*/
|
||||
void onChunkProgress(Map<String, String> headers, long loaded, long total) throws IOException;
|
||||
}
|
||||
|
||||
public MultipartStreamReader(BufferedSource source, String boundary) {
|
||||
@@ -55,34 +64,50 @@ public class MultipartStreamReader {
|
||||
return headers;
|
||||
}
|
||||
|
||||
private void emitChunk(Buffer chunk, boolean done, ChunkCallback callback) throws IOException {
|
||||
private void emitChunk(Buffer chunk, boolean done, ChunkListener listener) throws IOException {
|
||||
ByteString marker = ByteString.encodeUtf8(CRLF + CRLF);
|
||||
long indexOfMarker = chunk.indexOf(marker);
|
||||
if (indexOfMarker == -1) {
|
||||
callback.execute(null, chunk, done);
|
||||
listener.onChunkComplete(null, chunk, done);
|
||||
} else {
|
||||
Buffer headers = new Buffer();
|
||||
Buffer body = new Buffer();
|
||||
chunk.read(headers, indexOfMarker);
|
||||
chunk.skip(marker.size());
|
||||
chunk.readAll(body);
|
||||
callback.execute(parseHeaders(headers), body, done);
|
||||
listener.onChunkComplete(parseHeaders(headers), body, done);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitProgress(Map<String, String> headers, long contentLength, boolean isFinal, ChunkListener listener) throws IOException {
|
||||
if (headers == null || listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - mLastProgressEvent > 16 || isFinal) {
|
||||
mLastProgressEvent = currentTime;
|
||||
long headersContentLength = headers.get("Content-Length") != null ? Long.parseLong(headers.get("Content-Length")) : 0;
|
||||
listener.onChunkProgress(headers, contentLength, headersContentLength);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all parts of the multipart response and execute the callback for each chunk received.
|
||||
* @param callback Callback executed when a chunk is received
|
||||
* Reads all parts of the multipart response and execute the listener for each chunk received.
|
||||
* @param listener Listener invoked when chunks are received.
|
||||
* @return If the read was successful
|
||||
*/
|
||||
public boolean readAllParts(ChunkCallback callback) throws IOException {
|
||||
public boolean readAllParts(ChunkListener listener) throws IOException {
|
||||
ByteString delimiter = ByteString.encodeUtf8(CRLF + "--" + mBoundary + CRLF);
|
||||
ByteString closeDelimiter = ByteString.encodeUtf8(CRLF + "--" + mBoundary + "--" + CRLF);
|
||||
ByteString headersDelimiter = ByteString.encodeUtf8(CRLF + CRLF);
|
||||
|
||||
int bufferLen = 4 * 1024;
|
||||
long chunkStart = 0;
|
||||
long bytesSeen = 0;
|
||||
Buffer content = new Buffer();
|
||||
Map<String, String> currentHeaders = null;
|
||||
long currentHeadersLength = 0;
|
||||
|
||||
while (true) {
|
||||
boolean isCloseDelimiter = false;
|
||||
@@ -98,6 +123,20 @@ public class MultipartStreamReader {
|
||||
|
||||
if (indexOfDelimiter == -1) {
|
||||
bytesSeen = content.size();
|
||||
|
||||
if (currentHeaders == null) {
|
||||
long indexOfHeaders = content.indexOf(headersDelimiter, searchStart);
|
||||
if (indexOfHeaders >= 0) {
|
||||
mSource.read(content, indexOfHeaders);
|
||||
Buffer headers = new Buffer();
|
||||
content.copyTo(headers, searchStart, indexOfHeaders - searchStart);
|
||||
currentHeadersLength = headers.size() + headersDelimiter.size();
|
||||
currentHeaders = parseHeaders(headers);
|
||||
}
|
||||
} else {
|
||||
emitProgress(currentHeaders, content.size() - currentHeadersLength, false, listener);
|
||||
}
|
||||
|
||||
long bytesRead = mSource.read(content, bufferLen);
|
||||
if (bytesRead <= 0) {
|
||||
return false;
|
||||
@@ -113,7 +152,10 @@ public class MultipartStreamReader {
|
||||
Buffer chunk = new Buffer();
|
||||
content.skip(chunkStart);
|
||||
content.read(chunk, length);
|
||||
emitChunk(chunk, isCloseDelimiter, callback);
|
||||
emitProgress(currentHeaders, chunk.size() - currentHeadersLength, true, listener);
|
||||
emitChunk(chunk, isCloseDelimiter, listener);
|
||||
currentHeaders = null;
|
||||
currentHeadersLength = 0;
|
||||
} else {
|
||||
content.skip(chunkEnd);
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ import java.util.Map;
|
||||
public class ReactNativeVersion {
|
||||
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
|
||||
"major", 0,
|
||||
"minor", 0,
|
||||
"patch", 0,
|
||||
"minor", 54,
|
||||
"patch", 2,
|
||||
"prerelease", null);
|
||||
}
|
||||
|
||||
@@ -174,14 +174,16 @@ public class ReactEditText extends EditText {
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
ReactContext reactContext = (ReactContext) getContext();
|
||||
ReactEditTextInputConnectionWrapper inputConnectionWrapper =
|
||||
new ReactEditTextInputConnectionWrapper(super.onCreateInputConnection(outAttrs), reactContext, this);
|
||||
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
|
||||
if (inputConnection != null) {
|
||||
inputConnection = new ReactEditTextInputConnectionWrapper(inputConnection, reactContext, this);
|
||||
}
|
||||
|
||||
if (isMultiline() && getBlurOnSubmit()) {
|
||||
// Remove IME_FLAG_NO_ENTER_ACTION to keep the original IME_OPTION
|
||||
outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
|
||||
}
|
||||
return inputConnectionWrapper;
|
||||
return inputConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+6
-5
@@ -94,14 +94,15 @@ class ReactEditTextInputConnectionWrapper extends InputConnectionWrapper {
|
||||
int previousSelectionEnd = mEditText.getSelectionEnd();
|
||||
String key;
|
||||
boolean consumed = super.setComposingText(text, newCursorPosition);
|
||||
int currentSelectionStart = mEditText.getSelectionStart();
|
||||
boolean noPreviousSelection = previousSelectionStart == previousSelectionEnd;
|
||||
boolean cursorDidNotMove = mEditText.getSelectionStart() == previousSelectionStart;
|
||||
boolean cursorMovedBackwards = mEditText.getSelectionStart() < previousSelectionStart;
|
||||
if ((noPreviousSelection && cursorMovedBackwards)
|
||||
|| !noPreviousSelection && cursorDidNotMove) {
|
||||
boolean cursorDidNotMove = currentSelectionStart == previousSelectionStart;
|
||||
boolean cursorMovedBackwardsOrAtBeginningOfInput =
|
||||
(currentSelectionStart < previousSelectionStart) || currentSelectionStart <= 0;
|
||||
if (cursorMovedBackwardsOrAtBeginningOfInput || (!noPreviousSelection && cursorDidNotMove)) {
|
||||
key = BACKSPACE_KEY_VALUE;
|
||||
} else {
|
||||
key = String.valueOf(mEditText.getText().charAt(mEditText.getSelectionStart() - 1));
|
||||
key = String.valueOf(mEditText.getText().charAt(currentSelectionStart - 1));
|
||||
}
|
||||
dispatchKeyEventOrEnqueue(key);
|
||||
return consumed;
|
||||
|
||||
+23
-18
@@ -24,14 +24,19 @@ import static org.fest.assertions.api.Assertions.assertThat;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class MultipartStreamReaderTest {
|
||||
|
||||
class CallCountTrackingChunkCallback implements MultipartStreamReader.ChunkCallback {
|
||||
class CallCountTrackingChunkCallback implements MultipartStreamReader.ChunkListener {
|
||||
private int mCount = 0;
|
||||
|
||||
@Override
|
||||
public void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException {
|
||||
public void onChunkComplete(Map<String, String> headers, Buffer body, boolean done) throws IOException {
|
||||
mCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkProgress(Map<String, String> headers, long loaded, long total) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
public int getCallCount() {
|
||||
return mCount;
|
||||
}
|
||||
@@ -41,12 +46,12 @@ public class MultipartStreamReaderTest {
|
||||
public void testSimpleCase() throws IOException {
|
||||
ByteString response = ByteString.encodeUtf8(
|
||||
"preable, should be ignored\r\n" +
|
||||
"--sample_boundary\r\n" +
|
||||
"Content-Type: application/json; charset=utf-8\r\n" +
|
||||
"Content-Length: 2\r\n\r\n" +
|
||||
"{}\r\n" +
|
||||
"--sample_boundary--\r\n" +
|
||||
"epilogue, should be ignored");
|
||||
"--sample_boundary\r\n" +
|
||||
"Content-Type: application/json; charset=utf-8\r\n" +
|
||||
"Content-Length: 2\r\n\r\n" +
|
||||
"{}\r\n" +
|
||||
"--sample_boundary--\r\n" +
|
||||
"epilogue, should be ignored");
|
||||
|
||||
Buffer source = new Buffer();
|
||||
source.write(response);
|
||||
@@ -55,8 +60,8 @@ public class MultipartStreamReaderTest {
|
||||
|
||||
CallCountTrackingChunkCallback callback = new CallCountTrackingChunkCallback() {
|
||||
@Override
|
||||
public void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException {
|
||||
super.execute(headers, body, done);
|
||||
public void onChunkComplete(Map<String, String> headers, Buffer body, boolean done) throws IOException {
|
||||
super.onChunkComplete(headers, body, done);
|
||||
|
||||
assertThat(done).isTrue();
|
||||
assertThat(headers.get("Content-Type")).isEqualTo("application/json; charset=utf-8");
|
||||
@@ -89,8 +94,8 @@ public class MultipartStreamReaderTest {
|
||||
|
||||
CallCountTrackingChunkCallback callback = new CallCountTrackingChunkCallback() {
|
||||
@Override
|
||||
public void execute(Map<String, String> headers, Buffer body, boolean done) throws IOException {
|
||||
super.execute(headers, body, done);
|
||||
public void onChunkComplete(Map<String, String> headers, Buffer body, boolean done) throws IOException {
|
||||
super.onChunkComplete(headers, body, done);
|
||||
|
||||
assertThat(done).isEqualTo(getCallCount() == 3);
|
||||
assertThat(body.readUtf8()).isEqualTo(String.valueOf(getCallCount()));
|
||||
@@ -122,12 +127,12 @@ public class MultipartStreamReaderTest {
|
||||
public void testNoCloseDelimiter() throws IOException {
|
||||
ByteString response = ByteString.encodeUtf8(
|
||||
"preable, should be ignored\r\n" +
|
||||
"--sample_boundary\r\n" +
|
||||
"Content-Type: application/json; charset=utf-8\r\n" +
|
||||
"Content-Length: 2\r\n\r\n" +
|
||||
"{}\r\n" +
|
||||
"--sample_boundary\r\n" +
|
||||
"incomplete message...");
|
||||
"--sample_boundary\r\n" +
|
||||
"Content-Type: application/json; charset=utf-8\r\n" +
|
||||
"Content-Length: 2\r\n\r\n" +
|
||||
"{}\r\n" +
|
||||
"--sample_boundary\r\n" +
|
||||
"incomplete message...");
|
||||
|
||||
Buffer source = new Buffer();
|
||||
source.write(response);
|
||||
|
||||
@@ -126,3 +126,5 @@ exports.dependencyConfig = function dependencyConfigAndroid(folder, userConfig)
|
||||
|
||||
return { sourceDir, folder, manifest, packageImportPath, packageInstance };
|
||||
};
|
||||
|
||||
exports.linkConfig = require('../../link/android');
|
||||
|
||||
@@ -57,3 +57,5 @@ exports.projectConfig = function projectConfigIOS(folder, userConfig) {
|
||||
};
|
||||
|
||||
exports.dependencyConfig = exports.projectConfig;
|
||||
|
||||
exports.linkConfig = require('../../link/ios');
|
||||
|
||||
@@ -81,8 +81,10 @@ describe('link', () => {
|
||||
it('should register native module when android/ios projects are present', (done) => {
|
||||
const registerNativeModule = sinon.stub();
|
||||
const dependencyConfig = {android: {}, ios: {}, assets: [], commands: {}};
|
||||
const androidLinkConfig = require('../android');
|
||||
const iosLinkConfig = require('../ios');
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||
getPlatformConfig: () => ({ios: { linkConfig: iosLinkConfig }, android: { linkConfig: androidLinkConfig }}),
|
||||
getProjectConfig: () => ({android: {}, ios: {}, assets: []}),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
@@ -223,8 +225,9 @@ describe('link', () => {
|
||||
sinon.stub().returns(false)
|
||||
);
|
||||
|
||||
const linkConfig = require('../ios');
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ ios: {}}),
|
||||
getPlatformConfig: () => ({ ios: { linkConfig: linkConfig }}),
|
||||
getProjectConfig: () => ({ ios: {}, assets: [] }),
|
||||
getDependencyConfig: sinon.stub().returns({
|
||||
ios: {}, assets: [], commands: { prelink, postlink },
|
||||
@@ -251,8 +254,9 @@ describe('link', () => {
|
||||
copyAssets
|
||||
);
|
||||
|
||||
const linkConfig = require('../ios');
|
||||
const config = {
|
||||
getPlatformConfig: () => ({ ios: {} }),
|
||||
getPlatformConfig: () => ({ ios: { linkConfig: linkConfig } }),
|
||||
getProjectConfig: () => ({ ios: {}, assets: projectAssets }),
|
||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||
};
|
||||
|
||||
@@ -17,10 +17,10 @@ const groupFilesByType = require('../groupFilesByType');
|
||||
* For now, the only types of files that are handled are:
|
||||
* - Fonts (otf, ttf) - copied to targetPath/fonts under original name
|
||||
*/
|
||||
module.exports = function copyAssetsAndroid(files, targetPath) {
|
||||
module.exports = function copyAssetsAndroid(files, project) {
|
||||
const assets = groupFilesByType(files);
|
||||
|
||||
(assets.font || []).forEach(asset =>
|
||||
fs.copySync(asset, path.join(targetPath, 'fonts', path.basename(asset)))
|
||||
fs.copySync(asset, path.join(project.assetsPath, 'fonts', path.basename(asset)))
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
isInstalled: require('./isInstalled'),
|
||||
register: require('./registerNativeModule'),
|
||||
unregister: require('./unregisterNativeModule'),
|
||||
copyAssets: require('./copyAssets'),
|
||||
unlinkAssets: require('./unlinkAssets')
|
||||
};
|
||||
};
|
||||
@@ -17,11 +17,11 @@ const groupFilesByType = require('../groupFilesByType');
|
||||
* For now, the only types of files that are handled are:
|
||||
* - Fonts (otf, ttf) - copied to targetPath/fonts under original name
|
||||
*/
|
||||
module.exports = function unlinkAssetsAndroid(files, targetPath) {
|
||||
module.exports = function unlinkAssetsAndroid(files, project) {
|
||||
const assets = groupFilesByType(files);
|
||||
|
||||
(assets.font || []).forEach((file) => {
|
||||
const filePath = path.join(targetPath, 'fonts', path.basename(file));
|
||||
const filePath = path.join(project.assetsPath, 'fonts', path.basename(file));
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
const isInstalledIOS = require('../isInstalled');
|
||||
const isInstalledPods = require('../../pods/isInstalled');
|
||||
|
||||
module.exports = function isInstalled(projectConfig, name, dependencyConfig) {
|
||||
return isInstalledIOS(projectConfig, dependencyConfig) || isInstalledPods(projectConfig, dependencyConfig);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
const registerDependencyIOS = require('../registerNativeModule');
|
||||
const registerDependencyPods = require('../../pods/registerNativeModule');
|
||||
|
||||
module.exports = function registerNativeModule(
|
||||
name,
|
||||
dependencyConfig,
|
||||
params,
|
||||
projectConfig
|
||||
) {
|
||||
if (projectConfig.podfile && dependencyConfig.podspec) {
|
||||
registerDependencyPods(name, dependencyConfig, projectConfig);
|
||||
}
|
||||
else {
|
||||
registerDependencyIOS(dependencyConfig, projectConfig);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
const compact = require('lodash').compact;
|
||||
const isInstalledIOS = require('../isInstalled');
|
||||
const isInstalledPods = require('../../pods/isInstalled');
|
||||
const unregisterDependencyIOS = require('../unregisterNativeModule');
|
||||
const unregisterDependencyPods = require('../../pods/unregisterNativeModule');
|
||||
|
||||
module.exports = function unregisterNativeModule(
|
||||
name,
|
||||
dependencyConfig,
|
||||
projectConfig,
|
||||
otherDependencies
|
||||
) {
|
||||
const isIosInstalled = isInstalledIOS(projectConfig, dependencyConfig);
|
||||
const isPodInstalled = isInstalledPods(projectConfig, dependencyConfig);
|
||||
if (isIosInstalled) {
|
||||
const iOSDependencies = compact(otherDependencies.map(d => d.config.ios));
|
||||
unregisterDependencyIOS(dependencyConfig, projectConfig, iOSDependencies);
|
||||
}
|
||||
else if (isPodInstalled) {
|
||||
unregisterDependencyPods(dependencyConfig, projectConfig);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
isInstalled: require('./common/isInstalled'),
|
||||
register: require('./common/registerNativeModule'),
|
||||
unregister: require('./common/unregisterNativeModule'),
|
||||
copyAssets: require('./copyAssets'),
|
||||
unlinkAssets: require('./unlinkAssets')
|
||||
};
|
||||
};
|
||||
+3
-75
@@ -26,14 +26,6 @@ const chalk = require('chalk');
|
||||
* run Flow. */
|
||||
const isEmpty = require('lodash').isEmpty;
|
||||
const promiseWaterfall = require('./promiseWaterfall');
|
||||
const registerDependencyAndroid = require('./android/registerNativeModule');
|
||||
const registerDependencyIOS = require('./ios/registerNativeModule');
|
||||
const registerDependencyPods = require('./pods/registerNativeModule');
|
||||
const isInstalledAndroid = require('./android/isInstalled');
|
||||
const isInstalledIOS = require('./ios/isInstalled');
|
||||
const isInstalledPods = require('./pods/isInstalled');
|
||||
const copyAssetsAndroid = require('./android/copyAssets');
|
||||
const copyAssetsIOS = require('./ios/copyAssets');
|
||||
const getProjectDependencies = require('./getProjectDependencies');
|
||||
const getDependencyConfig = require('./getDependencyConfig');
|
||||
const pollParams = require('./pollParams');
|
||||
@@ -47,37 +39,8 @@ log.heading = 'rnpm-link';
|
||||
|
||||
const dedupeAssets = (assets) => uniqBy(assets, asset => path.basename(asset));
|
||||
|
||||
|
||||
const linkDependencyAndroid = (androidProject, dependency) => {
|
||||
if (!androidProject || !dependency.config.android) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isInstalled = isInstalledAndroid(androidProject, dependency.name);
|
||||
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`Android module ${dependency.name} is already linked`));
|
||||
return null;
|
||||
}
|
||||
|
||||
return pollParams(dependency.config.params).then(params => {
|
||||
log.info(`Linking ${dependency.name} android dependency`);
|
||||
|
||||
registerDependencyAndroid(
|
||||
dependency.name,
|
||||
dependency.config.android,
|
||||
params,
|
||||
androidProject
|
||||
);
|
||||
|
||||
log.info(`Android module ${dependency.name} has been successfully linked`);
|
||||
});
|
||||
};
|
||||
|
||||
const linkDependencyPlatforms = (platforms, project, dependency) => {
|
||||
const ignorePlatforms = ['android', 'ios'];
|
||||
const linkDependency = (platforms, project, dependency) => {
|
||||
Object.keys(platforms || {})
|
||||
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
|
||||
.forEach(platform => {
|
||||
if (!project[platform] || !dependency.config[platform]) {
|
||||
return null;
|
||||
@@ -88,7 +51,7 @@ const linkDependencyPlatforms = (platforms, project, dependency) => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isInstalled = linkConfig.isInstalled(project[platform], dependency.config[platform]);
|
||||
const isInstalled = linkConfig.isInstalled(project[platform], dependency.name, dependency.config[platform]);
|
||||
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`Platform '${platform}' module ${dependency.name} is already linked`));
|
||||
@@ -110,45 +73,12 @@ const linkDependencyPlatforms = (platforms, project, dependency) => {
|
||||
});
|
||||
};
|
||||
|
||||
const linkDependencyIOS = (iOSProject, dependency) => {
|
||||
if (!iOSProject || !dependency.config.ios) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isInstalled = isInstalledIOS(iOSProject, dependency.config.ios) || isInstalledPods(iOSProject, dependency.config.ios);
|
||||
if (isInstalled) {
|
||||
log.info(chalk.grey(`iOS module ${dependency.name} is already linked`));
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Linking ${dependency.name} ios dependency`);
|
||||
if (iOSProject.podfile && dependency.config.ios.podspec) {
|
||||
registerDependencyPods(dependency, iOSProject);
|
||||
}
|
||||
else {
|
||||
registerDependencyIOS(dependency.config.ios, iOSProject);
|
||||
}
|
||||
log.info(`iOS module ${dependency.name} has been successfully linked`);
|
||||
};
|
||||
|
||||
const linkAssets = (platforms, project, assets) => {
|
||||
if (isEmpty(assets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.ios) {
|
||||
log.info('Linking assets to ios project');
|
||||
copyAssetsIOS(assets, project.ios);
|
||||
}
|
||||
|
||||
if (project.android) {
|
||||
log.info('Linking assets to android project');
|
||||
copyAssetsAndroid(assets, project.android.assetsPath);
|
||||
}
|
||||
|
||||
const ignorePlatforms = ['android', 'ios'];
|
||||
Object.keys(platforms || {})
|
||||
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
|
||||
.forEach(platform => {
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.copyAssets) {
|
||||
@@ -212,9 +142,7 @@ function link(args: Array<string>, config: RNConfig) {
|
||||
|
||||
const tasks = flatten(dependencies.map(dependency => [
|
||||
() => promisify(dependency.config.commands.prelink || commandStub),
|
||||
() => linkDependencyAndroid(project.android, dependency),
|
||||
() => linkDependencyIOS(project.ios, dependency),
|
||||
() => linkDependencyPlatforms(platforms, project, dependency),
|
||||
() => linkDependency(platforms, project, dependency),
|
||||
() => promisify(dependency.config.commands.postlink || commandStub),
|
||||
]));
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ const findMarkedLinesInPodfile = require('./findMarkedLinesInPodfile');
|
||||
const addPodEntry = require('./addPodEntry');
|
||||
const savePodFile = require('./savePodFile');
|
||||
|
||||
module.exports = function registerNativeModulePods(dependency, iOSProject) {
|
||||
module.exports = function registerNativeModulePods(name, dependencyConfig, iOSProject) {
|
||||
const podLines = readPodfile(iOSProject.podfile);
|
||||
const linesToAddEntry = getLinesToAddEntry(podLines, iOSProject);
|
||||
addPodEntry(podLines, linesToAddEntry, dependency.config.ios.podspec, dependency.name);
|
||||
addPodEntry(podLines, linesToAddEntry, dependencyConfig.podspec, name);
|
||||
savePodFile(iOSProject.podfile, podLines);
|
||||
};
|
||||
|
||||
|
||||
+17
-72
@@ -10,16 +10,7 @@
|
||||
const log = require('npmlog');
|
||||
|
||||
const getProjectDependencies = require('./getProjectDependencies');
|
||||
const unregisterDependencyAndroid = require('./android/unregisterNativeModule');
|
||||
const unregisterDependencyIOS = require('./ios/unregisterNativeModule');
|
||||
const unregisterDependencyPods = require('./pods/unregisterNativeModule');
|
||||
const isInstalledAndroid = require('./android/isInstalled');
|
||||
const isInstalledIOS = require('./ios/isInstalled');
|
||||
const isInstalledPods = require('./pods/isInstalled');
|
||||
const unlinkAssetsAndroid = require('./android/unlinkAssets');
|
||||
const unlinkAssetsIOS = require('./ios/unlinkAssets');
|
||||
const getDependencyConfig = require('./getDependencyConfig');
|
||||
const compact = require('lodash').compact;
|
||||
const difference = require('lodash').difference;
|
||||
const filter = require('lodash').filter;
|
||||
const flatten = require('lodash').flatten;
|
||||
@@ -30,41 +21,20 @@ const promisify = require('./promisify');
|
||||
|
||||
log.heading = 'rnpm-link';
|
||||
|
||||
const unlinkDependencyAndroid = (androidProject, dependency, packageName) => {
|
||||
if (!androidProject || !dependency.android) {
|
||||
return;
|
||||
}
|
||||
const unlinkDependency = (platforms, project, dependency, packageName, otherDependencies) => {
|
||||
|
||||
const isInstalled = isInstalledAndroid(androidProject, packageName);
|
||||
|
||||
if (!isInstalled) {
|
||||
log.info(`Android module ${packageName} is not installed`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking ${packageName} android dependency`);
|
||||
|
||||
unregisterDependencyAndroid(packageName, dependency.android, androidProject);
|
||||
|
||||
log.info(`Android module ${packageName} has been successfully unlinked`);
|
||||
};
|
||||
|
||||
const unlinkDependencyPlatforms = (platforms, project, dependency, packageName) => {
|
||||
|
||||
const ignorePlatforms = ['android', 'ios'];
|
||||
Object.keys(platforms || {})
|
||||
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
|
||||
.forEach(platform => {
|
||||
if (!project[platform] || !dependency[platform]) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.isInstalled || !linkConfig.unregister) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
const isInstalled = linkConfig.isInstalled(project[platform], dependency[platform]);
|
||||
const isInstalled = linkConfig.isInstalled(project[platform], packageName, dependency[platform]);
|
||||
|
||||
if (!isInstalled) {
|
||||
log.info(`Platform '${platform}' module ${packageName} is not installed`);
|
||||
@@ -76,37 +46,14 @@ const unlinkDependencyPlatforms = (platforms, project, dependency, packageName)
|
||||
linkConfig.unregister(
|
||||
packageName,
|
||||
dependency[platform],
|
||||
project[platform]
|
||||
project[platform],
|
||||
otherDependencies
|
||||
);
|
||||
|
||||
log.info(`Platform '${platform}' module ${dependency.name} has been successfully unlinked`);
|
||||
});
|
||||
};
|
||||
|
||||
const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencies) => {
|
||||
if (!iOSProject || !dependency.ios) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isIosInstalled = isInstalledIOS(iOSProject, dependency.ios);
|
||||
const isPodInstalled = isInstalledPods(iOSProject, dependency.ios);
|
||||
if (!isIosInstalled && !isPodInstalled) {
|
||||
log.info(`iOS module ${packageName} is not installed`);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking ${packageName} ios dependency`);
|
||||
|
||||
if (isIosInstalled) {
|
||||
unregisterDependencyIOS(dependency.ios, iOSProject, iOSDependencies);
|
||||
}
|
||||
else if (isPodInstalled) {
|
||||
unregisterDependencyPods(dependency.ios, iOSProject);
|
||||
}
|
||||
|
||||
log.info(`iOS module ${packageName} has been successfully unlinked`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates project and unlink specific dependency
|
||||
*
|
||||
@@ -143,13 +90,10 @@ function unlink(args, config) {
|
||||
|
||||
const allDependencies = getDependencyConfig(config, getProjectDependencies());
|
||||
const otherDependencies = filter(allDependencies, d => d.name !== packageName);
|
||||
const iOSDependencies = compact(otherDependencies.map(d => d.config.ios));
|
||||
|
||||
const tasks = [
|
||||
() => promisify(dependency.commands.preunlink || commandStub),
|
||||
() => unlinkDependencyAndroid(project.android, dependency, packageName),
|
||||
() => unlinkDependencyIOS(project.ios, dependency, packageName, iOSDependencies),
|
||||
() => unlinkDependencyPlatforms(platforms, project, dependency, packageName),
|
||||
() => unlinkDependency(platforms, project, dependency, packageName, otherDependencies),
|
||||
() => promisify(dependency.commands.postunlink || commandStub)
|
||||
];
|
||||
|
||||
@@ -166,15 +110,16 @@ function unlink(args, config) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (project.ios) {
|
||||
log.info('Unlinking assets from ios project');
|
||||
unlinkAssetsIOS(assets, project.ios);
|
||||
}
|
||||
|
||||
if (project.android) {
|
||||
log.info('Unlinking assets from android project');
|
||||
unlinkAssetsAndroid(assets, project.android.assetsPath);
|
||||
}
|
||||
Object.keys(platforms || {})
|
||||
.forEach(platform => {
|
||||
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||
if (!linkConfig || !linkConfig.unlinkAssets) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info(`Unlinking assets from ${platform} project`);
|
||||
linkConfig.unlinkAssets(assets, project[platform]);
|
||||
});
|
||||
|
||||
log.info(
|
||||
`${packageName} assets has been successfully unlinked from your project`
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
pre: new Map(),
|
||||
post: new Map(),
|
||||
modules: new Map(),
|
||||
id: undefined,
|
||||
};
|
||||
this._initialized = false;
|
||||
this._lastNumModifiedFiles = 0;
|
||||
@@ -68,6 +69,7 @@
|
||||
pre: new Map(),
|
||||
post: new Map(),
|
||||
modules: new Map(),
|
||||
id: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,9 +84,15 @@
|
||||
this._patchMap(this._lastBundle.post, deltaBundle.post);
|
||||
this._patchMap(this._lastBundle.modules, deltaBundle.delta);
|
||||
|
||||
this._lastBundle.id = deltaBundle.id;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
getLastBundleId() {
|
||||
return this._lastBundle.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of modified files in the last received Delta. This is
|
||||
* currently used to populate the `X-Metro-Files-Changed-Count` HTTP header
|
||||
|
||||
@@ -22,31 +22,34 @@
|
||||
* whole JS bundle Blob.
|
||||
*/
|
||||
async function deltaUrlToBlobUrl(deltaUrl) {
|
||||
let cachedBundle = cachedBundleUrls.get(deltaUrl);
|
||||
const client = global.DeltaPatcher.get(deltaUrl);
|
||||
|
||||
const deltaBundleId = cachedBundle
|
||||
? `&deltaBundleId=${cachedBundle.id}`
|
||||
const deltaBundleId = client.getLastBundleId()
|
||||
? `&deltaBundleId=${client.getLastBundleId()}`
|
||||
: '';
|
||||
|
||||
const data = await fetch(deltaUrl + deltaBundleId);
|
||||
const bundle = await data.json();
|
||||
|
||||
const deltaPatcher = global.DeltaPatcher.get(bundle.id).applyDelta({
|
||||
const deltaPatcher = client.applyDelta({
|
||||
id: bundle.id,
|
||||
pre: new Map(bundle.pre),
|
||||
post: new Map(bundle.post),
|
||||
delta: new Map(bundle.delta),
|
||||
reset: bundle.reset,
|
||||
});
|
||||
|
||||
let cachedBundle = cachedBundleUrls.get(deltaUrl);
|
||||
|
||||
// If nothing changed, avoid recreating a bundle blob by reusing the
|
||||
// previous one.
|
||||
if (deltaPatcher.getLastNumModifiedFiles() === 0 && cachedBundle) {
|
||||
return cachedBundle.url;
|
||||
return cachedBundle;
|
||||
}
|
||||
|
||||
// Clean up the previous bundle URL to not leak memory.
|
||||
if (cachedBundle) {
|
||||
URL.revokeObjectURL(cachedBundle.url);
|
||||
URL.revokeObjectURL(cachedBundle);
|
||||
}
|
||||
|
||||
// To make Source Maps work correctly, we need to add a newline between
|
||||
@@ -60,13 +63,10 @@
|
||||
type: 'application/javascript',
|
||||
});
|
||||
|
||||
const bundleUrl = URL.createObjectURL(blob);
|
||||
cachedBundleUrls.set(deltaUrl, {
|
||||
id: bundle.id,
|
||||
url: bundleUrl,
|
||||
});
|
||||
const bundleContents = URL.createObjectURL(blob);
|
||||
cachedBundleUrls.set(deltaUrl, bundleContents);
|
||||
|
||||
return bundleUrl;
|
||||
return bundleContents;
|
||||
}
|
||||
|
||||
global.deltaUrlToBlobUrl = deltaUrlToBlobUrl;
|
||||
|
||||
@@ -17,7 +17,7 @@ const getPolyfills = require('../../rn-get-polyfills');
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
const path = require('path');
|
||||
|
||||
const {Config: MetroConfig} = require('metro');
|
||||
const {Config: MetroConfig, createBlacklist} = require('metro');
|
||||
|
||||
const RN_CLI_CONFIG = 'rn-cli.config.js';
|
||||
|
||||
@@ -56,6 +56,10 @@ const getProjectRoots = () => {
|
||||
return resolveSymlinksForRoots([getProjectPath()]);
|
||||
};
|
||||
|
||||
const getBlacklistRE = () => {
|
||||
return createBlacklist([/.*\/__fixtures__\/.*/]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Module capable of getting the configuration out of a given file.
|
||||
*
|
||||
@@ -67,6 +71,7 @@ const getProjectRoots = () => {
|
||||
const Config = {
|
||||
DEFAULT: ({
|
||||
...MetroConfig.DEFAULT,
|
||||
getBlacklistRE,
|
||||
getProjectRoots,
|
||||
getPolyfills,
|
||||
getModulesRunBeforeMainModule: () => [
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native",
|
||||
"version": "1000.0.0",
|
||||
"version": "0.54.2",
|
||||
"description": "A framework for building native apps using React",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
@@ -143,7 +143,7 @@
|
||||
"react-native": "local-cli/wrong-react-native.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.3.0-alpha.0"
|
||||
"react": "^16.3.0-alpha.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"absolute-path": "^0.0.0",
|
||||
@@ -175,8 +175,8 @@
|
||||
"graceful-fs": "^4.1.3",
|
||||
"inquirer": "^3.0.6",
|
||||
"lodash": "^4.17.5",
|
||||
"metro": "^0.25.1",
|
||||
"metro-core": "^0.25.1",
|
||||
"metro": "^0.28.0",
|
||||
"metro-core": "^0.28.0",
|
||||
"mime": "^1.3.4",
|
||||
"minimist": "^1.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
@@ -224,4 +224,4 @@
|
||||
"shelljs": "^0.7.8",
|
||||
"sinon": "^2.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user