From 88cac53ba1c2f3fe7b4f4e1afe7d54f292188892 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Fri, 31 May 2024 15:44:21 +0200 Subject: [PATCH] feat: expose Rive RendererType to choose renderer --- RNRiveRendererType.swift | 35 +++++++++++++++++++ RiveReactNativeRendererModule.swift | 24 +++++++++++++ RiveReactNativeRendererModuleBridge.m | 14 ++++++++ .../com/rivereactnative/RNRiveRendererType.kt | 28 +++++++++++++++ .../rivereactnative/RiveReactNativePackage.kt | 6 ++-- .../RiveReactNativeRendererModule.kt | 16 +++++++++ example/index.tsx | 4 +-- example/src/App.tsx | 29 +++++++++++++-- src/Rive.tsx | 7 ++++ src/index.tsx | 4 ++- src/types.ts | 19 ++++++++++ 11 files changed, 178 insertions(+), 8 deletions(-) create mode 100644 RNRiveRendererType.swift create mode 100644 RiveReactNativeRendererModule.swift create mode 100644 RiveReactNativeRendererModuleBridge.m create mode 100644 android/src/main/java/com/rivereactnative/RNRiveRendererType.kt create mode 100644 android/src/main/java/com/rivereactnative/RiveReactNativeRendererModule.kt diff --git a/RNRiveRendererType.swift b/RNRiveRendererType.swift new file mode 100644 index 0000000..2bebf29 --- /dev/null +++ b/RNRiveRendererType.swift @@ -0,0 +1,35 @@ +// +// RNRiveRendererType.swift +// rive-react-native +// +// Created by Peter G Hayes on 31/05/2024. +// + +import Foundation +import RiveRuntime + +enum RNRiveRendererType: String { + case Rive = "riveRenderer" + case Skia = "skiaRenderer" + case CoreGraphics = "cgRenderer" + + static func mapToRNRiveRendererType(value: String) -> RNRiveRendererType { + if let rnEnum = RNRiveRendererType(rawValue: value) { + return rnEnum + } else { + fatalError("Unsupported renderer type: \(value)") + } + } + + static func mapToRendererType(rnRendererType: RNRiveRendererType) -> RendererType { + switch rnRendererType { + case .Rive: + return RendererType.riveRenderer + case .Skia: + return RendererType.skiaRenderer + case .CoreGraphics: + return RendererType.cgRenderer + } + } +} + diff --git a/RiveReactNativeRendererModule.swift b/RiveReactNativeRendererModule.swift new file mode 100644 index 0000000..b1391b2 --- /dev/null +++ b/RiveReactNativeRendererModule.swift @@ -0,0 +1,24 @@ +// +// RiveReactNativeRendererModule.swift +// rive-react-native +// +// Created by Peter G Hayes on 31/05/2024. +// + +import Foundation +import RiveRuntime + +@objc(RiveReactNativeRendererModule) +class RiveReactNativeRendererModule: NSObject { + + @objc(defaultRenderer:androidRenderer:) + func defaultRenderer(_ iosRenderer: String, androidRenderer: String) -> Void { + let rnRendererType = RNRiveRendererType.mapToRNRiveRendererType(value: iosRenderer) + RenderContextManager.shared().defaultRenderer = RNRiveRendererType.mapToRendererType(rnRendererType: rnRendererType) + } + // Required to register the module with React Native + @objc static func requiresMainQueueSetup() -> Bool { + return true + } + +} diff --git a/RiveReactNativeRendererModuleBridge.m b/RiveReactNativeRendererModuleBridge.m new file mode 100644 index 0000000..c140555 --- /dev/null +++ b/RiveReactNativeRendererModuleBridge.m @@ -0,0 +1,14 @@ +// +// RiveReactNativeRendererModuleBridge.m +// rive-react-native +// +// Created by Peter G Hayes on 31/05/2024. +// + +#import + +@interface RCT_EXTERN_MODULE(RiveReactNativeRendererModule, NSObject) + +RCT_EXTERN_METHOD(defaultRenderer:(NSString *)iosRenderer androidRenderer:(NSString *)androidRenderer) + +@end diff --git a/android/src/main/java/com/rivereactnative/RNRiveRendererType.kt b/android/src/main/java/com/rivereactnative/RNRiveRendererType.kt new file mode 100644 index 0000000..c0d0251 --- /dev/null +++ b/android/src/main/java/com/rivereactnative/RNRiveRendererType.kt @@ -0,0 +1,28 @@ +package com.rivereactnative + +import app.rive.runtime.kotlin.core.RendererType + +enum class RNRiveRendererType(private val rendererTypeName: String) { + Rive("riveRenderer"), + Skia("skiaRenderer"), + Canvas("canvasRenderer"); + + override fun toString(): String { + return rendererTypeName + } + + companion object { + fun mapToRNRiveRendererType(rendererType: String): RNRiveRendererType { + return values().first { it.rendererTypeName == rendererType } + } + + fun mapToRiveRendererType(rnRendererType: RNRiveRendererType): RendererType { + return when (rnRendererType) { + Rive -> RendererType.Rive + Skia -> RendererType.Skia + Canvas -> RendererType.Canvas + } + } + } +} + diff --git a/android/src/main/java/com/rivereactnative/RiveReactNativePackage.kt b/android/src/main/java/com/rivereactnative/RiveReactNativePackage.kt index a8e61f9..0b5aae9 100644 --- a/android/src/main/java/com/rivereactnative/RiveReactNativePackage.kt +++ b/android/src/main/java/com/rivereactnative/RiveReactNativePackage.kt @@ -7,9 +7,9 @@ import com.facebook.react.uimanager.ViewManager class RiveReactNativePackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return emptyList() - } + override fun createNativeModules( + reactContext: ReactApplicationContext + ): MutableList = listOf(RiveReactNativeRendererModule(reactContext)).toMutableList() override fun createViewManagers(reactContext: ReactApplicationContext): List> { return listOf(RiveReactNativeViewManager()) diff --git a/android/src/main/java/com/rivereactnative/RiveReactNativeRendererModule.kt b/android/src/main/java/com/rivereactnative/RiveReactNativeRendererModule.kt new file mode 100644 index 0000000..c8454f6 --- /dev/null +++ b/android/src/main/java/com/rivereactnative/RiveReactNativeRendererModule.kt @@ -0,0 +1,16 @@ +package com.rivereactnative + +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReactMethod +import app.rive.runtime.kotlin.core.Rive + +class RiveReactNativeRendererModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { + override fun getName() = "RiveReactNativeRendererModule" + + @ReactMethod fun defaultRenderer(iosRenderer: String, androidRenderer: String) { + val rnRendererType = RNRiveRendererType.mapToRNRiveRendererType(androidRenderer); + val rendererType = RNRiveRendererType.mapToRiveRendererType(rnRendererType); + Rive.init(reactApplicationContext, defaultRenderer = rendererType) + } +} diff --git a/example/index.tsx b/example/index.tsx index 117ddca..08c82ac 100644 --- a/example/index.tsx +++ b/example/index.tsx @@ -1,5 +1,5 @@ import { AppRegistry } from 'react-native'; -import App from './src/App'; import { name as appName } from './app.json'; +import Main from './src/App'; -AppRegistry.registerComponent(appName, () => App); +AppRegistry.registerComponent(appName, () => Main); diff --git a/example/src/App.tsx b/example/src/App.tsx index ac57167..2411389 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { useEffect } from 'react'; import { createStackNavigator } from '@react-navigation/stack'; import { NavigationContainer } from '@react-navigation/native'; import { SafeAreaProvider } from 'react-native-safe-area-context'; @@ -17,9 +17,34 @@ import DynamicText from './DynamicText'; import NestedInputs from './NestedInputs'; import Events from './Events'; +import { + RiveRenderer, + RiveRendererAndroid, + RiveRendererIOS, +} from 'rive-react-native'; + const Stack = createStackNavigator(); -export default function App() { +export default function Main() { + // Configure the defualt renderer to use for both iOS and Android. + // For more information: https://rive.app/community/doc/overview/docD20dU9Rod + // + // This is optional. The current defaults are: + // - iOS: Skia + // - Android: Skia + // In the future the default will be the Rive Renderer (RiveRendererIOS.Rive and RiveRendererAndroid.Rive) + // + useEffect(() => { + RiveRenderer.defaultRenderer( + RiveRendererIOS.Rive, + RiveRendererAndroid.Skia + ); + }, []); + + return ; +} + +function App() { return ( diff --git a/src/Rive.tsx b/src/Rive.tsx index 6be8d0e..2784835 100644 --- a/src/Rive.tsx +++ b/src/Rive.tsx @@ -10,6 +10,7 @@ import { TouchableWithoutFeedback, GestureResponderEvent, StyleProp, + NativeModules, } from 'react-native'; import { RiveRef, @@ -19,11 +20,17 @@ import { ViewManagerMethod, RiveGeneralEvent, RiveOpenUrlEvent, + RiveRendererInterface, } from './types'; import { convertErrorFromNativeToRN, XOR } from './helpers'; import { Alignment, Fit } from './types'; +const { RiveReactNativeRendererModule } = NativeModules; + +export const RiveRenderer = + RiveReactNativeRendererModule as RiveRendererInterface; + type RiveProps = { onPlay?: ( event: NativeSyntheticEvent<{ diff --git a/src/index.tsx b/src/index.tsx index 5f5689a..dcdc306 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,4 +1,6 @@ export * from './types'; -import Rive from './Rive'; +import Rive, { RiveRenderer } from './Rive'; + +export { RiveRenderer }; export default Rive; diff --git a/src/types.ts b/src/types.ts index 99c6e81..2517528 100644 --- a/src/types.ts +++ b/src/types.ts @@ -67,6 +67,18 @@ export enum Direction { Forwards = 'forwards', } +export enum RiveRendererIOS { + Rive = 'riveRenderer', + Skia = 'skiaRenderer', + CoreGraphics = 'cgRenderer', +} + +export enum RiveRendererAndroid { + Rive = 'riveRenderer', + Skia = 'skiaRenderer', + Canvas = 'canvasRenderer', +} + export enum RNRiveErrorType { FileNotFound = 'FileNotFound', UnsupportedRuntimeVersion = 'UnsupportedRuntimeVersion', @@ -101,3 +113,10 @@ export interface RiveOpenUrlEvent extends RiveEvent { url?: string; target?: string; } + +export interface RiveRendererInterface { + defaultRenderer( + iosRenderer: RiveRendererIOS, + androidRenderer: RiveRendererAndroid + ): void; +}