Compare commits

...
Author SHA1 Message Date
Mike Grabowski 56a2d6d720 [0.54.4] Bump version numbers 2018-03-28 19:09:37 +02:00
Janic Duplessis 0ba6ed897a Fix blob response parsing for empty body on iOS
Summary:
We currently handle empty body poorly in the iOS blob implementation, this happens because of an early return that cause the blob response to not be processed by the blob module, resulting in an empty string as the body instead of a blob object. We also need to make sure to create an empty blob object when data is nil (empty body) as per the XMLHttpRequest spec. The Android implementation was already handling this properly.

Fixes #18223

Send a HEAD request

```js
fetch('https://apipre.monkimun.com/whoami', {
  body: null,
  method: 'HEAD',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
})
```

[IOS][BUGFIX][Blob] - Fix blob response parsing for empty body
Closes https://github.com/facebook/react-native/pull/18547

Differential Revision: D7415950

Pulled By: hramos

fbshipit-source-id: 56860532c6171255869f02a0960f55d155184a46
2018-03-28 19:09:23 +02:00
Eric Samelson 7e4cd53383 fix ReadableNativeMap.toHashMap() for nested maps and arrays
Summary:
<!--
  Required: Write your motivation here.
  If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when the PR is merged.
-->

Commit https://github.com/facebook/react-native/commit/7891805d22e3fdc821961ff0ccc5c450c3d625c8 broke the previous behavior of `ReadableNativeMap.toHashMap()` for nested maps and arrays. Previously, all nested `ReadableNativeMap`s and `ReadableNativeArray`s were recursively converted to `HashMap`s and `ArrayList`s, but this is lost when only `getLocalMap()` is returned.

<!--
  Required: Write your test plan here. If you changed any code, please provide us with
  clear instructions on how you verified your changes work. Bonus points for screenshots and videos!
-->

Call `ReadableNativeMap.toHashMap()` on a map with values of type `ReadableNativeMap` and `ReadableNativeArray`. Verify the returned hash map has these converted to `HashMap` and `ArrayList`, respectively.

<!--
  Does this PR require a documentation change?
  Create a PR at https://github.com/facebook/react-native-website and add a link to it here.
-->

<!--
  Required.
  Help reviewers and the release process by writing your own release notes. See below for an example.
-->

[ANDROID] [BUGFIX] [ReadableNativeMap] - Fix toHashMap() for nested maps and arrays

<!--
  **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**

    CATEGORY
  [----------]      TYPE
  [ CLI      ] [-------------]    LOCATION
  [ DOCS     ] [ BREAKING    ] [-------------]
  [ GENERAL  ] [ BUGFIX      ] [ {Component} ]
  [ INTERNAL ] [ ENHANCEMENT ] [ {Filename}  ]
  [ IOS      ] [ FEATURE     ] [ {Directory} ]   |-----------|
  [ ANDROID  ] [ MINOR       ] [ {Framework} ] - | {Message} |
  [----------] [-------------] [-------------]   |-----------|

 EXAMPLES:

 [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
 [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
 [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
 [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
 [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
 [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->
Closes https://github.com/facebook/react-native/pull/18455

Reviewed By: kathryngray

Differential Revision: D7347344

Pulled By: mdvacca

fbshipit-source-id: af2bca9dec6c0cb8a7da099b6757434fcc3ac785
2018-03-28 19:08:41 +02:00
Mike Grabowski 69c277051e [0.54.3] Bump version numbers 2018-03-23 10:27:08 +01:00
Artem Egorov 863a49f2ab While linking plugin ask for params only once
Summary:
Resolve #18333

CLI should ask users for params only once and waiting for response while linking plugin

Ran the `link` commands for iOS and Android and confirmed that params requested only once.

[CLI][FEATURE][local-cli/link/link.js] - Requesting link params only once for all platforms
Closes https://github.com/facebook/react-native/pull/18349

Differential Revision: D7342181

Pulled By: hramos

fbshipit-source-id: a10f0f7f2170f067d78b30e5a5221634b77da577
2018-03-22 18:21:15 +01:00
Valentin Shergin 5c00de7b6b Fixed problem in Text measurent on iOS
Summary: See the comment it code.

Reviewed By: mmmulani

Differential Revision: D7074168

fbshipit-source-id: e6eda9a47552142ccb0ba8e7bd9a103b0cb4f9f9
2018-03-22 18:19:57 +01:00
Héctor Ramos 17e0066c0d React sync for revisions ab4280b...ad9544f
Reviewed By: bvaughn

Differential Revision: D7256390

fbshipit-source-id: 9fe1324da93cb8f4a7f478e1037944774b9b95ff
2018-03-22 18:16:03 +01:00
Héctor Ramos ec542f44dd React sync for revisions a634e53...ab4280b
Reviewed By: bvaughn

Differential Revision: D7077686

fbshipit-source-id: de39027bef1f9d48802202555a5c765999d7bfe7
2018-03-22 18:15:22 +01:00
Brian Vaughn d9bd9d5587 React sync for revisions 467b103...a634e53
Reviewed By: flarnie

Differential Revision: D6965585

fbshipit-source-id: 48c20d0010f4daf83272a36b3bdaca94493ab8fa
2018-03-22 18:09:07 +01:00
samsafay 387e1c4d11 check for GET and Head in send request
Summary:
React Native had an underlying problem connecting to Firestore (Google's latest database) from Android devices. You can follow the issue [here](https://github.com/firebase/firebase-js-sdk/issues/283).
The main problem was in NetworkingModule.java. Please refer to section 3 of 4.5.6 in whatwg.org's guideline https://xhr.spec.whatwg.org/#dom-xmlhttprequest-send

In this [video](https://www.youtube.com/watch?v=tILagf46ys8), I am showing how the react native behaved before adding the new fix and how it worked after the new fix added.  The new fix starts at 50 seconds.

[ANDROID] [BUGFIX] [FIRESTORE][XMLHttpRequest][ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java] - Fixes the connection to Firestore by following whatwg.org's XMLHttpRequest send() method
Closes https://github.com/facebook/react-native/pull/17940

Differential Revision: D7173468

Pulled By: hramos

fbshipit-source-id: 354d36f03d611889073553b93a7c43c6d4363ff3
2018-03-21 15:28:57 -07:00
Mike Grabowski 9a3cad4d89 [0.54.2] Bump version numbers 2018-03-12 22:17:00 +01:00
Rafael Oleza 48f29a74c5 Make the chrome debugger handle dynamic delta ids
Differential Revision: D7112419

fbshipit-source-id: 1d80c0c13144dd19bbcd5535383befc6567cacf7
2018-03-12 22:16:44 +01:00
Eric Rozell 8e03ced500 Fixing bugs in link and unlink
Summary:
Android uses the name of the package, not the config, for the `isInstalled` check. Sending both parameters to `isInstalled` so we have a consistent API.

<!--
Thank you for sending the PR! We appreciate you spending the time to work on these changes.

Help us understand your motivation by explaining why you decided to make this change.

You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html

Happy contributing!

-->

A bug was uncovered in the react-native link command where Android would not unlink because the wrong parameters were being sent to `isInstalled`.

Successfully linked and unlinked `react-native-fs` on Windows and Mac. Jest tests pass.

<!--
Help reviewers and the release process by writing your own release notes

**INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**

  CATEGORY
[----------]        TYPE
[ CLI      ]   [-------------]      LOCATION
[ DOCS     ]   [ BREAKING    ]   [-------------]
[ GENERAL  ]   [ BUGFIX      ]   [-{Component}-]
[ INTERNAL ]   [ ENHANCEMENT ]   [ {File}      ]
[ IOS      ]   [ FEATURE     ]   [ {Directory} ]   |-----------|
[ ANDROID  ]   [ MINOR       ]   [ {Framework} ] - | {Message} |
[----------]   [-------------]   [-------------]   |-----------|

[CATEGORY] [TYPE] [LOCATION] - MESSAGE

 EXAMPLES:

 [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
 [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
 [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
 [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
 [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
 [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->

[CLI][BUGFIX][local-cli/link/link.js] - Fix issue with `isInstalled` check for Android
[CLI][BUGFIX][local-cli/link/unlink.js] - Fix issue with `isInstalled` check for Android
[CLI][BUGFIX][local-cli/link/ios/common/unregisterNativeModule.js] - Fix references to unregister implementations.
Closes https://github.com/facebook/react-native/pull/18207

Differential Revision: D7180885

Pulled By: hramos

fbshipit-source-id: 5f479cd9d7b1ebd8626b461e9dc1f22988e2c61f
2018-03-12 22:16:38 +01:00
Mike Grabowski ac55ffd777 Revert "Fix HmrClient path"
This reverts commit 8bdd98ea48.
2018-03-12 22:16:32 +01:00
Mike Grabowski 8bdd98ea48 Fix HmrClient path 2018-03-09 20:39:13 +01:00
Mike Grabowski 2d57335fa7 [0.54.1] Bump version numbers 2018-03-09 18:20:10 +01:00
Mike Grabowski 2f8446319a Update ReactFeatureFlags.js 2018-03-07 17:11:46 +01:00
Mike Grabowski 815a07c77b [0.54.0] Bump version numbers 2018-03-01 18:01:19 +01:00
Josh Hargreaves 53c1a4cc7b Fix crashes onKeyPress Android
Summary:
There appear to be two different types of crashes related to the recent addition of `onKeyPress` on Android introduce in `0.53`. This PR addresses the cause of both of them.

Firstly, it seems possible to get an `indexOutOfBoundsException` with some 3rd-party keyboards as observed in https://github.com/facebook/react-native/issues/17974 & https://github.com/facebook/react-native/issues/17922. I have simplified the backspace determining logic slightly, and also put in an explicit check for zero case so it is not possible to get an indexOutOfBoundsException & it should make sense in the context of the onKeyPress logic.

Secondly, it appears that `EditText#onCreateInputConnection` can return null. In this case, if we set `null` to be the target of our subclass of `ReactEditTextInputConnectionWrapper`, we will see the crashes as seen [here](https://github.com/facebook/react-native/issues/17974#issuecomment-368471737), whereby any of methods executed in the `InputConnection` interface can result in a crash. It's hard to reason about the state when `null` is returned from `onCreateInputConnection`, however I would might reason that any soft keyboard input cannot update the `EditText` with a `null` `input connection`, as there is no way of interfacing with the `EditText`. I'm am not sure, if there is a later point where we might return/set this input connection at a later point? As without the `InputConnection` onKeyPress will not work. But for now, this will fix this crash at least.

I have not managed to reproduce these crashes myself yet, but users have confirmed that the `indexOutOfBounds` exception is fixed with the 'zero' case and has been confirmed on the respective issues https://github.com/facebook/react-native/issues/17974#issuecomment-368471737.

For the `null` inputConnection target case, I have verified that explicitly setting the target as null in the constructor of `onCreateInputConnection` results in the same stack trace as the one linked. Here is also a [reference](https://github.com/stripe/stripe-android/pull/392/files#diff-6cc1685c98457d07fd4e2dd83f54d5bb) to the same issue closed with the same fix for another project on github.

It is also important to verify that the behavior of `onKeyPress` still functions the same after this change, which can be verified by running the RNTesterProject and the `KeyboardEvents` section in `InputText`.
The cases to check that I think are important to check are:
- Cursor at beginning of input & backspace
- Return key & return key at beginning of input
- Select text then press delete
- Selection then press a key
- Space key
- Different keyboard types

This should not be a breaking change.

 [ANDROID] [BUGFIX] [TextInput] - Fixes crashes with TextInput introduced in 0.53.
Closes https://github.com/facebook/react-native/pull/18114

Differential Revision: D7099570

Pulled By: hramos

fbshipit-source-id: 75b2dc468c1ed398a33eb00487c6aa14ae04e5c2
2018-03-01 18:00:10 +01:00
Mike Grabowski 67e67ec83c [0.54.0-rc.4] Bump version numbers 2018-02-27 09:58:06 +01:00
Mike Grabowski 0f96ebd93b Bump Metro version to fix issue for npm users 2018-02-27 09:57:58 +01:00
Rafael Oleza f4fde9d84a Bump metro@0.26.0
Reviewed By: cpojer

Differential Revision: D6976161

fbshipit-source-id: 0cf20f4b2372997a8aac41cc07a9bdd641a93ad4
2018-02-21 12:56:50 +01:00
Tadeu Valentt 4194bb242d Fix #17610, Add fixtures to metro blacklist
Summary:
Include a default blacklist into the build settings to prevent
processing of incorrect fixture files by Metro.

<!--
Thank you for sending the PR! We appreciate you spending the time to work on these changes.

Help us understand your motivation by explaining why you decided to make this change.

You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html

Happy contributing!

-->

Fix #17610 issue, preventing metro from processing fixture files

1. Have a working demo
2. Install https://github.com/oblador/react-native-vector-icons
3. Use in a component
4. Start the app
5. The app starts successfully and display the icons

[ GENERAL  ]  [ BUGFIX ]  [local-cli/util/Config.js] - Add default file blacklist
Closes https://github.com/facebook/react-native/pull/17672

Differential Revision: D7014627

Pulled By: hramos

fbshipit-source-id: 20974e6fdd0977eeeb1048c29c9d621c803c26e9
2018-02-21 12:55:54 +01:00
Janic Duplessis 675f14257a Bundle download progress on Android
Summary:
Android equivalent of #15066

Tested that download progress shows up properly when reloading the app.

[ANDROID] [FEATURE] [DevSupport] - Show bundle download progress on Android
Closes https://github.com/facebook/react-native/pull/17809

Differential Revision: D6982823

Pulled By: hramos

fbshipit-source-id: da01e42b8ebb1c603f4407f6bafd68e0b6b3ecba
2018-02-14 23:48:02 -08:00
Mike Grabowski 21dd3dd296 [0.54.0-rc.3] Bump version numbers 2018-02-13 18:11:48 +01:00
Mike Grabowski 03d7b2aa0e Bump React dependency 2018-02-13 18:11:04 +01:00
Eric Rozell 2c5fbd79a2 Uses a single code path to link and unlink all platforms
Summary:
This commit removes special cases for linking iOS and Android platforms.

A previous commit opened up link and other commands for other platforms to provide their own behaviors. It left special cases in tact for iOS and Android. This PR removes the special case.

- Added jest tests related to the link command.
- Ran the `link` and `unlink` commands for iOS and Android and confirmed no changes.

https://github.com/facebook/react-native/pull/17745

<!--
Help reviewers and the release process by writing your own release notes

**INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**

  CATEGORY
[----------]        TYPE
[ CLI      ]   [-------------]      LOCATION
[ DOCS     ]   [ BREAKING    ]   [-------------]
[ GENERAL  ]   [ BUGFIX      ]   [-{Component}-]
[ INTERNAL ]   [ ENHANCEMENT ]   [ {File}      ]
[ IOS      ]   [ FEATURE     ]   [ {Directory} ]   |-----------|
[ ANDROID  ]   [ MINOR       ]   [ {Framework} ] - | {Message} |
[----------]   [-------------]   [-------------]   |-----------|

[CATEGORY] [TYPE] [LOCATION] - MESSAGE

 EXAMPLES:

 [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
 [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
 [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
 [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
 [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
 [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->

[CLI][FEATURE][local-cli/link/link.js] - Removes special cases for linking in iOS and Android.
Closes https://github.com/facebook/react-native/pull/17961

Differential Revision: D6975951

Pulled By: hramos

fbshipit-source-id: 8dd5da35619e2124ce4b3b18db8b694757792363
2018-02-13 18:10:34 +01:00
Hector Ramos 49e35bd939 [0.54.0-rc.0] Bump version numbers 2018-02-12 12:19:05 -08:00
Mike Grabowski 829f675b8b [0.54.0-rc.2] Bump version numbers 2018-02-12 17:38:28 +01:00
Mike Grabowski b58d848d9c Fix CI publish step 2018-02-12 17:38:22 +01:00
Mike Grabowski 294d95a236 [0.54.0-rc.0] Bump version numbers 2018-02-12 13:10:05 +01:00
42 changed files with 5425 additions and 4552 deletions
+4
View File
@@ -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
+3
View File
@@ -260,6 +260,9 @@ RCT_EXPORT_METHOD(release:(NSString *)blobId)
- (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data
{
// An empty body will have nil for data, in this case we need to return
// an empty blob as per the XMLHttpRequest spec.
data = data ?: [NSData new];
return @{
@"blobId": [self store:data],
@"offset": @0,
+2 -2
View File
@@ -14,7 +14,7 @@
exports.version = {
major: 0,
minor: 0,
patch: 0,
minor: 54,
patch: 4,
prerelease: null,
};
+4 -4
View File
@@ -441,10 +441,6 @@ RCT_EXPORT_MODULE()
{
RCTAssertThread(_methodQueue, @"sendData: must be called on method queue");
if (data.length == 0) {
return;
}
id responseData = nil;
for (id<RCTNetworkingResponseHandler> handler in _responseHandlers) {
if ([handler canHandleNetworkingResponse:responseType]) {
@@ -454,6 +450,10 @@ RCT_EXPORT_MODULE()
}
if (!responseData) {
if (data.length == 0) {
return;
}
if ([responseType isEqualToString:@"text"]) {
// No carry storage is required here because the entire data has been loaded.
responseData = [RCTNetworking decodeTextData:data fromResponse:task.response withCarryData:nil];
+1 -1
View File
@@ -1 +1 @@
467b1034ce8af6807e11deb9dfeca4d4e922ed82
ad9544f48e58f2599a8ea0de1e9f4dd104db30bb
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -12,7 +12,7 @@
const ReactFeatureFlags = {
debugRenderPhaseSideEffects: false,
debugRenderPhaseSideEffectsForStrictMode: false,
warnAboutDeprecatedLifecycles: true,
warnAboutDeprecatedLifecycles: false,
};
module.exports = ReactFeatureFlags;
+6 -4
View File
@@ -80,10 +80,12 @@ export type ReactContext<T> = {
$$typeof: Symbol | number,
Consumer: ReactContext<T>,
Provider: ReactProviderType<T>,
calculateChangedBits: ((a: T, b: T) => number) | null,
defaultValue: T,
currentValue: T,
changedBits: number,
_calculateChangedBits: ((a: T, b: T) => number) | null,
_defaultValue: T,
_currentValue: T,
_changedBits: number,
// DEV only
_currentRenderer?: Object | null,
+5 -2
View File
@@ -350,9 +350,12 @@ static YGSize RCTTextShadowViewMeasure(YGNodeRef node, float width, YGMeasureMod
MIN(RCTCeilPixelValue(size.height), maximumSize.height)
};
// Adding epsilon value illuminates problems with converting values from
// `double` to `float`, and then rounding them to pixel grid in Yoga.
CGFloat epsilon = 0.001;
return (YGSize){
RCTYogaFloatFromCoreGraphicsFloat(size.width),
RCTYogaFloatFromCoreGraphicsFloat(size.height)
RCTYogaFloatFromCoreGraphicsFloat(size.width + epsilon),
RCTYogaFloatFromCoreGraphicsFloat(size.height + epsilon)
};
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

+2 -2
View File
@@ -11,7 +11,7 @@
#define RCT_REACT_NATIVE_VERSION @{ \
@"major": @(0), \
@"minor": @(0), \
@"patch": @(0), \
@"minor": @(54), \
@"patch": @(4), \
@"prerelease": [NSNull null], \
}
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_NAME=1000.0.0-master
VERSION_NAME=0.54.4
GROUP=com.facebook.react
POM_NAME=ReactNative
@@ -13,6 +13,7 @@ import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import java.util.HashMap;
import java.util.Iterator;
import com.facebook.infer.annotation.Assertions;
import javax.annotation.Nullable;
@@ -250,7 +251,31 @@ public class ReadableNativeMap extends NativeMap implements ReadableMap {
}
return hashMap;
}
return getLocalMap();
// we can almost just return getLocalMap(), but we need to convert nested arrays and maps to the
// correct types first
HashMap<String, Object> hashMap = new HashMap<>(getLocalMap());
Iterator iterator = hashMap.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
switch (getType(key)) {
case Null:
case Boolean:
case Number:
case String:
break;
case Map:
hashMap.put(key, Assertions.assertNotNull(getMap(key)).toHashMap());
break;
case Array:
hashMap.put(key, Assertions.assertNotNull(getArray(key)).toArrayList());
break;
default:
throw new IllegalArgumentException("Could not convert object with key: " + key + ".");
}
}
return hashMap;
}
/**
@@ -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(
@@ -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);
}
@@ -344,7 +344,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
}
RequestBody requestBody;
if (data == null) {
if (data == null || method.toLowerCase().equals("get") || method.toLowerCase().equals("head")) {
requestBody = RequestBodyUtil.getEmptyBody(method);
} else if (handler != null) {
requestBody = handler.toRequestBody(data, contentType);
@@ -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", 4,
"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
@@ -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;
@@ -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);
+2
View File
@@ -126,3 +126,5 @@ exports.dependencyConfig = function dependencyConfigAndroid(folder, userConfig)
return { sourceDir, folder, manifest, packageImportPath, packageInstance };
};
exports.linkConfig = require('../../link/android');
+2
View File
@@ -57,3 +57,5 @@ exports.projectConfig = function projectConfigIOS(folder, userConfig) {
};
exports.dependencyConfig = exports.projectConfig;
exports.linkConfig = require('../../link/ios');
+7 -3
View File
@@ -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),
};
+2 -2
View File
@@ -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)))
);
};
+9
View File
@@ -0,0 +1,9 @@
module.exports = function() {
return {
isInstalled: require('./isInstalled'),
register: require('./registerNativeModule'),
unregister: require('./unregisterNativeModule'),
copyAssets: require('./copyAssets'),
unlinkAssets: require('./unlinkAssets')
};
};
+2 -2
View File
@@ -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);
}
+6
View File
@@ -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);
}
};
+9
View File
@@ -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')
};
};
+12 -84
View File
@@ -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,10 @@ log.heading = 'rnpm-link';
const dedupeAssets = (assets) => uniqBy(assets, asset => path.basename(asset));
const linkDependency = async (platforms, project, dependency) => {
const params = await pollParams(dependency.config.params);
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'];
Object.keys(platforms || {})
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
.forEach(platform => {
if (!project[platform] || !dependency.config[platform]) {
return null;
@@ -88,67 +53,32 @@ 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`));
return null;
}
return pollParams(dependency.config.params).then(params => {
log.info(`Linking ${dependency.name} ${platform} dependency`);
log.info(`Linking ${dependency.name} ${platform} dependency`);
linkConfig.register(
dependency.name,
dependency.config[platform],
params,
project[platform]
);
linkConfig.register(
dependency.name,
dependency.config[platform],
params,
project[platform]
);
log.info(`Platform '${platform}' module ${dependency.name} has been successfully linked`);
});
log.info(`Platform '${platform}' module ${dependency.name} has been successfully linked`);
});
};
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),
]));
+2 -2
View File
@@ -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
View File
@@ -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;
+6 -1
View File
@@ -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: () => [
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "react-native",
"version": "1000.0.0",
"version": "0.54.4",
"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",
@@ -219,9 +219,9 @@
"jest": "22.2.1",
"jest-junit": "3.5.0",
"prettier": "1.9.1",
"react": "^16.3.0-alpha.0",
"react-test-renderer": "^16.3.0-alpha.0",
"react": "^16.3.0-alpha.1",
"react-test-renderer": "^16.3.0-alpha.1",
"shelljs": "^0.7.8",
"sinon": "^2.2.0"
}
}
}