voize-gmbh / reakt-native-toolkit Goto Github PK
View Code? Open in Web Editor NEWCombine React Native with Kotlin Multiplatform (KMP)
License: Apache License 2.0
Combine React Native with Kotlin Multiplatform (KMP)
License: Apache License 2.0
Hi guys!
I'm having a problem building my test application
I followed your instructions from the readme, made a clean Expo module, made a Kotlin multiplatform module, added annotations, generated classes
The problem occurred on Step 4
I'm trying to register a generated class but I'm getting a class incompatibility error.
Am I missing some step?
I'm trying to run the example app from the main branch with no modifications, and am getting the following error during the gradle build:
e: java.lang.IllegalStateException: e: Could not find "/Users/raman/source_ext/reakt-native-toolkit/example/android/shared/build/kotlinTransformedMetadataLibraries/commonMain/de.voize-reakt-native-toolkit-0.16.0-commonMain-_D7riQ.klib" in [/Users/raman/Library/Application Support/kotlin/daemon]
at org.jetbrains.kotlin.library.SingleFileResolveKt$resolveSingleFileKlib$1.fatal(SingleFileResolve.kt:21)
at org.jetbrains.kotlin.library.KotlinLibrarySearchPathResolver.resolve(SearchPathResolver.kt:171)
at org.jetbrains.kotlin.library.KotlinLibrarySearchPathResolver.resolve(SearchPathResolver.kt:176)
at org.jetbrains.kotlin.library.CompilerSingleFileKlibResolveStrategy.resolve(SearchPathResolver.kt:298)
at org.jetbrains.kotlin.library.SingleFileResolveKt.resolveSingleFileKlib(SingleFileResolve.kt:24)
at org.jetbrains.kotlin.library.SingleFileResolveKt.resolveSingleFileKlib$default(SingleFileResolve.kt:15)
at org.jetbrains.kotlin.cli.metadata.KlibMetadataDependencyContainer.<init>(K2MetadataKlibSerializer.kt:117)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer$serialize$analyzer$1.invoke(K2MetadataKlibSerializer.kt:49)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer$serialize$analyzer$1.invoke(K2MetadataKlibSerializer.kt:43)
at org.jetbrains.kotlin.cli.metadata.CommonAnalysisKt.runCommonAnalysisForSerialization(CommonAnalysis.kt:42)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer.serialize(K2MetadataKlibSerializer.kt:48)
at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:122)
at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:40)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:100)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:46)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1486)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Generated code in build dir for ios contains unused args, resulting in the build output warning.
"Parameter 'args' is never used, could be renamed to _"
To reproduce, create a suspended function with no properties:
@ReactNativeMethod
fun getInfo(): String {
return SDK.deviceManager.getInfo().asString()
}
Results with generated code:
RCTBridgeMethodWrapper("getInfo") { args, promise -> getInfo(promise as
PromiseIOS<String>)}
Hi. Just a few questions.
The create-react-native-library
tool instantiates modules in JavaScript with code that looks like this:
import { NativeModules, Platform } from 'react-native';
const LINKING_ERROR =
`The package 'foo' doesn't seem to be linked. Make sure: \n\n` +
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo Go\n';
const Foo = NativeModules.Foo
? NativeModules.Foo
: new Proxy(
{},
{
get() {
throw new Error(LINKING_ERROR);
},
}
);
If the module is not linked for some reason, this produces a nice error message. With the toolkit, the generated Typescript code simply tries to dereference the undefined module, which results in much less clear errors like:
Cannot read property 'unsubscribeFromToolkitUseFlow' of null
Currently useFlow logs to console if there was an error getting the next value.
Trying the example app. On iOS, consistently see the error shortly after clicking the "Subscribe" button:
Possible unhandled promise rejection (id: 2): Error: IllegalArgumentException: Unsupported value type Unit
If a flow is used in React and it throws an exception the subscription stops.
Hi,
I'm trying to use a module returning a flow but I'm receiving this error:
Next value promise in useFlow was rejected: Error: NoSuchElementException: Expected at least one element matching the predicate (kotlin.String) -> kotlin.Boolean
My module look like this:
@ReactNativeModule("FooUseCase")
class FooUseCaseRN(private val fooUseCase: FooUseCase) {
@ReactNativeFlow
suspend fun getFoo(): Flow<List<String>> {
[Some code returning a flow]
}
}
(I saw from the debugger that the code from the method getFoo is called and working)
I tried returning only a string instead of a list of string, thinking that it is working only for primitive, but I got the same error.
The generated modules.ts look like this:
// This file is generated by ReaktNativeToolkit. Do not edit.
import {NativeEventEmitter, NativeModules} from 'react-native';
import {Next} from 'reakt-native-toolkit';
interface NativeFooUseCaseInterface {
getFoo: Next<Array<string>>;
}
/**
* Module generated from {@link com.bar.baz.usecase.FooUseCaseRN}.
*/
export interface FooUseCaseInterface {
getFoo: Next<Array<string>>;
}
type _workaround = NativeEventEmitter;
const NativeFooUseCase = NativeModules.FooUseCase as NativeFooUseCaseInterface
export const FooUseCase: FooUseCaseInterface = {
...NativeFooUseCase,
getFoo: (currentValue: string | null) => NativeFooUseCase.getFoo(currentValue)
}
Finally, in my view, I'm calling it like this:
const foo = useFlow(FooUseCase.getFoo);
Any idea what could happen?
package bar.foo
import foo.bar.Test2
data class Test1(
val test: Test2
)
package foo.bar
data class Test2(
val test: String
)
Typescript namespace reference is not using disambiguous references.
Hi,
First of all, super cool library and idea!
At my company, we already use kotlin multiplatform a lot for our native apps.
And we also see a huge benefit in using it when developing native modules for some of our react-native apps. But since react-native is moving closer and closer to finally completing the new architecture work, it would be nice to know if you guys are planning to also make this toolkit compatible with TurboModules and bridgeless mode?
Thanks!
execute command
yarn install
# then
yarn android
kotlin version: 1.8.21
error message: java.lang.IllegalStateException: e: Could not find "/Users/user/github/reakt-native-toolkit/example/android/shared/build/kotlinTransformedMetadataLibraries/commonMain/de.voize-reakt-native-toolkit-0.13.1-commonMain-FzgqYA.klib" in [/Users/user/Library/Application Support/kotlin/daemon]
at org.jetbrains.kotlin.library.SingleFileResolveKt$resolveSingleFileKlib$1.fatal(SingleFileResolve.kt:21)
at org.jetbrains.kotlin.library.KotlinLibrarySearchPathResolver.resolve(SearchPathResolver.kt:171)
at org.jetbrains.kotlin.library.KotlinLibrarySearchPathResolver.resolve(SearchPathResolver.kt:176)
at org.jetbrains.kotlin.library.CompilerSingleFileKlibResolveStrategy.resolve(SearchPathResolver.kt:298)
at org.jetbrains.kotlin.library.SingleFileResolveKt.resolveSingleFileKlib(SingleFileResolve.kt:24)
at org.jetbrains.kotlin.library.SingleFileResolveKt.resolveSingleFileKlib$default(SingleFileResolve.kt:15)
at org.jetbrains.kotlin.cli.metadata.KlibMetadataDependencyContainer.<init>(K2MetadataKlibSerializer.kt:117)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer$serialize$analyzer$1.invoke(K2MetadataKlibSerializer.kt:49)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer$serialize$analyzer$1.invoke(K2MetadataKlibSerializer.kt:43)
at org.jetbrains.kotlin.cli.metadata.CommonAnalysisKt.runCommonAnalysisForSerialization(CommonAnalysis.kt:42)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer.serialize(K2MetadataKlibSerializer.kt:48)
at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:122)
at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:40)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:100)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:46)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1486)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.rmi/sun.rmi.transport.Transport$1.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Unknown Source)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
In JS there are many different builtin and libraries for representing and processing datetimes. In Kotlin the go to way is to use the official kotlinx-datetime library.
To keep the toolkit agnostic we can not enforce a single mapping and need to make it configurable. At first we will provide two mappings:
The following code:
interface CustomInterface {
fun foo(): String
}
fun CustomInterface.bar(): String {
return "bar"
}
@ReactNativeModule("Custom")
class CustomRNModule(
private val custom: CustomInterface
) {
// working
@ReactNativeMethod
fun getFoo(): String {
return custom.foo()
}
// not working
@ReactNativeMethod
fun getBar(): String {
return custom.bar()
}
}
fails to compile:
e: [ksp] java.lang.IllegalStateException: Interfaces are not supported
at de.voize.reaktnativetoolkit.ksp.processor.TypescriptGenerator.getTypescriptSerializedTypeName(TypescriptGenerator.kt:851)
at de.voize.reaktnativetoolkit.ksp.processor.TypescriptGenerator.createTypescriptRNModule(TypescriptGenerator.kt:184)
at de.voize.reaktnativetoolkit.ksp.processor.TypescriptGenerator.createRNModulesFile(TypescriptGenerator.kt:154)
at de.voize.reaktnativetoolkit.ksp.processor.TypescriptGenerator.generate(TypescriptGenerator.kt:107)
at de.voize.reaktnativetoolkit.ksp.processor.ToolkitSymbolProcessor.process(ToolkitSymbolProcessor.kt:247)
at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$8$1.invoke(KotlinSymbolProcessingExtension.kt:306)
at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension$doAnalysis$8$1.invoke(KotlinSymbolProcessingExtension.kt:304)
at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.handleException(KotlinSymbolProcessingExtension.kt:410)
at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:304)
at org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory$Companion.analyzeFiles(CommonResolverForModuleFactory.kt:203)
at org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory$Companion.analyzeFiles$default(CommonResolverForModuleFactory.kt:143)
at org.jetbrains.kotlin.cli.metadata.CommonAnalysisKt$runCommonAnalysisIteration$1.invoke(CommonAnalysis.kt:72)
at org.jetbrains.kotlin.cli.metadata.CommonAnalysisKt$runCommonAnalysisIteration$1.invoke(CommonAnalysis.kt:71)
at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:115)
at org.jetbrains.kotlin.cli.metadata.CommonAnalysisKt.runCommonAnalysisIteration(CommonAnalysis.kt:71)
at org.jetbrains.kotlin.cli.metadata.CommonAnalysisKt.runCommonAnalysisForSerialization(CommonAnalysis.kt:38)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer.analyze(K2MetadataKlibSerializer.kt:43)
at org.jetbrains.kotlin.cli.metadata.K2MetadataKlibSerializer.analyze(K2MetadataKlibSerializer.kt:38)
at org.jetbrains.kotlin.cli.metadata.AbstractMetadataSerializer.analyzeAndSerialize(AbstractMetadataSerializer.kt:34)
at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:126)
at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:40)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:104)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:48)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:101)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1523)
at jdk.internal.reflect.GeneratedMethodAccessor89.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.rmi/sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:360)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:200)
at java.rmi/sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
at java.rmi/sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at java.rmi/sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:587)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:828)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:705)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.rmi/sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:704)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:840)
After following the project setup steps, I tried to build my project after adding the @ReactNativeModule and @ReactNativeMethod annotations (using the example CalculatorRNModule class).
During the build process, the toolkit generates the CalculatorRNModuleProvider.kt file, which then causes the two compilation errors:
The CalculatorRNModule class in my project is defined under commonMain in the shared module.
I'm glad to let you know that I managed to add your library to our project and successfully migrated the first module 🥳
In our setup, the Kotlin project is outside of the RN project, so in our approach to the Kotlin project, we have a bridge
module where we keep modules and methods calling the main SDK to generate the code. Then we publish Android artefacts, build XCFramework, and move it with generated code to the RN project. For now, we only generate stuff and make RN use it like before. Next week will be changing the RN side to use the useFlow
finally 😃 🤞
The Example app has a function TimeProvider.time()
:
When this is used in a React Native view, the time updates very quickly -- on the order of every 1 or 2 milliseconds. When timeAsState
is used, the time updates every second as expected.
Is this just an example of using a Flow incorrectly i.e. without turning it into a StateFlow
? Or is it an indication of a bug in the flow toReact
code?
Can you maybe create an example folder where in is a react native project which has a proper setup to use your reakt-native-toolkit. I tried to follow your documentation and readme but I failed. It took me more than a day to find out all the options and setup which are needed. A little bit more documentation and help would be appreciated.
I am struggling using reakt-native-toolkit.
I get an error and I can't find information where to add the dependency
Execution failed for task ':shared:mapReleaseSourceSetPaths'.
> Could not resolve all files for configuration ':shared:releaseRuntimeClasspath'.
> Could not find com.facebook.react:react-native:0.69.4.
Required by:
project :shared > de.voize:reakt-native-toolkit:0.2.0 > de.voize:reakt-native-toolkit-android:0.2.0
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.