Compare commits

...
Author SHA1 Message Date
Eloy Durán c5ecc6ffff [0.62.0-rc.2] Bump version numbers 2020-02-13 17:47:01 +01:00
Eloy Durán cef001713f [Template] Upgrade metro babel preset
Related to 41f4efb364
2020-02-13 16:43:59 +01:00
Jason SafaiyehandEloy Durán 572f710492 Resolve React-cxxreact warnings (#28047)
Summary:
Resolve Xcode warnings from React-cxxreact.

## Changelog

[iOS] [Fixed] - Resolve Xcode warnings from React-cxxreact.
Pull Request resolved: https://github.com/facebook/react-native/pull/28047

Test Plan: React-cxxreact should no longer throw `... creates a copy from type...` warnings

Differential Revision: D19874043

Pulled By: hramos

fbshipit-source-id: 15a4a810adee268e6ede459d6d4917ccfa83c157
2020-02-13 16:19:33 +01:00
Janic DuplessisandEloy Durán 474861f4e7 Implement adjustsFontSizeToFit on Android (#26389)
Summary:
This adds support for `adjustsFontSizeToFit` and `minimumFontScale` on Android. The implementation tries to match closely the behaviour on iOS (hardcoded 4px min size for example). It uses a simpler linear algorithm for now, opened to improving it now if it is a deal breaker or in a follow up.

See https://twitter.com/janicduplessis/status/1171147709979516929 for a more detailed thread about the implementation

## Changelog

[Android] [Added] - Implement `adjustsFontSizeToFit` on Android
Pull Request resolved: https://github.com/facebook/react-native/pull/26389

Test Plan: Tested by adding the existing `adjustsFontSizeToFit` example from the iOS text page to android. Also added a case for limiting size by using `maxHeight` instead of `numberOfLines`.

Reviewed By: mdvacca

Differential Revision: D17285473

Pulled By: JoshuaGross

fbshipit-source-id: 43dbdb05e2d6418e9a390d11f921518bfa58e697
2020-02-13 16:19:14 +01:00
Michał PierzchałaandEloy Durán 048b537800 - Bump CLI to ^4.0.0 (#27976)
Summary:
Upgrading CLI to latest. This diff is intended to be cherry-picked to 0.62.

cc grabbou kelset

[Internal] [Changed] - Bump CLI to ^4.0.0
Pull Request resolved: https://github.com/facebook/react-native/pull/27976

Test Plan: None

Differential Revision: D19769017

Pulled By: cpojer

fbshipit-source-id: c3f5cd8afc0bc26372ee9f9e9dbaf4e68cdec216
2020-02-13 16:18:57 +01:00
Rick HanlonandEloy Durán 2a50905c0b Upgrade metro
Summary:
Upgrades metro so OSS gets code frames in LogBox.

Changelog: [Internal]

Reviewed By: cpojer

Differential Revision: D19621775

fbshipit-source-id: 02ee45e7282a5fd98e3365292d9221afa637dfeb
2020-02-13 16:17:54 +01:00
Jesse KatsumataandEloy Durán 14398752e3 chore: add eslint back to template (#27983)
Summary:
This PR is part of https://github.com/react-native-community/releases/issues/157#issuecomment-582504146
Adding eslint back to the template package.json

[Internal] [Fixed] - Add eslint back in template
Pull Request resolved: https://github.com/facebook/react-native/pull/27983

Test Plan:
(edited)
- npx react-native init RN062 --version 0.62.0-rc.1
- yarn add -d eslint
- add npm script for lint
- yarn lint

Differential Revision: D19784567

Pulled By: TheSavior

fbshipit-source-id: 9ce24c0b674c2b1ea9fee3ed5614e8922f992f72
2020-02-13 16:16:59 +01:00
Jorge BernalandEloy Durán 6d00239e49 Implement onRequestClose for iOS 13+ modals (#27618)
Summary:
Starting on iOS 13, a View Controller presented modally will have a "bottom sheet" style unless it's explicitly presented full screen.

Before this, modals on iOS were only being dismissed programatically by setting `visible={false}`. However, now that the dismissal can happen on the OS side, we need a callback to be able to update the state.

This PR reuses the `onRequestClose` prop already available for tvOS and Android, and makes it work on iOS for this use case.

Should fix https://github.com/facebook/react-native/issues/26892

## Changelog

[iOS] [Added] - Add support for onRequestClose prop to Modal on iOS 13+
Pull Request resolved: https://github.com/facebook/react-native/pull/27618

Test Plan:
I tested this using the RNTester app with the Modal example:

1. Select any presentation style other than the full screen ones
2. Tap Present and the modal is presented
3. Swipe down on the presented modal until dismissed
4. Tap Present again and a second modal should be presented

![Screen Recording 2019-12-26 at 14 05 33](https://user-images.githubusercontent.com/8739/71477208-0ac88c80-27e9-11ea-9342-8631426a9b80.gif)

Differential Revision: D19235758

Pulled By: shergin

fbshipit-source-id: c0f1d946c77ce8d1baab209eaef7eb64697851df
2020-02-13 16:08:41 +01:00
Panagiotis VekrisandEloy Durán cae662bfea Remove types-first from flowconfig template
Summary:
Removing the experimental types-first flag from RN templates, until these are properly documented in the docs. See https://github.com/facebook/flow/issues/8279 for context.

Changelog: [Internal]

Reviewed By: jbrown215

Differential Revision: D19728257

fbshipit-source-id: 8f7473b9c8383bd1eef76b5733ff3a26e2e554fc
2020-02-13 16:08:33 +01:00
Matt ChowningandEloy Durán 77305cadf0 Allow overriding EditText construction in ReactTextInputShadowNode (#27782)
Summary:
This PR makes it possible for subclasses of `ReactTextInputShadowNode` to control the construction of the "dummy" `EditText` instance that `ReactTextInputShadowNode` internally uses to determine the expected height of the view. This PR does not change the default behavior, it just opens up that default to being overriden.

This is useful in the case of custom views that have different behavior from a "default" `EditText` instance (`new EditText(context)`). For example, it might have a different style applied.

As a side benefit, this change also makes it easy to have subclasses not apply the default theme, which can allow the custom view to avoid a longstanding crash issue (https://github.com/facebook/react-native/issues/17530).

## Changelog

[Android] [Added] - Allow overriding `EditText` construction in `ReactTextInputShadowNode`
Pull Request resolved: https://github.com/facebook/react-native/pull/27782

Test Plan: All tests pass.

Reviewed By: mdvacca

Differential Revision: D19450593

Pulled By: JoshuaGross

fbshipit-source-id: 8d2ce6117246fc3e2108623312b38583af5722b3
2020-02-13 16:08:23 +01:00
Peter ArganyandEloy Durán 925330bb83 Fix animations in OSS debug builds by modifying Platform.isTesting() behaviour
Summary:
In D14244606 I "fixed" `Platform.isTesting()` in JS. By fixed, I made it return true when running SSTs.

People in OSS complained about this in discord and [github](https://github.com/facebook/react-native/issues/27010). The problem is that this call returns true whenever an RN project references Detox in the build.gradle file. In practice, this has been really annoying, because it has disabled animations in debug builds, due to D13811035.

The fix is to be more specific, and look for the exact screenshot test activity. I haven't explicitly verified this doesn't trigger from Detox, but it shouldn't. I'll coordinate on the github issue to verify.

Changelog: [Android][Fixed] Fix animations in OSS debug builds by modifying `Platform.isTesting()` behaviour

Reviewed By: TheSavior

Differential Revision: D19384098

fbshipit-source-id: 22c885219f2c00f5dcc3b930b068bfd2ad7e4b8e
2020-02-13 16:08:14 +01:00
Jason SafaiyehandEloy Durán d68013dd71 Make addCookies method public. (#27512)
Summary:
react-native-cookie-store wants the ability to set custom cookies on Android. We use ForwardingCookieHandler to mange the cookies. Exposing the `addCookies` method will allow the module to provide the same functionality on Android.

https://github.com/safaiyeh/react-native-cookie-store/issues/1

## Changelog

[Android] [Changed] - Expose addCookies method
Pull Request resolved: https://github.com/facebook/react-native/pull/27512

Test Plan: N/A

Differential Revision: D19236309

Pulled By: cpojer

fbshipit-source-id: bf1a0730165456c34c5bf432ac370176a881cbcf
2020-02-13 16:08:00 +01:00
Andy MatuschakandEloy Durán 80f5b6c110 Enabling RCTWebSocket on UIKitForMac (macOS Catalyst) (#27469)
Summary:
In https://github.com/facebook/react-native/issues/25427, radex added initial support for running React Native projects on macOS via Catalyst. However, `RCTWebSocket` was disabled for that target because of some compilation issues. This meant that running projects via a connection to the packager wasn't possible: no live reload, and projects must be run in "Release" mode. It also meant making manual changes to Xcode projects deploying to macOS and scattering a number of conditional checks throughout the codebase.

In this change, I've implemented support for `RCTWebSocket` on the macOS target and re-enabled the affected features. Live reload and the inspector now work for macOS targets. Manual modifications of Xcode build settings are no longer necessary for react-native projects running on macOS.

![Screen Shot 2019-12-10 at 8 36 38 AM](https://user-images.githubusercontent.com/2771/70549905-ce7b0800-1b29-11ea-85c6-07bf09811ae2.png)

### Limitations

There's no binding which displays the developer menu (since there's no shake event on macOS). We'll probably want to add one, perhaps to the menu bar.

I've chosen not to commit the modifications to RNTester which enable macOS support, since that would imply more "official" support for this target than I suspect you all would like to convey. I'm happy to add those chunks if it would be helpful.

## Changelog

[iOS] [Added] - Added web socket support for macOS (Catalyst), enabling debug builds and live reload
Pull Request resolved: https://github.com/facebook/react-native/pull/27469

Test Plan:
* Open RNTester/RNTester.xcodeproj with Xcode 11.2.1, run it like a normal iOS app -- make sure it compiles and runs correctly (no regression)
* Select "My Mac" as device target, and run. You may need to configure a valid development team to make signing work.
* RNTester should run fine with no additional configuration. Modify a file in RNTester, note that live reload is now working.
* Test the developer inspector. To display the developer menu, you'll need to manually show it; here's an example diff which does that:
```
 diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js
index 8245a68d12..a447ad3b1b 100644
 --- a/RNTester/js/RNTesterApp.ios.js
+++ b/RNTester/js/RNTesterApp.ios.js
@@ -19,6 +19,8 @@ const React = require('react');
 const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios');
 const URIActionMap = require('./utils/URIActionMap');

+import NativeDevMenu from '../../Libraries/NativeModules/specs/NativeDevMenu';
+
 const {
   AppRegistry,
   AsyncStorage,
@@ -143,6 +145,7 @@ class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {

   UNSAFE_componentWillMount() {
     BackHandler.addEventListener('hardwareBackPress', this._handleBack);
+    NativeDevMenu.show();
   }

   componentDidMount() {
```

Reviewed By: sammy-SC

Differential Revision: D18945861

Pulled By: hramos

fbshipit-source-id: edcf02c5803742c89a845a3e5d72bc7dacae839f
2020-02-13 16:07:37 +01:00
Eloy Durán 99ef72cad7 Add androidx.swiperefreshlayout to template build.gradle
Same as 2c89e51507, but for template.

Changelog: [Android] [Fixed] Template instacrash from missing androidx dependency
2020-02-13 16:00:05 +01:00
Eloy Durán b4d1fcfb2f Smoothen Flipper iOS integration (#28044)
Summary:
Addresses my feedback [here](https://github.com/facebook/react-native/issues/27565#issuecomment-580950480), [here](https://github.com/facebook/react-native/issues/27565#issuecomment-582490074), and [here](https://github.com/facebook/react-native/issues/27565#issuecomment-585456768).

## Changelog

[iOS] [Changed] - Updated Flipper iOS integration to be included by default in the `Debug` configuration
Pull Request resolved: https://github.com/facebook/react-native/pull/28044

Test Plan:
Manually tested that a new application from this template still works and that the Flipper integration works.

<img width="912" alt="Screenshot 2020-02-13 at 02 09 42" src="https://user-images.githubusercontent.com/2320/74391951-eb6fd800-4e05-11ea-9fde-7e0eb42c1ec4.png">

Differential Revision: D19871482

Pulled By: TheSavior

fbshipit-source-id: a805808fdd0c2dfdfe47dd59ffee02c81f3fdfa7
2020-02-13 14:47:47 +01:00
Pritesh NandgaonkarandEloy Durán 13cefd396c @allow-large-files [Flipper][RN] Integrated Flipper in RNTester application
Summary:
Changelog: [iOS] [Fixed]

Integrated Flipper in RNTester application and made sure that flipper connects with RNTester application

allow-large-files

Reviewed By: rickhanlonii

Differential Revision: D19813213

fbshipit-source-id: f0c7a5a42ffaccd488582b0f42ce37aea946c636
2020-02-13 14:33:47 +01:00
Pascal HartigandRick Hanlon e7bfa1fc2e Upgrade Flipper version (#27837)
Summary:
Depends on https://github.com/facebook/react-native/issues/27833.

Updates the Flipper version to the most recent release.

## Changelog

[Android] [Changed] - Upgrade Flipper version in default template
Pull Request resolved: https://github.com/facebook/react-native/pull/27837

Test Plan:
This is a bit annoying, but I can't test this against the 0.62-rc.0 version. I tried patching it by running `react-native init --version 0.62.0-rc.0  testproj`, which would fail because of a missing androidx dep. After adding `implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'` to the deps, that was fixed but now after updating, `libfbjni.so` is missing because my PR https://github.com/facebook/react-native/issues/27729 isn't part of the RN dependency yet.

Given that this mirrors the RNTester app, I'm pretty confident that the change here is otherwise correct and will work on top of master with the most recent template changes.

Differential Revision: D19619365

Pulled By: passy

fbshipit-source-id: 5723bd105ab3ab86b7f00e1a26e29e1e9dc58290
2020-02-05 14:10:50 +00:00
Eloy Durán 6a10d5dfd3 Remove FB copyright notices from iOS template (#27725)
Summary:
Files that are to be part of the user’s project shouldn’t have FB copyright notices.

There’s [one notice left](https://github.com/facebook/react-native/blob/66601e755fcad10698e61d20878d52194ad0e90c/template/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java#L2) in the `android` template, which is in a file that doesn’t seem to be intended to be changed by the user and so that seems fine to me.

[iOS] [Removed] - Remove copyright notices from iOS application template
Pull Request resolved: https://github.com/facebook/react-native/pull/27725

Test Plan:
```bash
npx react-native init TestTemplateUpdates --template ~/Code/ReactNative/react-native
cd ios
xcodebuild -workspace TestTemplateUpdates.xcworkspace \
  -scheme TestTemplateUpdates \
  -destination 'platform=iOS Simulator,OS=latest,name=iPhone 8' build
[…]
** BUILD SUCCEEDED **
```

Differential Revision: D19343386

Pulled By: TheSavior

fbshipit-source-id: a78be5e5d2fdc2477adedb51d6bb3ff19845b75f
2020-02-05 14:54:03 +01:00
Eloy Durán 60da5071a6 Make C++ requirement opt-in (#27730)
Summary:
When building as a framework these headers get automatically added to the framework umbrella header for React-Core. Instead of converting all the React sources to ObjC++ files and still forcing external users that build native source (and link against a framework build) to also compile as ObjC++, this makes the attribution related methods that were added in https://github.com/facebook/react-native/commit/fdcdca4 opt-in to ObjC++ builds.

This is also the reason for the current failure of the CI `test_ios_frameworks` run.

I’m unsure if this change really warrants an entry in the CHANGELOG, as it’s more of an amendment of the (afaik) unreleased [change](https://github.com/facebook/react-native/commit/fdcdca4).

[iOS] [Fixed] - Make framework builds work again by making `RCTImageLoader` C++ requirement opt-in
Pull Request resolved: https://github.com/facebook/react-native/pull/27730

Test Plan:
I tested static and dynamic (framework) builds and ran the test suite.

This change should make the `test_ios_frameworks` CI run _build_ again, ~~but it may still fail overall as in my local testing one of the tests leads to a segfault (which I will try to address separately)~~.

Reviewed By: PeteTheHeat

Differential Revision: D19348846

Pulled By: fkgozali

fbshipit-source-id: 8a74e6f7ad3ddce2cf10b080b9a5d7b399bd5fc0
2020-02-05 14:54:03 +01:00
Eloy Durán e3218a0d96 Remove empty Swift file for Flipper (#27922)
Summary:
Related to https://github.com/facebook/react-native/issues/27426 & https://github.com/facebook/react-native/issues/27565.

The wish to not include an empty Swift file to trigger the correct Xcode settings was voiced in https://github.com/facebook/react-native/issues/27426 & https://github.com/facebook/react-native/issues/27565.

[iOS] [Fixed] - Remove need for Swift file in the user’s project in order to use Flipper
Pull Request resolved: https://github.com/facebook/react-native/pull/27922

Test Plan:
An application created with the template, like so:

```bash
react-native init --template=~/Code/React/react-native TestFlipper
```

…will successfully build, launch, and have Flipper connect.

Differential Revision: D19690592

Pulled By: cpojer

fbshipit-source-id: ee696e0d747d6338534b0c2d62029e64ece02cd3
2020-02-05 14:54:03 +01:00
Rick Hanlon 2c89e51507 Add androidx.swiperefreshlayout to RNTester build.gradle
Summary:
Suggested fix from passy

Changelog: [General] [Fixed] RNTester instacrash from missing androidx dependency

Reviewed By: passy

Differential Revision: D19741935

fbshipit-source-id: 62e02169a92b7418471d2228a3d75ffffbe7a6a6
2020-02-05 13:27:30 +00:00
Pascal HartigandRick Hanlon 6f00f5f6b8 Remove NativeRunnableDeprecated (#27529)
Summary:
The class was deprecated in 2016 and is blocking an upgrade to fbjni
which no longer supports the `Countable` class this extends.

Changelog:
[Android] [Removed] - NativeRunnableDeprecated
Pull Request resolved: https://github.com/facebook/react-native/pull/27529

Test Plan: No references to it in this codebase.

Reviewed By: mdvacca

Differential Revision: D19087074

Pulled By: passy

fbshipit-source-id: a4ee73be7c13cedf1d86d2643f8e788ad4a2e31f
2020-02-05 11:33:06 +00:00
Jason SafaiyehandRick Hanlon 05f5cb534f initalizeFlipper should be set in template app by default (#27569)
Summary:
Issue: https://github.com/facebook/react-native/issues/27565

initalizeFlipper should be set in template app by default.

## Changelog

[iOS] [Changed] - Added Flipper to template app
[Android] [Changed] - Added Flipper to template app
Pull Request resolved: https://github.com/facebook/react-native/pull/27569

Test Plan:
Connect Flipper to the iOS application
Connect Flipper to the Android application

Reviewed By: passy

Differential Revision: D19344704

Pulled By: rickhanlonii

fbshipit-source-id: ca126fd2caab13751ddc2ce6d195bd0c644c704e
2020-02-05 11:04:26 +00:00
Jason SafaiyehandRick Hanlon 79e38e7d8e Integrate Flipper in RNTester on Android (#27631)
Summary:
0.62 Flipper Support items: https://github.com/facebook/react-native/issues/27565
Made RNTester's Android Flipper implementation consistent with the template.
~~Added Flipper to the iOS build.~~
<img width="1259" alt="Screen Shot 2019-12-28 at 7 06 42 PM" src="https://user-images.githubusercontent.com/8675043/71551835-37290800-29a5-11ea-9eac-b119a69a68c1.png">

## Changelog

[Internal] [Added] - RNTester Android Fipper updates
Pull Request resolved: https://github.com/facebook/react-native/pull/27631

Test Plan: Run RNTester and see if it connects to Flipper.

Reviewed By: rickhanlonii

Differential Revision: D19345093

Pulled By: passy

fbshipit-source-id: 6957c1ca3f4a5bb7f0e581c5daf8ddeac5d87eea
2020-02-05 11:04:03 +00:00
Pascal HartigandRick Hanlon b86f16aa4e Use new Flipper SDK (#27833)
Summary:
The FBJNI compat issue is gone so this is working now. �

Still a bit ugly to set up, but that's on our ToDo. Next: Template.

## Changelog

[Android] [Fixed] - Use modern Flipper SDK version for RNTester
Pull Request resolved: https://github.com/facebook/react-native/pull/27833

Test Plan:
```
./gradlew :RNTester:android:app:installHermesDebug
```

![Screenshot 2020-01-22 at 09 30 22](https://user-images.githubusercontent.com/9906/72883088-9c012500-3cfb-11ea-9997-b38831196259.png)

Reviewed By: cpojer

Differential Revision: D19513412

Pulled By: passy

fbshipit-source-id: af118bd364ab316732e2a1e657fa1b682bf7da59
2020-02-05 11:03:42 +00:00
Pascal HartigandRick Hanlon 4d9385d531 Fix BUCK build (#27826)
Summary:
This fixes a build failure with buck introduced with https://github.com/facebook/react-native/issues/27729. The internal and external buck overlays diverged in how fbjni was imported. The Buck re-export here ensures that the targets resolve both internall and externally.

## Changelog

[Android] [Fixed] - RNTester Buck Build
Pull Request resolved: https://github.com/facebook/react-native/pull/27826

Test Plan:
buck fetch rntester
buck build rntester

Reviewed By: jknoxville

Differential Revision: D19496769

Pulled By: passy

fbshipit-source-id: d699a5f64f691ed375cfc7a9d6a5a6f6e36ba283
2020-02-05 11:03:23 +00:00
Pascal HartigandRick Hanlon 8c11d3ffce Migrate to FBJNI (#27729)
Summary:
This is an incomplete effort to migrate from libfb to libfbjni. This is needed to restore the compatibility with Flipper and other FB Android projects that make use of FBJNI. Effectively, the outcome is that `fbjni` no longer has a checked-in copy here, but instead relies on the public artifacts published at github.com/facebookincubator/fbjni that can be deduplicated at build-time.

**A non-exhaustive list of tasks:**

* [X] Gradle builds the SDK and RNTester for Android.
* [X] Buck build for rntester works in OSS.
* [ ] Move from `java-only` release to full `fbjni` release. This requires finding a solution for stripping out `.so` files that the old `Android.mk` insists on including in the final artifacts and will clash with the full distribution.
* [ ] Import this and fix potential internal build issues.
* [ ] Verify that the changes made to the Hermes integration don't have any unintended consequences.

## Changelog

[Android] [Changed] - Migrated from libfb to libfbjni for JNI calls
Pull Request resolved: https://github.com/facebook/react-native/pull/27729

Test Plan:
- CI is already passing again for Gradle and Buck in OSS.
- After applying the following patch, RNTester builds and works with the latest Flipper SDK:

```
 diff --git a/RNTester/android/app/build.gradle b/RNTester/android/app/build.gradle
index b8a6437d7..eac942104 100644
 --- a/RNTester/android/app/build.gradle
+++ b/RNTester/android/app/build.gradle
@@ -170,10 +170,19 @@ dependencies {
     debugImplementation files(hermesPath + "hermes-debug.aar")
     releaseImplementation files(hermesPath + "hermes-release.aar")

-    debugImplementation("com.facebook.flipper:flipper:0.23.4") {
+    debugImplementation("com.facebook.flipper🐬+") {
         exclude group:'com.facebook.yoga'
-        exclude group:'com.facebook.flipper', module: 'fbjni'
-        exclude group:'com.facebook.litho', module: 'litho-annotations'
+        exclude group:'com.facebook.fbjni'
+    }
+
+    debugImplementation("com.facebook.flipper:flipper-network-plugin:+") {
+        exclude group:'com.facebook.yoga'
+        exclude group:'com.facebook.fbjni'
+    }
+
+    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:+") {
+        exclude group:'com.facebook.yoga'
+        exclude group:'com.facebook.fbjni'
     }

     if (useIntlJsc) {
```

Reviewed By: mdvacca

Differential Revision: D19345270

Pulled By: passy

fbshipit-source-id: 33811e7f97f44f2ec5999e1c35339909dc4fd3b1
2020-02-05 11:02:13 +00:00
Pascal HartigandRick Hanlon 89eb287be1 clang-format cpp
Summary:
Ran `arc f` against some CPP files to be modified with the next diff
to reduce the churn on it.

## Changelog

[Android] [Changed] - Formatted cpp/h code with clang-format

Reviewed By: javache

Differential Revision: D19371785

fbshipit-source-id: b7f7b92c4cb9ec7f8da728bb577db29cf11fbb39
2020-02-05 11:01:55 +00:00
Pascal HartigandRick Hanlon 3c3b4cf575 Fix RNTester integration with Flipper (#27482)
Summary:
There was a reflective call to a non-existent class. It did, however,
exist in the template, so I copied it over from there and updated
the references accordingly.
Pull Request resolved: https://github.com/facebook/react-native/pull/27482

Test Plan:
Built it and ran it. Works again with the latest Flipper desktop app.

![Screenshot 2019-12-11 16 02 40](https://user-images.githubusercontent.com/9906/70637975-02405580-1c30-11ea-9fec-23860c59cdb6.png)

Reviewed By: rickhanlonii

Differential Revision: D18933530

Pulled By: passy

fbshipit-source-id: 4515d7baaad9a9fff9a4b66e1cbf8a75889e6e45
2020-01-29 11:10:11 +00:00
brotskyandRick Hanlon 8f954b3659 Edits to flipper pods comments (#27485)
Summary:
grammar edits

## Changelog

[Internal] [Fixed] - Edits to flipper pods comments
Pull Request resolved: https://github.com/facebook/react-native/pull/27485

Differential Revision: D18962196

Pulled By: hramos

fbshipit-source-id: d8eb8b852130b9ceee8ab9b668f94d9d4d11a217
2020-01-29 11:07:39 +00:00
Lorenzo Sciandra 2bf7f1046d [0.62.0-rc.1] Bump version numbers 2020-01-21 08:27:36 +00:00
Rick Hanlon 5b4816741b LogBox - Double sync rendering timeout
Summary:
On slower devices , 0.5s is not fast enough and we frequently render a black screen. Let's bump the sync rendering timeout to 1s.

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D19282619

fbshipit-source-id: 0d9ae60f4869b0de7c4523c2cb33fbbf320c6438
2020-01-07 06:55:57 -05:00
sunnylqmandRick Hanlon 39e5a83062 Fix android modal not disappear when reload (#27542)
Summary:
Fixes https://github.com/facebook/react-native/issues/17986

See above issue

After apply this change:
![ezgif-4-45d9add85b74](https://user-images.githubusercontent.com/615282/70987576-2520ad00-20fb-11ea-9b90-c9a7839824a5.gif)

## Changelog

[Android] [Fixed] - Fix android modal not disappear when reload
Pull Request resolved: https://github.com/facebook/react-native/pull/27542

Test Plan: Open a modal and do a refresh to see whether it disappears

Differential Revision: D19178803

Pulled By: mdvacca

fbshipit-source-id: 61894927fc481650804b2196df06a80c16b64e6c
2019-12-20 09:47:45 -05:00
Rick Hanlon fe348ab53d LogBox fixes for OSS
Summary:
This diff fixes two issues with LogBox in OSS.

Changelog: [Internal]

Reviewed By: mmmulani

Differential Revision: D19165696

fbshipit-source-id: 4dd9c480ea3d2b205f8e65cb32203949b1e32e8a
2019-12-19 07:32:26 -05:00
Rick Hanlon 0fd83e4786 LogBox - lazily initialize on iOS, use sync APIs
Summary:
Update LogBox on iOS to lazily initialize, using a synchronous RCTSurface, behind RCTSharedApplication checks.

This results in faster of LogBox, without keeping around a long lived window in the background, and only used when LogBox is used.

On Android, we still start the react app in the background but we create a dialog when it's shown and then destroy it when it's hidden. Once we have the sync APIs on android we can update it to use the same strategy.

Changelog: [Internal]

Reviewed By: fkgozali

Differential Revision: D18925538

fbshipit-source-id: 1a72c39aa0fc26c8ba657d36c7fa7bc0ae777eb9
2019-12-19 07:30:59 -05:00
Kevin GozaliandRick Hanlon e97baa6066 LogBox iOS: don't initialize logbox window if redbox flag is disabled
Summary:
If redbox flag is disabled, don't initialize LogBox window even if the native module exists. This makes the module noop.

Changelog: [Internal]

Reviewed By: shergin

Differential Revision: D18927309

fbshipit-source-id: 3dc6c08ed537925594cabf77d1142568d47132e9
2019-12-19 07:30:59 -05:00
Rick Hanlon 76557f00d7 Add WarningFilter handling for YellowBox
Summary:
This diff backports warning filter handling to yellow box. I also backported the skipped warning handling so that ignored patterns do not log to the console, same as LogBox.

Changelog: [Internal]

Reviewed By: gaearon

Differential Revision: D18573288

fbshipit-source-id: 5bf8e86f754adc808313d7ed02f98daaf65de98c
2019-12-19 07:30:59 -05:00
Rick Hanlon 4693170d63 Hotfix - register null logbox outside of dev
Summary:
Outside of __DEV__ the app may still try to use LogBox. We're going to fix that but until we do, if it tries to use LogBox outside of dev render null.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D18932666

fbshipit-source-id: ef0f2542a295dc9332cae8b77faed78f8be350fe
2019-12-19 07:30:59 -05:00
Rick Hanlon 51dcb0195b Disable LogBox if native module is not available
Summary: Changelog: [Internal]

Reviewed By: mmmulani

Differential Revision: D18920345

fbshipit-source-id: e5213dc9c3a1aa775138e71a8040a3472e9bbd67
2019-12-19 07:30:59 -05:00
Lorenzo Sciandra 203f3e3399 [0.62.0-rc.0] Bump version numbers 2019-12-18 15:36:07 +00:00
Spencer AhrensandHéctor Ramos e7c289b56e emit Dimensions change enent when app goes split screen
Summary:
Fixes https://github.com/facebook/react-native/issues/26830 by removing version gating around `RCTUserInterfaceStyleDidChangeNotification` sent by `RCTRootView` and observing that notif for `Dimensions` changes.

Also centralizes `RCTUserInterfaceStyleDidChangeNotification` constant definition in new `RCTConstants` file.

Changelog:
[iOS] [Fixed] - `Dimensions` module now updates on initial split screen

Reviewed By: sammy-SC

Differential Revision: D18931098

fbshipit-source-id: e9784be3f544f3b10360fbc2d6ad0324273b1a8f
2019-12-11 14:05:45 -08:00
Rick Hanlon 3cfbae6540 Fix logs stuck in pending symbolocated state
Summary:
This diff fixes an issue where symbolicated logs were getting stuck in a "pending" state if the timeout occurred before symbolication finished.

Changelog: [Internal]

Reviewed By: sahrens

Differential Revision: D18894154

fbshipit-source-id: ed225962468f67aef40e430aa798f8d426d31027
2019-12-10 19:53:38 +00:00
Rick Hanlon 3fd98d95ef RN DevX] LogBox - Handle tapping component stacks if possible
Summary:
This diff adds handling for tapping to open components in component stacks, whenever they're available.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D18882338

fbshipit-source-id: 574bff1c41c952c33e647cb142d278ace60b4631
2019-12-10 19:53:29 +00:00
Rick Hanlon c194ed2dbb Add unstable_enableLogBox
Summary:
This diff adds a new `unstable_enableLogBox` function to opt-into the new LogBox experience. If LogBox is not enabled early enough, we show an error with instructions.

With this, LogBox can be enabled with:

```
require('react-native').unstable_enableLogBox();
```

Changelog: [General] [Adds] unstable_enableLogBox

Reviewed By: zackargyle, rubennorte

Differential Revision: D18808940

fbshipit-source-id: 4b0234ddc4d1646515bf63110d5b02133780512e
2019-12-10 19:53:18 +00:00
Rick Hanlon 93bbab3878 LogBox - Update to use it's own root for the inspector
Summary:
Apologies for the large diff, it was difficult to break down.

This diff is a major refactor of LogBox that:
- Separates LogBoxNotification and LogBoxInspector
- Moves them each to their own container
- Updates AppContainer to only render the notification
- Updates the native logbox root to render the inspector
- Adds withSubscription HOC to manage subscribing to LogBoxData
- Simplifies LogBox to export an object instead of a component

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D18750011

fbshipit-source-id: 639885d29e55e125892d1c2b6bbf2826f27d78db
2019-12-10 19:53:09 +00:00
Rick Hanlon 1a305fd79b Add NativeLogBox module on Android
Summary:
This diff adds a NativeLogBox module implementation on Android to manage rendering LogBox the way we render RedBox, except rendering a React Native component instead of a native view.

The strategy here is:
- initialize: will create a React rootview and render it.
- show: will add the rootview to a dialog and display the dialog.
- hide: will remove the rootview from it's parent, dismiss the dialog, and release the reference to the activity to prevent leaks.

Most of this is copied from the way RedBox works, the difference here is that we eagerly initialize the rootview with the `initialize` function so that it's warm by the time the dialog needs to render.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D18768517

fbshipit-source-id: 2510d6c186ccf73153ef9372c736c9e0c71bbc7d
2019-12-10 19:52:58 +00:00
Rick Hanlon 45a43241cd Add NativeLogBox module on iOS
Summary:
This diff adds a NativeLogBox module implementation on iOS to manage rendering LogBox the way we render RedBox, except rendering a React Native component instead of a native view.

The strategy here is:
- initialize: will create a hidden window (the way redbox does) and render the LogBox to it
- show: will show the window
- hide: will hide the window

Most of this is copied from the way RedBox works, the difference here is that we eagerly initialize the window with the `initialize` function so that it's warm by the time LogBox needs to render.

Changelog: [Internal]

Reviewed By: RSNara

Differential Revision: D18750008

fbshipit-source-id: 013e55ded55c8572bb08e0219ff4cd0060ebe0da
2019-12-10 19:52:44 +00:00
Rick Hanlon 041c392ec9 Register LogBox by default in dev
Summary:
This diff stubs out registering LogBox as a renderable component. In later diffs, we'll render this component on the native side.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D18750005

fbshipit-source-id: 4db082ca2104731641d2d10de1ba83a318ab44fb
2019-12-10 19:52:23 +00:00
273 changed files with 4845 additions and 10846 deletions
+1
View File
@@ -8,6 +8,7 @@
[maven_repositories]
central = https://repo1.maven.org/maven2
google = https://maven.google.com/
jcenter = https://jcenter.bintray.com/
[alias]
rntester = //RNTester/android/app:app
+1 -1
View File
@@ -83,7 +83,7 @@ function reportException(e: ExtendedError, isFatal: boolean) {
e.jsEngine == null ? message : `${message}, js engine: ${e.jsEngine}`;
const isHandledByLogBox =
e.forceRedbox !== true && global.__reactExperimentalLogBox;
e.forceRedbox !== true && global.__unstable_isLogBoxEnabled === true;
const data = preprocessException({
message,
+4 -4
View File
@@ -1,17 +1,17 @@
/**
* @generated by scripts/bump-oss-version.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @generated by scripts/bump-oss-version.js
* @flow
*/
exports.version = {
major: 0,
minor: 0,
minor: 62,
patch: 0,
prerelease: null,
prerelease: 'rc.2',
};
@@ -1671,6 +1671,33 @@ namespace facebook {
}
} // namespace react
} // namespace facebook
namespace facebook {
namespace react {
static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_show(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "show", @selector(show), args, count);
}
static facebook::jsi::Value __hostFunction_NativeLogBoxSpecJSI_hide(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
return static_cast<ObjCTurboModule&>(turboModule).invokeObjCMethod(rt, VoidKind, "hide", @selector(hide), args, count);
}
NativeLogBoxSpecJSI::NativeLogBoxSpecJSI(id<RCTTurboModule> instance, std::shared_ptr<CallInvoker> jsInvoker)
: ObjCTurboModule("LogBox", instance, jsInvoker) {
methodMap_["show"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_show};
methodMap_["hide"] = MethodMetadata {0, __hostFunction_NativeLogBoxSpecJSI_hide};
}
} // namespace react
@@ -1771,6 +1771,25 @@ namespace facebook {
};
} // namespace react
} // namespace facebook
@protocol NativeLogBoxSpec <RCTBridgeModule, RCTTurboModule>
- (void)show;
- (void)hide;
@end
namespace facebook {
namespace react {
/**
* ObjC++ class for module 'LogBox'
*/
class JSI_EXPORT NativeLogBoxSpecJSI : public ObjCTurboModule {
public:
NativeLogBoxSpecJSI(id<RCTTurboModule> instance, std::shared_ptr<CallInvoker> jsInvoker);
};
} // namespace react
} // namespace facebook
@protocol NativeModalManagerSpec <RCTBridgeModule, RCTTurboModule>
- (void)addListener:(NSString *)eventName;
@@ -12,6 +12,8 @@
@protocol RCTImageLoaderWithAttributionProtocol<RCTImageLoaderProtocol>
// TODO (T61325135): Remove C++ checks
#ifdef __cplusplus
/**
* Same as the variant in RCTImageURLLoaderProtocol, but allows passing attribution
* information that each image URL loader can process.
@@ -25,5 +27,6 @@
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
#endif
@end
@@ -7,6 +7,8 @@
#import <React/RCTImageURLLoader.h>
// TODO (T61325135): Remove C++ checks
#ifdef __cplusplus
namespace facebook {
namespace react {
@@ -17,6 +19,7 @@ struct ImageURLLoaderAttribution {
} // namespace react
} // namespace facebook
#endif
/**
* Same as the RCTImageURLLoader interface, but allows passing in optional `attribution` information.
@@ -24,6 +27,8 @@ struct ImageURLLoaderAttribution {
*/
@protocol RCTImageURLLoaderWithAttribution <RCTImageURLLoader>
// TODO (T61325135): Remove C++ checks
#ifdef __cplusplus
/**
* Same as the RCTImageURLLoader variant above, but allows optional `attribution` information.
*/
@@ -35,5 +40,6 @@ struct ImageURLLoaderAttribution {
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
#endif
@end
+133 -25
View File
@@ -10,6 +10,7 @@
('use strict');
import * as React from 'react';
import LogBoxLog from './LogBoxLog';
import {parseLogBoxException} from './parseLogBoxLog';
import type {LogLevel} from './LogBoxLog';
@@ -21,7 +22,7 @@ import type {
} from './parseLogBoxLog';
import parseErrorStack from '../../Core/Devtools/parseErrorStack';
import type {ExtendedError} from '../../Core/Devtools/parseErrorStack';
import NativeLogBox from '../../NativeModules/specs/NativeLogBox';
export type LogBoxLogs = Set<LogBoxLog>;
export type LogData = $ReadOnly<{|
level: LogLevel,
@@ -73,7 +74,7 @@ let warningFilter: WarningFilter = function(format) {
return {
finalFormat: format,
forceDialogImmediately: false,
suppressDialog_LEGACY: false,
suppressDialog_LEGACY: true,
suppressCompletely: false,
monitorEvent: 'unknown',
monitorListVersion: 0,
@@ -85,20 +86,6 @@ const LOGBOX_ERROR_MESSAGE =
'An error was thrown when attempting to render log messages via LogBox.';
function getNextState() {
const logArray = Array.from(logs);
let index = logArray.length - 1;
while (index >= 0) {
// The latest syntax error is selected and displayed before all other logs.
if (logArray[index].level === 'syntax') {
return {
logs,
isDisabled: _isDisabled,
selectedLogIndex: index,
};
}
index -= 1;
}
return {
logs,
isDisabled: _isDisabled,
@@ -174,9 +161,10 @@ function appendNewLog(newLog) {
let addPendingLog = () => {
logs.add(newLog);
if (_selectedIndex <= 0) {
_selectedIndex = logs.size - 1;
setSelectedLog(logs.size - 1);
} else {
handleUpdate();
}
handleUpdate();
addPendingLog = null;
};
@@ -190,8 +178,14 @@ function appendNewLog(newLog) {
if (addPendingLog && status !== 'PENDING') {
addPendingLog();
clearTimeout(optimisticTimeout);
} else if (status !== 'PENDING') {
// The log has already been added but we need to trigger a render.
handleUpdate();
}
});
} else if (newLog.level === 'syntax') {
logs.add(newLog);
setSelectedLog(logs.size - 1);
} else {
logs.add(newLog);
handleUpdate();
@@ -255,21 +249,42 @@ export function symbolicateLogLazy(log: LogBoxLog) {
export function clear(): void {
if (logs.size > 0) {
logs = new Set();
_selectedIndex = -1;
handleUpdate();
setSelectedLog(-1);
}
}
export function setSelectedLog(index: number): void {
_selectedIndex = index;
export function setSelectedLog(proposedNewIndex: number): void {
const oldIndex = _selectedIndex;
let newIndex = proposedNewIndex;
const logArray = Array.from(logs);
let index = logArray.length - 1;
while (index >= 0) {
// The latest syntax error is selected and displayed before all other logs.
if (logArray[index].level === 'syntax') {
newIndex = index;
break;
}
index -= 1;
}
_selectedIndex = newIndex;
handleUpdate();
if (NativeLogBox) {
setTimeout(() => {
if (oldIndex < 0 && newIndex >= 0) {
NativeLogBox.show();
} else if (oldIndex >= 0 && newIndex < 0) {
NativeLogBox.hide();
}
}, 0);
}
}
export function clearWarnings(): void {
const newLogs = Array.from(logs).filter(log => log.level !== 'warn');
if (newLogs.length !== logs.size) {
logs = new Set(newLogs);
_selectedIndex = -1;
setSelectedLog(-1);
handleUpdate();
}
}
@@ -280,8 +295,7 @@ export function clearErrors(): void {
);
if (newLogs.length !== logs.size) {
logs = new Set(newLogs);
_selectedIndex = -1;
handleUpdate();
setSelectedLog(-1);
}
}
@@ -369,3 +383,97 @@ export function observe(observer: Observer): Subscription {
},
};
}
type Props = $ReadOnly<{||}>;
type State = $ReadOnly<{|
logs: LogBoxLogs,
isDisabled: boolean,
hasError: boolean,
selectedLogIndex: number,
|}>;
type SubscribedComponent = React.AbstractComponent<
$ReadOnly<{|
logs: $ReadOnlyArray<LogBoxLog>,
isDisabled: boolean,
selectedLogIndex: number,
|}>,
>;
export function withSubscription(
WrappedComponent: SubscribedComponent,
): React.AbstractComponent<{||}> {
class LogBoxStateSubscription extends React.Component<Props, State> {
static getDerivedStateFromError() {
return {hasError: true};
}
componentDidCatch(err: Error, errorInfo: {componentStack: string, ...}) {
reportLogBoxError(err, errorInfo.componentStack);
}
_subscription: ?Subscription;
state = {
logs: new Set(),
isDisabled: false,
hasError: false,
selectedLogIndex: -1,
};
render(): React.Node {
if (this.state.hasError) {
// This happens when the component failed to render, in which case we delegate to the native redbox.
// We can't show anyback fallback UI here, because the error may be with <View> or <Text>.
return null;
}
return (
<WrappedComponent
logs={Array.from(this.state.logs)}
isDisabled={this.state.isDisabled}
selectedLogIndex={this.state.selectedLogIndex}
/>
);
}
componentDidMount(): void {
this._subscription = observe(data => {
this.setState(data);
});
}
componentWillUnmount(): void {
if (this._subscription != null) {
this._subscription.unsubscribe();
}
}
_handleDismiss = (): void => {
// Here we handle the cases when the log is dismissed and it
// was either the last log, or when the current index
// is now outside the bounds of the log array.
const {selectedLogIndex, logs: stateLogs} = this.state;
const logsArray = Array.from(stateLogs);
if (selectedLogIndex != null) {
if (logsArray.length - 1 <= 0) {
setSelectedLog(-1);
} else if (selectedLogIndex >= logsArray.length - 1) {
setSelectedLog(selectedLogIndex - 1);
}
dismiss(logsArray[selectedLogIndex]);
}
};
_handleMinimize = (): void => {
setSelectedLog(-1);
};
_handleSetSelectedLog = (index: number): void => {
setSelectedLog(index);
};
}
return LogBoxStateSubscription;
}
@@ -25,7 +25,13 @@ function getLogBoxLog() {
message: {content: '...', substitutions: []},
stack: createStack(['A', 'B', 'C']),
category: 'Message category...',
componentStack: [{component: 'LogBoxLog', location: 'LogBoxLog.js:1'}],
componentStack: [
{
content: 'LogBoxLog',
fileName: 'LogBoxLog.js',
location: {column: -1, row: 1},
},
],
codeFrame: {
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
location: {row: 199, column: 0},
@@ -69,7 +75,11 @@ describe('LogBoxLog', () => {
expect(log.stack).toEqual(createStack(['A', 'B', 'C']));
expect(log.category).toEqual('Message category...');
expect(log.componentStack).toEqual([
{component: 'LogBoxLog', location: 'LogBoxLog.js:1'},
{
content: 'LogBoxLog',
fileName: 'LogBoxLog.js',
location: {column: -1, row: 1},
},
]);
expect(log.codeFrame).toEqual({
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
@@ -117,8 +117,16 @@ describe('parseLogBoxLog', () => {
]),
).toEqual({
componentStack: [
{component: 'MyComponent', location: 'filename.js:1'},
{component: 'MyOtherComponent', location: 'filename2.js:1'},
{
content: 'MyComponent',
fileName: 'filename.js',
location: {column: -1, row: 1},
},
{
content: 'MyOtherComponent',
fileName: 'filename2.js',
location: {column: -1, row: 1},
},
],
category:
'Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?%s',
@@ -143,8 +151,16 @@ describe('parseLogBoxLog', () => {
]),
).toEqual({
componentStack: [
{component: 'MyComponent', location: 'filename.js:1'},
{component: 'MyOtherComponent', location: 'filename2.js:1'},
{
content: 'MyComponent',
fileName: 'filename.js',
location: {column: -1, row: 1},
},
{
content: 'MyOtherComponent',
fileName: 'filename2.js',
location: {column: -1, row: 1},
},
],
category: 'Some kind of message',
message: {
@@ -164,8 +180,16 @@ describe('parseLogBoxLog', () => {
]),
).toEqual({
componentStack: [
{component: 'MyComponent', location: 'filename.js:1'},
{component: 'MyOtherComponent', location: 'filename2.js:1'},
{
content: 'MyComponent',
fileName: 'filename.js',
location: {column: -1, row: 1},
},
{
content: 'MyOtherComponent',
fileName: 'filename2.js',
location: {column: -1, row: 1},
},
],
category:
'Some kind of message Some other kind of message Some third kind of message',
@@ -418,12 +442,14 @@ Please follow the instructions at: fburl.com/rn-remote-assets`,
},
componentStack: [
{
component: 'MyComponent',
location: 'filename.js:1',
content: 'MyComponent',
fileName: 'filename.js',
location: {column: -1, row: 1},
},
{
component: 'MyOtherComponent',
location: 'filename2.js:1',
content: 'MyOtherComponent',
fileName: 'filename2.js',
location: {column: -1, row: 1},
},
],
stack: [
+12 -10
View File
@@ -42,12 +42,7 @@ export type Message = $ReadOnly<{|
>,
|}>;
export type ComponentStack = $ReadOnlyArray<
$ReadOnly<{|
component: string,
location: string,
|}>,
>;
export type ComponentStack = $ReadOnlyArray<CodeFrame>;
const SUBSTITUTION = UTFSequence.BOM + '%s';
@@ -127,6 +122,7 @@ export function parseCategory(
},
};
}
export function parseComponentStack(message: string): ComponentStack {
return message
.split(/\n {4}in /g)
@@ -134,11 +130,17 @@ export function parseComponentStack(message: string): ComponentStack {
if (!s) {
return null;
}
let [component, location] = s.split(/ \(at /);
if (!location) {
[component, location] = s.split(/ \(/);
const match = s.match(/(.*) \(at (.*\.js):([\d]+)\)/);
if (!match) {
return null;
}
return {component, location: location && location.replace(')', '')};
let [content, fileName, row] = match.slice(1);
return {
content,
fileName,
location: {column: -1, row: parseInt(row, 10)},
};
})
.filter(Boolean);
}
+28 -98
View File
@@ -10,26 +10,14 @@
'use strict';
import * as React from 'react';
import Platform from '../Utilities/Platform';
import RCTLog from '../Utilities/RCTLog';
import LogBoxContainer from './UI/LogBoxContainer';
import * as LogBoxData from './Data/LogBoxData';
import {parseLogBoxLog} from './Data/parseLogBoxLog';
import type {LogBoxLogs, Subscription, IgnorePattern} from './Data/LogBoxData';
import type {IgnorePattern} from './Data/LogBoxData';
import LogBoxLog from './Data/LogBoxLog';
type Props = $ReadOnly<{||}>;
type State = {|
logs: LogBoxLogs,
isDisabled: boolean,
hasError: boolean,
selectedLogIndex: number,
|};
let LogBoxComponent;
let LogBox;
/**
* LogBox displays logs in the app.
@@ -48,25 +36,26 @@ if (__DEV__) {
warnImpl(...args);
};
LogBoxComponent = class LogBox extends React.Component<Props, State> {
static getDerivedStateFromError() {
return {hasError: true};
}
componentDidCatch(err, errorInfo) {
LogBoxData.reportLogBoxError(err, errorInfo.componentStack);
}
LogBox = {
// TODO: deprecated, replace with ignoreLogs
static ignoreWarnings(patterns: $ReadOnlyArray<IgnorePattern>): void {
ignoreWarnings: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
LogBox.ignoreLogs(patterns);
}
},
static ignoreLogs(patterns: $ReadOnlyArray<IgnorePattern>): void {
ignoreLogs: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
LogBoxData.addIgnorePatterns(patterns);
}
},
uninstall: (): void => {
errorImpl = error;
warnImpl = warn;
delete (console: any).disableLogBox;
},
install: (): void => {
// Trigger lazy initialization of module.
require('../NativeModules/specs/NativeLogBox');
static install(): void {
errorImpl = function(...args) {
registerError(...args);
};
@@ -92,62 +81,7 @@ if (__DEV__) {
RCTLog.setWarningHandler((...args) => {
registerWarning(...args);
});
}
static uninstall(): void {
errorImpl = error;
warnImpl = warn;
delete (console: any).disableLogBox;
}
_subscription: ?Subscription;
state = {
logs: new Set(),
isDisabled: false,
hasError: false,
selectedLogIndex: -1,
};
render(): React.Node {
if (this.state.hasError) {
// This happens when the component failed to render, in which case we delegate to the native redbox.
// We can't show anyback fallback UI here, because the error may be with <View> or <Text>.
return null;
}
return this.state.logs == null ? null : (
<LogBoxContainer
onDismiss={this._handleDismiss}
onDismissWarns={LogBoxData.clearWarnings}
onDismissErrors={LogBoxData.clearErrors}
logs={this.state.logs}
isDisabled={this.state.isDisabled}
selectedLogIndex={this.state.selectedLogIndex}
setSelectedLog={this._handleSetSelectedLog}
/>
);
}
componentDidMount(): void {
this._subscription = LogBoxData.observe(data => {
this.setState(data);
});
}
componentWillUnmount(): void {
if (this._subscription != null) {
this._subscription.unsubscribe();
}
}
_handleDismiss(log: LogBoxLog): void {
LogBoxData.dismiss(log);
}
_handleSetSelectedLog(index: number): void {
LogBoxData.setSelectedLog(index);
}
},
};
const isRCTLogAdviceWarning = (...args) => {
@@ -227,31 +161,27 @@ if (__DEV__) {
}
};
} else {
LogBoxComponent = class extends React.Component<Props, State> {
LogBox = {
// TODO: deprecated, replace with ignoreLogs
static ignoreWarnings(patterns: $ReadOnlyArray<IgnorePattern>): void {
ignoreWarnings: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
// Do nothing.
}
},
static ignoreLogs(patterns: $ReadOnlyArray<IgnorePattern>): void {
ignoreLogs: (patterns: $ReadOnlyArray<IgnorePattern>): void => {
// Do nothing.
}
},
static install(): void {
install: (): void => {
// Do nothing.
}
},
static uninstall(): void {
uninstall: (): void => {
// Do nothing.
}
render(): React.Node {
return null;
}
},
};
}
module.exports = (LogBoxComponent: Class<React.Component<Props, State>> & {
module.exports = (LogBox: {
// TODO: deprecated, replace with ignoreLogs
ignoreWarnings($ReadOnlyArray<IgnorePattern>): void,
ignoreLogs($ReadOnlyArray<IgnorePattern>): void,
@@ -0,0 +1,68 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import * as React from 'react';
import {View, StyleSheet} from 'react-native';
import * as LogBoxData from './Data/LogBoxData';
import LogBoxInspector from './UI/LogBoxInspector';
import type LogBoxLog from './Data/LogBoxLog';
type Props = $ReadOnly<{|
logs: $ReadOnlyArray<LogBoxLog>,
selectedLogIndex: number,
isDisabled?: ?boolean,
|}>;
export class _LogBoxInspectorContainer extends React.Component<Props> {
render(): React.Node {
return (
<View style={StyleSheet.absoluteFill}>
<LogBoxInspector
onDismiss={this._handleDismiss}
onMinimize={this._handleMinimize}
onChangeSelectedIndex={this._handleSetSelectedLog}
logs={this.props.logs}
selectedIndex={this.props.selectedLogIndex}
/>
</View>
);
}
_handleDismiss = (): void => {
// Here we handle the cases when the log is dismissed and it
// was either the last log, or when the current index
// is now outside the bounds of the log array.
const {selectedLogIndex, logs} = this.props;
const logsArray = Array.from(logs);
if (selectedLogIndex != null) {
if (logsArray.length - 1 <= 0) {
LogBoxData.setSelectedLog(-1);
} else if (selectedLogIndex >= logsArray.length - 1) {
LogBoxData.setSelectedLog(selectedLogIndex - 1);
}
LogBoxData.dismiss(logsArray[selectedLogIndex]);
}
};
_handleMinimize = (): void => {
LogBoxData.setSelectedLog(-1);
};
_handleSetSelectedLog = (index: number): void => {
LogBoxData.setSelectedLog(index);
};
}
export default (LogBoxData.withSubscription(
_LogBoxInspectorContainer,
): React.AbstractComponent<{||}>);
@@ -11,46 +11,31 @@
'use strict';
import * as React from 'react';
import SafeAreaView from '../../Components/SafeAreaView/SafeAreaView';
import StyleSheet from '../../StyleSheet/StyleSheet';
import View from '../../Components/View/View';
import LogBoxInspector from './LogBoxInspector';
import LogBoxLog from '../Data/LogBoxLog';
import LogBoxLogNotification from './LogBoxLogNotification';
import type {LogBoxLogs} from '../Data/LogBoxData';
import StyleSheet from '../StyleSheet/StyleSheet';
import View from '../Components/View/View';
import * as LogBoxData from './Data/LogBoxData';
import LogBoxLog from './Data/LogBoxLog';
import LogBoxLogNotification from './UI/LogBoxNotification';
type Props = $ReadOnly<{|
onDismiss: (log: LogBoxLog) => void,
onDismissWarns: () => void,
onDismissErrors: () => void,
setSelectedLog: number => void,
logs: LogBoxLogs,
logs: $ReadOnlyArray<LogBoxLog>,
selectedLogIndex: number,
isDisabled?: ?boolean,
|}>;
function LogBoxContainer(props: Props): React.Node {
const {selectedLogIndex, setSelectedLog} = props;
export function _LogBoxNotificationContainer(props: Props): React.Node {
const {logs} = props;
const logs = Array.from(props.logs);
const onDismissWarns = () => {
LogBoxData.clearWarnings();
};
const onDismissErrors = () => {
LogBoxData.clearErrors();
};
function handleInspectorDismiss() {
// Here we handle the cases when the log is dismissed and it
// was either the last log, or when the current index
// is now outside the bounds of the log array.
if (selectedLogIndex != null) {
if (logs.length - 1 <= 0) {
setSelectedLog(-1);
} else if (selectedLogIndex >= logs.length - 1) {
setSelectedLog(selectedLogIndex - 1);
}
props.onDismiss(logs[selectedLogIndex]);
}
}
function handleInspectorMinimize() {
setSelectedLog(-1);
}
const setSelectedLog = (index: number): void => {
LogBoxData.setSelectedLog(index);
};
function openLog(log: LogBoxLog) {
let index = logs.length - 1;
@@ -62,20 +47,6 @@ function LogBoxContainer(props: Props): React.Node {
setSelectedLog(index);
}
if (selectedLogIndex > -1) {
return (
<View style={StyleSheet.absoluteFill}>
<LogBoxInspector
onDismiss={handleInspectorDismiss}
onMinimize={handleInspectorMinimize}
onChangeSelectedIndex={setSelectedLog}
logs={logs}
selectedIndex={selectedLogIndex}
/>
</View>
);
}
if (logs.length === 0 || props.isDisabled === true) {
return null;
}
@@ -93,7 +64,7 @@ function LogBoxContainer(props: Props): React.Node {
level="warn"
totalLogCount={warnings.length}
onPressOpen={() => openLog(warnings[warnings.length - 1])}
onPressDismiss={props.onDismissWarns}
onPressDismiss={onDismissWarns}
/>
</View>
)}
@@ -104,7 +75,7 @@ function LogBoxContainer(props: Props): React.Node {
level="error"
totalLogCount={errors.length}
onPressOpen={() => openLog(errors[errors.length - 1])}
onPressDismiss={props.onDismissErrors}
onPressDismiss={onDismissErrors}
/>
</View>
)}
@@ -126,4 +97,6 @@ const styles = StyleSheet.create({
},
});
export default LogBoxContainer;
export default (LogBoxData.withSubscription(
_LogBoxNotificationContainer,
): React.AbstractComponent<{||}>);
+12 -12
View File
@@ -14,7 +14,7 @@ import LogBoxInspectorCodeFrame from './LogBoxInspectorCodeFrame';
import * as React from 'react';
import ScrollView from '../../Components/ScrollView/ScrollView';
import StyleSheet from '../../StyleSheet/StyleSheet';
import Modal from '../../Modal/Modal';
import View from '../../Components/View/View';
import * as LogBoxData from '../Data/LogBoxData';
import Keyboard from '../../Components/Keyboard/Keyboard';
import LogBoxInspectorFooter from './LogBoxInspectorFooter';
@@ -23,8 +23,7 @@ import LogBoxInspectorReactFrames from './LogBoxInspectorReactFrames';
import LogBoxInspectorStackFrames from './LogBoxInspectorStackFrames';
import LogBoxInspectorHeader from './LogBoxInspectorHeader';
import * as LogBoxStyle from './LogBoxStyle';
import type LogBoxLog, {LogLevel} from '../Data/LogBoxLog';
import LogBoxLog, {type LogLevel} from '../Data/LogBoxLog';
type Props = $ReadOnly<{|
onDismiss: () => void,
@@ -37,10 +36,12 @@ type Props = $ReadOnly<{|
function LogBoxInspector(props: Props): React.Node {
const {logs, selectedIndex} = props;
let log = logs[selectedIndex];
const log = logs[selectedIndex];
React.useEffect(() => {
LogBoxData.symbolicateLogNow(log);
if (log) {
LogBoxData.symbolicateLogNow(log);
}
}, [log]);
React.useEffect(() => {
@@ -68,12 +69,7 @@ function LogBoxInspector(props: Props): React.Node {
}
return (
<Modal
animationType="none"
visible
statusBarTranslucent
supportedOrientations={['portrait']}
presentationStyle="overFullScreen">
<View style={styles.root}>
<LogBoxInspectorHeader
onSelectIndex={props.onChangeSelectedIndex}
selectedIndex={selectedIndex}
@@ -86,7 +82,7 @@ function LogBoxInspector(props: Props): React.Node {
onMinimize={props.onMinimize}
level={log.level}
/>
</Modal>
</View>
);
}
@@ -143,6 +139,10 @@ function LogBoxInspectorBody(props) {
}
const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: LogBoxStyle.getTextColor(),
},
scrollBody: {
backgroundColor: LogBoxStyle.getBackgroundColor(0.9),
flex: 1,
+4 -2
View File
@@ -101,9 +101,11 @@ const styles = StyleSheet.create({
syntaxErrorText: {
textAlign: 'center',
width: '100%',
height: 48,
fontSize: 14,
paddingTop: 15,
paddingBottom: 15,
lineHeight: 20,
paddingTop: 20,
paddingBottom: 50,
fontStyle: 'italic',
color: LogBoxStyle.getTextColor(0.6),
},
+2 -2
View File
@@ -126,7 +126,7 @@ const headerStyles = StyleSheet.create({
borderRadius: 3,
},
buttonImage: {
tintColor: LogBoxStyle.getBackgroundColor(1),
tintColor: LogBoxStyle.getTextColor(),
},
});
@@ -156,7 +156,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
},
titleText: {
color: LogBoxStyle.getBackgroundColor(1),
color: LogBoxStyle.getTextColor(),
fontSize: 16,
fontWeight: '600',
includeFontPadding: false,
@@ -18,12 +18,37 @@ import View from '../../Components/View/View';
import LogBoxButton from './LogBoxButton';
import * as LogBoxStyle from './LogBoxStyle';
import LogBoxInspectorSection from './LogBoxInspectorSection';
import openFileInEditor from '../../Core/Devtools/openFileInEditor';
import type LogBoxLog from '../Data/LogBoxLog';
type Props = $ReadOnly<{|
log: LogBoxLog,
|}>;
const BEFORE_SLASH_RE = /^(.*)[\\/]/;
// Taken from React https://github.com/facebook/react/blob/206d61f72214e8ae5b935f0bf8628491cb7f0797/packages/react-devtools-shared/src/backend/describeComponentFrame.js#L27-L41
function getPrettyFileName(path) {
let fileName = path.replace(BEFORE_SLASH_RE, '');
// In DEV, include code for a common special case:
// prefer "folder/index.js" instead of just "index.js".
if (/^index\./.test(fileName)) {
const match = path.match(BEFORE_SLASH_RE);
if (match) {
const pathBeforeSlash = match[1];
if (pathBeforeSlash) {
const folderName = pathBeforeSlash.replace(BEFORE_SLASH_RE, '');
// Note the below string contains a zero width space after the "/" character.
// This is to prevent browsers like Chrome from formatting the file name as a link.
// (Since this is a source link, it would not work to open the source file anyway.)
fileName = folderName + '/' + fileName;
}
}
}
return fileName;
}
function LogBoxInspectorReactFrames(props: Props): React.Node {
const [collapsed, setCollapsed] = React.useState(true);
if (props.log.componentStack == null || props.log.componentStack.length < 1) {
@@ -39,6 +64,10 @@ function LogBoxInspectorReactFrames(props: Props): React.Node {
}
function getCollapseMessage() {
if (props.log.componentStack.length <= 3) {
return;
}
const count = props.log.componentStack.length - 3;
if (collapsed) {
return `See ${count} more components`;
@@ -53,15 +82,34 @@ function LogBoxInspectorReactFrames(props: Props): React.Node {
<View
// Unfortunately we don't have a unique identifier for stack traces.
key={index}
style={componentStyles.frame}>
<View style={componentStyles.component}>
<Text style={componentStyles.frameName}>
<Text style={componentStyles.bracket}>{'<'}</Text>
{frame.component}
<Text style={componentStyles.bracket}>{' />'}</Text>
style={componentStyles.frameContainer}>
<LogBoxButton
backgroundColor={{
default: 'transparent',
pressed: LogBoxStyle.getBackgroundColor(1),
}}
onPress={
// Older versions of DevTools do not provide full path.
// This will not work on Windows, remove check once the
// DevTools return the full file path.
frame.fileName.startsWith('/')
? () =>
openFileInEditor(frame.fileName, frame.location?.row ?? 1)
: null
}
style={componentStyles.frame}>
<View style={componentStyles.component}>
<Text style={componentStyles.frameName}>
<Text style={componentStyles.bracket}>{'<'}</Text>
{frame.content}
<Text style={componentStyles.bracket}>{' />'}</Text>
</Text>
</View>
<Text style={componentStyles.frameLocation}>
{getPrettyFileName(frame.fileName)}
{frame.location ? `:${frame.location.row}` : ''}
</Text>
</View>
<Text style={componentStyles.frameLocation}>{frame.location}</Text>
</LogBoxButton>
</View>
))}
<View style={componentStyles.collapseContainer}>
@@ -96,9 +144,15 @@ const componentStyles = StyleSheet.create({
paddingVertical: 5,
paddingHorizontal: 10,
},
frameContainer: {
flexDirection: 'row',
paddingHorizontal: 15,
},
frame: {
paddingHorizontal: 25,
flex: 1,
paddingVertical: 4,
paddingHorizontal: 10,
borderRadius: 5,
},
component: {
flexDirection: 'row',
@@ -1,254 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @emails oncall+react_native
* @flow strict-local
*/
'use strict';
const React = require('react');
const LogBoxContainer = require('../LogBoxContainer').default;
const LogBoxLog = require('../../Data/LogBoxLog').default;
const render = require('../../../../jest/renderer');
describe('LogBoxContainer', () => {
it('should render null with no logs', () => {
const output = render.shallowRender(
<LogBoxContainer
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={-1}
logs={new Set()}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render null with no selected log and disabled', () => {
const output = render.shallowRender(
<LogBoxContainer
isDisabled
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
])
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render the latest warning notification', () => {
const output = render.shallowRender(
<LogBoxContainer
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
])
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render the latest error notification', () => {
const output = render.shallowRender(
<LogBoxContainer
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
])
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render both an error and warning notification', () => {
const output = render.shallowRender(
<LogBoxContainer
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={-1}
logs={
new Set([
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
])
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render selected fatal error even when disabled', () => {
const output = render.shallowRender(
<LogBoxContainer
isDisabled
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={0}
logs={
new Set([
new LogBoxLog({
level: 'fatal',
isComponentError: false,
message: {
content: 'Should be selected',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
])
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render selected syntax error even when disabled', () => {
const output = render.shallowRender(
<LogBoxContainer
isDisabled
onDismiss={() => {}}
onDismissWarns={() => {}}
onDismissErrors={() => {}}
setSelectedLog={() => {}}
selectedLogIndex={0}
logs={
new Set([
new LogBoxLog({
level: 'syntax',
isComponentError: false,
message: {
content: 'Should be selected',
substitutions: [],
},
stack: [],
category: 'Some kind of syntax error message',
componentStack: [],
codeFrame: {
fileName:
'/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
location: {row: 199, column: 0},
content: ` 197 | });
198 |
> 199 | export default CrashReactApp;
| ^
200 |`,
},
}),
])
}
/>,
);
expect(output).toMatchSnapshot();
});
});
@@ -40,7 +40,7 @@ describe('LogBoxInspectorReactFrames', () => {
expect(output).toMatchSnapshot();
});
it('should render componentStack frames', () => {
it('should render componentStack frames without full path pressable', () => {
const output = render.shallowRender(
<LogBoxInspectorReactFrames
log={
@@ -55,8 +55,129 @@ describe('LogBoxInspectorReactFrames', () => {
category: 'Some kind of message',
componentStack: [
{
component: 'MyComponent',
location: 'MyComponentFile.js:1',
content: 'MyComponent',
fileName: 'MyComponentFile.js',
location: {
row: 1,
column: -1,
},
},
],
})
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render componentStack frames with full path pressable', () => {
const output = render.shallowRender(
<LogBoxInspectorReactFrames
log={
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [
{
content: 'MyComponent',
fileName: '/path/to/MyComponentFile.js',
location: {
row: 1,
column: -1,
},
},
],
})
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render componentStack frames with parent folder of index.js', () => {
const output = render.shallowRender(
<LogBoxInspectorReactFrames
log={
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [
{
content: 'MyComponent',
fileName: '/path/to/index.js',
location: {
row: 1,
column: -1,
},
},
],
})
}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render componentStack frames with more than 3 stacks', () => {
const output = render.shallowRender(
<LogBoxInspectorReactFrames
log={
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [
{
content: 'MyComponent',
fileName: '/path/to/index.js',
location: {
row: 1,
column: -1,
},
},
{
content: 'MyComponent2',
fileName: '/path/to/index2.js',
location: {
row: 1,
column: -1,
},
},
{
content: 'MyComponent3',
fileName: '/path/to/index3.js',
location: {
row: 1,
column: -1,
},
},
{
content: 'MyComponent4',
fileName: '/path/to/index4.js',
location: {
row: 1,
column: -1,
},
},
],
})
@@ -12,7 +12,7 @@
'use strict';
const React = require('react');
const LogBoxLogNotification = require('../LogBoxLogNotification').default;
const LogBoxNotification = require('../LogBoxNotification').default;
const LogBoxLog = require('../../Data/LogBoxLog').default;
const render = require('../../../../jest/renderer');
@@ -28,10 +28,10 @@ const log = new LogBoxLog({
componentStack: [],
});
describe('LogBoxLogNotification', () => {
describe('LogBoxNotification', () => {
it('should render log', () => {
const output = render.shallowRender(
<LogBoxLogNotification
<LogBoxNotification
log={log}
totalLogCount={1}
level="warn"
@@ -1,17 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = `
<Component
animationType="none"
hardwareAccelerated={false}
presentationStyle="overFullScreen"
statusBarTranslucent={true}
supportedOrientations={
Array [
"portrait",
]
<View
style={
Object {
"backgroundColor": "rgba(255, 255, 255, 1)",
"flex": 1,
}
}
visible={true}
>
<LogBoxInspectorHeader
level="fatal"
@@ -47,23 +43,19 @@ exports[`LogBoxContainer should render fatal with selectedIndex 2 1`] = `
onDismiss={[Function]}
onMinimize={[Function]}
/>
</Component>
</View>
`;
exports[`LogBoxContainer should render null with no logs 1`] = `null`;
exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
<Component
animationType="none"
hardwareAccelerated={false}
presentationStyle="overFullScreen"
statusBarTranslucent={true}
supportedOrientations={
Array [
"portrait",
]
<View
style={
Object {
"backgroundColor": "rgba(255, 255, 255, 1)",
"flex": 1,
}
}
visible={true}
>
<LogBoxInspectorHeader
level="warn"
@@ -99,5 +91,5 @@ exports[`LogBoxContainer should render warning with selectedIndex 0 1`] = `
onDismiss={[Function]}
onMinimize={[Function]}
/>
</Component>
</View>
`;
@@ -29,8 +29,10 @@ exports[`LogBoxInspectorFooter should render no buttons and a message for syntax
"color": "rgba(255, 255, 255, 0.6)",
"fontSize": 14,
"fontStyle": "italic",
"paddingBottom": 15,
"paddingTop": 15,
"height": 48,
"lineHeight": 20,
"paddingBottom": 50,
"paddingTop": 20,
"textAlign": "center",
"width": "100%",
}
@@ -39,7 +39,7 @@ exports[`LogBoxInspectorHeader should render both buttons for two total 1`] = `
<Text
style={
Object {
"color": "rgba(51, 51, 51, 1)",
"color": "rgba(255, 255, 255, 1)",
"fontSize": 16,
"fontWeight": "600",
"includeFontPadding": false,
@@ -99,7 +99,7 @@ exports[`LogBoxInspectorHeader should render no buttons for one total 1`] = `
<Text
style={
Object {
"color": "rgba(51, 51, 51, 1)",
"color": "rgba(255, 255, 255, 1)",
"fontSize": 16,
"fontWeight": "600",
"includeFontPadding": false,
@@ -153,7 +153,7 @@ exports[`LogBoxInspectorHeader should render syntax error header 1`] = `
<Text
style={
Object {
"color": "rgba(51, 51, 51, 1)",
"color": "rgba(255, 255, 255, 1)",
"fontSize": 16,
"fontWeight": "600",
"includeFontPadding": false,
@@ -207,7 +207,7 @@ exports[`LogBoxInspectorHeader should render two buttons for three or more total
<Text
style={
Object {
"color": "rgba(51, 51, 51, 1)",
"color": "rgba(255, 255, 255, 1)",
"fontSize": 16,
"fontWeight": "600",
"includeFontPadding": false,
@@ -1,81 +1,420 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LogBoxInspectorReactFrames should render componentStack frames 1`] = `
exports[`LogBoxInspectorReactFrames should render componentStack frames with full path pressable 1`] = `
<LogBoxInspectorSection
heading="Component Stack"
>
<View
style={
Object {
"paddingHorizontal": 25,
"paddingVertical": 4,
"flexDirection": "row",
"paddingHorizontal": 15,
}
}
>
<View
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"flexDirection": "row",
"paddingRight": 10,
"borderRadius": 5,
"flex": 1,
"paddingHorizontal": 10,
"paddingVertical": 4,
}
}
>
<Text
<View
style={
Object {
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"includeFontPadding": false,
"lineHeight": 18,
"flexDirection": "row",
"paddingRight": 10,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
&lt;
</Text>
MyComponent
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
}
>
/&gt;
>
&lt;
</Text>
MyComponent
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
/&gt;
</Text>
</Text>
</View>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
}
}
>
MyComponentFile.js
:1
</Text>
</View>
<Text
</LogBoxButton>
</View>
<View
style={
Object {
"flexDirection": "row",
"marginLeft": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
"borderRadius": 5,
}
}
>
MyComponentFile.js:1
</Text>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 20,
"marginTop": 0,
"paddingHorizontal": 10,
"paddingVertical": 5,
}
}
/>
</LogBoxButton>
</View>
</LogBoxInspectorSection>
`;
exports[`LogBoxInspectorReactFrames should render componentStack frames with more than 3 stacks 1`] = `
<LogBoxInspectorSection
heading="Component Stack"
>
<View
style={
Object {
"flexDirection": "row",
"paddingHorizontal": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"borderRadius": 5,
"flex": 1,
"paddingHorizontal": 10,
"paddingVertical": 4,
}
}
>
<View
style={
Object {
"flexDirection": "row",
"paddingRight": 10,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
&lt;
</Text>
MyComponent
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
/&gt;
</Text>
</Text>
</View>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
}
}
>
to/index.js
:1
</Text>
</LogBoxButton>
</View>
<View
style={
Object {
"flexDirection": "row",
"paddingHorizontal": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"borderRadius": 5,
"flex": 1,
"paddingHorizontal": 10,
"paddingVertical": 4,
}
}
>
<View
style={
Object {
"flexDirection": "row",
"paddingRight": 10,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
&lt;
</Text>
MyComponent2
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
/&gt;
</Text>
</Text>
</View>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
}
}
>
index2.js
:1
</Text>
</LogBoxButton>
</View>
<View
style={
Object {
"flexDirection": "row",
"paddingHorizontal": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"borderRadius": 5,
"flex": 1,
"paddingHorizontal": 10,
"paddingVertical": 4,
}
}
>
<View
style={
Object {
"flexDirection": "row",
"paddingRight": 10,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
&lt;
</Text>
MyComponent3
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
/&gt;
</Text>
</Text>
</View>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
}
}
>
index3.js
:1
</Text>
</LogBoxButton>
</View>
<View
style={
@@ -112,11 +451,283 @@ exports[`LogBoxInspectorReactFrames should render componentStack frames 1`] = `
}
}
>
See -2 more components
See 1 more components
</Text>
</LogBoxButton>
</View>
</LogBoxInspectorSection>
`;
exports[`LogBoxInspectorReactFrames should render componentStack frames with parent folder of index.js 1`] = `
<LogBoxInspectorSection
heading="Component Stack"
>
<View
style={
Object {
"flexDirection": "row",
"paddingHorizontal": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"borderRadius": 5,
"flex": 1,
"paddingHorizontal": 10,
"paddingVertical": 4,
}
}
>
<View
style={
Object {
"flexDirection": "row",
"paddingRight": 10,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
&lt;
</Text>
MyComponent
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
/&gt;
</Text>
</Text>
</View>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
}
}
>
to/index.js
:1
</Text>
</LogBoxButton>
</View>
<View
style={
Object {
"flexDirection": "row",
"marginLeft": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"borderRadius": 5,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 20,
"marginTop": 0,
"paddingHorizontal": 10,
"paddingVertical": 5,
}
}
/>
</LogBoxButton>
</View>
</LogBoxInspectorSection>
`;
exports[`LogBoxInspectorReactFrames should render componentStack frames without full path pressable 1`] = `
<LogBoxInspectorSection
heading="Component Stack"
>
<View
style={
Object {
"flexDirection": "row",
"paddingHorizontal": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={null}
style={
Object {
"borderRadius": 5,
"flex": 1,
"paddingHorizontal": 10,
"paddingVertical": 4,
}
}
>
<View
style={
Object {
"flexDirection": "row",
"paddingRight": 10,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 1)",
"fontFamily": "Menlo",
"fontSize": 14,
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
&lt;
</Text>
MyComponent
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.4)",
"fontFamily": "Menlo",
"fontSize": 14,
"fontWeight": "500",
"includeFontPadding": false,
"lineHeight": 18,
}
}
>
/&gt;
</Text>
</Text>
</View>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"includeFontPadding": false,
"lineHeight": 16,
"paddingLeft": 10,
}
}
>
MyComponentFile.js
:1
</Text>
</LogBoxButton>
</View>
<View
style={
Object {
"flexDirection": "row",
"marginLeft": 15,
}
}
>
<LogBoxButton
backgroundColor={
Object {
"default": "transparent",
"pressed": "rgba(51, 51, 51, 1)",
}
}
onPress={[Function]}
style={
Object {
"borderRadius": 5,
}
}
>
<Text
style={
Object {
"color": "rgba(255, 255, 255, 0.7)",
"fontSize": 12,
"fontWeight": "300",
"lineHeight": 20,
"marginTop": 0,
"paddingHorizontal": 10,
"paddingVertical": 5,
}
}
/>
</LogBoxButton>
</View>
</LogBoxInspectorSection>
`;
exports[`LogBoxInspectorReactFrames should render null for no componentStack frames 1`] = `null`;
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LogBoxLogNotification should render log 1`] = `
exports[`LogBoxNotification should render log 1`] = `
<View
style={
Object {
@@ -0,0 +1,212 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @emails oncall+react_native
* @flow
*/
'use strict';
const React = require('react');
const {
_LogBoxNotificationContainer: LogBoxNotificationContainer,
} = require('../LogBoxNotificationContainer');
const LogBoxLog = require('../Data/LogBoxLog').default;
const render = require('../../../jest/renderer');
describe('LogBoxNotificationContainer', () => {
it('should render null with no logs', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer selectedLogIndex={-1} logs={[]} />,
);
expect(output).toMatchSnapshot();
});
it('should render null with no selected log and disabled', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer
isDisabled
selectedLogIndex={-1}
logs={[
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render the latest warning notification', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer
selectedLogIndex={-1}
logs={[
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render the latest error notification', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer
selectedLogIndex={-1}
logs={[
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render both an error and warning notification', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer
selectedLogIndex={-1}
logs={[
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render selected fatal error even when disabled', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer
isDisabled
selectedLogIndex={0}
logs={[
new LogBoxLog({
level: 'fatal',
isComponentError: false,
message: {
content: 'Should be selected',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
it('should render selected syntax error even when disabled', () => {
const output = render.shallowRender(
<LogBoxNotificationContainer
isDisabled
selectedLogIndex={0}
logs={[
new LogBoxLog({
level: 'syntax',
isComponentError: false,
message: {
content: 'Should be selected',
substitutions: [],
},
stack: [],
category: 'Some kind of syntax error message',
componentStack: [],
codeFrame: {
fileName: '/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js',
location: {row: 199, column: 0},
content: ` 197 | });
198 |
> 199 | export default CrashReactApp;
| ^
200 |`,
},
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
});
@@ -0,0 +1,56 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @emails oncall+react_native
* @flow strict-local
*/
'use strict';
const React = require('react');
const {
_LogBoxInspectorContainer: LogBoxInspectorContainer,
} = require('../LogBoxInspectorContainer');
const LogBoxLog = require('../Data/LogBoxLog').default;
const render = require('../../../jest/renderer');
describe('LogBoxNotificationContainer', () => {
it('should render inspector with logs, even when disabled', () => {
const output = render.shallowRender(
<LogBoxInspectorContainer
isDisabled
selectedLogIndex={-1}
logs={[
new LogBoxLog({
level: 'warn',
isComponentError: false,
message: {
content: 'Some kind of message',
substitutions: [],
},
stack: [],
category: 'Some kind of message',
componentStack: [],
}),
new LogBoxLog({
level: 'error',
isComponentError: false,
message: {
content: 'Some kind of message (latest)',
substitutions: [],
},
stack: [],
category: 'Some kind of message (latest)',
componentStack: [],
}),
]}
/>,
);
expect(output).toMatchSnapshot();
});
});
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LogBoxContainer should render both an error and warning notification 1`] = `
exports[`LogBoxNotificationContainer should render both an error and warning notification 1`] = `
<View
style={
Object {
@@ -86,108 +86,15 @@ exports[`LogBoxContainer should render both an error and warning notification 1`
</View>
`;
exports[`LogBoxContainer should render null with no logs 1`] = `null`;
exports[`LogBoxNotificationContainer should render null with no logs 1`] = `null`;
exports[`LogBoxContainer should render null with no selected log and disabled 1`] = `null`;
exports[`LogBoxNotificationContainer should render null with no selected log and disabled 1`] = `null`;
exports[`LogBoxContainer should render selected fatal error even when disabled 1`] = `
<View
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<LogBoxInspector
logs={
Array [
LogBoxLog {
"category": "Some kind of message",
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "fatal",
"message": Object {
"content": "Should be selected",
"substitutions": Array [],
},
"stack": Array [],
"symbolicated": Object {
"error": null,
"stack": null,
"status": "NONE",
},
},
]
}
onChangeSelectedIndex={[Function]}
onDismiss={[Function]}
onMinimize={[Function]}
selectedIndex={0}
/>
</View>
`;
exports[`LogBoxNotificationContainer should render selected fatal error even when disabled 1`] = `null`;
exports[`LogBoxContainer should render selected syntax error even when disabled 1`] = `
<View
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<LogBoxInspector
logs={
Array [
LogBoxLog {
"category": "Some kind of syntax error message",
"codeFrame": Object {
"content": " 197 | });
198 |
> 199 | export default CrashReactApp;
| ^
200 |",
"fileName": "/path/to/RKJSModules/Apps/CrashReact/CrashReactApp.js",
"location": Object {
"column": 0,
"row": 199,
},
},
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "syntax",
"message": Object {
"content": "Should be selected",
"substitutions": Array [],
},
"stack": Array [],
"symbolicated": Object {
"error": null,
"stack": null,
"status": "NONE",
},
},
]
}
onChangeSelectedIndex={[Function]}
onDismiss={[Function]}
onMinimize={[Function]}
selectedIndex={0}
/>
</View>
`;
exports[`LogBoxNotificationContainer should render selected syntax error even when disabled 1`] = `null`;
exports[`LogBoxContainer should render the latest error notification 1`] = `
exports[`LogBoxNotificationContainer should render the latest error notification 1`] = `
<View
style={
Object {
@@ -237,7 +144,7 @@ exports[`LogBoxContainer should render the latest error notification 1`] = `
</View>
`;
exports[`LogBoxContainer should render the latest warning notification 1`] = `
exports[`LogBoxNotificationContainer should render the latest warning notification 1`] = `
<View
style={
Object {
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LogBoxNotificationContainer should render inspector with logs, even when disabled 1`] = `
<View
style={
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
}
}
>
<LogBoxInspector
logs={
Array [
LogBoxLog {
"category": "Some kind of message",
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "warn",
"message": Object {
"content": "Some kind of message",
"substitutions": Array [],
},
"stack": Array [],
"symbolicated": Object {
"error": null,
"stack": null,
"status": "NONE",
},
},
LogBoxLog {
"category": "Some kind of message (latest)",
"codeFrame": undefined,
"componentStack": Array [],
"count": 1,
"isComponentError": false,
"level": "error",
"message": Object {
"content": "Some kind of message (latest)",
"substitutions": Array [],
},
"stack": Array [],
"symbolicated": Object {
"error": null,
"stack": null,
"status": "NONE",
},
},
]
}
onChangeSelectedIndex={[Function]}
onDismiss={[Function]}
onMinimize={[Function]}
selectedIndex={-1}
/>
</View>
`;
+3 -2
View File
@@ -95,7 +95,8 @@ export type Props = $ReadOnly<{|
/**
* The `onRequestClose` callback is called when the user taps the hardware
* back button on Android or the menu button on Apple TV.
* back button on Android, the menu button on Apple TV, or a modal is dismissed
* with a gesture on iOS 13+.
*
* This is required on Apple TV and Android.
*
@@ -229,7 +230,7 @@ class Modal extends React.Component<Props> {
}
const innerChildren = __DEV__ ? (
<AppContainer rootTag={this.context.rootTag} internal_excludeLogBox>
<AppContainer rootTag={this.context.rootTag}>
{this.props.children}
</AppContainer>
) : (
@@ -70,7 +70,8 @@ type NativeProps = $ReadOnly<{|
/**
* The `onRequestClose` callback is called when the user taps the hardware
* back button on Android or the menu button on Apple TV.
* back button on Android, the menu button on Apple TV, or a modal is dismissed
* with a gesture on iOS 13+.
*
* This is required on Apple TV and Android.
*
@@ -0,0 +1,21 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from 'react-native/Libraries/TurboModule/RCTExport';
import * as TurboModuleRegistry from 'react-native/Libraries/TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+show: () => void;
+hide: () => void;
}
export default (TurboModuleRegistry.get<Spec>('LogBox'): ?Spec);
@@ -26,7 +26,7 @@ static NSString *const kRemoteNotificationRegistrationFailed = @"RemoteNotificat
static NSString *const kErrorUnableToRequestPermissions = @"E_UNABLE_TO_REQUEST_PERMISSIONS";
#if !TARGET_OS_TV && !TARGET_OS_UIKITFORMAC
#if !TARGET_OS_TV
@implementation RCTConvert (NSCalendarUnit)
RCT_ENUM_CONVERTER(NSCalendarUnit,
+11 -27
View File
@@ -94,16 +94,14 @@ class AppContainer extends React.Component<Props, State> {
}
render(): React.Node {
let logBox = null;
if (__DEV__ && !this.props.internal_excludeLogBox) {
if (!global.__RCTProfileIsProfiling) {
if (global.__reactExperimentalLogBox) {
const LogBox = require('../LogBox/LogBox');
logBox = <LogBox />;
} else {
const YellowBox = require('../YellowBox/YellowBox');
logBox = <YellowBox />;
}
let yellowBox = null;
if (__DEV__) {
if (
!global.__RCTProfileIsProfiling &&
!this.props.internal_excludeLogBox
) {
const YellowBox = require('../YellowBox/YellowBox');
yellowBox = <YellowBox />;
}
}
@@ -137,7 +135,7 @@ class AppContainer extends React.Component<Props, State> {
<View style={styles.appContainer} pointerEvents="box-none">
{!this.state.hasError && innerView}
{this.state.inspector}
{logBox}
{yellowBox}
</View>
</RootTagContext.Provider>
);
@@ -152,22 +150,8 @@ const styles = StyleSheet.create({
if (__DEV__) {
if (!global.__RCTProfileIsProfiling) {
if (global.__reactExperimentalLogBox) {
const LogBox = require('../LogBox/LogBox');
LogBox.install();
// TODO: (rickhanlonii) T57484314 Temporary hack to fix LogBox experiment but we need to
// either decide to provide an error boundary by default or move this to a separate root.
AppContainer.getDerivedStateFromError = function getDerivedStateFromError(
error,
state,
) {
return {...state, hasError: true};
};
} else {
const YellowBox = require('../YellowBox/YellowBox');
YellowBox.install();
}
const YellowBox = require('../YellowBox/YellowBox');
YellowBox.install();
}
}
+23 -7
View File
@@ -125,6 +125,7 @@ const AppRegistry = {
appParameters.fabric,
showArchitectureIndicator,
scopedPerformanceLogger,
appKey === 'LogBox',
);
},
};
@@ -180,13 +181,15 @@ const AppRegistry = {
* See http://facebook.github.io/react-native/docs/appregistry.html#runapplication
*/
runApplication(appKey: string, appParameters: any): void {
const msg =
'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
infoLog(msg);
BugReporting.addSource(
'AppRegistry.runApplication' + runCount++,
() => msg,
);
if (appKey !== 'LogBox') {
const msg =
'Running "' + appKey + '" with ' + JSON.stringify(appParameters);
infoLog(msg);
BugReporting.addSource(
'AppRegistry.runApplication' + runCount++,
() => msg,
);
}
invariant(
runnables[appKey] && runnables[appKey].run,
`"${appKey}" has not been registered. This can happen if:\n` +
@@ -292,4 +295,17 @@ const AppRegistry = {
BatchedBridge.registerCallableModule('AppRegistry', AppRegistry);
if (__DEV__) {
const LogBoxInspector = require('../LogBox/LogBoxInspectorContainer').default;
AppRegistry.registerComponent('LogBox', () => LogBoxInspector);
} else {
AppRegistry.registerComponent(
'LogBox',
() =>
function NoOp() {
return null;
},
);
}
module.exports = AppRegistry;
+3 -1
View File
@@ -29,6 +29,7 @@ function renderApplication<Props: Object>(
fabric?: boolean,
showArchitectureIndicator?: boolean,
scopedPerformanceLogger?: IPerformanceLogger,
isLogBox?: boolean,
) {
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
@@ -39,7 +40,8 @@ function renderApplication<Props: Object>(
rootTag={rootTag}
fabric={fabric}
showArchitectureIndicator={showArchitectureIndicator}
WrapperComponent={WrapperComponent}>
WrapperComponent={WrapperComponent}
internal_excludeLogBox={isLogBox}>
<RootComponent {...initialProps} rootTag={rootTag} />
</AppContainer>
</PerformanceLoggerContext.Provider>
+6 -11
View File
@@ -14,12 +14,9 @@
// limitations under the License.
//
#if !TARGET_OS_UIKITFORMAC
#import <React/RCTSRWebSocket.h>
#import <Availability.h>
#import <Endian.h>
#import <Security/SecRandom.h>
@@ -580,7 +577,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize];
NSData *payload = mutablePayload;
((uint16_t *)mutablePayload.mutableBytes)[0] = EndianU16_BtoN(code);
((uint16_t *)mutablePayload.mutableBytes)[0] = NSSwapBigShortToHost(code);
if (reason) {
NSRange remainingRange = {0};
@@ -749,7 +746,7 @@ static inline BOOL closeCodeIsValid(int closeCode)
return;
} else if (dataSize >= 2) {
[data getBytes:&closeCode length:sizeof(closeCode)];
_closeCode = EndianU16_BtoN(closeCode);
_closeCode = NSSwapBigShortToHost(closeCode);
if (!closeCodeIsValid(_closeCode)) {
[self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]];
return;
@@ -972,12 +969,12 @@ static const uint8_t RCTSRPayloadLenMask = 0x7F;
if (header.payload_length == 126) {
assert(mapped_size >= sizeof(uint16_t));
uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer));
uint16_t newLen = NSSwapBigShortToHost(*(uint16_t *)(mapped_buffer));
header.payload_length = newLen;
offset += sizeof(uint16_t);
} else if (header.payload_length == 127) {
assert(mapped_size >= sizeof(uint64_t));
header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer));
header.payload_length = NSSwapBigLongLongToHost(*(uint64_t *)(mapped_buffer));
offset += sizeof(uint64_t);
} else {
assert(header.payload_length < 126 && header.payload_length >= 0);
@@ -1264,11 +1261,11 @@ static const size_t RCTSRFrameHeaderOverhead = 32;
frame_buffer[1] |= payloadLength;
} else if (payloadLength <= UINT16_MAX) {
frame_buffer[1] |= 126;
*((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength);
*((uint16_t *)(frame_buffer + frame_buffer_size)) = NSSwapBigShortToHost((uint16_t)payloadLength);
frame_buffer_size += sizeof(uint16_t);
} else {
frame_buffer[1] |= 127;
*((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength);
*((uint64_t *)(frame_buffer + frame_buffer_size)) = NSSwapBigLongLongToHost((uint64_t)payloadLength);
frame_buffer_size += sizeof(uint64_t);
}
@@ -1637,5 +1634,3 @@ static NSRunLoop *networkRunLoop = nil;
}
@end
#endif
+26 -28
View File
@@ -12,8 +12,8 @@
const YellowBoxWarning = require('./YellowBoxWarning');
import type {Category} from './YellowBoxCategory';
import type {Category, Message} from './YellowBoxCategory';
import type {Stack} from './YellowBoxSymbolication';
export type Registry = Map<Category, $ReadOnlyArray<YellowBoxWarning>>;
export type Observer = (registry: Registry) => void;
@@ -32,25 +32,13 @@ let disabled = false;
let projection = new Map();
let updateTimeout = null;
function isWarningIgnored(warning: YellowBoxWarning): boolean {
for (const pattern of ignorePatterns) {
if (pattern instanceof RegExp && pattern.test(warning.message.content)) {
return true;
} else if (
typeof pattern === 'string' &&
warning.message.content.includes(pattern)
) {
return true;
}
}
return false;
}
function handleUpdate(): void {
projection = new Map();
if (!disabled) {
for (const [category, warnings] of registry) {
const filtered = warnings.filter(warning => !isWarningIgnored(warning));
const filtered = warnings.filter(
warning => !YellowBoxRegistry.isWarningIgnored(warning.message),
);
if (filtered.length > 0) {
projection.set(category, filtered);
}
@@ -67,18 +55,28 @@ function handleUpdate(): void {
}
const YellowBoxRegistry = {
add({
args,
}: $ReadOnly<{|
args: $ReadOnlyArray<mixed>,
|}>): void {
if (typeof args[0] === 'string' && args[0].startsWith('(ADVICE)')) {
return;
isWarningIgnored(message: Message): boolean {
for (const pattern of ignorePatterns) {
if (pattern instanceof RegExp && pattern.test(message.content)) {
return true;
} else if (
typeof pattern === 'string' &&
message.content.includes(pattern)
) {
return true;
}
}
const {category, message, stack} = YellowBoxWarning.parse({
args,
});
return false;
},
add({
category,
message,
stack,
}: $ReadOnly<{|
category: Category,
message: Message,
stack: Stack,
|}>): void {
let warnings = registry.get(category);
if (warnings == null) {
warnings = [];
@@ -11,6 +11,7 @@
'use strict';
const YellowBoxWarning = require('../YellowBoxWarning');
const YellowBoxCategory = require('../YellowBoxCategory');
const YellowBoxRegistry = require('../YellowBoxRegistry');
@@ -34,7 +35,7 @@ describe('YellowBoxRegistry', () => {
});
it('adds and deletes warnings', () => {
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
const {category: categoryA} = YellowBoxCategory.parse(['A']);
expect(registry().size).toBe(1);
@@ -46,9 +47,9 @@ describe('YellowBoxRegistry', () => {
});
it('clears all warnings', () => {
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add({args: ['B']});
YellowBoxRegistry.add({args: ['C']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C']}));
expect(registry().size).toBe(3);
@@ -57,9 +58,9 @@ describe('YellowBoxRegistry', () => {
});
it('sorts warnings in chronological order', () => {
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add({args: ['B']});
YellowBoxRegistry.add({args: ['C']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C']}));
const {category: categoryA} = YellowBoxCategory.parse(['A']);
const {category: categoryB} = YellowBoxCategory.parse(['B']);
@@ -71,7 +72,7 @@ describe('YellowBoxRegistry', () => {
categoryC,
]);
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
// Expect `A` to be hoisted to the end of the registry.
expect(Array.from(registry().keys())).toEqual([
@@ -82,9 +83,9 @@ describe('YellowBoxRegistry', () => {
});
it('ignores warnings matching patterns', () => {
YellowBoxRegistry.add({args: ['A!']});
YellowBoxRegistry.add({args: ['B?']});
YellowBoxRegistry.add({args: ['C!']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A!']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B?']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C!']}));
expect(registry().size).toBe(3);
YellowBoxRegistry.addIgnorePatterns(['!']);
@@ -95,9 +96,9 @@ describe('YellowBoxRegistry', () => {
});
it('ignores warnings matching regexs or pattern', () => {
YellowBoxRegistry.add({args: ['There are 4 dogs']});
YellowBoxRegistry.add({args: ['There are 3 cats']});
YellowBoxRegistry.add({args: ['There are H cats']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['There are 4 dogs']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['There are 3 cats']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['There are H cats']}));
expect(registry().size).toBe(3);
YellowBoxRegistry.addIgnorePatterns(['dogs']);
@@ -111,9 +112,9 @@ describe('YellowBoxRegistry', () => {
});
it('ignores all warnings when disabled', () => {
YellowBoxRegistry.add({args: ['A!']});
YellowBoxRegistry.add({args: ['B?']});
YellowBoxRegistry.add({args: ['C!']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A!']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B?']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['C!']}));
expect(registry().size).toBe(3);
YellowBoxRegistry.setDisabled(true);
@@ -124,57 +125,54 @@ describe('YellowBoxRegistry', () => {
});
it('groups warnings by simple categories', () => {
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
expect(registry().size).toBe(2);
});
it('groups warnings by format string categories', () => {
YellowBoxRegistry.add({args: ['%s', 'A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'A']}));
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['%s', 'B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'B']}));
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
expect(registry().size).toBe(2);
YellowBoxRegistry.add({args: ['B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
expect(registry().size).toBe(3);
});
it('groups warnings with consideration for arguments', () => {
YellowBoxRegistry.add({args: ['A', 'B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A', 'B']}));
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A', 'B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A', 'B']}));
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A', 'C']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A', 'C']}));
expect(registry().size).toBe(2);
YellowBoxRegistry.add({args: ['%s', 'A', 'A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'A', 'A']}));
expect(registry().size).toBe(3);
YellowBoxRegistry.add({args: ['%s', 'B', 'A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'B', 'A']}));
expect(registry().size).toBe(3);
YellowBoxRegistry.add({args: ['%s', 'B', 'B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['%s', 'B', 'B']}));
expect(registry().size).toBe(4);
});
it('ignores warnings starting with "(ADVICE)"', () => {
YellowBoxRegistry.add({args: ['(ADVICE) ...']});
expect(registry().size).toBe(0);
});
it('does not ignore warnings formatted to start with "(ADVICE)"', () => {
YellowBoxRegistry.add({args: ['%s ...', '(ADVICE)']});
YellowBoxRegistry.add(
YellowBoxWarning.parse({args: ['%s ...', '(ADVICE)']}),
);
expect(registry().size).toBe(1);
});
@@ -189,8 +187,8 @@ describe('YellowBoxRegistry', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add({args: ['B']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['B']}));
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
});
@@ -207,7 +205,7 @@ describe('YellowBoxRegistry', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
@@ -226,7 +224,7 @@ describe('YellowBoxRegistry', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.add({args: ['A']});
YellowBoxRegistry.add(YellowBoxWarning.parse({args: ['A']}));
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
+102 -44
View File
@@ -12,13 +12,12 @@
const React = require('react');
import type {Category} from './Data/YellowBoxCategory';
import type {
Registry,
Subscription,
IgnorePattern,
} from './Data/YellowBoxRegistry';
import type {Registry, IgnorePattern} from './Data/YellowBoxRegistry';
import YellowBoxWarning from './Data/YellowBoxWarning';
import * as LogBoxData from '../LogBox/Data/LogBoxData';
import NativeLogBox from '../NativeModules/specs/NativeLogBox';
type Props = $ReadOnly<{||}>;
type State = {|
registry: ?Registry,
@@ -47,14 +46,19 @@ let YellowBox;
if (__DEV__) {
const Platform = require('../Utilities/Platform');
const RCTLog = require('../Utilities/RCTLog');
const YellowBoxList = require('./UI/YellowBoxList');
const YellowBoxContainer = require('./YellowBoxContainer').default;
const LogBox = require('../LogBox/LogBox');
const YellowBoxRegistry = require('./Data/YellowBoxRegistry');
const LogBoxNotificationContainer = require('../LogBox/LogBoxNotificationContainer')
.default;
// YellowBox needs to insert itself early,
// in order to access the component stacks appended by React DevTools.
const {error, warn} = console;
let errorImpl = error;
let warnImpl = warn;
let _isLogBoxEnabled = false;
let _isInstalled = false;
(console: any).error = function(...args) {
errorImpl(...args);
};
@@ -70,16 +74,17 @@ if (__DEV__) {
}
static install(): void {
if (_isLogBoxEnabled) {
LogBox.install();
return;
}
_isInstalled = true;
errorImpl = function(...args) {
error.call(console, ...args);
// Show YellowBox for the `warning` module.
if (typeof args[0] === 'string' && args[0].startsWith('Warning: ')) {
registerWarning(...args);
}
registerError(...args);
};
warnImpl = function(...args) {
warn.call(console, ...args);
registerWarning(...args);
};
@@ -102,51 +107,95 @@ if (__DEV__) {
}
static uninstall(): void {
if (_isLogBoxEnabled) {
LogBox.uninstall();
return;
}
_isInstalled = false;
errorImpl = error;
warnImpl = warn;
delete (console: any).disableYellowBox;
}
_subscription: ?Subscription;
static __unstable_enableLogBox(): void {
if (NativeLogBox == null) {
// The native module is required to enable LogBox.
return;
}
state = {
registry: null,
};
if (_isInstalled) {
throw new Error(
'LogBox must be enabled before AppContainer is required so that it can properly wrap the console methods.\n\nPlease enable LogBox earlier in your app.\n\n',
);
}
_isLogBoxEnabled = true;
// TODO: Temporary hack to prevent cycles with the ExceptionManager.
global.__unstable_isLogBoxEnabled = true;
}
static __unstable_isLogBoxEnabled(): boolean {
return !!_isLogBoxEnabled;
}
render(): React.Node {
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
return this.state.registry == null ? null : (
<YellowBoxList
onDismiss={this._handleDismiss}
onDismissAll={this._handleDismissAll}
registry={this.state.registry}
/>
);
}
componentDidMount(): void {
this._subscription = YellowBoxRegistry.observe(registry => {
this.setState({registry});
});
}
componentWillUnmount(): void {
if (this._subscription != null) {
this._subscription.unsubscribe();
if (_isLogBoxEnabled) {
return <LogBoxNotificationContainer />;
}
}
_handleDismiss = (category: Category): void => {
YellowBoxRegistry.delete(category);
};
_handleDismissAll(): void {
YellowBoxRegistry.clear();
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
return <YellowBoxContainer />;
}
};
const registerWarning = (...args): void => {
YellowBoxRegistry.add({args});
if (typeof args[0] === 'string' && args[0].startsWith('(ADVICE)')) {
return;
}
const {category, message, stack} = YellowBoxWarning.parse({
args,
});
if (!YellowBoxRegistry.isWarningIgnored(message)) {
YellowBoxRegistry.add({category, message, stack});
warn.call(console, ...args);
}
};
const registerError = (...args): void => {
// Only show YellowBox for the `warning` module, otherwise pass through and skip.
if (typeof args[0] !== 'string' || !args[0].startsWith('Warning: ')) {
error.call(console, ...args);
return;
}
const format = args[0].replace('Warning: ', '');
const filterResult = LogBoxData.checkWarningFilter(format);
if (filterResult.suppressCompletely) {
return;
}
args[0] = filterResult.finalFormat;
const {category, message, stack} = YellowBoxWarning.parse({
args,
});
if (YellowBoxRegistry.isWarningIgnored(message)) {
return;
}
if (filterResult.forceDialogImmediately === true) {
// This will pop a redbox. Do not downgrade. These are real bugs with same severity as throws.
error.call(console, message.content);
} else {
// Unfortunately, we need to add the Warning: prefix back so we don't show a redbox later.
args[0] = `Warning: ${filterResult.finalFormat}`;
// Note: YellowBox has no concept of "soft errors" so we're showing YellowBox for those.
YellowBoxRegistry.add({category, message, stack});
error.call(console, ...args);
}
};
} else {
YellowBox = class extends React.Component<Props, State> {
@@ -162,6 +211,13 @@ if (__DEV__) {
// Do nothing.
}
static __unstable_enableLogBox(): void {
// Do nothing.
}
static __unstable_isLogBoxEnabled(): boolean {
return false;
}
render(): React.Node {
return null;
}
@@ -172,5 +228,7 @@ module.exports = (YellowBox: Class<React.Component<Props, State>> & {
ignoreWarnings($ReadOnlyArray<IgnorePattern>): void,
install(): void,
uninstall(): void,
__unstable_enableLogBox(): void,
__unstable_isLogBoxEnabled(): boolean,
...
});
+65
View File
@@ -0,0 +1,65 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const React = require('react');
import type {Category} from './Data/YellowBoxCategory';
import type {Registry, Subscription} from './Data/YellowBoxRegistry';
type Props = $ReadOnly<{||}>;
type State = $ReadOnly<{|
registry: ?Registry,
|}>;
const YellowBoxList = require('./UI/YellowBoxList');
const YellowBoxRegistry = require('./Data/YellowBoxRegistry');
class YellowBoxContainer extends React.Component<Props, State> {
_subscription: ?Subscription;
state: State = {
registry: null,
};
render(): React.Node {
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
return this.state.registry == null ? null : (
<YellowBoxList
onDismiss={this._handleDismiss}
onDismissAll={this._handleDismissAll}
registry={this.state.registry}
/>
);
}
componentDidMount(): void {
this._subscription = YellowBoxRegistry.observe(registry => {
this.setState({registry});
});
}
componentWillUnmount(): void {
if (this._subscription != null) {
this._subscription.unsubscribe();
}
}
_handleDismiss = (category: Category): void => {
YellowBoxRegistry.delete(category);
};
_handleDismissAll(): void {
YellowBoxRegistry.clear();
}
}
export default YellowBoxContainer;
+202 -9
View File
@@ -11,20 +11,62 @@
'use strict';
const YellowBox = require('../YellowBox');
import * as React from 'react';
const YellowBoxRegistry = require('../Data/YellowBoxRegistry');
const LogBoxData = require('../../LogBox/Data/LogBoxData');
const render = require('../../../jest/renderer');
jest.mock('../../NativeModules/specs/NativeLogBox', () => true);
jest.mock('../../LogBox/LogBoxNotificationContainer', () => ({
__esModule: true,
default: 'LogBoxNotificationContainer',
}));
type Overrides = {|
forceDialogImmediately?: boolean,
suppressDialog_LEGACY?: boolean,
suppressCompletely?: boolean,
|};
const setFilter = (options?: Overrides) => {
LogBoxData.setWarningFilter(format => ({
finalFormat: format,
forceDialogImmediately: false,
suppressDialog_LEGACY: false,
suppressCompletely: false,
monitorEvent: null,
monitorListVersion: 0,
monitorSampleRate: 0,
...options,
}));
};
const install = () => {
const YellowBox = require('../YellowBox');
YellowBox.install();
};
const uninstall = () => {
const YellowBox = require('../YellowBox');
YellowBox.uninstall();
};
describe('YellowBox', () => {
const {error, warn} = console;
const mockError = jest.fn();
const mockWarn = jest.fn();
beforeEach(() => {
jest.resetModules();
(console: any).error = jest.fn();
(console: any).warn = jest.fn();
mockError.mockClear();
mockWarn.mockClear();
(console: any).error = mockError;
(console: any).warn = mockWarn;
});
afterEach(() => {
YellowBox.uninstall();
uninstall();
(console: any).error = error;
(console: any).warn = warn;
});
@@ -32,7 +74,7 @@ describe('YellowBox', () => {
it('can set `disableYellowBox` after installing', () => {
expect((console: any).disableYellowBox).toBe(undefined);
YellowBox.install();
install();
expect((console: any).disableYellowBox).toBe(false);
expect(YellowBoxRegistry.isDisabled()).toBe(false);
@@ -47,7 +89,7 @@ describe('YellowBox', () => {
expect((console: any).disableYellowBox).toBe(undefined);
(console: any).disableYellowBox = true;
YellowBox.install();
install();
expect((console: any).disableYellowBox).toBe(true);
expect(YellowBoxRegistry.isDisabled()).toBe(true);
@@ -56,22 +98,173 @@ describe('YellowBox', () => {
it('registers warnings', () => {
jest.mock('../Data/YellowBoxRegistry');
YellowBox.install();
install();
expect(YellowBoxRegistry.add).not.toBeCalled();
(console: any).warn('...');
expect(YellowBoxRegistry.add).toBeCalled();
expect(mockWarn).toBeCalledTimes(1);
expect(mockWarn).toBeCalledWith('...');
});
it('registers errors beginning with "Warning: "', () => {
it('registers errors', () => {
jest.mock('../Data/YellowBoxRegistry');
YellowBox.install();
install();
(console: any).error('...');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(mockError).toBeCalledTimes(1);
expect(mockError).toBeCalledWith('...');
});
it('skips ADVICE warnings', () => {
jest.mock('../Data/YellowBoxRegistry');
install();
(console: any).warn('(ADVICE) Ignore me');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(mockWarn).not.toBeCalled();
});
it('skips ignored warnings', () => {
jest.mock('../Data/YellowBoxRegistry');
install();
(YellowBoxRegistry: any).isWarningIgnored.mockReturnValue(true);
(console: any).warn('Ignore me');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(mockWarn).not.toBeCalled();
});
it('registers Warning module errors with default options to YellowBox', () => {
jest.mock('../Data/YellowBoxRegistry');
setFilter();
install();
(console: any).error('Warning: ...');
expect(YellowBoxRegistry.add).toBeCalled();
expect(mockError).toBeCalled();
expect(mockError).toBeCalledTimes(1);
expect(mockWarn).not.toBeCalled();
});
it('skips Warning module errors with forceDialogImmediately', () => {
jest.mock('../Data/YellowBoxRegistry');
setFilter({
suppressCompletely: true,
});
install();
(console: any).error('Warning: ...');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(mockError).not.toBeCalled();
expect(mockWarn).not.toBeCalled();
});
it('registers Warning errors with forceDialogImmediately as console.error (with interpolation)', () => {
jest.mock('../Data/YellowBoxRegistry');
setFilter({
forceDialogImmediately: true,
});
install();
(console: any).error('Warning: %s', 'Something');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(mockWarn).not.toBeCalled();
expect(mockError).toBeCalledTimes(1);
// We expect this to be the interpolated value because we don't do interpolation downstream.
// We also strip the "Warning" prefix, otherwise the redbox would be skipped downstream.
expect(mockError).toBeCalledWith('Something');
});
it('registers Warning errors with suppressDialog_LEGACY to YellowBox', () => {
jest.mock('../Data/YellowBoxRegistry');
setFilter({
suppressDialog_LEGACY: true,
});
install();
(console: any).error('Warning: Something');
expect(YellowBoxRegistry.add).toBeCalledTimes(1);
expect(mockWarn).not.toBeCalled();
expect(mockError).toBeCalledTimes(1);
// We cannot strip the "Warning" prefix or it would pop a redbox.
expect(mockError).toBeCalledWith('Warning: Something');
});
it('skips Warning errors sent to YellowBox but ignored by patterns', () => {
jest.mock('../Data/YellowBoxRegistry');
setFilter({
suppressDialog_LEGACY: true,
});
install();
(YellowBoxRegistry: any).isWarningIgnored.mockReturnValue(true);
(console: any).error('Warning: ...');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(mockWarn).not.toBeCalled();
expect(mockError).not.toBeCalled();
});
it('if LogBox is enabled, installs and uninstalls LogBox', () => {
jest.mock('../../LogBox/Data/LogBoxData');
jest.mock('../Data/YellowBoxRegistry');
const YellowBox = require('../YellowBox');
YellowBox.__unstable_enableLogBox();
install();
(console: any).warn('Some warning');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(LogBoxData.addLog).toBeCalled();
expect(require('../YellowBox').__unstable_isLogBoxEnabled()).toBe(true);
uninstall();
(LogBoxData.addLog: any).mockClear();
(console: any).warn('Some warning');
expect(YellowBoxRegistry.add).not.toBeCalled();
expect(LogBoxData.addLog).not.toBeCalled();
expect(YellowBox.__unstable_isLogBoxEnabled()).toBe(true);
});
it('throws if LogBox is enabled after YellowBox is installed', () => {
jest.mock('../Data/YellowBoxRegistry');
const YellowBox = require('../YellowBox');
install();
expect(() => YellowBox.__unstable_enableLogBox()).toThrow(
'LogBox must be enabled before AppContainer is required so that it can properly wrap the console methods.\n\nPlease enable LogBox earlier in your app.\n\n',
);
});
it('should render YellowBoxContainer by default', () => {
const YellowBox = require('../YellowBox');
const output = render.shallowRender(<YellowBox />);
expect(output).toMatchSnapshot();
});
it('should render LogBoxNotificationContainer when LogBox is enabled', () => {
const YellowBox = require('../YellowBox');
YellowBox.__unstable_enableLogBox();
const output = render.shallowRender(<YellowBox />);
expect(output).toMatchSnapshot();
});
});
@@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`YellowBox should render LogBoxNotificationContainer when LogBox is enabled 1`] = `<LogBoxNotificationContainer />`;
exports[`YellowBox should render YellowBoxContainer by default 1`] = `<YellowBoxContainer />`;
+49 -1
View File
@@ -17,15 +17,62 @@ def pods()
# Additional Pods which aren't included in the default Podfile
pod 'React-ART', :path => '../Libraries/ART'
pod 'React-RCTPushNotification', :path => '../Libraries/PushNotificationIOS'
pod 'Yoga',:path => '../ReactCommon/yoga', :modular_headers => true
# Additional Pods which are classed as unstable
#
# To use fabric: add `fabric_enabled` option to the use_react_native method above, like below
# use_react_native!(path: "..", fabric_enabled: true)
end
def flipper_pods()
flipperkit_version = '0.30.1'
pod 'FlipperKit', '~>' + flipperkit_version, :configuration => 'Debug'
pod 'FlipperKit/FlipperKitLayoutPlugin', '~>' + flipperkit_version, :configuration => 'Debug'
pod 'FlipperKit/SKIOSNetworkPlugin', '~>' + flipperkit_version, :configuration => 'Debug'
pod 'FlipperKit/FlipperKitUserDefaultsPlugin', '~>' + flipperkit_version, :configuration => 'Debug'
pod 'FlipperKit/FlipperKitReactPlugin', '~>' + flipperkit_version, :configuration => 'Debug'
if ENV['USE_FRAMEWORKS'] == '1'
$static_framework = ['FlipperKit', 'Flipper', 'Flipper-Folly',
'CocoaAsyncSocket', 'ComponentKit', 'Flipper-DoubleConversion',
'Flipper-Glog', 'Flipper-PeerTalk', 'Flipper-RSocket',
'CocoaLibEvent', 'OpenSSL-Universal', 'boost-for-react-native']
pre_install do |installer|
Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
installer.pod_targets.each do |pod|
if $static_framework.include?(pod.name)
def pod.build_type;
Pod::Target::BuildType.static_library
end
end
end
end
end
end
# Post Install processing for Flipper
def flipper_post_install(installer)
file_name = Dir.glob("*.xcodeproj")[0]
app_project = Xcodeproj::Project.open(file_name)
app_project.native_targets.each do |target|
target.build_configurations.each do |config|
cflags = config.build_settings['OTHER_CFLAGS'] || '$(inherited) '
unless cflags.include? '-DFB_SONARKIT_ENABLED=1'
puts 'Adding -DFB_SONARKIT_ENABLED=1 in OTHER_CFLAGS...'
cflags << ' -DFB_SONARKIT_ENABLED=1 '
end
config.build_settings['OTHER_CFLAGS'] = cflags
end
app_project.save
end
installer.pods_project.save
end
target 'RNTester' do
pods()
flipper_pods()
end
target 'RNTesterUnitTests' do
@@ -39,6 +86,7 @@ target 'RNTesterIntegrationTests' do
end
post_install do |installer|
flipper_post_install(installer)
installer.pods_project.targets.each do |target|
puts target.name
end
+275 -201
View File
@@ -1,14 +1,60 @@
PODS:
- boost-for-react-native (1.63.0)
- CocoaAsyncSocket (7.6.3)
- CocoaLibEvent (1.0.0)
- DoubleConversion (1.1.6)
- FBLazyVector (1000.0.0)
- FBReactNativeSpec (1000.0.0):
- FBLazyVector (0.62.0-rc.1)
- FBReactNativeSpec (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- RCTRequired (= 1000.0.0)
- RCTTypeSafety (= 1000.0.0)
- React-Core (= 1000.0.0)
- React-jsi (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- RCTRequired (= 0.62.0-rc.1)
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- Flipper (0.30.1):
- Flipper-Folly (~> 2.1)
- Flipper-RSocket (~> 1.0)
- Flipper-Folly (2.1.0):
- boost-for-react-native
- CocoaLibEvent (~> 1.0)
- DoubleConversion
- glog
- OpenSSL-Universal (= 1.0.2.19)
- Flipper-PeerTalk (0.0.4)
- Flipper-RSocket (1.0.0):
- Flipper-Folly (~> 2.0)
- FlipperKit (0.30.1):
- FlipperKit/Core (= 0.30.1)
- FlipperKit/Core (0.30.1):
- Flipper (~> 0.30.1)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- FlipperKit/CppBridge (0.30.1):
- Flipper (~> 0.30.1)
- FlipperKit/FBCxxFollyDynamicConvert (0.30.1):
- Flipper-Folly (~> 2.1)
- FlipperKit/FBDefines (0.30.1)
- FlipperKit/FKPortForwarding (0.30.1):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- FlipperKit/FlipperKitHighlightOverlay (0.30.1)
- FlipperKit/FlipperKitLayoutPlugin (0.30.1):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
- YogaKit (~> 1.18)
- FlipperKit/FlipperKitLayoutTextSearchable (0.30.1)
- FlipperKit/FlipperKitNetworkPlugin (0.30.1):
- FlipperKit/Core
- FlipperKit/FlipperKitReactPlugin (0.30.1):
- FlipperKit/Core
- FlipperKit/FlipperKitUserDefaultsPlugin (0.30.1):
- FlipperKit/Core
- FlipperKit/SKIOSNetworkPlugin (0.30.1):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- Folly (2018.10.22.00):
- boost-for-react-native
- DoubleConversion
@@ -19,269 +65,279 @@ PODS:
- DoubleConversion
- glog
- glog (0.3.5)
- RCTRequired (1000.0.0)
- RCTTypeSafety (1000.0.0):
- FBLazyVector (= 1000.0.0)
- OpenSSL-Universal (1.0.2.19):
- OpenSSL-Universal/Static (= 1.0.2.19)
- OpenSSL-Universal/Static (1.0.2.19)
- RCTRequired (0.62.0-rc.1)
- RCTTypeSafety (0.62.0-rc.1):
- FBLazyVector (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- RCTRequired (= 1000.0.0)
- React-Core (= 1000.0.0)
- React (1000.0.0):
- React-Core (= 1000.0.0)
- React-Core/DevSupport (= 1000.0.0)
- React-Core/RCTWebSocket (= 1000.0.0)
- React-RCTActionSheet (= 1000.0.0)
- React-RCTAnimation (= 1000.0.0)
- React-RCTBlob (= 1000.0.0)
- React-RCTImage (= 1000.0.0)
- React-RCTLinking (= 1000.0.0)
- React-RCTNetwork (= 1000.0.0)
- React-RCTSettings (= 1000.0.0)
- React-RCTText (= 1000.0.0)
- React-RCTVibration (= 1000.0.0)
- React-ART (1000.0.0):
- React-Core/ARTHeaders (= 1000.0.0)
- React-Core (1000.0.0):
- RCTRequired (= 0.62.0-rc.1)
- React-Core (= 0.62.0-rc.1)
- React (0.62.0-rc.1):
- React-Core (= 0.62.0-rc.1)
- React-Core/DevSupport (= 0.62.0-rc.1)
- React-Core/RCTWebSocket (= 0.62.0-rc.1)
- React-RCTActionSheet (= 0.62.0-rc.1)
- React-RCTAnimation (= 0.62.0-rc.1)
- React-RCTBlob (= 0.62.0-rc.1)
- React-RCTImage (= 0.62.0-rc.1)
- React-RCTLinking (= 0.62.0-rc.1)
- React-RCTNetwork (= 0.62.0-rc.1)
- React-RCTSettings (= 0.62.0-rc.1)
- React-RCTText (= 0.62.0-rc.1)
- React-RCTVibration (= 0.62.0-rc.1)
- React-ART (0.62.0-rc.1):
- React-Core/ARTHeaders (= 0.62.0-rc.1)
- React-Core (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default (= 1000.0.0)
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-Core/Default (= 0.62.0-rc.1)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/ARTHeaders (1000.0.0):
- React-Core/ARTHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/CoreModulesHeaders (1000.0.0):
- React-Core/CoreModulesHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/Default (1000.0.0):
- React-Core/Default (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/DevSupport (1000.0.0):
- React-Core/DevSupport (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default (= 1000.0.0)
- React-Core/RCTWebSocket (= 1000.0.0)
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-jsinspector (= 1000.0.0)
- React-Core/Default (= 0.62.0-rc.1)
- React-Core/RCTWebSocket (= 0.62.0-rc.1)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- React-jsinspector (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTActionSheetHeaders (1000.0.0):
- React-Core/RCTActionSheetHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTAnimationHeaders (1000.0.0):
- React-Core/RCTAnimationHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTBlobHeaders (1000.0.0):
- React-Core/RCTBlobHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTImageHeaders (1000.0.0):
- React-Core/RCTImageHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTLinkingHeaders (1000.0.0):
- React-Core/RCTLinkingHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTNetworkHeaders (1000.0.0):
- React-Core/RCTNetworkHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTPushNotificationHeaders (1000.0.0):
- React-Core/RCTPushNotificationHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTSettingsHeaders (1000.0.0):
- React-Core/RCTSettingsHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTTextHeaders (1000.0.0):
- React-Core/RCTTextHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTVibrationHeaders (1000.0.0):
- React-Core/RCTVibrationHeaders (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-Core/RCTWebSocket (1000.0.0):
- React-Core/RCTWebSocket (0.62.0-rc.1):
- Folly (= 2018.10.22.00)
- glog
- React-Core/Default (= 1000.0.0)
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsiexecutor (= 1000.0.0)
- React-Core/Default (= 0.62.0-rc.1)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsiexecutor (= 0.62.0-rc.1)
- Yoga
- React-CoreModules (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- React-CoreModules (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- RCTTypeSafety (= 1000.0.0)
- React-Core/CoreModulesHeaders (= 1000.0.0)
- React-RCTImage (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-cxxreact (1000.0.0):
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core/CoreModulesHeaders (= 0.62.0-rc.1)
- React-RCTImage (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-cxxreact (0.62.0-rc.1):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsinspector (= 1000.0.0)
- React-jsi (1000.0.0):
- React-jsinspector (= 0.62.0-rc.1)
- React-jsi (0.62.0-rc.1):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsi/Default (= 1000.0.0)
- React-jsi/Default (1000.0.0):
- React-jsi/Default (= 0.62.0-rc.1)
- React-jsi/Default (0.62.0-rc.1):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-jsiexecutor (1000.0.0):
- React-jsiexecutor (0.62.0-rc.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-jsinspector (1000.0.0)
- React-RCTActionSheet (1000.0.0):
- React-Core/RCTActionSheetHeaders (= 1000.0.0)
- React-RCTAnimation (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-jsinspector (0.62.0-rc.1)
- React-RCTActionSheet (0.62.0-rc.1):
- React-Core/RCTActionSheetHeaders (= 0.62.0-rc.1)
- React-RCTAnimation (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- RCTTypeSafety (= 1000.0.0)
- React-Core/RCTAnimationHeaders (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTBlob (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core/RCTAnimationHeaders (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTBlob (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- React-Core/RCTBlobHeaders (= 1000.0.0)
- React-Core/RCTWebSocket (= 1000.0.0)
- React-jsi (= 1000.0.0)
- React-RCTNetwork (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTImage (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- React-Core/RCTBlobHeaders (= 0.62.0-rc.1)
- React-Core/RCTWebSocket (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- React-RCTNetwork (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTImage (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- RCTTypeSafety (= 1000.0.0)
- React-Core/RCTImageHeaders (= 1000.0.0)
- React-RCTNetwork (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTLinking (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- React-Core/RCTLinkingHeaders (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTNetwork (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core/RCTImageHeaders (= 0.62.0-rc.1)
- React-RCTNetwork (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTLinking (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- React-Core/RCTLinkingHeaders (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTNetwork (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- RCTTypeSafety (= 1000.0.0)
- React-Core/RCTNetworkHeaders (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTPushNotification (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- RCTTypeSafety (= 1000.0.0)
- React-Core/RCTPushNotificationHeaders (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTSettings (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core/RCTNetworkHeaders (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTPushNotification (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core/RCTPushNotificationHeaders (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTSettings (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- RCTTypeSafety (= 1000.0.0)
- React-Core/RCTSettingsHeaders (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-RCTTest (1000.0.0):
- React-Core (= 1000.0.0)
- React-CoreModules (= 1000.0.0)
- React-RCTText (1000.0.0):
- React-Core/RCTTextHeaders (= 1000.0.0)
- React-RCTVibration (1000.0.0):
- FBReactNativeSpec (= 1000.0.0)
- RCTTypeSafety (= 0.62.0-rc.1)
- React-Core/RCTSettingsHeaders (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- React-RCTTest (0.62.0-rc.1):
- React-Core (= 0.62.0-rc.1)
- React-CoreModules (= 0.62.0-rc.1)
- React-RCTText (0.62.0-rc.1):
- React-Core/RCTTextHeaders (= 0.62.0-rc.1)
- React-RCTVibration (0.62.0-rc.1):
- FBReactNativeSpec (= 0.62.0-rc.1)
- Folly (= 2018.10.22.00)
- React-Core/RCTVibrationHeaders (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- ReactCommon/callinvoker (1000.0.0):
- React-Core/RCTVibrationHeaders (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- ReactCommon/callinvoker (0.62.0-rc.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-cxxreact (= 1000.0.0)
- ReactCommon/turbomodule/core (1000.0.0):
- React-cxxreact (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (0.62.0-rc.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-Core (= 1000.0.0)
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- ReactCommon/callinvoker (= 1000.0.0)
- ReactCommon/turbomodule/samples (1000.0.0):
- React-Core (= 0.62.0-rc.1)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- ReactCommon/callinvoker (= 0.62.0-rc.1)
- ReactCommon/turbomodule/samples (0.62.0-rc.1):
- DoubleConversion
- Folly (= 2018.10.22.00)
- glog
- React-Core (= 1000.0.0)
- React-cxxreact (= 1000.0.0)
- React-jsi (= 1000.0.0)
- ReactCommon/callinvoker (= 1000.0.0)
- ReactCommon/turbomodule/core (= 1000.0.0)
- React-Core (= 0.62.0-rc.1)
- React-cxxreact (= 0.62.0-rc.1)
- React-jsi (= 0.62.0-rc.1)
- ReactCommon/callinvoker (= 0.62.0-rc.1)
- ReactCommon/turbomodule/core (= 0.62.0-rc.1)
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
DEPENDENCIES:
- DoubleConversion (from `../third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../Libraries/FBReactNativeSpec`)
- FlipperKit (~> 0.30.1)
- FlipperKit/FlipperKitLayoutPlugin (~> 0.30.1)
- FlipperKit/FlipperKitReactPlugin (~> 0.30.1)
- FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.30.1)
- FlipperKit/SKIOSNetworkPlugin (~> 0.30.1)
- Folly (from `../third-party-podspecs/Folly.podspec`)
- glog (from `../third-party-podspecs/glog.podspec`)
- RCTRequired (from `../Libraries/RCTRequired`)
@@ -313,8 +369,17 @@ DEPENDENCIES:
- Yoga (from `../ReactCommon/yoga`)
SPEC REPOS:
trunk:
https://cdn.cocoapods.org/:
- boost-for-react-native
- CocoaAsyncSocket
- CocoaLibEvent
- Flipper
- Flipper-Folly
- Flipper-PeerTalk
- Flipper-RSocket
- FlipperKit
- OpenSSL-Universal
- YogaKit
EXTERNAL SOURCES:
DoubleConversion:
@@ -376,35 +441,44 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
FBLazyVector: 34431b7e61740bed29b082ff81500b0ffafaffa0
FBReactNativeSpec: e9febd2d5cc091662f172724165922b2e28d10a3
CocoaAsyncSocket: eafaa68a7e0ec99ead0a7b35015e0bf25d2c8987
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 9349d70d60793fce157f7c3837f51c60bc81a91b
FBReactNativeSpec: 36215b34017aa3bb62f1ed494b50fbaa242649fb
Flipper: d591b88245dc8c8147819aa249f911923c7417fc
Flipper-Folly: bcae82405dafd18ac9f8d9d4902fd1c2ef2a7e77
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
Flipper-RSocket: 1260a31c05c238eabfa9bb8a64e3983049048371
FlipperKit: 3e13631bca7c5ec0dd54ee1d096f5e5d32a5d784
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
RCTRequired: 33f3b89d2d82ef01c02b9b4f8146c43762e509d8
RCTTypeSafety: 2b1cb2d92b779aa9a3522f67bd4f07e6b6d0797e
React: 28a654b69575941571c073a656bc06795825e7f7
React-ART: a5da06a892342d03896e0db45a7072525981f63c
React-Core: f8656b21cfe16b1fe276686f3b921bce0fa6de4d
React-CoreModules: 96b2f1e0b84493e6c1b7f3bb21357f24fdcfce2f
React-cxxreact: 7c4242192149ce0205b53efaa03e3bf86ba4337c
React-jsi: 98d1f9d8a79d2720ba6a44c2d928a77f315b7e4f
React-jsiexecutor: c0ab8c80a6e88380d63f583690a50d4a723b47b5
React-jsinspector: ea0a218071a11c3687cef2480580180caa6a64c0
React-RCTActionSheet: 090e7bd7c5774d919c47c4eeff78223a7fd8c19c
React-RCTAnimation: 891c2b3404c214dc19faee57b5f249da6deeb099
React-RCTBlob: 8df793b30385b7ffe7e6703651043bad369cd756
React-RCTImage: 3ee9a6cd02c7741ebe3a001d51a18c349019778f
React-RCTLinking: 7ccb8f6dcfd4b95b68a73119aca7bca9fa530b08
React-RCTNetwork: 565fa6cc6108db9210fe5774f04ce52edccbb8ed
React-RCTPushNotification: 494ccfc569e2a699c0cc1a816eaebf8197a2ebc8
React-RCTSettings: 8138286da8de74839cb436dd37704ed64d4bfe78
React-RCTTest: d148e0657ce77ffd43a10325c284f47f25fb0532
React-RCTText: 9078167d3bc011162326f2d8ef4dd580ec1eca17
React-RCTVibration: e3269787c533de8c4f54f489202d848fdef33e1d
ReactCommon: 9d212865526209dc2d01be40340c8d27b53e6bea
Yoga: d88d8b51ee5b247f43211e2edf272438df1b484f
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
RCTRequired: 418abaf045a635a391e68ee0573035553c1c4d7b
RCTTypeSafety: ea8dd81f61436a394b943dac4435a304c59906ff
React: f591e8a044a8ee4a4b20ab632b2906461a241370
React-ART: 11785e335a25cc0397fcd008cd0f8e0d340340f0
React-Core: 0bb33e607db817c4f60c967448c16f7d31bb973b
React-CoreModules: 15064232a166bf4408d0a723a739815c317635be
React-cxxreact: dc7b272c44c80616385c25242f54f8594951b57f
React-jsi: e3f33d91999ba00d787ceceb6783aa314ecf175d
React-jsiexecutor: ccf2361cd90f691e04ff73585f099aa179ae8b52
React-jsinspector: fabb3a8cad7bce396f2d4c29cbf83e87022b07ec
React-RCTActionSheet: a9a397cdf75149175eab539e536eeb42518f529c
React-RCTAnimation: 3fddf9e5dc82ea620c1c44b4206149688b43e054
React-RCTBlob: 245f8f0b4578bbecff5e99062f8e2db580218434
React-RCTImage: 8205ce960be3d68fcb8dbab729761d828223cd39
React-RCTLinking: 27d5e8256b0656d87a00b41af6e55155a70e349b
React-RCTNetwork: c6a346f734121eecc855aaaed4572883f502978d
React-RCTPushNotification: 658436eec8559a1248c3b859246012e859fadefd
React-RCTSettings: 9ae19dc86054cf5317086ab302e820e9616da193
React-RCTTest: 399480c8fcfacba1b3e6c0af6fced4f24d62e2da
React-RCTText: f2f9976b77661b5a1d628cf7ebfe6c08b6168f8a
React-RCTVibration: 2e7618e869b2ba4a15042d6def29dd32df734793
ReactCommon: 13c3473a975e73db91b1999e0d6d89c62400785d
Yoga: b9a1f7189009fa4b6266ee0a63235547326295d2
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 060903e270072f1e192b064848e6c34528af1c87
PODFILE CHECKSUM: 6c950c0173bc4754b0d9fa5aba9232943ac228b4
COCOAPODS: 1.8.4
+30
View File
@@ -33,6 +33,19 @@
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#endif
#if DEBUG
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitLayoutPlugin/SKDescriptorMapper.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#endif
#endif
#import <ReactCommon/RCTTurboModuleManager.h>
#import "RNTesterTurboModuleProvider.h"
@@ -83,6 +96,7 @@
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[self initializeFlipper:application];
return YES;
}
@@ -94,6 +108,22 @@
fallbackResource:nil];
}
- (void)initializeFlipper:(UIApplication *)application
{
#if DEBUG
#ifdef FB_SONARKIT_ENABLED
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application
withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
#endif
#endif
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
+55 -16
View File
@@ -13,11 +13,11 @@
27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; };
2DDEF0101F84BF7B00DBDF73 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */; };
3D2AFAF51D646CF80089D1A3 /* legacy_image@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */; };
42C7FD8921D436BBA216216D /* libPods-RNTester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EA4C77A9826FF02A56911142 /* libPods-RNTester.a */; };
442B673CCEF28320AE16877B /* libPods-RNTester.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D3C8BDC1E54DFC8EB0F67828 /* libPods-RNTester.a */; };
5C60EB1C226440DB0018C04F /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C60EB1B226440DB0018C04F /* AppDelegate.mm */; };
5CB07C9B226467E60039471C /* RNTesterTurboModuleProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5CB07C99226467E60039471C /* RNTesterTurboModuleProvider.mm */; };
69B65AC442B001534251D909 /* libPods-RNTesterIntegrationTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5BBFF3E3792E27C4FBA2CB43 /* libPods-RNTesterIntegrationTests.a */; };
C23B0809CAE8A115772B092E /* libPods-RNTesterUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42A6C306038665FDDA3E54E2 /* libPods-RNTesterUnitTests.a */; };
AB71F075B51B1FA0C65DCF39 /* libPods-RNTesterUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2723489EF058D50FF7217FD9 /* libPods-RNTesterUnitTests.a */; };
CBC719CA19D2FD9247BD28F1 /* libPods-RNTesterIntegrationTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67373A0E14C242E758EE729F /* libPods-RNTesterIntegrationTests.a */; };
E7C1241A22BEC44B00DA25C0 /* RNTesterIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C1241922BEC44B00DA25C0 /* RNTesterIntegrationTests.m */; };
E7DB20D122B2BAA6005AC45F /* RCTBundleURLProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E7DB20A922B2BAA3005AC45F /* RCTBundleURLProviderTests.m */; };
E7DB20D222B2BAA6005AC45F /* RCTModuleInitNotificationRaceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E7DB20AA22B2BAA3005AC45F /* RCTModuleInitNotificationRaceTests.m */; };
@@ -74,6 +74,7 @@
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNTester/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RNTester/main.m; sourceTree = "<group>"; };
2723489EF058D50FF7217FD9 /* libPods-RNTesterUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdatePropertiesExampleView.h; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.h; sourceTree = "<group>"; };
272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = "<group>"; };
27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FlexibleSizeExampleView.m; path = RNTester/NativeExampleViews/FlexibleSizeExampleView.m; sourceTree = "<group>"; };
@@ -81,15 +82,15 @@
2DDEF00F1F84BF7B00DBDF73 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = RNTester/Images.xcassets; sourceTree = "<group>"; };
34028D6B10F47E490042EB27 /* Pods-RNTesterUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RNTesterUnitTests/Pods-RNTesterUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "legacy_image@2x.png"; path = "RNTester/legacy_image@2x.png"; sourceTree = "<group>"; };
42A6C306038665FDDA3E54E2 /* libPods-RNTesterUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5BBFF3E3792E27C4FBA2CB43 /* libPods-RNTesterIntegrationTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterIntegrationTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5BEC8567F3741044B6A5EFC5 /* Pods-RNTester.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTester.release.xcconfig"; path = "Pods/Target Support Files/Pods-RNTester/Pods-RNTester.release.xcconfig"; sourceTree = "<group>"; };
5C60EB1B226440DB0018C04F /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = RNTester/AppDelegate.mm; sourceTree = "<group>"; };
5CB07C99226467E60039471C /* RNTesterTurboModuleProvider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RNTesterTurboModuleProvider.mm; path = RNTester/RNTesterTurboModuleProvider.mm; sourceTree = "<group>"; };
5CB07C9A226467E60039471C /* RNTesterTurboModuleProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNTesterTurboModuleProvider.h; path = RNTester/RNTesterTurboModuleProvider.h; sourceTree = "<group>"; };
67373A0E14C242E758EE729F /* libPods-RNTesterIntegrationTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTesterIntegrationTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7D51F73F0DA20287418D98BD /* Pods-RNTesterIntegrationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterIntegrationTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RNTesterIntegrationTests/Pods-RNTesterIntegrationTests.release.xcconfig"; sourceTree = "<group>"; };
972A459EE6CF8CC63531A088 /* Pods-RNTesterIntegrationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterIntegrationTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RNTesterIntegrationTests/Pods-RNTesterIntegrationTests.debug.xcconfig"; sourceTree = "<group>"; };
98233960D1D6A1977D1C7EAF /* Pods-RNTester.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTester.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RNTester/Pods-RNTester.debug.xcconfig"; sourceTree = "<group>"; };
D3C8BDC1E54DFC8EB0F67828 /* libPods-RNTester.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTester.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E771AEEA22B44E3100EA1189 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RNTester/Info.plist; sourceTree = "<group>"; };
E7C1241922BEC44B00DA25C0 /* RNTesterIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterIntegrationTests.m; sourceTree = "<group>"; };
E7DB209F22B2BA84005AC45F /* RNTesterUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNTesterUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -163,7 +164,6 @@
E7DB216122B2F3EC005AC45F /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
E7DB218B22B41FCD005AC45F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
E9618482EC8608D4872A6E28 /* Pods-RNTesterUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNTesterUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RNTesterUnitTests/Pods-RNTesterUnitTests.release.xcconfig"; sourceTree = "<group>"; };
EA4C77A9826FF02A56911142 /* libPods-RNTester.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RNTester.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -171,7 +171,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
42C7FD8921D436BBA216216D /* libPods-RNTester.a in Frameworks */,
442B673CCEF28320AE16877B /* libPods-RNTester.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -181,7 +181,7 @@
files = (
E7DB213122B2C649005AC45F /* JavaScriptCore.framework in Frameworks */,
E7DB213222B2C67D005AC45F /* libOCMock.a in Frameworks */,
C23B0809CAE8A115772B092E /* libPods-RNTesterUnitTests.a in Frameworks */,
AB71F075B51B1FA0C65DCF39 /* libPods-RNTesterUnitTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -191,7 +191,7 @@
files = (
E7DB218C22B41FCD005AC45F /* XCTest.framework in Frameworks */,
E7DB216722B2F69F005AC45F /* JavaScriptCore.framework in Frameworks */,
69B65AC442B001534251D909 /* libPods-RNTesterIntegrationTests.a in Frameworks */,
CBC719CA19D2FD9247BD28F1 /* libPods-RNTesterIntegrationTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -261,9 +261,9 @@
E7DB211822B2BD53005AC45F /* libReact-RCTText.a */,
E7DB211A22B2BD53005AC45F /* libReact-RCTVibration.a */,
E7DB212222B2BD53005AC45F /* libyoga.a */,
EA4C77A9826FF02A56911142 /* libPods-RNTester.a */,
5BBFF3E3792E27C4FBA2CB43 /* libPods-RNTesterIntegrationTests.a */,
42A6C306038665FDDA3E54E2 /* libPods-RNTesterUnitTests.a */,
D3C8BDC1E54DFC8EB0F67828 /* libPods-RNTester.a */,
67373A0E14C242E758EE729F /* libPods-RNTesterIntegrationTests.a */,
2723489EF058D50FF7217FD9 /* libPods-RNTesterUnitTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -725,8 +725,20 @@
);
INFOPLIST_FILE = "$(SRCROOT)/RNTester/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = "$(inherited)";
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=*]" = "$(inherited)";
OTHER_CFLAGS = (
"$(inherited)",
"-DFB_SONARKIT_ENABLED=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -779,8 +791,19 @@
);
INFOPLIST_FILE = "$(SRCROOT)/RNTester/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_CFLAGS = "$(inherited)";
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
);
OTHER_CFLAGS = (
"$(inherited)",
"-DFB_SONARKIT_ENABLED=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -974,6 +997,10 @@
);
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
"$(inherited)",
"-DFB_SONARKIT_ENABLED=1",
);
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.RNTesterUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1005,6 +1032,10 @@
"$(PROJECT_DIR)/RNTesterUnitTests",
);
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
"$(inherited)",
"-DFB_SONARKIT_ENABLED=1",
);
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.RNTesterUnitTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1037,6 +1068,10 @@
);
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
"$(inherited)",
"-DFB_SONARKIT_ENABLED=1",
);
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.RNTesterIntegrationTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1066,6 +1101,10 @@
"@loader_path/Frameworks",
);
MTL_FAST_MATH = YES;
OTHER_CFLAGS = (
"$(inherited)",
"-DFB_SONARKIT_ENABLED=1",
);
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.RNTesterIntegrationTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
+12 -4
View File
@@ -166,14 +166,22 @@ dependencies {
// Build React Native from source
implementation project(':ReactAndroid')
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
def hermesPath = '$projectDir/../../../../node_modules/hermes-engine/android/'
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
debugImplementation("com.facebook.flipper:flipper:0.23.4") {
exclude group:'com.facebook.yoga'
exclude group:'com.facebook.flipper', module: 'fbjni'
exclude group:'com.facebook.litho', module: 'litho-annotations'
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (useIntlJsc) {
+3
View File
@@ -7,3 +7,6 @@ MYAPP_RELEASE_KEY_PASSWORD=android
android.useAndroidX=true
android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.30.2
@@ -0,0 +1,72 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.uiapp;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}
@@ -11,6 +11,7 @@ import android.app.Application;
import android.content.Context;
import com.facebook.react.BuildConfig;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
@@ -48,7 +49,8 @@ public class RNTesterApplication extends Application implements ReactApplication
public void onCreate() {
ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik);
super.onCreate();
initializeFlipper(this);
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
@Override
@@ -56,15 +58,25 @@ public class RNTesterApplication extends Application implements ReactApplication
return mReactNativeHost;
}
private static void initializeFlipper(Context context) {
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
Class<?> aClass = Class.forName("com.facebook.react.uiapp.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
@@ -16,7 +16,7 @@ const React = require('react');
const TextInlineView = require('../../components/TextInlineView');
const TextLegend = require('../../components/TextLegend');
const {StyleSheet, Text, View} = require('react-native');
const {LayoutAnimation, StyleSheet, Text, View} = require('react-native');
class Entity extends React.Component<{|children: React.Node|}> {
render() {
@@ -70,10 +70,137 @@ class AttributeToggler extends React.Component<{...}, $FlowFixMeState> {
}
}
type AdjustingFontSizeProps = $ReadOnly<{||}>;
type AdjustingFontSizeState = {|
dynamicText: string,
shouldRender: boolean,
|};
class AdjustingFontSize extends React.Component<
AdjustingFontSizeProps,
AdjustingFontSizeState,
> {
state = {
dynamicText: '',
shouldRender: true,
};
reset = () => {
LayoutAnimation.easeInEaseOut();
this.setState({
shouldRender: false,
});
setTimeout(() => {
LayoutAnimation.easeInEaseOut();
this.setState({
dynamicText: '',
shouldRender: true,
});
}, 300);
};
addText = () => {
this.setState({
dynamicText:
this.state.dynamicText +
(Math.floor((Math.random() * 10) % 2) ? ' foo' : ' bar'),
});
};
removeText = () => {
this.setState({
dynamicText: this.state.dynamicText.slice(
0,
this.state.dynamicText.length - 4,
),
});
};
render() {
if (!this.state.shouldRender) {
return <View />;
}
return (
<View>
<Text
ellipsizeMode="tail"
numberOfLines={1}
style={{fontSize: 36, marginVertical: 6}}>
Truncated text is baaaaad.
</Text>
<Text
numberOfLines={1}
adjustsFontSizeToFit={true}
style={{fontSize: 40, marginVertical: 6}}>
Shrinking to fit available space is much better!
</Text>
<Text
adjustsFontSizeToFit={true}
numberOfLines={1}
style={{fontSize: 30, marginVertical: 6}}>
{'Add text to me to watch me shrink!' + ' ' + this.state.dynamicText}
</Text>
<Text
adjustsFontSizeToFit={true}
numberOfLines={4}
style={{fontSize: 20, marginVertical: 6}}>
{'Multiline text component shrinking is supported, watch as this reeeeaaaally loooooong teeeeeeext grooooows and then shriiiinks as you add text to me! ioahsdia soady auydoa aoisyd aosdy ' +
' ' +
this.state.dynamicText}
</Text>
<Text
adjustsFontSizeToFit={true}
style={{fontSize: 20, marginVertical: 6, maxHeight: 50}}>
{'Text limited by height, watch as this reeeeaaaally loooooong teeeeeeext grooooows and then shriiiinks as you add text to me! ioahsdia soady auydoa aoisyd aosdy ' +
' ' +
this.state.dynamicText}
</Text>
<Text
adjustsFontSizeToFit={true}
numberOfLines={1}
style={{marginVertical: 6}}>
<Text style={{fontSize: 14}}>
{'Differently sized nested elements will shrink together. '}
</Text>
<Text style={{fontSize: 20}}>
{'LARGE TEXT! ' + this.state.dynamicText}
</Text>
</Text>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-around',
marginTop: 5,
marginVertical: 6,
}}>
<Text style={{backgroundColor: '#ffaaaa'}} onPress={this.reset}>
Reset
</Text>
<Text style={{backgroundColor: '#aaaaff'}} onPress={this.removeText}>
Remove Text
</Text>
<Text style={{backgroundColor: '#aaffaa'}} onPress={this.addText}>
Add Text
</Text>
</View>
</View>
);
}
}
class TextExample extends React.Component<{...}> {
render(): React.Node {
return (
<RNTesterPage title="<Text>">
<RNTesterBlock title="Dynamic Font Size Adjustment">
<AdjustingFontSize />
</RNTesterBlock>
<RNTesterBlock title="Wrap">
<Text>
The text should wrap if it goes on multiple lines. See, this is
@@ -222,6 +222,14 @@ class AdjustingFontSize extends React.Component<
this.state.dynamicText}
</Text>
<Text
adjustsFontSizeToFit={true}
style={{fontSize: 20, marginVertical: 6, maxHeight: 50}}>
{'Text limited by height, watch as this reeeeaaaally loooooong teeeeeeext grooooows and then shriiiinks as you add text to me! ioahsdia soady auydoa aoisyd aosdy ' +
' ' +
this.state.dynamicText}
</Text>
<Text
adjustsFontSizeToFit={true}
numberOfLines={1}
+1 -1
View File
@@ -305,7 +305,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
*/
- (void)reloadWithReason:(NSString *)reason
{
#if RCT_ENABLE_INSPECTOR && !TARGET_OS_UIKITFORMAC
#if RCT_ENABLE_INSPECTOR
// Disable debugger to resume the JsVM & avoid thread locks while reloading
[RCTInspectorDevServerHelper disableDebugger];
#endif
@@ -5,12 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#import <React/RCTDefines.h>
#include <fb/visibility.h>
namespace facebook {
namespace jni {
void FBEXPORT installTerminateHandler();
}};
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotification;
RCT_EXTERN NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey;
+11
View File
@@ -0,0 +1,11 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTConstants.h"
NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
NSString *const RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey = @"traitCollection";
+1 -1
View File
@@ -63,7 +63,7 @@
#endif
#ifndef ENABLE_PACKAGER_CONNECTION
#if RCT_DEV && (__has_include("RCTPackagerConnection.h") || __has_include(<React/RCTPackagerConnection.h>)) && !TARGET_OS_UIKITFORMAC
#if RCT_DEV && (__has_include("RCTPackagerConnection.h") || __has_include(<React/RCTPackagerConnection.h>))
#define ENABLE_PACKAGER_CONNECTION 1
#else
#define ENABLE_PACKAGER_CONNECTION 0
+6 -11
View File
@@ -14,6 +14,7 @@
#import "RCTAssert.h"
#import "RCTBridge.h"
#import "RCTBridge+Private.h"
#import "RCTConstants.h"
#import "RCTEventDispatcher.h"
#import "RCTKeyCommands.h"
#import "RCTLog.h"
@@ -33,7 +34,6 @@
#endif
NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification";
static NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
@interface RCTUIManager (RCTRootView)
@@ -367,21 +367,16 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
[self showLoadingView];
}
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[super traitCollectionDidChange:previousTraitCollection];
if (@available(iOS 13.0, *)) {
if ([previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection]) {
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{@"traitCollection": self.traitCollection}];
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey: self.traitCollection,
}];
}
#endif
- (void)dealloc
{
+5 -5
View File
@@ -21,11 +21,11 @@ NSDictionary* RCTGetReactNativeVersion(void)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^(void){
__rnVersion = @{
RCTVersionMajor: @(0),
RCTVersionMinor: @(0),
RCTVersionPatch: @(0),
RCTVersionPrerelease: [NSNull null],
};
RCTVersionMajor: @(0),
RCTVersionMinor: @(62),
RCTVersionPatch: @(0),
RCTVersionPrerelease: @"rc.2",
};
});
return __rnVersion;
}
@@ -7,14 +7,13 @@
#import "RCTSurfaceHostingView.h"
#import "RCTConstants.h"
#import "RCTDefines.h"
#import "RCTSurface.h"
#import "RCTSurfaceDelegate.h"
#import "RCTSurfaceView.h"
#import "RCTUtils.h"
static NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
@interface RCTSurfaceHostingView ()
@property (nonatomic, assign) BOOL isActivityIndicatorViewVisible;
@@ -208,21 +207,15 @@ RCT_NOT_IMPLEMENTED(- (nullable instancetype)initWithCoder:(NSCoder *)coder)
#pragma mark - UITraitCollection updates
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
{
[super traitCollectionDidChange:previousTraitCollection];
if (@available(iOS 13.0, *)) {
if ([previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection]) {
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{@"traitCollection": self.traitCollection}];
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification
object:self
userInfo:@{
RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey: self.traitCollection,
}];
}
#endif
#pragma mark - Private stuff
+3
View File
@@ -96,6 +96,9 @@ rn_apple_library(
) + react_module_plugin_providers(
name = "RedBox",
native_class_func = "RCTRedBoxCls",
) + react_module_plugin_providers(
name = "LogBox",
native_class_func = "RCTLogBoxCls",
) + react_module_plugin_providers(
name = "TVNavigationEventEmitter",
native_class_func = "RCTTVNavigationEventEmitterCls",
+1
View File
@@ -48,6 +48,7 @@ Class RCTPerfMonitorCls(void) __attribute__((used));
Class RCTDevMenuCls(void) __attribute__((used));
Class RCTDevSettingsCls(void) __attribute__((used));
Class RCTRedBoxCls(void) __attribute__((used));
Class RCTLogBoxCls(void) __attribute__((used));
Class RCTTVNavigationEventEmitterCls(void) __attribute__((used));
Class RCTWebSocketExecutorCls(void) __attribute__((used));
Class RCTWebSocketModuleCls(void) __attribute__((used));
+1
View File
@@ -37,6 +37,7 @@ Class RCTCoreModulesClassProvider(const char *name) {
{"DevMenu", RCTDevMenuCls},
{"DevSettings", RCTDevSettingsCls},
{"RedBox", RCTRedBoxCls},
{"LogBox", RCTLogBoxCls},
{"TVNavigationEventEmitter", RCTTVNavigationEventEmitterCls},
{"WebSocketExecutor", RCTWebSocketExecutorCls},
{"WebSocketModule", RCTWebSocketModuleCls},
-2
View File
@@ -12,7 +12,5 @@
RCT_EXTERN void RCTEnableAppearancePreference(BOOL enabled);
NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification";
@interface RCTAppearance : RCTEventEmitter <RCTBridgeModule>
@end
+2 -1
View File
@@ -8,6 +8,7 @@
#import "RCTAppearance.h"
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConstants.h>
#import <React/RCTEventEmitter.h>
#import "CoreModulesPlugins.h"
@@ -86,7 +87,7 @@ RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme)
NSDictionary *userInfo = [notification userInfo];
UITraitCollection *traitCollection = nil;
if (userInfo) {
traitCollection = userInfo[@"traitCollection"];
traitCollection = userInfo[RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey];
}
NSString *newColorScheme = RCTColorSchemePreference(traitCollection);
if (![_currentColorScheme isEqualToString:newColorScheme]) {
+1 -1
View File
@@ -262,7 +262,7 @@ RCT_EXPORT_MODULE()
if (devSettings.isNuclideDebuggingAvailable && !devSettings.isDebuggingRemotely) {
[items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Debug with Nuclide"
handler:^{
#if RCT_ENABLE_INSPECTOR && !TARGET_OS_UIKITFORMAC
#if RCT_ENABLE_INSPECTOR
[RCTInspectorDevServerHelper
attachDebugger:@"ReactNative"
withBundleURL:bridge.bundleURL
+1 -1
View File
@@ -176,7 +176,7 @@ RCT_EXPORT_MODULE()
forMethod:@"reload"];
#endif
#if RCT_ENABLE_INSPECTOR && !TARGET_OS_UIKITFORMAC
#if RCT_ENABLE_INSPECTOR
// we need this dispatch back to the main thread because even though this
// is executed on the main thread, at this point the bridge is not yet
// finished with its initialisation. But it does finish by the time it
+10 -3
View File
@@ -10,6 +10,7 @@
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTAccessibilityManager.h>
#import <React/RCTAssert.h>
#import <React/RCTConstants.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTUIUtils.h>
#import <React/RCTUtils.h>
@@ -61,9 +62,15 @@ RCT_EXPORT_MODULE()
_currentInterfaceDimensions = RCTExportedDimensions(_bridge);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interfaceFrameDidChange)
name:UIApplicationDidBecomeActiveNotification
object:nil];
selector:@selector(interfaceFrameDidChange)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interfaceFrameDidChange)
name:RCTUserInterfaceStyleDidChangeNotification
object:nil];
#endif
}
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTBridge.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTErrorCustomizer.h>
@class RCTJSStackFrame;
@interface RCTLogBox : NSObject <RCTBridgeModule>
- (void)show;
- (void)hide;
@end
+159
View File
@@ -0,0 +1,159 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTLogBox.h"
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTBridge.h>
#import <React/RCTRootView.h>
#import <React/RCTConvert.h>
#import <React/RCTDefines.h>
#import <React/RCTErrorInfo.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTJSStackFrame.h>
#import <React/RCTRedBoxSetEnabled.h>
#import <React/RCTReloadCommand.h>
#import <React/RCTRedBoxSetEnabled.h>
#import <React/RCTSurface.h>
#import <React/RCTUtils.h>
#import <objc/runtime.h>
#import "CoreModulesPlugins.h"
#if RCT_DEV_MENU
@class RCTLogBoxView;
@interface RCTLogBoxView : UIView
@end
@implementation RCTLogBoxView
{
UIViewController *_rootViewController;
RCTSurface *_surface;
}
- (instancetype)initWithFrame:(CGRect)frame bridge:(RCTBridge *)bridge
{
if ((self = [super initWithFrame:frame])) {
self.backgroundColor = [UIColor clearColor];
_surface = [[RCTSurface alloc] initWithBridge:bridge moduleName:@"LogBox" initialProperties:@{}];
[_surface start];
[_surface setSize:frame.size];
if (![_surface synchronouslyWaitForStage:RCTSurfaceStageSurfaceDidInitialMounting timeout:1]) {
RCTLogInfo(@"Failed to mount LogBox within 1s");
}
_rootViewController = [UIViewController new];
_rootViewController.view = (UIView *)_surface.view;
_rootViewController.view.backgroundColor = [UIColor clearColor];
_rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;
}
return self;
}
- (void)dealloc
{
// Dismiss by deallocating the window.
// This will also handle JS reload, otherwise the LogBox view would be stuck on top.
[_rootViewController.view resignFirstResponder];
[_rootViewController dismissViewControllerAnimated:NO completion:NULL];
}
- (void)show
{
[RCTSharedApplication().delegate.window.rootViewController presentViewController:_rootViewController animated:NO completion:^{
[self->_rootViewController.view becomeFirstResponder];
}];
}
@end
@interface RCTLogBox () <NativeLogBoxSpec>
@end
@implementation RCTLogBox
{
RCTLogBoxView *_view;
}
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE()
+ (BOOL)requiresMainQueueSetup
{
return YES;
}
RCT_EXPORT_METHOD(show)
{
if (RCTRedBoxGetEnabled()) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!self->_view) {
self->_view = [[RCTLogBoxView alloc] initWithFrame:[UIScreen mainScreen].bounds bridge: self->_bridge];
}
[self->_view show];
});
}
}
RCT_EXPORT_METHOD(hide)
{
if (RCTRedBoxGetEnabled()) {
dispatch_async(dispatch_get_main_queue(), ^{
self->_view = nil;
});
}
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
if (RCTRedBoxGetEnabled()) {
return std::make_shared<facebook::react::NativeLogBoxSpecJSI>(self, jsInvoker);
}
return nullptr;
}
@end
#else // Disabled
@interface RCTLogBox() <NativeLogBoxSpec>
@end
@implementation RCTLogBox
+ (NSString *)moduleName
{
return nil;
}
- (void)show {
// noop
}
- (void)hide {
// noop
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return std::make_shared<facebook::react::NativeLogBoxSpecJSI>(self, jsInvoker);
}
@end
#endif
Class RCTLogBoxCls(void) {
return RCTLogBox.class;
}
@@ -11,7 +11,7 @@
#import <React/RCTDefines.h>
#import <React/RCTInspectorPackagerConnection.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
@interface RCTInspectorDevServerHelper : NSObject
@@ -7,7 +7,7 @@
#import <React/RCTInspectorDevServerHelper.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
#import <React/RCTLog.h>
#import <UIKit/UIKit.h>
+1 -1
View File
@@ -9,7 +9,7 @@
#import <React/RCTDefines.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
NS_ASSUME_NONNULL_BEGIN
+1 -1
View File
@@ -21,7 +21,7 @@
#import <React/RCTReconnectingWebSocket.h>
#import <React/RCTUtils.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
#import <React/RCTSRWebSocket.h>
@@ -91,7 +91,9 @@ static ModalHostViewOnOrientationChangeStruct onOrientationChangeStruct(CGRect r
return {orientation};
}
@interface RCTModalHostViewComponentView () <RCTFabricModalHostViewControllerDelegate>
@interface RCTModalHostViewComponentView () <
RCTFabricModalHostViewControllerDelegate,
UIAdaptivePresentationControllerDelegate>
@end
@@ -110,6 +112,7 @@ static ModalHostViewOnOrientationChangeStruct onOrientationChangeStruct(CGRect r
_viewController = [RCTFabricModalHostViewController new];
_viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
_viewController.delegate = self;
_viewController.presentationController.delegate = self;
}
return self;
@@ -214,4 +217,17 @@ static ModalHostViewOnOrientationChangeStruct onOrientationChangeStruct(CGRect r
[childComponentView removeFromSuperview];
}
#pragma mark - UIAdaptivePresentationControllerDelegate
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
{
if (!_eventEmitter) {
return;
}
assert(std::dynamic_pointer_cast<ModalHostViewEventEmitter const>(_eventEmitter));
auto eventEmitter = std::static_pointer_cast<ModalHostViewEventEmitter const>(_eventEmitter);
eventEmitter->onRequestClose({});
}
@end
+1 -1
View File
@@ -7,7 +7,7 @@
#import <React/RCTInspector.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
#include <jsinspector/InspectorInterfaces.h>
@@ -8,7 +8,7 @@
#import <Foundation/Foundation.h>
#import <React/RCTDefines.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
@interface RCTBundleStatus : NSObject
@property (atomic, assign) BOOL isLastBundleDownloadSuccess;
@@ -7,7 +7,7 @@
#import <React/RCTInspectorPackagerConnection.h>
#if RCT_DEV && !TARGET_OS_UIKITFORMAC
#if RCT_DEV
#import <React/RCTDefines.h>
#import <React/RCTInspector.h>
+2 -1
View File
@@ -32,8 +32,9 @@
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;
@property (nonatomic, copy) RCTDirectEventBlock onOrientationChange;
#if TARGET_OS_TV
@property (nonatomic, copy) RCTDirectEventBlock onRequestClose;
#if TARGET_OS_TV
@property (nonatomic, strong) RCTTVRemoteHandler *tvRemoteHandler;
#endif
+15 -1
View File
@@ -20,6 +20,10 @@
#import "RCTTVRemoteHandler.h"
#endif
@interface RCTModalHostView () <UIAdaptivePresentationControllerDelegate>
@end
@implementation RCTModalHostView
{
__weak RCTBridge *_bridge;
@@ -46,6 +50,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder)
UIView *containerView = [UIView new];
containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_modalViewController.view = containerView;
_modalViewController.presentationController.delegate = self;
_touchHandler = [[RCTTouchHandler alloc] initWithBridge:bridge];
#if TARGET_OS_TV
_menuButtonGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(menuButtonPressed:)];
@@ -70,10 +75,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder)
_onRequestClose(nil);
}
}
#endif
- (void)setOnRequestClose:(RCTDirectEventBlock)onRequestClose
{
_onRequestClose = onRequestClose;
#if TARGET_OS_TV
if (_reactSubview) {
if (_onRequestClose && _menuButtonGestureRecognizer) {
[_reactSubview addGestureRecognizer:_menuButtonGestureRecognizer];
@@ -81,8 +88,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder)
[_reactSubview removeGestureRecognizer:_menuButtonGestureRecognizer];
}
}
#endif
}
#endif
- (void)notifyForBoundsChange:(CGRect)newBounds
{
@@ -257,4 +264,11 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:coder)
}
#endif
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
{
if (_onRequestClose) {
_onRequestClose(nil);
}
}
@end
-3
View File
@@ -108,9 +108,6 @@ RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(identifier, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(supportedOrientations, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock)
#if TARGET_OS_TV
RCT_EXPORT_VIEW_PROPERTY(onRequestClose, RCTDirectEventBlock)
#endif
@end
+41 -2
View File
@@ -296,7 +296,8 @@ def getNdkBuildFullPath() {
}
def buildReactNdkLib = tasks.register("buildReactNdkLib", Exec) {
dependsOn(prepareJSC, prepareHermes, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog)
dependsOn(prepareJSC, prepareHermes, prepareBoost, prepareDoubleConversion, prepareFolly, prepareGlog, extractAARHeaders, extractJNIFiles)
inputs.dir("$projectDir/../ReactCommon")
inputs.dir("src/main/jni")
inputs.dir("src/main/java/com/facebook/react/modules/blob")
@@ -344,6 +345,34 @@ def packageReactNdkLibsForBuck = tasks.register("packageReactNdkLibsForBuck", Co
into("src/main/jni/prebuilt/lib")
}
task extractAARHeaders {
doLast {
configurations.extractHeaders.files.each {
def file = it.absoluteFile
def packageName = file.name.tokenize('-')[0]
copy {
from zipTree(file)
into "$projectDir/src/main/jni/first-party/$packageName/headers"
include "**/*.h"
}
}
}
}
task extractJNIFiles {
doLast {
configurations.extractJNI.files.each {
def file = it.absoluteFile
def packageName = file.name.tokenize('-')[0]
copy {
from zipTree(file)
into "$projectDir/src/main/jni/first-party/$packageName/"
include "jni/**/*"
}
}
}
}
android {
compileSdkVersion 28
@@ -386,7 +415,8 @@ android {
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn(packageReactNdkLibs)
compileTask ->
compileTask.dependsOn(packageReactNdkLibs)
}
clean.dependsOn(cleanReactNdkLib)
@@ -394,10 +424,16 @@ android {
lintOptions {
abortOnError(false)
}
packagingOptions {
exclude("META-INF/NOTICE")
exclude("META-INF/LICENSE")
}
configurations {
extractHeaders
extractJNI
}
}
dependencies {
@@ -412,6 +448,9 @@ dependencies {
api("com.squareup.okhttp3:okhttp:${OKHTTP_VERSION}")
api("com.squareup.okhttp3:okhttp-urlconnection:${OKHTTP_VERSION}")
api("com.squareup.okio:okio:1.15.0")
api("com.facebook.fbjni:fbjni-java-only:0.0.3")
extractHeaders("com.facebook.fbjni:fbjni:0.0.2:headers")
extractJNI("com.facebook.fbjni:fbjni:0.0.2")
testImplementation("junit:junit:${JUNIT_VERSION}")
testImplementation("org.powermock:powermock-api-mockito:${POWERMOCK_VERSION}")
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_NAME=1000.0.0-master
VERSION_NAME=0.62.0-rc.2
GROUP=com.facebook.react
POM_NAME=ReactNative
+1 -1
View File
@@ -5,7 +5,7 @@ rn_android_library(
srcs = glob(["yoga/*.java"]),
visibility = ["PUBLIC"],
deps = [
react_native_dep("java/com/facebook/jni:jni"),
react_native_dep("libraries/fbjni:java"),
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
@@ -0,0 +1,31 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*
* <p>Generated by an internal genrule from Flow types.
*
* @generated
* @nolint
*/
package com.facebook.fbreact.specs;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactModuleWithSpec;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
public abstract class NativeLogBoxSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule {
public NativeLogBoxSpec(ReactApplicationContext reactContext) {
super(reactContext);
}
@ReactMethod
public abstract void hide();
@ReactMethod
public abstract void show();
}
@@ -19,7 +19,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH) $(REACT_NATIVE)/ReactCommon/jsi $(call find-no
LOCAL_CPP_FEATURES := exceptions
LOCAL_STATIC_LIBRARIES := libjsireact libjsi
LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni libhermes
LOCAL_SHARED_LIBRARIES := libfolly_json libfb libfbjni libreactnativejni libhermes
include $(BUILD_SHARED_LIBRARY)
@@ -15,7 +15,7 @@ rn_android_library(
deps = [
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
react_native_dep("java/com/facebook/jni:jni"),
react_native_dep("libraries/fbjni:java"),
":jni_hermes_samplingprofiler",
],
)
@@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
#include <fb/fbjni.h>
#include <fbjni/fbjni.h>
#include <string>
namespace facebook {
@@ -8,8 +8,7 @@
#ifndef HERMESSAMPLINGPROFILER_H_
#define HERMESSAMPLINGPROFILER_H_
#include <fb/fbjni.h>
#include <jni/Registration.h>
#include <fbjni/fbjni.h>
#include <jsi/jsi.h>
namespace facebook {
@@ -18,7 +18,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH) $(REACT_NATIVE)/ReactCommon/jsi $(call find-no
LOCAL_CPP_FEATURES := exceptions
LOCAL_STATIC_LIBRARIES := libjsireact libjsi
LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni libhermes
LOCAL_SHARED_LIBRARIES := libfolly_json libfb libfbjni libreactnativejni libhermes
include $(BUILD_SHARED_LIBRARY)
@@ -35,6 +35,6 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH) $(REACT_NATIVE)/ReactCommon/jsi $(call find-no
LOCAL_CPP_FEATURES := exceptions
LOCAL_STATIC_LIBRARIES := libjsireact libjsi libhermes-inspector
LOCAL_SHARED_LIBRARIES := libfolly_json libfb libreactnativejni libhermes
LOCAL_SHARED_LIBRARIES := libfolly_json libfb libfbjni libreactnativejni libhermes
include $(BUILD_SHARED_LIBRARY)
@@ -7,7 +7,7 @@
#include <../instrumentation/HermesMemoryDumper.h>
#include <HermesExecutorFactory.h>
#include <fb/fbjni.h>
#include <fbjni/fbjni.h>
#include <hermes/Public/GCConfig.h>
#include <hermes/Public/RuntimeConfig.h>
#include <jni.h>
@@ -1,16 +0,0 @@
load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "rn_android_library")
rn_android_library(
name = "jni",
srcs = glob(["**/*.java"]),
proguard_config = "fbjni.pro",
visibility = [
"PUBLIC",
],
deps = [
react_native_dep("third-party/android/androidx:annotation"),
react_native_dep("java/com/facebook/proguard/annotations:annotations"),
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
],
)
@@ -1,39 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.jni;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.soloader.SoLoader;
/**
* A Java Object that has native memory allocated corresponding to this instance.
*
* <p>NB: THREAD SAFETY (this comment also exists at Countable.cpp)
*
* <p>{@link #dispose} deletes the corresponding native object on whatever thread the method is
* called on. In the common case when this is called by Countable#finalize(), this will be called on
* the system finalizer thread. If you manually call dispose on the Java object, the native object
* will be deleted synchronously on that thread.
*/
@DoNotStrip
public class Countable {
static {
SoLoader.loadLibrary("fb");
}
// Private C++ instance
@DoNotStrip private long mInstance = 0;
public native void dispose();
protected void finalize() throws Throwable {
dispose();
super.finalize();
}
}
@@ -1,29 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.jni;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.soloader.SoLoader;
/** Utility class to determine CPU capabilities */
@DoNotStrip
public class CpuCapabilitiesJni {
static {
SoLoader.loadLibrary("fb");
}
@DoNotStrip
public static native boolean nativeDeviceSupportsNeon();
@DoNotStrip
public static native boolean nativeDeviceSupportsVFPFP16();
@DoNotStrip
public static native boolean nativeDeviceSupportsX86();
}
@@ -1,139 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.jni;
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.atomic.AtomicReference;
/**
* A thread which invokes the "destruct" routine for objects after they have been garbage collected.
*
* <p>An object which needs to be destructed should create a static subclass of {@link Destructor}.
* Once the referent object is garbage collected, the DestructorThread will callback to the {@link
* Destructor#destruct()} method.
*
* <p>The underlying thread in DestructorThread starts when the first Destructor is constructed and
* then runs indefinitely.
*/
public class DestructorThread {
/**
* N.B The Destructor <b>SHOULD NOT</b> refer back to its referent object either explicitly or
* implicitly (for example, as a non-static inner class). This will create a reference cycle where
* the referent object will never be garbage collected.
*/
public abstract static class Destructor extends PhantomReference<Object> {
private Destructor next;
private Destructor previous;
public Destructor(Object referent) {
super(referent, sReferenceQueue);
sDestructorStack.push(this);
}
private Destructor() {
super(null, sReferenceQueue);
}
/** Callback which is invoked when the original object has been garbage collected. */
protected abstract void destruct();
}
/** A list to keep all active Destructors in memory confined to the Destructor thread. */
private static DestructorList sDestructorList;
/** A thread safe stack where new Destructors are placed before being add to sDestructorList. */
private static DestructorStack sDestructorStack;
private static ReferenceQueue sReferenceQueue;
private static Thread sThread;
static {
sDestructorStack = new DestructorStack();
sReferenceQueue = new ReferenceQueue();
sDestructorList = new DestructorList();
sThread =
new Thread("HybridData DestructorThread") {
@Override
public void run() {
while (true) {
try {
Destructor current = (Destructor) sReferenceQueue.remove();
current.destruct();
// If current is in the sDestructorStack,
// transfer all the Destructors in the stack to the list.
if (current.previous == null) {
sDestructorStack.transferAllToList();
}
DestructorList.drop(current);
} catch (InterruptedException e) {
// Continue. This thread should never be terminated.
}
}
}
};
sThread.start();
}
private static class Terminus extends Destructor {
@Override
protected void destruct() {
throw new IllegalStateException("Cannot destroy Terminus Destructor.");
}
}
/** This is a thread safe, lock-free Treiber-like Stack of Destructors. */
private static class DestructorStack {
private AtomicReference<Destructor> mHead = new AtomicReference<>();
public void push(Destructor newHead) {
Destructor oldHead;
do {
oldHead = mHead.get();
newHead.next = oldHead;
} while (!mHead.compareAndSet(oldHead, newHead));
}
public void transferAllToList() {
Destructor current = mHead.getAndSet(null);
while (current != null) {
Destructor next = current.next;
sDestructorList.enqueue(current);
current = next;
}
}
}
/** A doubly-linked list of Destructors. */
private static class DestructorList {
private Destructor mHead;
public DestructorList() {
mHead = new Terminus();
mHead.next = new Terminus();
mHead.next.previous = mHead;
}
public void enqueue(Destructor current) {
current.next = mHead.next;
mHead.next = current;
current.next.previous = current;
current.previous = mHead;
}
private static void drop(Destructor current) {
current.next.previous = current.previous;
current.previous.next = current.next;
}
}
}
@@ -1,13 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.jni;
import com.facebook.proguard.annotations.DoNotStrip;
@DoNotStrip
public abstract class HybridClassBase extends HybridData {}
@@ -1,78 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.jni;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.soloader.SoLoader;
/**
* This object holds a native C++ member for hybrid Java/C++ objects.
*
* <p>NB: THREAD SAFETY
*
* <p>{@link #resetNative} deletes the corresponding native object synchronously on whatever thread
* the method is called on. Otherwise, deletion will occur on the {@link DestructorThread} thread.
*/
@DoNotStrip
public class HybridData {
static {
SoLoader.loadLibrary("fb");
}
@DoNotStrip private Destructor mDestructor = new Destructor(this);
/**
* To explicitly delete the instance, call resetNative(). If the C++ instance is referenced after
* this is called, a NullPointerException will be thrown. resetNative() may be called multiple
* times safely. Because the {@link DestructorThread} also calls resetNative, the instance will
* not leak if this is not called, but timing of deletion and the thread the C++ dtor is called on
* will be at the whim of the Java GC. If you want to control the thread and timing of the
* destructor, you should call resetNative() explicitly.
*/
public synchronized void resetNative() {
mDestructor.destruct();
}
/**
* N.B. Thread safety. If you call isValid from a different thread than {@link #resetNative()}
* then be sure to do so while synchronizing on the hybrid. For example:
*
* <pre><code>
* synchronized(hybrid) {
* if (hybrid.isValid) {
* // Do stuff.
* }
* }
* </code></pre>
*/
public boolean isValid() {
return mDestructor.mNativePointer != 0;
}
public static class Destructor extends DestructorThread.Destructor {
// Private C++ instance
@DoNotStrip private long mNativePointer;
Destructor(Object referent) {
super(referent);
}
@Override
protected final void destruct() {
// When invoked from the DestructorThread instead of resetNative,
// the DestructorThread has exclusive ownership of the HybridData
// so synchronization is not necessary.
deleteNative(mNativePointer);
mNativePointer = 0;
}
static native void deleteNative(long pointer);
}
}

Some files were not shown because too many files have changed in this diff Show More