diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index 14acfc78de..05a8f9718c 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 - uses: actions/cache@v3 id: cache with: diff --git a/sample-new-architecture/.buckconfig b/sample-new-architecture/.buckconfig deleted file mode 100644 index 934256cb29..0000000000 --- a/sample-new-architecture/.buckconfig +++ /dev/null @@ -1,6 +0,0 @@ - -[android] - target = Google Inc.:Google APIs:23 - -[maven_repositories] - central = https://repo1.maven.org/maven2 diff --git a/sample-new-architecture/.gitignore b/sample-new-architecture/.gitignore index 2423126f72..16f8c30773 100644 --- a/sample-new-architecture/.gitignore +++ b/sample-new-architecture/.gitignore @@ -31,6 +31,8 @@ local.properties *.iml *.hprof .cxx/ +*.keystore +!debug.keystore # node.js # @@ -38,12 +40,6 @@ node_modules/ npm-debug.log yarn-error.log -# BUCK -buck-out/ -\.buckd/ -*.keystore -!debug.keystore - # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the @@ -62,3 +58,6 @@ buck-out/ # Ruby / CocoaPods /ios/Pods/ /vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* diff --git a/sample-new-architecture/Gemfile b/sample-new-architecture/Gemfile index 99d5919539..3a766de9c0 100644 --- a/sample-new-architecture/Gemfile +++ b/sample-new-architecture/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version -ruby '2.7.6' +ruby File.read(File.join(__dir__, '_ruby-version')).strip -gem 'cocoapods', '~> 1.11', '>= 1.11.2' +gem 'cocoapods', '~> 1.11', '>= 1.11.3' diff --git a/sample-new-architecture/__tests__/App-test.tsx b/sample-new-architecture/__tests__/App-test.tsx index 827cbb6696..b71837e8ef 100644 --- a/sample-new-architecture/__tests__/App-test.tsx +++ b/sample-new-architecture/__tests__/App-test.tsx @@ -9,5 +9,5 @@ import React from 'react'; import renderer from 'react-test-renderer'; it('dummy test', () => { - renderer.create(
); + renderer.create(
); }); diff --git a/sample-new-architecture/android/app/_BUCK b/sample-new-architecture/android/app/_BUCK deleted file mode 100644 index bb06f87121..0000000000 --- a/sample-new-architecture/android/app/_BUCK +++ /dev/null @@ -1,55 +0,0 @@ -# To learn about Buck see [Docs](https://buckbuild.com/). -# To run your application with Buck: -# - install Buck -# - `npm start` - to start the packager -# - `cd android` -# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` -# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck -# - `buck install -r android/app` - compile, install and run application -# - -load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") - -lib_deps = [] - -create_aar_targets(glob(["libs/*.aar"])) - -create_jar_targets(glob(["libs/*.jar"])) - -android_library( - name = "all-libs", - exported_deps = lib_deps, -) - -android_library( - name = "app-code", - srcs = glob([ - "src/main/java/**/*.java", - ]), - deps = [ - ":all-libs", - ":build_config", - ":res", - ], -) - -android_build_config( - name = "build_config", - package = "com.samplenewarchitecture", -) - -android_resource( - name = "res", - package = "com.samplenewarchitecture", - res = "src/main/res", -) - -android_binary( - name = "app", - keystore = "//android/keystores:debug", - manifest = "src/main/AndroidManifest.xml", - package_type = "debug", - deps = [ - ":app-code", - ], -) diff --git a/sample-new-architecture/android/app/build.gradle b/sample-new-architecture/android/app/build.gradle index df04a2c7ea..0b37d64a8e 100644 --- a/sample-new-architecture/android/app/build.gradle +++ b/sample-new-architecture/android/app/build.gradle @@ -1,86 +1,49 @@ apply plugin: "com.android.application" +apply plugin: "com.facebook.react" import com.android.build.OutputFile -import org.apache.tools.ant.taskdefs.condition.Os -/** - * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets - * and bundleReleaseJsAndAssets). - * These basically call `react-native bundle` with the correct arguments during the Android build - * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the - * bundle directly from the development server. Below you can see all the possible configurations - * and their defaults. If you decide to add a configuration block, make sure to add it before the - * `apply from: "../../node_modules/react-native/react.gradle"` line. - * - * project.ext.react = [ - * // the name of the generated asset file containing your JS bundle - * bundleAssetName: "index.android.bundle", - * - * // the entry file for bundle generation. If none specified and - * // "index.android.js" exists, it will be used. Otherwise "index.js" is - * // default. Can be overridden with ENTRY_FILE environment variable. - * entryFile: "index.android.js", - * - * // https://reactnative.dev/docs/performance#enable-the-ram-format - * bundleCommand: "ram-bundle", - * - * // whether to bundle JS and assets in debug mode - * bundleInDebug: false, - * - * // whether to bundle JS and assets in release mode - * bundleInRelease: true, - * - * // whether to bundle JS and assets in another build variant (if configured). - * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants - * // The configuration property can be in the following formats - * // 'bundleIn${productFlavor}${buildType}' - * // 'bundleIn${buildType}' - * // bundleInFreeDebug: true, - * // bundleInPaidRelease: true, - * // bundleInBeta: true, - * - * // whether to disable dev mode in custom build variants (by default only disabled in release) - * // for example: to disable dev mode in the staging build type (if configured) - * devDisabledInStaging: true, - * // The configuration property can be in the following formats - * // 'devDisabledIn${productFlavor}${buildType}' - * // 'devDisabledIn${buildType}' - * - * // the root of your project, i.e. where "package.json" lives - * root: "../../", - * - * // where to put the JS bundle asset in debug mode - * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", - * - * // where to put the JS bundle asset in release mode - * jsBundleDirRelease: "$buildDir/intermediates/assets/release", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in debug mode - * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", - * - * // where to put drawable resources / React Native assets, e.g. the ones you use via - * // require('./image.png')), in release mode - * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", - * - * // by default the gradle tasks are skipped if none of the JS files or assets change; this means - * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to - * // date; if you have any other folders that you want to ignore for performance reasons (gradle - * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ - * // for example, you might want to remove it from here. - * inputExcludes: ["android/**", "ios/**"], - * - * // override which node gets called and with what additional arguments - * nodeExecutableAndArgs: ["node"], - * - * // supply additional arguments to the packager - * extraPackagerArgs: [] - * ] - */ - -project.ext.react = [ - enableHermes: true, // clean and rebuild if changing -] +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen + // codegenDir = file("../node_modules/react-native-codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} project.ext.sentryCli = [ collectModulesScript: "../../../dist/js/tools/collectModules.js", @@ -91,21 +54,18 @@ project.ext.sentryCli = [ skipCollectModules: false, ] -apply from: "../../node_modules/react-native/react.gradle" apply from: "../../../sentry.gradle" /** - * Set this to true to create two separate APKs instead of one: - * - An APK that only works on ARM devices - * - An APK that only works on x86 devices - * The advantage is the size of the APK is reduced by about 4MB. - * Upload all the APKs to the Play Store and people will download - * the correct one based on the CPU architecture of their device. + * Set this to true to create four separate APKs instead of one, + * one for each native architecture. This is useful if you don't + * use App Bundles (https://developer.android.com/guide/app-bundle/) + * and want to have separate APKs to upload to the Play Store. */ def enableSeparateBuildPerCPUArchitecture = false /** - * Run Proguard to shrink the Java bytecode in release builds. + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ def enableProguardInReleaseBuilds = false @@ -122,15 +82,6 @@ def enableProguardInReleaseBuilds = false */ def jscFlavor = 'org.webkit:android-jsc:+' -/** - * Whether to enable the Hermes VM. - * - * This should be set on project.ext.react and that value will be read here. If it is not set - * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode - * and the benefits of using Hermes will therefore be sharply reduced. - */ -def enableHermes = project.ext.react.get("enableHermes", false); - /** * Architectures to build native code for. */ @@ -144,72 +95,13 @@ android { compileSdkVersion rootProject.ext.compileSdkVersion + namespace "com.samplenewarchitecture" defaultConfig { applicationId "com.samplenewarchitecture" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" - buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() - - if (isNewArchitectureEnabled()) { - // We configure the CMake build only if you decide to opt-in for the New Architecture. - externalNativeBuild { - cmake { - arguments "-DPROJECT_BUILD_DIR=$buildDir", - "-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid", - "-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build", - "-DNODE_MODULES_DIR=$rootDir/../node_modules", - "-DANDROID_STL=c++_shared" - } - } - if (!enableSeparateBuildPerCPUArchitecture) { - ndk { - abiFilters (*reactNativeArchitectures()) - } - } - } - } - - if (isNewArchitectureEnabled()) { - // We configure the NDK build only if you decide to opt-in for the New Architecture. - externalNativeBuild { - cmake { - path "$projectDir/src/main/jni/CMakeLists.txt" - } - } - def reactAndroidProjectDir = project(':ReactAndroid').projectDir - def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) { - dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck") - from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") - into("$buildDir/react-ndk/exported") - } - def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) { - dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck") - from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib") - into("$buildDir/react-ndk/exported") - } - afterEvaluate { - // If you wish to add a custom TurboModule or component locally, - // you should uncomment this line. - // preBuild.dependsOn("generateCodegenArtifactsFromSchema") - preDebugBuild.dependsOn(packageReactNdkDebugLibs) - preReleaseBuild.dependsOn(packageReactNdkReleaseLibs) - - // Due to a bug inside AGP, we have to explicitly set a dependency - // between configureCMakeDebug* tasks and the preBuild tasks. - // This can be removed once this is solved: https://issuetracker.google.com/issues/207403732 - configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild) - configureCMakeDebug.dependsOn(preDebugBuild) - reactNativeArchitectures().each { architecture -> - tasks.findByName("configureCMakeDebug[${architecture}]")?.configure { - dependsOn("preDebugBuild") - } - tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure { - dependsOn("preReleaseBuild") - } - } - } } splits { @@ -241,15 +133,6 @@ android { } } - sourceSets.main { - java { - // RNSentry. - srcDirs += [ - "../../android/app/src/main", - ] - } - } - // applicationVariants are e.g. debug, release applicationVariants.all { variant -> variant.outputs.each { output -> @@ -265,69 +148,35 @@ android { } } + + } dependencies { - implementation fileTree(dir: "libs", include: ["*.jar"]) - - //noinspection GradleDynamicVersion - implementation "com.facebook.react:react-native:+" // From node_modules + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" - implementation project(path: ':sentry_react-native') - - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { - exclude group:'com.facebook.fbjni' - } + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.facebook.flipper' exclude group:'com.squareup.okhttp3', module:'okhttp' } + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { - exclude group:'com.facebook.flipper' - } - - if (enableHermes) { - //noinspection GradleDynamicVersion - implementation("com.facebook.react:hermes-engine:+") { // From node_modules - exclude group:'com.facebook.fbjni' - } + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") } else { implementation jscFlavor } } -if (isNewArchitectureEnabled()) { - // If new architecture is enabled, we let you build RN from source - // Otherwise we fallback to a prebuilt .aar bundled in the NPM package. - // This will be applied to all the imported transtitive dependency. - configurations.all { - resolutionStrategy.dependencySubstitution { - substitute(module("com.facebook.react:react-native")) - .using(project(":ReactAndroid")) - .because("On New Architecture we're building React Native from source") - substitute(module("com.facebook.react:hermes-engine")) - .using(project(":ReactAndroid:hermes-engine")) - .because("On New Architecture we're building Hermes from source") - } - } -} - -// Run this once to be able to run the application with BUCK -// puts all compile dependencies into folder libs for BUCK to use -task copyDownloadableDepsToLibs(type: Copy) { - from configurations.implementation - into 'libs' -} - apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) -def isNewArchitectureEnabled() { - // To opt-in for the New Architecture, you can either: - // - Set `newArchEnabled` to true inside the `gradle.properties` file - // - Invoke gradle with `-newArchEnabled=true` - // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` - return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +android { + externalNativeBuild { + cmake { + path "src/main/jni/CMakeLists.txt" + } + } } diff --git a/sample-new-architecture/android/app/build_defs.bzl b/sample-new-architecture/android/app/build_defs.bzl deleted file mode 100644 index fff270f8d1..0000000000 --- a/sample-new-architecture/android/app/build_defs.bzl +++ /dev/null @@ -1,19 +0,0 @@ -"""Helper definitions to glob .aar and .jar targets""" - -def create_aar_targets(aarfiles): - for aarfile in aarfiles: - name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] - lib_deps.append(":" + name) - android_prebuilt_aar( - name = name, - aar = aarfile, - ) - -def create_jar_targets(jarfiles): - for jarfile in jarfiles: - name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] - lib_deps.append(":" + name) - prebuilt_jar( - name = name, - binary_jar = jarfile, - ) diff --git a/sample-new-architecture/android/app/src/debug/java/com/samplenewarchitecture/ReactNativeFlipper.java b/sample-new-architecture/android/app/src/debug/java/com/samplenewarchitecture/ReactNativeFlipper.java index 64df06e65b..0d9fb8a02a 100644 --- a/sample-new-architecture/android/app/src/debug/java/com/samplenewarchitecture/ReactNativeFlipper.java +++ b/sample-new-architecture/android/app/src/debug/java/com/samplenewarchitecture/ReactNativeFlipper.java @@ -17,7 +17,6 @@ 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.ReactInstanceEventListener; import com.facebook.react.ReactInstanceManager; @@ -25,13 +24,16 @@ import com.facebook.react.modules.network.NetworkingModule; import okhttp3.OkHttpClient; +/** + * Class responsible of loading Flipper inside your React Native application. This is the debug + * flavor of it. Here you can add your own plugins and customize the Flipper setup. + */ 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()); diff --git a/sample-new-architecture/android/app/src/main/AndroidManifest.xml b/sample-new-architecture/android/app/src/main/AndroidManifest.xml index ba9f274480..4122f36a59 100644 --- a/sample-new-architecture/android/app/src/main/AndroidManifest.xml +++ b/sample-new-architecture/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainActivity.java b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainActivity.java index d8e9f2895f..906ed3cd6a 100644 --- a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainActivity.java +++ b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainActivity.java @@ -3,7 +3,8 @@ import android.os.Bundle; import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; -import com.facebook.react.ReactRootView; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactActivityDelegate; public class MainActivity extends ReactActivity { @@ -17,34 +18,20 @@ protected String getMainComponentName() { } /** - * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and - * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer - * (Paper). + * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link + * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. */ @Override protected ReactActivityDelegate createReactActivityDelegate() { - return new MainActivityDelegate(this, getMainComponentName()); - } - - public static class MainActivityDelegate extends ReactActivityDelegate { - public MainActivityDelegate(ReactActivity activity, String mainComponentName) { - super(activity, mainComponentName); - } - - @Override - protected ReactRootView createRootView() { - ReactRootView reactRootView = new ReactRootView(getContext()); - // If you opted-in for the New Architecture, we enable the Fabric Renderer. - reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); - return reactRootView; - } - - @Override - protected boolean isConcurrentRootEnabled() { - // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18). - // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html - return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; - } + return new DefaultReactActivityDelegate( + this, + getMainComponentName(), + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled + // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). + DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled + ); } @Override diff --git a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainApplication.java b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainApplication.java index f086074bc5..8e772e3ba5 100644 --- a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainApplication.java +++ b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/MainApplication.java @@ -1,16 +1,13 @@ package com.samplenewarchitecture; import android.app.Application; -import android.content.Context; import com.facebook.react.PackageList; import com.facebook.react.ReactApplication; -import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; -import com.facebook.react.config.ReactFeatureFlags; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactNativeHost; import com.facebook.soloader.SoLoader; -import com.samplenewarchitecture.newarchitecture.MainApplicationReactNativeHost; -import java.lang.reflect.InvocationTargetException; import java.util.List; import io.sentry.react.RNSentryPackage; @@ -18,7 +15,7 @@ public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = - new ReactNativeHost(this) { + new DefaultReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; @@ -44,57 +41,33 @@ protected List getPackages() { protected String getJSMainModuleName() { return "index"; } - }; - private final ReactNativeHost mNewArchitectureNativeHost = - new MainApplicationReactNativeHost(this); + @Override + protected boolean isNewArchEnabled() { + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + + @Override + protected Boolean isHermesEnabled() { + return BuildConfig.IS_HERMES_ENABLED; + } + }; @Override public ReactNativeHost getReactNativeHost() { - if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { - return mNewArchitectureNativeHost; - } else { return mReactNativeHost; - } } @Override public void onCreate() { super.onCreate(); - // If you opted-in for the New Architecture, we enable the TurboModule system - ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; SoLoader.init(this, /* native exopackage */ false); - initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); - } - /** - * 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.samplenewarchitecture.ReactNativeFlipper"); - aClass - .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) - .invoke(null, context, reactInstanceManager); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + DefaultNewArchitectureEntryPoint.load(); } + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); } + } diff --git a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/MainApplicationReactNativeHost.java b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/MainApplicationReactNativeHost.java deleted file mode 100644 index 3b107dcf43..0000000000 --- a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/MainApplicationReactNativeHost.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.samplenewarchitecture.newarchitecture; - -import android.app.Application; -import androidx.annotation.NonNull; -import com.facebook.react.PackageList; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.ReactPackageTurboModuleManagerDelegate; -import com.facebook.react.bridge.JSIModulePackage; -import com.facebook.react.bridge.JSIModuleProvider; -import com.facebook.react.bridge.JSIModuleSpec; -import com.facebook.react.bridge.JSIModuleType; -import com.facebook.react.bridge.JavaScriptContextHolder; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.UIManager; -import com.facebook.react.fabric.ComponentFactory; -import com.facebook.react.fabric.CoreComponentsRegistry; -import com.facebook.react.fabric.FabricJSIModuleProvider; -import com.facebook.react.fabric.ReactNativeConfig; -import com.facebook.react.uimanager.ViewManagerRegistry; -import com.samplenewarchitecture.BuildConfig; -import com.samplenewarchitecture.newarchitecture.components.MainComponentsRegistry; -import com.samplenewarchitecture.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate; -import java.util.ArrayList; -import java.util.List; - -import io.sentry.react.RNSentryPackage; - -/** - * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both - * TurboModule delegates and the Fabric Renderer. - * - *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the - * `newArchEnabled` property). Is ignored otherwise. - */ -public class MainApplicationReactNativeHost extends ReactNativeHost { - public MainApplicationReactNativeHost(Application application) { - super(application); - } - - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - List packages = new PackageList(this).getPackages(); - // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); - // TurboModules must also be loaded here providing a valid TurboReactPackage implementation: - // packages.add(new TurboReactPackage() { ... }); - // If you have custom Fabric Components, their ViewManagers should also be loaded here - // inside a ReactPackage. - for (ReactPackage pkg : packages) { - if (pkg instanceof RNSentryPackage) { - return packages; - } - } - packages.add(new RNSentryPackage()); - return packages; - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - - @NonNull - @Override - protected ReactPackageTurboModuleManagerDelegate.Builder - getReactPackageTurboModuleManagerDelegateBuilder() { - // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary - // for the new architecture and to use TurboModules correctly. - return new MainApplicationTurboModuleManagerDelegate.Builder(); - } - - @Override - protected JSIModulePackage getJSIModulePackage() { - return new JSIModulePackage() { - @Override - public List getJSIModules( - final ReactApplicationContext reactApplicationContext, - final JavaScriptContextHolder jsContext) { - final List specs = new ArrayList<>(); - - // Here we provide a new JSIModuleSpec that will be responsible of providing the - // custom Fabric Components. - specs.add( - new JSIModuleSpec() { - @Override - public JSIModuleType getJSIModuleType() { - return JSIModuleType.UIManager; - } - - @Override - public JSIModuleProvider getJSIModuleProvider() { - final ComponentFactory componentFactory = new ComponentFactory(); - CoreComponentsRegistry.register(componentFactory); - - // Here we register a Components Registry. - // The one that is generated with the template contains no components - // and just provides you the one from React Native core. - MainComponentsRegistry.register(componentFactory); - - final ReactInstanceManager reactInstanceManager = getReactInstanceManager(); - - ViewManagerRegistry viewManagerRegistry = - new ViewManagerRegistry( - reactInstanceManager.getOrCreateViewManagers(reactApplicationContext)); - - return new FabricJSIModuleProvider( - reactApplicationContext, - componentFactory, - ReactNativeConfig.DEFAULT_CONFIG, - viewManagerRegistry); - } - }); - return specs; - } - }; - } -} diff --git a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/components/MainComponentsRegistry.java b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/components/MainComponentsRegistry.java deleted file mode 100644 index e4e294306e..0000000000 --- a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/components/MainComponentsRegistry.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.samplenewarchitecture.newarchitecture.components; - -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.fabric.ComponentFactory; -import com.facebook.soloader.SoLoader; - -/** - * Class responsible to load the custom Fabric Components. This class has native methods and needs a - * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ - * folder for you). - * - *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the - * `newArchEnabled` property). Is ignored otherwise. - */ -@DoNotStrip -public class MainComponentsRegistry { - static { - SoLoader.loadLibrary("fabricjni"); - } - - @DoNotStrip private final HybridData mHybridData; - - @DoNotStrip - private native HybridData initHybrid(ComponentFactory componentFactory); - - @DoNotStrip - private MainComponentsRegistry(ComponentFactory componentFactory) { - mHybridData = initHybrid(componentFactory); - } - - @DoNotStrip - public static MainComponentsRegistry register(ComponentFactory componentFactory) { - return new MainComponentsRegistry(componentFactory); - } -} diff --git a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java b/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java deleted file mode 100644 index 7406f8d7ed..0000000000 --- a/sample-new-architecture/android/app/src/main/java/com/samplenewarchitecture/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.samplenewarchitecture.newarchitecture.modules; - -import com.facebook.jni.HybridData; -import com.facebook.react.ReactPackage; -import com.facebook.react.ReactPackageTurboModuleManagerDelegate; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.soloader.SoLoader; -import java.util.List; - -/** - * Class responsible to load the TurboModules. This class has native methods and needs a - * corresponding C++ implementation/header file to work correctly (already placed inside the jni/ - * folder for you). - * - *

Please note that this class is used ONLY if you opt-in for the New Architecture (see the - * `newArchEnabled` property). Is ignored otherwise. - */ -public class MainApplicationTurboModuleManagerDelegate - extends ReactPackageTurboModuleManagerDelegate { - - private static volatile boolean sIsSoLibraryLoaded; - - protected MainApplicationTurboModuleManagerDelegate( - ReactApplicationContext reactApplicationContext, List packages) { - super(reactApplicationContext, packages); - } - - protected native HybridData initHybrid(); - - native boolean canCreateTurboModule(String moduleName); - - public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder { - protected MainApplicationTurboModuleManagerDelegate build( - ReactApplicationContext context, List packages) { - return new MainApplicationTurboModuleManagerDelegate(context, packages); - } - } - - @Override - protected synchronized void maybeLoadOtherSoLibraries() { - if (!sIsSoLibraryLoaded) { - // If you change the name of your application .so file in the Android.mk file, - // make sure you update the name here as well. - SoLoader.loadLibrary("samplenewarchitecture_appmodules"); - sIsSoLibraryLoaded = true; - } - } -} diff --git a/sample-new-architecture/android/app/src/main/jni/CMakeLists.txt b/sample-new-architecture/android/app/src/main/jni/CMakeLists.txt index 702d7f14bd..4e34bb3db5 100644 --- a/sample-new-architecture/android/app/src/main/jni/CMakeLists.txt +++ b/sample-new-architecture/android/app/src/main/jni/CMakeLists.txt @@ -1,15 +1,35 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# This CMake file is the default used by apps and is placed inside react-native +# to encapsulate it from user space (so you won't need to touch C++/Cmake code at all on Android). +# +# If you wish to customize it (because you want to manually link a C++ library or pass a custom +# compilation flag) you can: +# +# 1. Copy this CMake file inside the `android/app/src/main/jni` folder of your project +# 2. Copy the OnLoad.cpp (in this same folder) file inside the same folder as above. +# 3. Extend your `android/app/build.gradle` as follows +# +# android { +# // Other config here... +# externalNativeBuild { +# cmake { +# path "src/main/jni/CMakeLists.txt" +# } +# } +# } + cmake_minimum_required(VERSION 3.13) # Define the library name here. -project(samplenewarchitecture_appmodules) +project(appmodules) # This file includes all the necessary to let you build your application with the New Architecture. include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) -# Manual linking should be done after the build as otherwise -# it fails on linking a library that is not build byt the application -add_subdirectory(${NODE_MODULES_DIR}/../../android/build/generated/source/codegen/jni/ rnsentry_build) - -# sample-new-architecture needs to link against the rn_sentry turbo module -target_link_libraries(${CMAKE_PROJECT_NAME} - react_codegen_RNSentrySpec) +# App needs to add and link against tm (TurboModules) folder +add_subdirectory(${REACT_ANDROID_DIR}/../../../tm/ tm_build) +target_link_libraries(${CMAKE_PROJECT_NAME} tm) diff --git a/sample-new-architecture/android/app/src/main/jni/MainApplicationModuleProvider.cpp b/sample-new-architecture/android/app/src/main/jni/MainApplicationModuleProvider.cpp deleted file mode 100644 index d57183b668..0000000000 --- a/sample-new-architecture/android/app/src/main/jni/MainApplicationModuleProvider.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "MainApplicationModuleProvider.h" - -#include -#include -#include - -namespace facebook { -namespace react { - -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms) { - // Here you can provide your own module provider for TurboModules coming from - // either your application or from external libraries. The approach to follow - // is similar to the following (for a library called `samplelibrary`: - // - // auto module = samplelibrary_ModuleProvider(moduleName, params); - // if (module != nullptr) { - // return module; - // } - // return rncore_ModuleProvider(moduleName, params); - - // Module providers autolinked by RN CLI - auto rncli_module = rncli_ModuleProvider(moduleName, params); - if (rncli_module != nullptr) { - return rncli_module; - } - - auto rnsentry_module = RNSentrySpec_ModuleProvider(moduleName, params); - if (rnsentry_module != nullptr) - { - return rnsentry_module; - } - - return rncore_ModuleProvider(moduleName, params); -} - -} // namespace react -} // namespace facebook diff --git a/sample-new-architecture/android/app/src/main/jni/MainApplicationModuleProvider.h b/sample-new-architecture/android/app/src/main/jni/MainApplicationModuleProvider.h deleted file mode 100644 index b38ccf53fd..0000000000 --- a/sample-new-architecture/android/app/src/main/jni/MainApplicationModuleProvider.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace facebook { -namespace react { - -std::shared_ptr MainApplicationModuleProvider( - const std::string &moduleName, - const JavaTurboModule::InitParams ¶ms); - -} // namespace react -} // namespace facebook diff --git a/sample-new-architecture/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp b/sample-new-architecture/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp deleted file mode 100644 index 5fd688c509..0000000000 --- a/sample-new-architecture/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "MainApplicationTurboModuleManagerDelegate.h" -#include "MainApplicationModuleProvider.h" - -namespace facebook { -namespace react { - -jni::local_ref -MainApplicationTurboModuleManagerDelegate::initHybrid( - jni::alias_ref) { - return makeCxxInstance(); -} - -void MainApplicationTurboModuleManagerDelegate::registerNatives() { - registerHybrid({ - makeNativeMethod( - "initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid), - makeNativeMethod( - "canCreateTurboModule", - MainApplicationTurboModuleManagerDelegate::canCreateTurboModule), - }); -} - -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) { - // Not implemented yet: provide pure-C++ NativeModules here. - return nullptr; -} - -std::shared_ptr -MainApplicationTurboModuleManagerDelegate::getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) { - return MainApplicationModuleProvider(name, params); -} - -bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule( - const std::string &name) { - return getTurboModule(name, nullptr) != nullptr || - getTurboModule(name, {.moduleName = name}) != nullptr; -} - -} // namespace react -} // namespace facebook diff --git a/sample-new-architecture/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h b/sample-new-architecture/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h deleted file mode 100644 index 8c6ab5c303..0000000000 --- a/sample-new-architecture/android/app/src/main/jni/MainApplicationTurboModuleManagerDelegate.h +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -#include -#include - -namespace facebook { -namespace react { - -class MainApplicationTurboModuleManagerDelegate - : public jni::HybridClass< - MainApplicationTurboModuleManagerDelegate, - TurboModuleManagerDelegate> { - public: - // Adapt it to the package you used for your Java class. - static constexpr auto kJavaDescriptor = - "Lcom/samplenewarchitecture/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;"; - - static jni::local_ref initHybrid(jni::alias_ref); - - static void registerNatives(); - - std::shared_ptr getTurboModule( - const std::string &name, - const std::shared_ptr &jsInvoker) override; - std::shared_ptr getTurboModule( - const std::string &name, - const JavaTurboModule::InitParams ¶ms) override; - - /** - * Test-only method. Allows user to verify whether a TurboModule can be - * created by instances of this class. - */ - bool canCreateTurboModule(const std::string &name); -}; - -} // namespace react -} // namespace facebook diff --git a/sample-new-architecture/android/app/src/main/jni/MainComponentsRegistry.cpp b/sample-new-architecture/android/app/src/main/jni/MainComponentsRegistry.cpp deleted file mode 100644 index 54f598a486..0000000000 --- a/sample-new-architecture/android/app/src/main/jni/MainComponentsRegistry.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "MainComponentsRegistry.h" - -#include -#include -#include -#include -#include - -namespace facebook { -namespace react { - -MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {} - -std::shared_ptr -MainComponentsRegistry::sharedProviderRegistry() { - auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry(); - - // Autolinked providers registered by RN CLI - rncli_registerProviders(providerRegistry); - - // Custom Fabric Components go here. You can register custom - // components coming from your App or from 3rd party libraries here. - // - // providerRegistry->add(concreteComponentDescriptorProvider< - // AocViewerComponentDescriptor>()); - return providerRegistry; -} - -jni::local_ref -MainComponentsRegistry::initHybrid( - jni::alias_ref, - ComponentFactory *delegate) { - auto instance = makeCxxInstance(delegate); - - auto buildRegistryFunction = - [](EventDispatcher::Weak const &eventDispatcher, - ContextContainer::Shared const &contextContainer) - -> ComponentDescriptorRegistry::Shared { - auto registry = MainComponentsRegistry::sharedProviderRegistry() - ->createComponentDescriptorRegistry( - {eventDispatcher, contextContainer}); - - auto mutableRegistry = - std::const_pointer_cast(registry); - - mutableRegistry->setFallbackComponentDescriptor( - std::make_shared( - ComponentDescriptorParameters{ - eventDispatcher, contextContainer, nullptr})); - - return registry; - }; - - delegate->buildRegistryFunction = buildRegistryFunction; - return instance; -} - -void MainComponentsRegistry::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid), - }); -} - -} // namespace react -} // namespace facebook diff --git a/sample-new-architecture/android/app/src/main/jni/MainComponentsRegistry.h b/sample-new-architecture/android/app/src/main/jni/MainComponentsRegistry.h deleted file mode 100644 index 2ee57ea04c..0000000000 --- a/sample-new-architecture/android/app/src/main/jni/MainComponentsRegistry.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace facebook { -namespace react { - -class MainComponentsRegistry - : public facebook::jni::HybridClass { - public: - // Adapt it to the package you used for your Java class. - constexpr static auto kJavaDescriptor = - "Lcom/samplenewarchitecture/newarchitecture/components/MainComponentsRegistry;"; - - static void registerNatives(); - - MainComponentsRegistry(ComponentFactory *delegate); - - private: - static std::shared_ptr - sharedProviderRegistry(); - - static jni::local_ref initHybrid( - jni::alias_ref, - ComponentFactory *delegate); -}; - -} // namespace react -} // namespace facebook diff --git a/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp b/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp index c569b6e865..6e1d156699 100644 --- a/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp +++ b/sample-new-architecture/android/app/src/main/jni/OnLoad.cpp @@ -1,11 +1,93 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// This C++ file is part of the default configuration used by apps and is placed +// inside react-native to encapsulate it from user space (so you won't need to +// touch C++/Cmake code at all on Android). +// +// If you wish to customize it (because you want to manually link a C++ library +// or pass a custom compilation flag) you can: +// +// 1. Copy this CMake file inside the `android/app/src/main/jni` folder of your +// project +// 2. Copy the OnLoad.cpp (in this same folder) file inside the same folder as +// above. +// 3. Extend your `android/app/build.gradle` as follows +// +// android { +// // Other config here... +// externalNativeBuild { +// cmake { +// path "src/main/jni/CMakeLists.txt" +// } +// } +// } + +#include +#include #include -#include "MainApplicationTurboModuleManagerDelegate.h" -#include "MainComponentsRegistry.h" +#include +#include +#include + +namespace facebook { +namespace react { + +void registerComponents( + std::shared_ptr registry) { + // Custom Fabric Components go here. You can register custom + // components coming from your App or from 3rd party libraries here. + // + // providerRegistry->add(concreteComponentDescriptorProvider< + // AocViewerComponentDescriptor>()); + + // By default we just use the components autolinked by RN CLI + rncli_registerProviders(registry); +} + +std::shared_ptr cxxModuleProvider( + const std::string &name, + const std::shared_ptr &jsInvoker) { + // Not implemented yet: provide pure-C++ NativeModules here. + if (name == "NativeSampleModule") + { + return std::make_shared(jsInvoker); + } + return nullptr; +} + +std::shared_ptr javaModuleProvider( + const std::string &name, + const JavaTurboModule::InitParams ¶ms) { + // Here you can provide your own module provider for TurboModules coming from + // either your application or from external libraries. The approach to follow + // is similar to the following (for a library called `samplelibrary`): + // + // auto module = samplelibrary_ModuleProvider(moduleName, params); + // if (module != nullptr) { + // return module; + // } + // return rncore_ModuleProvider(moduleName, params); + + // By default we just use the module providers autolinked by RN CLI + return rncli_ModuleProvider(name, params); +} + +} // namespace react +} // namespace facebook JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { return facebook::jni::initialize(vm, [] { - facebook::react::MainApplicationTurboModuleManagerDelegate:: - registerNatives(); - facebook::react::MainComponentsRegistry::registerNatives(); + facebook::react::DefaultTurboModuleManagerDelegate::cxxModuleProvider = + &facebook::react::cxxModuleProvider; + facebook::react::DefaultTurboModuleManagerDelegate::javaModuleProvider = + &facebook::react::javaModuleProvider; + facebook::react::DefaultComponentsRegistry:: + registerComponentDescriptorsFromEntryPoint = + &facebook::react::registerComponents; }); } diff --git a/sample-new-architecture/android/app/src/release/java/com/samplenewarchitecture/ReactNativeFlipper.java b/sample-new-architecture/android/app/src/release/java/com/samplenewarchitecture/ReactNativeFlipper.java new file mode 100644 index 0000000000..9292b4aa02 --- /dev/null +++ b/sample-new-architecture/android/app/src/release/java/com/samplenewarchitecture/ReactNativeFlipper.java @@ -0,0 +1,18 @@ +/** + * Copyright (c) Meta Platforms, Inc. and 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.samplenewarchitecture; +import android.content.Context; +import com.facebook.react.ReactInstanceManager; +/** + * Class responsible of loading Flipper inside your React Native application. This is the release + * flavor of it so it's empty as we don't want to load Flipper. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + // Do nothing as we don't want to initialize Flipper on Release. + } +} diff --git a/sample-new-architecture/android/build.gradle b/sample-new-architecture/android/build.gradle index 8569fee3a7..67d887b030 100644 --- a/sample-new-architecture/android/build.gradle +++ b/sample-new-architecture/android/build.gradle @@ -2,50 +2,20 @@ buildscript { ext { - buildToolsVersion = "31.0.0" + buildToolsVersion = "33.0.0" minSdkVersion = 21 - compileSdkVersion = 31 - targetSdkVersion = 31 + compileSdkVersion = 33 + targetSdkVersion = 33 - if (System.properties['os.arch'] == "aarch64") { - // For M1 Users we need to use the NDK 24 which added support for aarch64 - ndkVersion = "24.0.8215888" - } else { - // Otherwise we default to the side-by-side NDK version from AGP. - ndkVersion = "21.4.7075529" - } + // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. + ndkVersion = "23.1.7779620" } repositories { google() mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.2.1") + classpath("com.android.tools.build:gradle:7.3.1") classpath("com.facebook.react:react-native-gradle-plugin") - classpath("de.undercouch:gradle-download-task:5.0.1") - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } -} - -allprojects { - repositories { - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url("$rootDir/../node_modules/react-native/android") - } - maven { - // Android JSC is installed from npm - url("$rootDir/../node_modules/jsc-android/dist") - } - mavenCentral { - // We don't want to fetch react-native from Maven Central as there are - // older versions over there. - content { - excludeGroup "com.facebook.react" - } - } - google() - maven { url 'https://www.jitpack.io' } } } diff --git a/sample-new-architecture/android/gradle.properties b/sample-new-architecture/android/gradle.properties index aad9fe4755..6b6e1f8522 100644 --- a/sample-new-architecture/android/gradle.properties +++ b/sample-new-architecture/android/gradle.properties @@ -38,3 +38,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # to write custom TurboModules/Fabric components OR use libraries that # are providing them. newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true diff --git a/sample-new-architecture/android/settings.gradle b/sample-new-architecture/android/settings.gradle index 4dae1167ac..ad4844d2a8 100644 --- a/sample-new-architecture/android/settings.gradle +++ b/sample-new-architecture/android/settings.gradle @@ -1,13 +1,4 @@ rootProject.name = 'sampleNewArchitecture' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' -include ':sentry_react-native' -project(':sentry_react-native').projectDir = new File(rootProject.projectDir, '../../android') includeBuild('../node_modules/react-native-gradle-plugin') - -if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { - include(":ReactAndroid") - project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') - include(":ReactAndroid:hermes-engine") - project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') -} diff --git a/sample-new-architecture/ios/Podfile b/sample-new-architecture/ios/Podfile index 843c46aa1e..f4697edb85 100644 --- a/sample-new-architecture/ios/Podfile +++ b/sample-new-architecture/ios/Podfile @@ -1,8 +1,23 @@ require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, '12.4' -install! 'cocoapods', :deterministic_uuids => false +platform :ios, min_ios_version_supported +prepare_react_native_project! +# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. +# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded +# +# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` +# ```js +# module.exports = { +# dependencies: { +# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), +# ``` +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end target 'sampleNewArchitecture' do config = use_native_modules! @@ -15,19 +30,23 @@ target 'sampleNewArchitecture' do # Hermes is now enabled by default. Disable by setting this flag to false. # Upcoming versions of React Native may rely on get_default_flags(), but # we make it explicit here to aid in the React Native upgrade process. - :hermes_enabled => true, + :hermes_enabled => flags[:hermes_enabled], :fabric_enabled => flags[:fabric_enabled], # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. - :flipper_configuration => FlipperConfiguration.enabled(["Debug"], { 'Flipper' => '0.166.0' }), + :flipper_configuration => flipper_config, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) + if ENV['RCT_NEW_ARCH_ENABLED'] == '1' + pod 'AppTurboModules', :path => "./../tm" + end + if !ENV['TEST'] - pod 'RNSentry', :path => '../../RNSentry.podspec' + pod 'RNSentry', :path => '../..' end target 'sampleNewArchitectureTests' do diff --git a/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.h b/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.h index ef1de86a2a..5d2808256c 100644 --- a/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.h +++ b/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.h @@ -1,8 +1,6 @@ -#import +#import #import -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; +@interface AppDelegate : RCTAppDelegate @end diff --git a/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.mm b/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.mm index 1fe732ff6f..57d1bdd738 100644 --- a/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.mm +++ b/sample-new-architecture/ios/sampleNewArchitecture/AppDelegate.mm @@ -1,85 +1,23 @@ #import "AppDelegate.h" -#import #import -#import - -#import - -#if RCT_NEW_ARCH_ENABLED #import -#import -#import -#import -#import #import +#import -#import - -static NSString *const kRNConcurrentRoot = @"concurrentRoot"; - -@interface AppDelegate () { - RCTTurboModuleManager *_turboModuleManager; - RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; - std::shared_ptr _reactNativeConfig; - facebook::react::ContextContainer::Shared _contextContainer; -} +@interface AppDelegate () {} @end -#endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - RCTAppSetupPrepareApp(application); - - RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; + self.moduleName = @"sampleNewArchitecture"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React + self.initialProps = @{}; -#if RCT_NEW_ARCH_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); - _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; - bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; -#endif - - NSDictionary *initProps = [self prepareInitialProps]; - UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"sampleNewArchitecture", initProps); - - if (@available(iOS 13.0, *)) { - rootView.backgroundColor = [UIColor systemBackgroundColor]; - } else { - rootView.backgroundColor = [UIColor whiteColor]; - } - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; -} - -/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. -/// -/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html -/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). -/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. -- (BOOL)concurrentRootEnabled -{ - // Switch this bool to turn on and off the concurrent root - return true; -} - -- (NSDictionary *)prepareInitialProps -{ - NSMutableDictionary *initProps = [NSMutableDictionary new]; - -#ifdef RCT_NEW_ARCH_ENABLED - initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); -#endif - - return initProps; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge @@ -91,43 +29,25 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge #endif } -#if RCT_NEW_ARCH_ENABLED - -#pragma mark - RCTCxxBridgeDelegate - -- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge +/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled { - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); + return true; } #pragma mark RCTTurboModuleManagerDelegate -- (Class)getModuleClassFromName:(const char *)name -{ - return RCTCoreModulesClassProvider(name); -} - - (std::shared_ptr)getTurboModule:(const std::string &)name jsInvoker:(std::shared_ptr)jsInvoker { + if (name == "NativeSampleModule") { + return std::make_shared(jsInvoker); + } return nullptr; } -- (std::shared_ptr)getTurboModule:(const std::string &)name - initParams: - (const facebook::react::ObjCTurboModule::InitParams &)params -{ - return nullptr; -} - -- (id)getModuleInstanceFromClass:(Class)moduleClass -{ - return RCTAppSetupDefaultModuleFromClass(moduleClass); -} - -#endif - @end diff --git a/sample-new-architecture/metro.config.js b/sample-new-architecture/metro.config.js index fee6c0859a..facf387250 100644 --- a/sample-new-architecture/metro.config.js +++ b/sample-new-architecture/metro.config.js @@ -12,7 +12,11 @@ const parentDir = path.resolve(__dirname, '..'); module.exports = { projectRoot: __dirname, - watchFolders: [path.resolve(__dirname, 'node_modules'), parentDir], + watchFolders: [ + path.resolve(__dirname, 'node_modules'), + `${parentDir}/dist`, + `${parentDir}/node_modules`, + ], resolver: { blacklistRE: blacklist([ new RegExp(`${parentDir}/node_modules/react-native/.*`), diff --git a/sample-new-architecture/package.json b/sample-new-architecture/package.json index 48efd686f4..6bd8ef7ac3 100644 --- a/sample-new-architecture/package.json +++ b/sample-new-architecture/package.json @@ -14,34 +14,37 @@ "pod-install-legacy-production": "cd ios; PRODUCTION=1 bundle exec pod install; cd .." }, "dependencies": { - "react": "18.1.0", - "react-native": "0.70.1", - "@react-navigation/native": "^6.0.13", - "@react-navigation/stack": "^6.3.2", - "react-redux": "^8.0.4", - "redux": "^4.2.0", - "react-native-gesture-handler": "^2.7.0", - "react-native-safe-area-context": "^4.4.1", - "react-native-screens": "^3.18.1" + "@react-native-community/cli-platform-android": "^10.1.3", + "@react-navigation/native": "^6.1.2", + "@react-navigation/stack": "^6.3.11", + "react": "18.2.0", + "react-native": "0.71.1", + "react-native-gesture-handler": "^2.9.0", + "react-native-safe-area-context": "^4.5.0", + "react-native-screens": "^3.19.0", + "react-redux": "^8.0.5", + "redux": "^4.2.0" }, "devDependencies": { - "@babel/core": "^7.12.9", - "@babel/preset-env": "^7", - "@babel/runtime": "^7.12.5", - "@react-native-community/eslint-config": "^2.0.0", + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@react-native-community/eslint-config": "^3.0.0", "@tsconfig/react-native": "^2.0.2", - "@types/jest": "^26.0.23", - "@types/react-native": "^0.70.0", + "@types/jest": "^29.2.1", "@types/react-test-renderer": "^18.0.0", "@typescript-eslint/eslint-plugin": "^5.37.0", "@typescript-eslint/parser": "^5.37.0", - "babel-jest": "^26.6.3", - "babel-plugin-module-resolver": "^4.1.0", - "eslint": "^7.32.0", - "jest": "^26.6.3", - "metro-react-native-babel-preset": "^0.72.1", - "react-test-renderer": "18.1.0", - "typescript": "^4.8.3" + "babel-jest": "^29.2.1", + "babel-plugin-module-resolver": "^5.0.0", + "eslint": "^8.19.0", + "eslint-plugin-ft-flow": "^2.0.3", + "eslint-plugin-jest": "^27.2.1", + "jest": "^29.2.1", + "metro-react-native-babel-preset": "^0.73.7", + "prettier": "^2.4.1", + "react-test-renderer": "18.2.0", + "typescript": "4.8.4" }, "jest": { "preset": "react-native", @@ -57,5 +60,13 @@ "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/mocks/fileMock.js", "\\.(css|less)$": "/mocks/fileMock.js" } + }, + "codegenConfig": { + "name": "AppSpecs", + "type": "all", + "jsSrcsDir": "tm", + "android": { + "javaPackageName": "com.facebook.fbreact.specs" + } } } diff --git a/sample-new-architecture/react-native.config.js b/sample-new-architecture/react-native.config.js index c6c1a74e55..3cf8f35a71 100644 --- a/sample-new-architecture/react-native.config.js +++ b/sample-new-architecture/react-native.config.js @@ -1,10 +1,12 @@ // Without this config the codegen fails // because it can find @sentry/react-native // in the dependencies +const path = require('path'); + module.exports = { dependencies: { RNSentry: { - root: '../', + root: path.resolve(__dirname, '..'), }, }, }; diff --git a/sample-new-architecture/src/Screens/HomeScreen.tsx b/sample-new-architecture/src/Screens/HomeScreen.tsx index d4438c96c0..930556697b 100644 --- a/sample-new-architecture/src/Screens/HomeScreen.tsx +++ b/sample-new-architecture/src/Screens/HomeScreen.tsx @@ -15,6 +15,8 @@ import { setScopeProperties } from '../setScopeProperties'; import { StackNavigationProp } from '@react-navigation/stack'; import { CommonActions } from '@react-navigation/native'; import { UserFeedbackModal } from '../components/UserFeedbackModal'; +import { FallbackRender } from '@sentry/react'; +import NativeSampleModule from '../../tm/NativeSampleModule'; interface Props { navigation: StackNavigationProp; @@ -41,13 +43,14 @@ const HomeScreen = (props: Props) => { ); }; + const errorBoundaryFallback: FallbackRender = ({ eventId }) => ( + Error boundary caught with event id: {eventId} + ); + return ( <> - + Hey there!