UNPKG

nitro-codegen

Version:

The code-generator for react-native-nitro-modules.

160 lines (142 loc) 5.58 kB
import { NitroConfig } from '../../config/NitroConfig.js'; import { createCppHybridObjectRegistration } from '../../syntax/c++/CppHybridObjectRegistration.js'; import { includeHeader } from '../../syntax/c++/includeNitroHeader.js'; import { createFileMetadataString, isNotDuplicate, } from '../../syntax/helpers.js'; import { getJNINativeRegistrations } from '../../syntax/kotlin/JNINativeRegistrations.js'; import { createJNIHybridObjectRegistration } from '../../syntax/kotlin/KotlinHybridObjectRegistration.js'; import { indent } from '../../utils.js'; import { getBuildingWithGeneratedCmakeDefinition } from './createCMakeExtension.js'; export function createHybridObjectIntializer() { const cxxNamespace = NitroConfig.getCxxNamespace('c++'); const cppLibName = NitroConfig.getAndroidCxxLibName(); const javaNamespace = NitroConfig.getAndroidPackage('java/kotlin'); const autolinkingClassName = `${NitroConfig.getAndroidCxxLibName()}OnLoad`; const jniRegistrations = getJNINativeRegistrations() .map((r) => `${r.namespace}::${r.className}::registerNatives();`) .filter(isNotDuplicate); const autolinkedHybridObjects = NitroConfig.getAutolinkedHybridObjects(); const cppHybridObjectImports = []; const cppRegistrations = []; for (const hybridObjectName of Object.keys(autolinkedHybridObjects)) { const config = autolinkedHybridObjects[hybridObjectName]; if (config?.cpp != null) { // Autolink a C++ HybridObject! const { cppCode, requiredImports } = createCppHybridObjectRegistration({ hybridObjectName: hybridObjectName, cppClassName: config.cpp, }); cppHybridObjectImports.push(...requiredImports); cppRegistrations.push(cppCode); } if (config?.kotlin != null) { // Autolink a Kotlin HybridObject through JNI/C++! const { cppCode, requiredImports } = createJNIHybridObjectRegistration({ hybridObjectName: hybridObjectName, jniClassName: config.kotlin, }); cppHybridObjectImports.push(...requiredImports); cppRegistrations.push(cppCode); } } const buildingWithDefinition = getBuildingWithGeneratedCmakeDefinition(); const includes = [ ...getJNINativeRegistrations().map((r) => includeHeader(r.import)), ...cppHybridObjectImports.map((i) => includeHeader(i)), ] .filter(isNotDuplicate) .join('\n'); const hppCode = ` ${createFileMetadataString(`${autolinkingClassName}.hpp`)} #include <jni.h> #include <NitroModules/NitroDefines.hpp> namespace ${cxxNamespace} { /** * Initializes the native (C++) part of ${cppLibName}, and autolinks all Hybrid Objects. * Call this in your \`JNI_OnLoad\` function (probably inside \`cpp-adapter.cpp\`). * Example: * \`\`\`cpp (cpp-adapter.cpp) * JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) { * return ${cxxNamespace}::initialize(vm); * } * \`\`\` */ int initialize(JavaVM* vm); } // namespace ${cxxNamespace} `; const cppCode = ` ${createFileMetadataString(`${autolinkingClassName}.cpp`)} #ifndef ${buildingWithDefinition} #error ${autolinkingClassName}.cpp is not being built with the autogenerated CMakeLists.txt project. Is a different CMakeLists.txt building this? #endif #include "${autolinkingClassName}.hpp" #include <jni.h> #include <fbjni/fbjni.h> #include <NitroModules/HybridObjectRegistry.hpp> ${includes} namespace ${cxxNamespace} { int initialize(JavaVM* vm) { using namespace margelo::nitro; using namespace ${cxxNamespace}; using namespace facebook; return facebook::jni::initialize(vm, [] { // Register native JNI methods ${indent(jniRegistrations.join('\n'), ' ')} // Register Nitro Hybrid Objects ${indent(cppRegistrations.join('\n'), ' ')} }); } } // namespace ${cxxNamespace} `.trim(); const kotlinCode = ` ${createFileMetadataString(`${autolinkingClassName}.kt`)} package ${javaNamespace} import android.util.Log internal class ${autolinkingClassName} { companion object { private const val TAG = "${autolinkingClassName}" private var didLoad = false /** * Initializes the native part of "${cppLibName}". * This method is idempotent and can be called more than once. */ @JvmStatic fun initializeNative() { if (didLoad) return try { Log.i(TAG, "Loading ${cppLibName} C++ library...") System.loadLibrary("${cppLibName}") Log.i(TAG, "Successfully loaded ${cppLibName} C++ library!") didLoad = true } catch (e: Error) { Log.e(TAG, "Failed to load ${cppLibName} C++ library! Is it properly installed and linked? " + "Is the name correct? (see \`CMakeLists.txt\`, at \`add_library(...)\`)", e) throw e } } } } `.trim(); return [ { content: hppCode, language: 'c++', name: `${autolinkingClassName}.hpp`, platform: 'android', subdirectory: [], }, { content: cppCode, language: 'c++', name: `${autolinkingClassName}.cpp`, platform: 'android', subdirectory: [], }, { content: kotlinCode, language: 'kotlin', name: `${autolinkingClassName}.kt`, platform: 'android', subdirectory: ['kotlin', ...javaNamespace.split('.')], }, ]; }