diff --git a/example/src/screens/HybridObjectTestsScreen.tsx b/example/src/screens/HybridObjectTestsScreen.tsx index 93092695..196a05c2 100644 --- a/example/src/screens/HybridObjectTestsScreen.tsx +++ b/example/src/screens/HybridObjectTestsScreen.tsx @@ -12,6 +12,7 @@ import { HybridTestObjectCpp, HybridTestObjectSwiftKotlin, HybridChild, + HybridBase, } from 'react-native-nitro-image' import { getTests, type TestRunner } from '../getTests' import { SafeAreaView } from 'react-native-safe-area-context' @@ -20,6 +21,7 @@ import SegmentedControl from '@react-native-segmented-control/segmented-control' import { NitroModules } from 'react-native-nitro-modules' logPrototypeChain(HybridChild) +console.log(HybridBase.baseValue) console.log(HybridChild.baseValue) console.log(HybridChild.childValue) diff --git a/packages/nitrogen/src/syntax/kotlin/FbjniHybridObject.ts b/packages/nitrogen/src/syntax/kotlin/FbjniHybridObject.ts index 9a6dbc96..cb1f3754 100644 --- a/packages/nitrogen/src/syntax/kotlin/FbjniHybridObject.ts +++ b/packages/nitrogen/src/syntax/kotlin/FbjniHybridObject.ts @@ -1,5 +1,6 @@ import { NitroConfig } from '../../config/NitroConfig.js' import { createIndentation, indent } from '../../utils.js' +import { getForwardDeclaration } from '../c++/getForwardDeclaration.js' import { includeHeader } from '../c++/includeNitroHeader.js' import { getAllTypes } from '../getAllTypes.js' import { getHybridObjectName } from '../getHybridObjectName.js' @@ -7,16 +8,27 @@ import { createFileMetadataString, isNotDuplicate } from '../helpers.js' import type { HybridObjectSpec } from '../HybridObjectSpec.js' import { Method } from '../Method.js' import type { Property } from '../Property.js' -import type { SourceFile } from '../SourceFile.js' +import type { SourceFile, SourceImport } from '../SourceFile.js' import { addJNINativeRegistration } from './JNINativeRegistrations.js' import { KotlinCxxBridgedType } from './KotlinCxxBridgedType.js' export function createFbjniHybridObject(spec: HybridObjectSpec): SourceFile[] { const name = getHybridObjectName(spec.name) - const propertiesDecl = spec.properties + + // Because we cache JNI methods as `static` inside our method bodies, + // we need to re-create the method bodies per inherited class. + // This way `Child`'s statically cached `someMethod()` JNI reference + // is not the same as `Base`'s statically cached `someMethod()` JNI reference. + const properties = [ + ...spec.properties, + ...spec.baseTypes.flatMap((b) => b.properties), + ] + const methods = [...spec.methods, ...spec.baseTypes.flatMap((b) => b.methods)] + + const propertiesDecl = properties .map((p) => p.getCode('c++', { override: true })) .join('\n') - const methodsDecl = spec.methods + const methodsDecl = methods .map((p) => p.getCode('c++', { override: true })) .join('\n') const jniClassDescriptor = NitroConfig.getAndroidPackage( @@ -26,6 +38,32 @@ export function createFbjniHybridObject(spec: HybridObjectSpec): SourceFile[] { const cxxNamespace = NitroConfig.getCxxNamespace('c++') const spaces = createIndentation(name.JHybridTSpec.length) + let cppBase = 'JHybridObject' + if (spec.baseTypes.length > 0) { + if (spec.baseTypes.length > 1) { + throw new Error( + `${name.T}: Inheriting from multiple HybridObject bases is not yet supported on Kotlin!` + ) + } + cppBase = getHybridObjectName(spec.baseTypes[0]!.name).JHybridTSpec + } + const cppImports: SourceImport[] = [] + const cppConstructorCalls = [`HybridObject(${name.HybridTSpec}::TAG)`] + for (const base of spec.baseTypes) { + const { JHybridTSpec } = getHybridObjectName(base.name) + cppConstructorCalls.push('HybridBase(jThis)') + cppImports.push({ + language: 'c++', + name: `${JHybridTSpec}.hpp`, + space: 'user', + forwardDeclaration: getForwardDeclaration( + 'class', + JHybridTSpec, + NitroConfig.getCxxNamespace('c++') + ), + }) + } + const cppHeaderCode = ` ${createFileMetadataString(`${name.HybridTSpec}.hpp`)} @@ -35,21 +73,27 @@ ${createFileMetadataString(`${name.HybridTSpec}.hpp`)} #include #include "${name.HybridTSpec}.hpp" +${cppImports + .map((i) => i.forwardDeclaration) + .filter((f) => f != null) + .join('\n')} +${cppImports.map((i) => includeHeader(i)).join('\n')} + namespace ${cxxNamespace} { using namespace facebook; - class ${name.JHybridTSpec} final: public jni::HybridClass<${name.JHybridTSpec}, JHybridObject>, -${spaces} public ${name.HybridTSpec} { + class ${name.JHybridTSpec}: public jni::HybridClass<${name.JHybridTSpec}, ${cppBase}>, +${spaces} public virtual ${name.HybridTSpec} { public: static auto constexpr kJavaDescriptor = "L${jniClassDescriptor};"; static jni::local_ref initHybrid(jni::alias_ref jThis); static void registerNatives(); - private: + protected: // C++ constructor (called from Java via \`initHybrid()\`) explicit ${name.JHybridTSpec}(jni::alias_ref jThis) : - HybridObject(${name.HybridTSpec}::TAG), + ${indent(cppConstructorCalls.join(',\n'), ' ')}, _javaPart(jni::make_global(jThis)) {} public: @@ -88,10 +132,10 @@ ${spaces} public ${name.HybridTSpec} { }, }) - const propertiesImpl = spec.properties + const propertiesImpl = properties .map((m) => getFbjniPropertyForwardImplementation(spec, m)) .join('\n') - const methodsImpl = spec.methods + const methodsImpl = methods .map((m) => getFbjniMethodForwardImplementation(spec, m)) .join('\n') const allTypes = getAllTypes(spec) diff --git a/packages/nitrogen/src/syntax/kotlin/KotlinHybridObject.ts b/packages/nitrogen/src/syntax/kotlin/KotlinHybridObject.ts index 400b8b10..5bf8e65d 100644 --- a/packages/nitrogen/src/syntax/kotlin/KotlinHybridObject.ts +++ b/packages/nitrogen/src/syntax/kotlin/KotlinHybridObject.ts @@ -23,6 +23,17 @@ export function createKotlinHybridObject(spec: HybridObjectSpec): SourceFile[] { const javaPackage = NitroConfig.getAndroidPackage('java/kotlin') const cppLibName = NitroConfig.getAndroidCxxLibName() + let kotlinBase = 'HybridObject' + if (spec.baseTypes.length > 0) { + if (spec.baseTypes.length > 1) { + throw new Error( + `${name.T}: Inheriting from multiple HybridObject bases is not yet supported in Kotlin!` + ) + } + const base = spec.baseTypes[0]!.name + kotlinBase = getHybridObjectName(base).HybridTSpec + } + // 1. Create Kotlin abstract class definition const abstractClassCode = ` ${createFileMetadataString(`${name.HybridTSpec}.kt`)} @@ -42,11 +53,9 @@ import com.margelo.nitro.core.* @DoNotStrip @Keep @Suppress("RedundantSuppression", "KotlinJniMissingFunction", "PropertyName", "RedundantUnitReturnType", "unused") -abstract class ${name.HybridTSpec}: HybridObject() { - protected val TAG = "${name.HybridTSpec}" - +abstract class ${name.HybridTSpec}: ${kotlinBase}() { @DoNotStrip - val mHybridData: HybridData = initHybrid() + private var mHybridData: HybridData = initHybrid() init { // Pass this \`HybridData\` through to it's base class, @@ -54,6 +63,13 @@ abstract class ${name.HybridTSpec}: HybridObject() { super.updateNative(mHybridData) } + /** + * Call from a child class to initialize HybridData with a child. + */ + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + } + // Properties ${indent(properties, ' ')} diff --git a/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridBase.kt b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridBase.kt new file mode 100644 index 00000000..3a6cff12 --- /dev/null +++ b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridBase.kt @@ -0,0 +1,9 @@ +package com.margelo.nitro.image + +class HybridBase: HybridBaseSpec() { + override val baseValue: Double + get() = 10.0 + + override val memorySize: Long + get() = 0L +} diff --git a/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridChild.kt b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridChild.kt new file mode 100644 index 00000000..f58cb990 --- /dev/null +++ b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridChild.kt @@ -0,0 +1,11 @@ +package com.margelo.nitro.image + +class HybridChild: HybridChildSpec() { + override val baseValue: Double + get() = 20.0 + override val childValue: Double + get() = 30.0 + + override val memorySize: Long + get() = 0L +} diff --git a/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridTestObjectKotlin.kt b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridTestObjectKotlin.kt index f6bf4922..ae3e610d 100644 --- a/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridTestObjectKotlin.kt +++ b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/HybridTestObjectKotlin.kt @@ -8,6 +8,8 @@ import com.margelo.nitro.core.Promise import kotlinx.coroutines.delay class HybridTestObjectKotlin: HybridTestObjectSwiftKotlinSpec() { + private val TAG = "HybridTestObjectKotlin" + override var numberValue: Double = 0.0 override var boolValue: Boolean = false override var stringValue: String = "" diff --git a/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/Image.kt b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/Image.kt index 7d485643..2d849549 100644 --- a/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/Image.kt +++ b/packages/react-native-nitro-image/android/src/main/java/com/margelo/nitro/image/Image.kt @@ -6,6 +6,8 @@ import android.os.Looper import android.util.Log class Image(val bitmap: Bitmap): HybridImageSpec() { + private val TAG = "Image" + override val size: ImageSize get() { return ImageSize(bitmap.width.toDouble(), bitmap.height.toDouble()) diff --git a/packages/react-native-nitro-image/nitro.json b/packages/react-native-nitro-image/nitro.json index e75ef51e..6304a1ba 100644 --- a/packages/react-native-nitro-image/nitro.json +++ b/packages/react-native-nitro-image/nitro.json @@ -20,10 +20,12 @@ "kotlin": "HybridTestObjectKotlin" }, "Base": { - "swift": "HybridBase" + "swift": "HybridBase", + "kotlin": "HybridBase" }, "Child": { - "swift": "HybridChild" + "swift": "HybridChild", + "kotlin": "HybridChild" } }, "ignorePaths": ["node_modules"] diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/NitroImage+autolinking.cmake b/packages/react-native-nitro-image/nitrogen/generated/android/NitroImage+autolinking.cmake index d5625c8e..3b72f161 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/NitroImage+autolinking.cmake +++ b/packages/react-native-nitro-image/nitrogen/generated/android/NitroImage+autolinking.cmake @@ -37,6 +37,8 @@ target_sources( ../nitrogen/generated/android/c++/JHybridImageSpec.cpp ../nitrogen/generated/android/c++/JHybridImageFactorySpec.cpp ../nitrogen/generated/android/c++/JHybridTestObjectSwiftKotlinSpec.cpp + ../nitrogen/generated/android/c++/JHybridBaseSpec.cpp + ../nitrogen/generated/android/c++/JHybridChildSpec.cpp ) # Add all libraries required by the generated specs diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp b/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp index ccc65f20..8c5e32b9 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp +++ b/packages/react-native-nitro-image/nitrogen/generated/android/NitroImageOnLoad.cpp @@ -17,6 +17,8 @@ #include "JHybridTestObjectSwiftKotlinSpec.hpp" #include "JFunc_void.hpp" #include "JFunc_void_std__optional_double_.hpp" +#include "JHybridBaseSpec.hpp" +#include "JHybridChildSpec.hpp" #include #include "HybridTestObjectCpp.hpp" @@ -38,6 +40,8 @@ int initialize(JavaVM* vm) { margelo::nitro::image::JFunc_void::registerNatives(); margelo::nitro::image::JFunc_void::registerNatives(); margelo::nitro::image::JFunc_void_std__optional_double_::registerNatives(); + margelo::nitro::image::JHybridBaseSpec::registerNatives(); + margelo::nitro::image::JHybridChildSpec::registerNatives(); // Register Nitro Hybrid Objects HybridObjectRegistry::registerHybridObjectConstructor( @@ -81,6 +85,38 @@ int initialize(JavaVM* vm) { return JNISharedPtr::make_shared_from_jni(globalRef); } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "Base", + []() -> std::shared_ptr { + static auto javaClass = jni::findClassStatic("com/margelo/nitro/image/HybridBase"); + static auto defaultConstructor = javaClass->getConstructor(); + + auto instance = javaClass->newObject(defaultConstructor); + #ifdef NITRO_DEBUG + if (instance == nullptr) [[unlikely]] { + throw std::runtime_error("Failed to create an instance of \"JHybridBaseSpec\" - the constructor returned null!"); + } + #endif + auto globalRef = jni::make_global(instance); + return JNISharedPtr::make_shared_from_jni(globalRef); + } + ); + HybridObjectRegistry::registerHybridObjectConstructor( + "Child", + []() -> std::shared_ptr { + static auto javaClass = jni::findClassStatic("com/margelo/nitro/image/HybridChild"); + static auto defaultConstructor = javaClass->getConstructor(); + + auto instance = javaClass->newObject(defaultConstructor); + #ifdef NITRO_DEBUG + if (instance == nullptr) [[unlikely]] { + throw std::runtime_error("Failed to create an instance of \"JHybridChildSpec\" - the constructor returned null!"); + } + #endif + auto globalRef = jni::make_global(instance); + return JNISharedPtr::make_shared_from_jni(globalRef); + } + ); }); } diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridBaseSpec.cpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridBaseSpec.cpp new file mode 100644 index 00000000..b0b42be6 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridBaseSpec.cpp @@ -0,0 +1,41 @@ +/// +/// JHybridBaseSpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#include "JHybridBaseSpec.hpp" + + + + + +namespace margelo::nitro::image { + + jni::local_ref JHybridBaseSpec::initHybrid(jni::alias_ref jThis) { + return makeCxxInstance(jThis); + } + + void JHybridBaseSpec::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JHybridBaseSpec::initHybrid), + }); + } + + size_t JHybridBaseSpec::getExternalMemorySize() noexcept { + static const auto method = _javaPart->getClass()->getMethod("getMemorySize"); + return method(_javaPart); + } + + // Properties + double JHybridBaseSpec::getBaseValue() { + static const auto method = _javaPart->getClass()->getMethod("getBaseValue"); + auto result = method(_javaPart); + return result; + } + + // Methods + + +} // namespace margelo::nitro::image diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridBaseSpec.hpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridBaseSpec.hpp new file mode 100644 index 00000000..f11158c9 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridBaseSpec.hpp @@ -0,0 +1,56 @@ +/// +/// HybridBaseSpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include +#include "HybridBaseSpec.hpp" + + + + +namespace margelo::nitro::image { + + using namespace facebook; + + class JHybridBaseSpec: public jni::HybridClass, + public virtual HybridBaseSpec { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/image/HybridBaseSpec;"; + static jni::local_ref initHybrid(jni::alias_ref jThis); + static void registerNatives(); + + protected: + // C++ constructor (called from Java via `initHybrid()`) + explicit JHybridBaseSpec(jni::alias_ref jThis) : + HybridObject(HybridBaseSpec::TAG), + _javaPart(jni::make_global(jThis)) {} + + public: + size_t getExternalMemorySize() noexcept override; + + public: + inline const jni::global_ref& getJavaPart() const noexcept { + return _javaPart; + } + + public: + // Properties + double getBaseValue() override; + + public: + // Methods + + + private: + friend HybridBase; + using HybridBase::HybridBase; + jni::global_ref _javaPart; + }; + +} // namespace margelo::nitro::image diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridChildSpec.cpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridChildSpec.cpp new file mode 100644 index 00000000..60deff05 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridChildSpec.cpp @@ -0,0 +1,46 @@ +/// +/// JHybridChildSpec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#include "JHybridChildSpec.hpp" + + + + + +namespace margelo::nitro::image { + + jni::local_ref JHybridChildSpec::initHybrid(jni::alias_ref jThis) { + return makeCxxInstance(jThis); + } + + void JHybridChildSpec::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JHybridChildSpec::initHybrid), + }); + } + + size_t JHybridChildSpec::getExternalMemorySize() noexcept { + static const auto method = _javaPart->getClass()->getMethod("getMemorySize"); + return method(_javaPart); + } + + // Properties + double JHybridChildSpec::getChildValue() { + static const auto method = _javaPart->getClass()->getMethod("getChildValue"); + auto result = method(_javaPart); + return result; + } + double JHybridChildSpec::getBaseValue() { + static const auto method = _javaPart->getClass()->getMethod("getBaseValue"); + auto result = method(_javaPart); + return result; + } + + // Methods + + +} // namespace margelo::nitro::image diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridChildSpec.hpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridChildSpec.hpp new file mode 100644 index 00000000..2dec7ac3 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridChildSpec.hpp @@ -0,0 +1,59 @@ +/// +/// HybridChildSpec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include +#include "HybridChildSpec.hpp" + +// Forward declaration of `JHybridBaseSpec` to properly resolve imports. +namespace margelo::nitro::image { class JHybridBaseSpec; } +#include "JHybridBaseSpec.hpp" + +namespace margelo::nitro::image { + + using namespace facebook; + + class JHybridChildSpec: public jni::HybridClass, + public virtual HybridChildSpec { + public: + static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/image/HybridChildSpec;"; + static jni::local_ref initHybrid(jni::alias_ref jThis); + static void registerNatives(); + + protected: + // C++ constructor (called from Java via `initHybrid()`) + explicit JHybridChildSpec(jni::alias_ref jThis) : + HybridObject(HybridChildSpec::TAG), + HybridBase(jThis), + _javaPart(jni::make_global(jThis)) {} + + public: + size_t getExternalMemorySize() noexcept override; + + public: + inline const jni::global_ref& getJavaPart() const noexcept { + return _javaPart; + } + + public: + // Properties + double getChildValue() override; + double getBaseValue() override; + + public: + // Methods + + + private: + friend HybridBase; + using HybridBase::HybridBase; + jni::global_ref _javaPart; + }; + +} // namespace margelo::nitro::image diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageFactorySpec.hpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageFactorySpec.hpp index 4f7ca137..9a807e4e 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageFactorySpec.hpp +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageFactorySpec.hpp @@ -11,18 +11,21 @@ #include #include "HybridImageFactorySpec.hpp" + + + namespace margelo::nitro::image { using namespace facebook; - class JHybridImageFactorySpec final: public jni::HybridClass, - public HybridImageFactorySpec { + class JHybridImageFactorySpec: public jni::HybridClass, + public virtual HybridImageFactorySpec { public: static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/image/HybridImageFactorySpec;"; static jni::local_ref initHybrid(jni::alias_ref jThis); static void registerNatives(); - private: + protected: // C++ constructor (called from Java via `initHybrid()`) explicit JHybridImageFactorySpec(jni::alias_ref jThis) : HybridObject(HybridImageFactorySpec::TAG), diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageSpec.hpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageSpec.hpp index 290a0208..d6a6ba48 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageSpec.hpp +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridImageSpec.hpp @@ -11,18 +11,21 @@ #include #include "HybridImageSpec.hpp" + + + namespace margelo::nitro::image { using namespace facebook; - class JHybridImageSpec final: public jni::HybridClass, - public HybridImageSpec { + class JHybridImageSpec: public jni::HybridClass, + public virtual HybridImageSpec { public: static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/image/HybridImageSpec;"; static jni::local_ref initHybrid(jni::alias_ref jThis); static void registerNatives(); - private: + protected: // C++ constructor (called from Java via `initHybrid()`) explicit JHybridImageSpec(jni::alias_ref jThis) : HybridObject(HybridImageSpec::TAG), diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridTestObjectSwiftKotlinSpec.hpp b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridTestObjectSwiftKotlinSpec.hpp index ff8b26a1..961d4d71 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridTestObjectSwiftKotlinSpec.hpp +++ b/packages/react-native-nitro-image/nitrogen/generated/android/c++/JHybridTestObjectSwiftKotlinSpec.hpp @@ -11,18 +11,21 @@ #include #include "HybridTestObjectSwiftKotlinSpec.hpp" + + + namespace margelo::nitro::image { using namespace facebook; - class JHybridTestObjectSwiftKotlinSpec final: public jni::HybridClass, - public HybridTestObjectSwiftKotlinSpec { + class JHybridTestObjectSwiftKotlinSpec: public jni::HybridClass, + public virtual HybridTestObjectSwiftKotlinSpec { public: static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/image/HybridTestObjectSwiftKotlinSpec;"; static jni::local_ref initHybrid(jni::alias_ref jThis); static void registerNatives(); - private: + protected: // C++ constructor (called from Java via `initHybrid()`) explicit JHybridTestObjectSwiftKotlinSpec(jni::alias_ref jThis) : HybridObject(HybridTestObjectSwiftKotlinSpec::TAG), diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridBaseSpec.kt b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridBaseSpec.kt new file mode 100644 index 00000000..8783b845 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridBaseSpec.kt @@ -0,0 +1,64 @@ +/// +/// HybridBaseSpec.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.image + +import android.util.Log +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.margelo.nitro.core.* + +/** + * A Kotlin class representing the Base HybridObject. + * Implement this abstract class to create Kotlin-based instances of Base. + */ +@DoNotStrip +@Keep +@Suppress("RedundantSuppression", "KotlinJniMissingFunction", "PropertyName", "RedundantUnitReturnType", "unused") +abstract class HybridBaseSpec: HybridObject() { + @DoNotStrip + private var mHybridData: HybridData = initHybrid() + + init { + // Pass this `HybridData` through to it's base class, + // to represent inheritance to JHybridObject on C++ side + super.updateNative(mHybridData) + } + + /** + * Call from a child class to initialize HybridData with a child. + */ + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + } + + // Properties + @get:DoNotStrip + @get:Keep + abstract val baseValue: Double + + // Methods + + + private external fun initHybrid(): HybridData + + companion object { + private const val TAG = "HybridBaseSpec" + init { + try { + Log.i(TAG, "Loading NitroImage C++ library...") + System.loadLibrary("NitroImage") + Log.i(TAG, "Successfully loaded NitroImage C++ library!") + } catch (e: Error) { + Log.e(TAG, "Failed to load NitroImage C++ library! Is it properly installed and linked? " + + "Is the name correct? (see `CMakeLists.txt`, at `add_library(...)`)", e) + throw e + } + } + } +} diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridChildSpec.kt b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridChildSpec.kt new file mode 100644 index 00000000..7c2cda56 --- /dev/null +++ b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridChildSpec.kt @@ -0,0 +1,64 @@ +/// +/// HybridChildSpec.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © 2024 Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.image + +import android.util.Log +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.margelo.nitro.core.* + +/** + * A Kotlin class representing the Child HybridObject. + * Implement this abstract class to create Kotlin-based instances of Child. + */ +@DoNotStrip +@Keep +@Suppress("RedundantSuppression", "KotlinJniMissingFunction", "PropertyName", "RedundantUnitReturnType", "unused") +abstract class HybridChildSpec: HybridBaseSpec() { + @DoNotStrip + private var mHybridData: HybridData = initHybrid() + + init { + // Pass this `HybridData` through to it's base class, + // to represent inheritance to JHybridObject on C++ side + super.updateNative(mHybridData) + } + + /** + * Call from a child class to initialize HybridData with a child. + */ + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + } + + // Properties + @get:DoNotStrip + @get:Keep + abstract val childValue: Double + + // Methods + + + private external fun initHybrid(): HybridData + + companion object { + private const val TAG = "HybridChildSpec" + init { + try { + Log.i(TAG, "Loading NitroImage C++ library...") + System.loadLibrary("NitroImage") + Log.i(TAG, "Successfully loaded NitroImage C++ library!") + } catch (e: Error) { + Log.e(TAG, "Failed to load NitroImage C++ library! Is it properly installed and linked? " + + "Is the name correct? (see `CMakeLists.txt`, at `add_library(...)`)", e) + throw e + } + } + } +} diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageFactorySpec.kt b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageFactorySpec.kt index aa09c0ec..a6c11ab1 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageFactorySpec.kt +++ b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageFactorySpec.kt @@ -21,10 +21,8 @@ import com.margelo.nitro.core.* @Keep @Suppress("RedundantSuppression", "KotlinJniMissingFunction", "PropertyName", "RedundantUnitReturnType", "unused") abstract class HybridImageFactorySpec: HybridObject() { - protected val TAG = "HybridImageFactorySpec" - @DoNotStrip - val mHybridData: HybridData = initHybrid() + private var mHybridData: HybridData = initHybrid() init { // Pass this `HybridData` through to it's base class, @@ -32,6 +30,13 @@ abstract class HybridImageFactorySpec: HybridObject() { super.updateNative(mHybridData) } + /** + * Call from a child class to initialize HybridData with a child. + */ + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + } + // Properties diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageSpec.kt b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageSpec.kt index de5a6c84..c9519b7d 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageSpec.kt +++ b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridImageSpec.kt @@ -21,10 +21,8 @@ import com.margelo.nitro.core.* @Keep @Suppress("RedundantSuppression", "KotlinJniMissingFunction", "PropertyName", "RedundantUnitReturnType", "unused") abstract class HybridImageSpec: HybridObject() { - protected val TAG = "HybridImageSpec" - @DoNotStrip - val mHybridData: HybridData = initHybrid() + private var mHybridData: HybridData = initHybrid() init { // Pass this `HybridData` through to it's base class, @@ -32,6 +30,13 @@ abstract class HybridImageSpec: HybridObject() { super.updateNative(mHybridData) } + /** + * Call from a child class to initialize HybridData with a child. + */ + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + } + // Properties @get:DoNotStrip @get:Keep diff --git a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridTestObjectSwiftKotlinSpec.kt b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridTestObjectSwiftKotlinSpec.kt index a2108f1f..7d84bb35 100644 --- a/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridTestObjectSwiftKotlinSpec.kt +++ b/packages/react-native-nitro-image/nitrogen/generated/android/kotlin/com/margelo/nitro/image/HybridTestObjectSwiftKotlinSpec.kt @@ -21,10 +21,8 @@ import com.margelo.nitro.core.* @Keep @Suppress("RedundantSuppression", "KotlinJniMissingFunction", "PropertyName", "RedundantUnitReturnType", "unused") abstract class HybridTestObjectSwiftKotlinSpec: HybridObject() { - protected val TAG = "HybridTestObjectSwiftKotlinSpec" - @DoNotStrip - val mHybridData: HybridData = initHybrid() + private var mHybridData: HybridData = initHybrid() init { // Pass this `HybridData` through to it's base class, @@ -32,6 +30,13 @@ abstract class HybridTestObjectSwiftKotlinSpec: HybridObject() { super.updateNative(mHybridData) } + /** + * Call from a child class to initialize HybridData with a child. + */ + override fun updateNative(hybridData: HybridData) { + mHybridData = hybridData + } + // Properties @get:DoNotStrip @get:Keep diff --git a/packages/react-native-nitro-image/src/specs/TestObject.nitro.ts b/packages/react-native-nitro-image/src/specs/TestObject.nitro.ts index 9f47d2e0..68bd4891 100644 --- a/packages/react-native-nitro-image/src/specs/TestObject.nitro.ts +++ b/packages/react-native-nitro-image/src/specs/TestObject.nitro.ts @@ -120,7 +120,8 @@ export interface TestObjectSwiftKotlin newTestObject(): TestObjectSwiftKotlin } -export interface Base extends HybridObject<{ ios: 'swift' }> { +export interface Base + extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> { readonly baseValue: number } diff --git a/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/HybridObject.kt b/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/HybridObject.kt index a11223db..178fce47 100644 --- a/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/HybridObject.kt +++ b/packages/react-native-nitro-modules/android/src/main/java/com/margelo/nitro/core/HybridObject.kt @@ -4,12 +4,16 @@ import androidx.annotation.Keep import com.facebook.jni.HybridData import com.facebook.proguard.annotations.DoNotStrip +interface ExtendableHybridClass { + fun updateNative(hybridData: HybridData) +} + /** * A base class for all Kotlin-based HybridObjects. */ @Keep @DoNotStrip -abstract class HybridObject { +abstract class HybridObject: ExtendableHybridClass { /** * Get the memory size of the Kotlin instance (plus any external heap allocations), * in bytes. @@ -41,7 +45,7 @@ abstract class HybridObject { * Must be called in the constructor of a subclass of `HybridObject`, to initialize the C++ * `JHybridObject` with a subclass of it. */ - protected fun updateNative(hybridData: HybridData) { + override fun updateNative(hybridData: HybridData) { mHybridData = hybridData } }