Skip to content

Commit

Permalink
Hide the C++/Cmake configuration from user space inside the framework
Browse files Browse the repository at this point in the history
Summary:
This change encapsulates all the NDK configuration logic inside the React Native
Gradle Plugin. The changes are additive so that the user can still specify a
custom configuration if they wish.

So far I've applied the changes to RN Tester. Changes to the template require a
bump of the Gradle Plugin NPM package.

Changelog:
[Android] [Changed] - Hide the C++/Cmake configuration from user space inside the framework

Reviewed By: cipolleschi

Differential Revision: D40139557

fbshipit-source-id: 013220695791e3d0d458e118de16953e0545c3de
  • Loading branch information
cortinico authored and facebook-github-bot committed Oct 6, 2022
1 parent 36c9716 commit c9e6a60
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 18 deletions.
31 changes: 31 additions & 0 deletions ReactAndroid/cmake-utils/default-app-setup/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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(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)
79 changes: 79 additions & 0 deletions ReactAndroid/cmake-utils/default-app-setup/OnLoad.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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 <DefaultComponentsRegistry.h>
#include <DefaultTurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <rncli.h>

namespace facebook {
namespace react {

void registerComponents(
std::shared_ptr<ComponentDescriptorProviderRegistry const> 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<TurboModule> provideModules(
const std::string &name,
const JavaTurboModule::InitParams &params) {
// 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::DefaultTurboModuleManagerDelegate::
moduleProvidersFromEntryPoint = &facebook::react::provideModules;
facebook::react::DefaultComponentsRegistry::
registerComponentDescriptorsFromEntryPoint =
&facebook::react::registerComponents;
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import com.facebook.react.tasks.BuildCodegenCLITask
import com.facebook.react.tasks.GenerateCodegenArtifactsTask
import com.facebook.react.tasks.GenerateCodegenSchemaTask
import com.facebook.react.utils.JsonUtils
import com.facebook.react.utils.NdkConfiguratorUtils.configureReactNativePrefab
import com.facebook.react.utils.NdkConfiguratorUtils.configureReactNativeNdk
import com.facebook.react.utils.findPackageJsonFile
import java.io.File
import kotlin.system.exitProcess
Expand Down Expand Up @@ -54,7 +54,7 @@ class ReactPlugin : Plugin<Project> {
}

private fun applyAppPlugin(project: Project, config: ReactExtension) {
configureReactNativePrefab(project)
configureReactNativeNdk(project, config)
project.afterEvaluate {
if (config.applyAppPlugin.getOrElse(false)) {
val androidConfiguration = project.extensions.getByType(BaseExtension::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
package com.facebook.react.utils

import com.android.build.api.variant.AndroidComponentsExtension
import com.facebook.react.ReactExtension
import com.facebook.react.utils.ProjectUtils.isNewArchEnabled
import java.io.File
import org.gradle.api.Project

internal object NdkConfiguratorUtils {
@Suppress("UnstableApiUsage")
fun configureReactNativePrefab(project: Project) {
fun configureReactNativeNdk(project: Project, extension: ReactExtension) {
if (!project.isNewArchEnabled) {
return
}
Expand Down Expand Up @@ -54,6 +56,34 @@ internal object NdkConfiguratorUtils {
// AGP will give priority of libc++_shared coming from App modules.
"**/libc++_shared.so",
))

// If the user has not provided a CmakeLists.txt path, let's provide
// the default one from the framework
if (ext.externalNativeBuild.cmake.path == null) {
System.err.println("NCOR: Patching cmake path file")
ext.externalNativeBuild.cmake.path = File("TODO")
}

// Parameters should be provided in an additive manner (do not override what
// the user provided, but allow for sensible defaults).
val cmakeArgs = ext.defaultConfig.externalNativeBuild.cmake.arguments
if ("-DGENERATED_SRC_DIR" !in cmakeArgs) {
cmakeArgs.add("-DGENERATED_SRC_DIR=${File(project.buildDir, "generated/source")}")
}
if ("-DPROJECT_BUILD_DIR" !in cmakeArgs) {
cmakeArgs.add("-DPROJECT_BUILD_DIR=${project.buildDir}")
}
if ("-DREACT_ANDROID_DIR" !in cmakeArgs) {
cmakeArgs.add(
"-DREACT_ANDROID_DIR=${extension.reactNativeDir.file("ReactAndroid").get().asFile}")
}
if ("-DREACT_ANDROID_BUILD_DIR" !in cmakeArgs) {
cmakeArgs.add(
"-DREACT_ANDROID_BUILD_DIR=${extension.reactNativeDir.file("ReactAndroid/build").get().asFile}")
}
if ("-DANDROID_STL" !in cmakeArgs) {
cmakeArgs.add("-DANDROID_STL=c++_shared")
}
}
}
}
Expand Down
17 changes: 2 additions & 15 deletions packages/rn-tester/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -215,24 +215,11 @@ dependencies {
androidTestImplementation 'junit:junit:4.12'
}

// TODO: Move all this logic to CodegenPlugin.java.
def reactAndroidProjectDir = project(':ReactAndroid').projectDir;
def reactAndroidBuildDir = project(':ReactAndroid').buildDir;

android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DGENERATED_SRC_DIR=$buildDir/generated/source",
"-DPROJECT_BUILD_DIR=$buildDir",
"-DREACT_ANDROID_DIR=$reactAndroidProjectDir",
"-DREACT_ANDROID_BUILD_DIR=$reactAndroidBuildDir",
"-DANDROID_STL=c++_shared"
}
}
}
externalNativeBuild {
cmake {
// RN Tester is doing custom linking of C++ libraries therefore needs
// a dedicated CMakeLists.txt file.
path "src/main/jni/CMakeLists.txt"
}
}
Expand Down

0 comments on commit c9e6a60

Please sign in to comment.