diff --git a/android/app/build.gradle b/android/app/build.gradle index 11077127e8b..c158636eecc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -240,7 +240,7 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) //noinspection GradleDynamicVersion - implementation "com.facebook.react:react-native:+" // From node_modules + implementation project(':ReactAndroid') implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" diff --git a/android/build.gradle b/android/build.gradle index 478a605ac32..3b6819cfd59 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -13,13 +13,16 @@ buildscript { // but some testing is required and code changes are often required. // See upstream for background and more discussion: // https://medium.com/androiddevelopers/picking-your-compilesdkversion-minsdkversion-targetsdkversion-a098a0341ebd - targetSdkVersion = 33 + targetSdkVersion = 34 // Should be the latest SDK version available. See upstream recommendation: // https://medium.com/androiddevelopers/picking-your-compilesdkversion-minsdkversion-targetsdkversion-a098a0341ebd // What's the latest? Consult this list: // https://developer.android.com/studio/releases/platforms compileSdkVersion = 34 + + // Latest NDK 24, for Apple Silicon compatibility. + ndkVersion = "24.0.8215888" } repositories { google() @@ -61,6 +64,15 @@ allprojects { mavenCentral() google() } + + configurations.all { + resolutionStrategy { + dependencySubstitution { + // Make our dependencies look at our RN fork built from source. + substitute module("com.facebook.react:react-native:+") with project(":ReactAndroid") + } + } + } } subprojects { diff --git a/android/gradle.properties b/android/gradle.properties index d4e0f20d1e3..962d341038e 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -13,7 +13,7 @@ # -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Xms256m -Xmx512m # We allow more space (no MaxMetaspaceSize; bigger -Xmx), # and don't litter heap dumps if that still proves insufficient. -org.gradle.jvmargs=-Xms256m -Xmx1280m +org.gradle.jvmargs=-Xms256m -Xmx2048m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/android/settings.gradle b/android/settings.gradle index a9a7399319d..e85003cfe91 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,3 +1,11 @@ +pluginManagement { + repositories { + gradlePluginPortal() + mavenLocal() + google() + } +} + rootProject.name = 'ZulipMobile' apply from: '../node_modules/expo/scripts/autolinking.gradle' @@ -7,3 +15,11 @@ apply from: file("../node_modules/@react-native-community/cli-platform-android/n applyNativeModulesSettingsGradle(settings) include ':app' + +include ':ReactAndroid' +project(':ReactAndroid').projectDir = new File( + rootProject.projectDir, '../node_modules/react-native/ReactAndroid') + +// The RN Gradle Plugin is needed to build RN from source. +// (We do that to make some changes to RN, with our zulip/react-native fork.) +includeBuild('../node_modules/react-native/packages/react-native-gradle-plugin') diff --git a/docs/howto/forked-rn.md b/docs/howto/forked-rn.md new file mode 100644 index 00000000000..0f57fce9134 --- /dev/null +++ b/docs/howto/forked-rn.md @@ -0,0 +1,24 @@ +# Using a `react-native` with cherry-picked or custom changes + +Since 2024-09, we use a fork of `react-native` to make changes +atop 0.68.7. We prefer to avoid upgrading to later `react-native` +releases because it's laborious and we're eager to retire this +codebase and transition to `zulip-flutter`. + +When there's an issue in React Native that calls for changes in +React Native: + +- Push those changes to our RN fork, `zulip/react-native`, + on the `0.68.7-zulip` branch. + +- Update the `package.json`: + + ```json + "react-native": "zulip/react-native#", + ``` + +- Run `yarn`. + +When building for Android, it will take longer the first time because +React Native is built from source. (`react-native` releases on NPM, +which we've been using until recently, come with a pre-built binary.) diff --git a/docs/howto/rn-from-git.md b/docs/howto/rn-from-git.md deleted file mode 100644 index 40632d00387..00000000000 --- a/docs/howto/rn-from-git.md +++ /dev/null @@ -1,190 +0,0 @@ -# Using a React Native version from Git - -When there's an issue in React Native, or some behavior in it that requires -investigation, it can be helpful to use a version of RN from your own Git -clone which you can make changes to. - -This guide describes how to use an RN version from Git in a small test app, -which is helpful for reporting and investigating issues upstream. Doing so -for Zulip Mobile itself will be another subject. - -## iOS - -No data. It would be good for someone to work out how to do this on iOS -and fill in this section. - -## Android - -There is [an upstream -doc](https://reactnative.dev/docs/building-from-source) -for this. Ideally it would make these instructions unnecessary, but it's -not very clear or complete. - -Instead, try following these instructions. We'll refer to sections of that -doc for specific things where it's helpful. - -There are a lot of gotchas in this process, and the error messages they -produce tend to be cryptic. See the "Troubleshooting" section below. -Please add to it with any additional issues you run into and their solutions. - -**NOTE**: Although these instructions were tested and debugged when -new, on RN 0.55; they haven't been updated for newer RN versions and -will need some changes. - -### One-time (per-machine) setup - -1. You'll need the Android SDK. You already have this if you've - successfully set up a Zulip Mobile dev environment and built the app for - Android. - -2. You'll need the Android NDK, the "native development kit". Don't follow - the standard Android instructions for this; those will get you a current - version, and React Native requires a specific old version, namely release - 10e, which is from 2015. (NB: This is one thing that changed in RN - 0.57; this was updated to NDK r17b, the latest.) - - * Instead, download the appropriate zip file [linked - here](https://reactnative.dev/docs/building-from-source#download-links-for-android-ndk) - and unzip it somewhere convenient. - - * If your Android SDK is at `~/Android/Sdk`, you might put the NDK at - `~/Android/Sdk/ndk-r10e`. The location doesn't matter; you'll just - need to set it as `ndk.dir` below. - - * Note: The NDK is 3.7 GB in size, and the zip file is 1.2 GB. Make sure - you have enough free disk space first. - -### Per-project setup - -1. Create the test app, if you don't have one already. You'll want - `react-native init`; not `create-react-native-app`, which creates an Expo - app. Expo is an extra layer that makes this more complicated. - -2. Remove `node_modules/react-native/`, and replace it with a Git clone. - Optionally, if you already have another clone somewhere of the RN repo, - you can mention it to the `git clone` command with `--reference` to save - some disk space. - -3. Optionally, make Git in the app track your RN clone as a "submodule". - - a. In `.gitignore` for the app, replace the line `node_modules/` with - these two lines, to make Git stop ignoring the clone's path: - - node_modules/* - !node_modules/react-native/ - - b. Run `git submodule add git@github.com:facebook/react-native node_modules/react-native`. - - c. Commit the result. - -4. Follow the various steps in [this - doc](https://reactnative.dev/docs/building-from-source#building-the-source) - that involve tweaking several Gradle files located under `android/` in - the app. Commit the result. - -5. Optionally, you might upgrade the versions of Gradle in - `android/gradle/wrapper/gradle-wrapper.properties` and of the Android - Gradle Plugin in `android/build.gradle`. If you do, you'll also want to - add `google()` in both `repositories` blocks in `android/build.gradle`. - This upgrade isn't necessary, though, and may not be helpful. - -6. Create or edit the file `android/local.properties` in your app worktree - (it's ignored and you won't commit it, because it's configuration that's - local to your machine), with two settings: - - * `sdk.dir` is just like in the same file in your Zulip Mobile worktree. - - * `ndk.dir` is the directory you unzipped the Android NDK as, above. - -### Build and run - -Now `tools/run-android` in your app should work! - -And if you `cd node_modules/react-native`, then check out a different -version or make an edit, and `cd` back, then `tools/run-android` -should again work and use the new version. - -### Troubleshooting - -#### `react-native start` aborts - -You might see a failure like this: - -``` -$ react-native start -Scanning folders for symlinks in /home/greg/z/tmp/rn-textinput/node_modules (15ms) - -Cannot read property 'length' of undefined - -$ -``` - -where `react-native start` promptly aborts and doesn't serve the app. - -The cause is unknown. This seems to happen on some RN versions but not -others -- in particular, it happens on v0.54.4, and on some early versions -after the 0.54 branch, but later versions leading up to v0.55 work fine. - -It'd be good to determine exactly what version fixes it; that should help -find a way to fix it for older versions. - -#### Build failure about `registerGeneratedResFolders` - -When trying to build the app, you might see a failure like this: - -``` -Building and installing the app on the device (cd android && ./gradlew installDebug)... -Incremental java compilation is an incubating feature. - -FAILURE: Build failed with an exception. - -* Where: -Script '/home/greg/z/tmp/rn-textinput/node_modules/react-native/react.gradle' line: 82 - -* What went wrong: -Could not find method registerGeneratedResFolders() for arguments [file collection] on object of type com.android.build.gradle.internal.api.ApplicationVariantImpl. -``` - -This was a regression in one commit between v0.54 and v0.55, fixed in a -later commit in that range. It affects older Gradle and/or Android Gradle -Plugin versions, including the default versions used by `react-native init`. - -You can fix it by cherry-picking that revert onto whatever RN version you're -trying to build from: `git cherry-pick 3f8a04ba6`. - -#### Build failure about `fbjni` - -When trying to build the app, you might see a failure like this: - -``` -make: Entering directory `/home/greg/z/tmp/rn-textinput/node_modules/react-native/ReactAndroid/src/main/jni/react/jni' -/home/greg/Android/Sdk/ndk-bundle/build/core/build-binary.mk:688: Android NDK: Module reactnativejni depends on undefined modules: fbjni -make: Leaving directory `/home/greg/z/tmp/rn-textinput/node_modules/react-native/ReactAndroid/src/main/jni/react/jni' -/home/greg/Android/Sdk/ndk-bundle/build/core/build-binary.mk:701: *** Android NDK: Aborting (set APP_ALLOW_MISSING_DEPS=true to allow missing dependencies) . Stop. - - -FAILURE: Build failed with an exception. - -* What went wrong: -Execution failed for task ':ReactAndroid:buildReactNdkLib'. -> Process 'command '/home/greg/Android/Sdk/ndk-bundle/ndk-build'' finished with non-zero exit value 2 -``` - -This happens when trying to build with a current NDK, at least with release -17 (the latest as of mid-2018). You need release 10e; see above. - -#### Could not find lint-gradle - -When trying to build the app, you might see a failure like this: - -``` -FAILURE: Build failed with an exception. - -* What went wrong: -Could not resolve all files for configuration ':ReactAndroid:lintClassPath'. -> Could not find com.android.tools.lint:lint-gradle:26.1.3. -``` - -This seems probably caused by upgrading the Android Gradle Plugin. It's -fixed by adding `google()` in `allprojects` -> `repositories` in -`android/build.gradle`. diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5926f2d82ad..657223164ab 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -599,7 +599,7 @@ SPEC CHECKSUMS: EXScreenOrientation: e3c072fb0add472a3037482ea43ccbade9b88a25 EXSQLite: 2b9accd925438293f9f39e0a57a08cca13bdffb2 FBLazyVector: 63b89dc85804d5817261f56dc4cfb43a9b6d57f5 - FBReactNativeSpec: 1fa200a9862d9369a53b6fddbbfcdc22bab24062 + FBReactNativeSpec: de66c1e28c6823a30a53b51dd933560edb24ed3f fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 476ee3e89abb49e07f822b48323c51c57124b572 RCT-Folly: 4d8508a426467c48885f1151029bc15fa5d7b3b8 diff --git a/package.json b/package.json index c05cf720ee2..548db2cc359 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "lodash.uniq": "^4.5.0", "react": "17.0.2", "react-intl": "5.24.6", - "react-native": "0.68.7", + "react-native": "zulip/react-native#b7b2f6c22", "react-native-document-picker": "^8.1.3", "react-native-gesture-handler": "^2.8.0", "react-native-image-picker": "^5.3.1", diff --git a/patches/react-native+0.68.7.patch b/patches/react-native+0.68.7.patch deleted file mode 100644 index fe4cc5f9760..00000000000 --- a/patches/react-native+0.68.7.patch +++ /dev/null @@ -1,102 +0,0 @@ -diff --git a/node_modules/react-native/jest/setup.js b/node_modules/react-native/jest/setup.js -index 5bc654475..e61bbf49c 100644 ---- a/node_modules/react-native/jest/setup.js -+++ b/node_modules/react-native/jest/setup.js -@@ -15,22 +15,52 @@ const mockComponent = jest.requireActual('./mockComponent'); - jest.requireActual('@react-native/polyfills/Object.es8'); - jest.requireActual('@react-native/polyfills/error-guard'); - --global.__DEV__ = true; -- --global.performance = { -- now: jest.fn(Date.now), --}; -- --global.Promise = jest.requireActual('promise'); --global.regeneratorRuntime = jest.requireActual('regenerator-runtime/runtime'); --global.window = global; -- --global.requestAnimationFrame = function (callback) { -- return setTimeout(callback, 0); --}; --global.cancelAnimationFrame = function (id) { -- clearTimeout(id); --}; -+Object.defineProperties(global, { -+ __DEV__: { -+ configurable: true, -+ enumerable: true, -+ value: true, -+ writable: true, -+ }, -+ Promise: { -+ configurable: true, -+ enumerable: true, -+ value: jest.requireActual('promise'), -+ writable: true, -+ }, -+ cancelAnimationFrame: { -+ configurable: true, -+ enumerable: true, -+ value: id => clearTimeout(id), -+ writable: true, -+ }, -+ performance: { -+ configurable: true, -+ enumerable: true, -+ value: { -+ now: jest.fn(Date.now), -+ }, -+ writable: true, -+ }, -+ regeneratorRuntime: { -+ configurable: true, -+ enumerable: true, -+ value: jest.requireActual('regenerator-runtime/runtime'), -+ writable: true, -+ }, -+ requestAnimationFrame: { -+ configurable: true, -+ enumerable: true, -+ value: callback => setTimeout(callback, 0), -+ writable: true, -+ }, -+ window: { -+ configurable: true, -+ enumerable: true, -+ value: global, -+ writable: true, -+ }, -+}); - - // there's a __mock__ for it. - jest.setMock( -diff --git a/node_modules/react-native/scripts/react_native_pods.rb b/node_modules/react-native/scripts/react_native_pods.rb -index f2ceeda..c618f77 100644 ---- a/node_modules/react-native/scripts/react_native_pods.rb -+++ b/node_modules/react-native/scripts/react_native_pods.rb -@@ -254,6 +254,7 @@ def react_native_post_install(installer) - cpp_flags = NEW_ARCH_OTHER_CPLUSPLUSFLAGS - end - modify_flags_for_new_architecture(installer, cpp_flags) -+ apply_xcode_15_patch(installer) - - end - -@@ -661,3 +662,16 @@ def __apply_Xcode_12_5_M1_post_install_workaround(installer) - time_header = "#{Pod::Config.instance.installation_root.to_s}/Pods/RCT-Folly/folly/portability/Time.h" - `sed -i -e $'s/ && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)//' #{time_header}` - end -+ -+# Fix to build react native on Xcode 15 beta 1 -+def apply_xcode_15_patch(installer) -+ installer.target_installation_results.pod_target_installation_results -+ .each do |pod_name, target_installation_result| -+ target_installation_result.native_target.build_configurations.each do |config| -+ # unary_function and binary_function are no longer provided in C++17 and newer standard modes as part of Xcode 15. They can be re-enabled with setting _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION -+ # Ref: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes#Deprecations -+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= '$(inherited) ' -+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << '"_LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION" ' -+ end -+ end -+end diff --git a/yarn.lock b/yarn.lock index 6acdc98ba8e..60677171a9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10850,10 +10850,9 @@ react-native-webview@^11.6.4: escape-string-regexp "2.0.0" invariant "2.2.4" -react-native@0.68.7: +react-native@zulip/react-native#b7b2f6c22: version "0.68.7" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.68.7.tgz#9b179f909ac8640e369957696f98070ddf7c32e7" - integrity sha512-t7XvcwKyXhN9vR8GfgLUyEYYccwI390pG7debFSGns/5Vb0+/ZiGuSmVZGLNt1NVc3UH2zI2GGkDdSJR8Locig== + resolved "https://codeload.github.com/zulip/react-native/tar.gz/b7b2f6c229b80467fcb68986207a006d09c53ee0" dependencies: "@jest/create-cache-key-function" "^27.0.1" "@react-native-community/cli" "^7.0.3"