From 644057b40e46bf27c30cc72e9eb65d2b7df9e84d Mon Sep 17 00:00:00 2001 From: txbrown Date: Wed, 26 Feb 2025 00:40:56 +0000 Subject: [PATCH 01/16] chore: remove flipper config --- example/ios/Podfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/example/ios/Podfile b/example/ios/Podfile index 8b0db43..5ed8ca9 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -17,7 +17,6 @@ prepare_react_native_project! # dependencies: { # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), # ``` -flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled linkage = ENV['USE_FRAMEWORKS'] if linkage != nil @@ -40,7 +39,6 @@ target 'ElementaryExample' do # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. - :flipper_configuration => flipper_config, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) From c2528562bf0e2507ebdf7c643e596b23e3411528 Mon Sep 17 00:00:00 2001 From: txbrown Date: Wed, 26 Feb 2025 00:41:27 +0000 Subject: [PATCH 02/16] chore: bump ruby version --- .ruby-version | 1 + example/ios/Podfile.lock | 112 ++------------------------------------- 2 files changed, 4 insertions(+), 109 deletions(-) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..fd2a018 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.1.0 diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 3778af4..12da8db 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,6 +1,5 @@ PODS: - boost (1.76.0) - - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - FBLazyVector (0.72.3) - FBReactNativeSpec (0.72.3): @@ -10,71 +9,12 @@ PODS: - React-Core (= 0.72.3) - React-jsi (= 0.72.3) - ReactCommon/turbomodule/core (= 0.72.3) - - Flipper (0.182.0): - - Flipper-Folly (~> 2.6) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - FlipperKit (0.182.0): - - FlipperKit/Core (= 0.182.0) - - FlipperKit/Core (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.182.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.182.0) - - FlipperKit/FKPortForwarding (0.182.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.182.0) - - FlipperKit/FlipperKitLayoutHelpers (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) - hermes-engine (0.72.3): - hermes-engine/Pre-built (= 0.72.3) - hermes-engine/Pre-built (0.72.3) - libevent (2.1.12) - - OpenSSL-Universal (1.1.1100) - RCT-Folly (2021.07.22.00): - boost - DoubleConversion @@ -490,38 +430,15 @@ PODS: - React-perflogger (= 0.72.3) - SocketRocket (0.6.1) - Yoga (1.14.0) - - YogaKit (1.18.1): - - Yoga (~> 1.14) DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - - Flipper (= 0.182.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - FlipperKit (= 0.182.0) - - FlipperKit/Core (= 0.182.0) - - FlipperKit/CppBridge (= 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0) - - FlipperKit/FBDefines (= 0.182.0) - - FlipperKit/FKPortForwarding (= 0.182.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0) - - FlipperKit/FlipperKitReactPlugin (= 0.182.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) @@ -529,7 +446,6 @@ DEPENDENCIES: - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) - - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) @@ -561,20 +477,9 @@ DEPENDENCIES: SPEC REPOS: trunk: - - CocoaAsyncSocket - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - FlipperKit - fmt - libevent - - OpenSSL-Universal - SocketRocket - - YogaKit EXTERNAL SOURCES: boost: @@ -660,24 +565,14 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - boost: 57d2868c099736d80fcd648bf211b4431e51a558 - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + boost: 7dcd2de282d72e344012f7d6564d024930a6a440 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: 4cce221dd782d3ff7c4172167bba09d58af67ccb FBReactNativeSpec: c6bd9e179757b3c0ecf815864fae8032377903ef - Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b hermes-engine: 10fbd3f62405c41ea07e71973ea61e1878d07322 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: a2faf4bad4e438ca37b2040cb8f7799baa065c18 RCTTypeSafety: cb09f3e4747b6d18331a15eb05271de7441ca0b3 @@ -713,8 +608,7 @@ SPEC CHECKSUMS: ReactCommon: 3ccb8fb14e6b3277e38c73b0ff5e4a1b8db017a9 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: c47ec4940290e3bfb41ae3cb4272c588ec4f4318 +PODFILE CHECKSUM: 789a01bd60f1aa66a6c580d432d27de6c553fdb7 -COCOAPODS: 1.14.3 +COCOAPODS: 1.16.2 From 79b46d102dda85fab674ec19cd96c545cd2bb108 Mon Sep 17 00:00:00 2001 From: txbrown Date: Wed, 26 Feb 2025 01:42:48 +0000 Subject: [PATCH 03/16] feat: attempt to upgrade to new arch --- .elementaryspec | 22 ++++++++++ .../com/elementary/ElementaryTurboModule.java | 25 +++++++++++ .../elementary/ElementaryTurboPackage.java | 43 +++++++++++++++++++ example/ios/Podfile | 14 ++++++ example/ios/Podfile.lock | 2 +- ios/Elementary.h | 4 +- ios/Elementary.mm | 8 ++++ package.json | 8 ++++ src/NativeElementary.ts | 9 ++++ src/index.tsx | 15 ++++--- 10 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 .elementaryspec create mode 100644 android/src/newarch/com/elementary/ElementaryTurboModule.java create mode 100644 android/src/newarch/com/elementary/ElementaryTurboPackage.java create mode 100644 src/NativeElementary.ts diff --git a/.elementaryspec b/.elementaryspec new file mode 100644 index 0000000..1936194 --- /dev/null +++ b/.elementaryspec @@ -0,0 +1,22 @@ +{ + "modules": { + "Elementary": { + "type": "NativeModule", + "methods": { + "getSampleRate": { + "type": "Promise", + "returnType": "number" + }, + "applyInstructions": { + "type": "method", + "arguments": [ + { + "name": "message", + "type": "string" + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/android/src/newarch/com/elementary/ElementaryTurboModule.java b/android/src/newarch/com/elementary/ElementaryTurboModule.java new file mode 100644 index 0000000..b88e922 --- /dev/null +++ b/android/src/newarch/com/elementary/ElementaryTurboModule.java @@ -0,0 +1,25 @@ +package com.elementary; + +import androidx.annotation.NonNull; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.Promise; +import com.elementary.NativeElementarySpec; + +public class ElementaryTurboModule extends NativeElementarySpec { + private final ElementaryModule module; + + public ElementaryTurboModule(ReactApplicationContext reactContext) { + super(reactContext); + module = new ElementaryModule(reactContext); + } + + @Override + public void getSampleRate(Promise promise) { + module.getSampleRate(promise); + } + + @Override + public void applyInstructions(String message) { + module.applyInstructions(message); + } +} \ No newline at end of file diff --git a/android/src/newarch/com/elementary/ElementaryTurboPackage.java b/android/src/newarch/com/elementary/ElementaryTurboPackage.java new file mode 100644 index 0000000..b14d730 --- /dev/null +++ b/android/src/newarch/com/elementary/ElementaryTurboPackage.java @@ -0,0 +1,43 @@ +package com.elementary; + +import androidx.annotation.Nullable; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.TurboReactPackage; + +import java.util.HashMap; +import java.util.Map; + +public class ElementaryTurboPackage extends TurboReactPackage { + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(ElementaryModule.NAME)) { + return new ElementaryTurboModule(reactContext); + } else { + return null; + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + moduleInfos.put( + ElementaryModule.NAME, + new ReactModuleInfo( + ElementaryModule.NAME, + ElementaryModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + true // isTurboModule + ) + ); + return moduleInfos; + }; + } +} \ No newline at end of file diff --git a/example/ios/Podfile b/example/ios/Podfile index 5ed8ca9..26014f6 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -56,5 +56,19 @@ target 'ElementaryExample' do :mac_catalyst_enabled => false ) __apply_Xcode_12_5_M1_post_install_workaround(installer) + + # Force all pods to use iOS 13.0 minimum + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' + + # Fix C++ standard library issues for react-native-elementary + if target.name == 'react-native-elementary' + config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++17' + config.build_settings['CLANG_CXX_LIBRARY'] = 'libc++' + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)', 'ELEMENTARY_IOS=1'] + end + end + end end end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 12da8db..d6432a6 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -609,6 +609,6 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce -PODFILE CHECKSUM: 789a01bd60f1aa66a6c580d432d27de6c553fdb7 +PODFILE CHECKSUM: 7069de68d386166d3eada37aa0505bd27a97176f COCOAPODS: 1.16.2 diff --git a/ios/Elementary.h b/ios/Elementary.h index abe3b56..3cb4a53 100644 --- a/ios/Elementary.h +++ b/ios/Elementary.h @@ -15,7 +15,7 @@ @interface Elementary : RCTEventEmitter #endif -@property (nonatomic, strong) AVAudioEngine *audioEngine; -@property (nonatomic, assign) std::shared_ptr> runtime; +@property(nonatomic, strong) AVAudioEngine *audioEngine; +@property(nonatomic, assign) std::shared_ptr> runtime; @end diff --git a/ios/Elementary.mm b/ios/Elementary.mm index e6070a3..ef886a8 100644 --- a/ios/Elementary.mm +++ b/ios/Elementary.mm @@ -88,4 +88,12 @@ + (BOOL) requiresMainQueueSetup { return @[@"AudioPlaybackFinished"]; } +// For the new architecture +#ifdef RCT_NEW_ARCH_ENABLED +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} +#endif @end diff --git a/package.json b/package.json index 22ee584..3d2d1fc 100644 --- a/package.json +++ b/package.json @@ -163,5 +163,13 @@ } ] ] + }, + "codegenConfig": { + "name": "RNElementarySpec", + "type": "modules", + "jsSrcsDir": "src", + "android": { + "javaPackageName": "com.elementary" + } } } diff --git a/src/NativeElementary.ts b/src/NativeElementary.ts new file mode 100644 index 0000000..2fa7cee --- /dev/null +++ b/src/NativeElementary.ts @@ -0,0 +1,9 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + getSampleRate(): Promise; + applyInstructions(message: string): void; +} + +export default TurboModuleRegistry.getEnforcing('Elementary'); diff --git a/src/index.tsx b/src/index.tsx index 4800a11..369a051 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,7 @@ import { NativeModules, Platform } from 'react-native'; import { Renderer } from '@elemaudio/core'; import { useEffect, useRef, useState } from 'react'; +import NativeElementary from './NativeElementary'; const LINKING_ERROR = `The package 'react-native-elementary' doesn't seem to be linked. Make sure: \n\n` + @@ -8,8 +9,12 @@ const LINKING_ERROR = '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n'; -const Elementary = - NativeModules.Elementary ?? +// Get the native module +const Elementary = NativeElementary || NativeModules.Elementary; + +// Fall back to error if module is not available +const ElementaryModule = + Elementary ?? new Proxy( {}, { @@ -20,15 +25,13 @@ const Elementary = ); export function getSampleRate(): Promise { - // Native modules need first parameter to distinguish between params and callbacks - // in the bridge layer. - return Elementary.getSampleRate(1); + return ElementaryModule.getSampleRate(); } export class NativeRenderer extends Renderer { constructor(sampleRate: number) { super(sampleRate, (instructions: unknown) => { - Elementary.applyInstructions(JSON.stringify(instructions)); + ElementaryModule.applyInstructions(JSON.stringify(instructions)); }); } } From 6f551c3c2135b1d8851a2aea19f2f018b500dc8c Mon Sep 17 00:00:00 2001 From: txbrown Date: Wed, 26 Feb 2025 01:43:26 +0000 Subject: [PATCH 04/16] feat: add expo example app - so we can test it works on expo --- example-expo-app/.gitignore | 36 + example-expo-app/App.tsx | 50 + example-expo-app/app.json | 28 + example-expo-app/assets/adaptive-icon.png | Bin 0 -> 17547 bytes example-expo-app/assets/favicon.png | Bin 0 -> 1466 bytes example-expo-app/assets/icon.png | Bin 0 -> 22380 bytes example-expo-app/assets/splash-icon.png | Bin 0 -> 17547 bytes example-expo-app/index.ts | 8 + example-expo-app/package-lock.json | 10105 ++++++++++++++++++++ example-expo-app/package.json | 25 + example-expo-app/tsconfig.json | 6 + 11 files changed, 10258 insertions(+) create mode 100644 example-expo-app/.gitignore create mode 100644 example-expo-app/App.tsx create mode 100644 example-expo-app/app.json create mode 100644 example-expo-app/assets/adaptive-icon.png create mode 100644 example-expo-app/assets/favicon.png create mode 100644 example-expo-app/assets/icon.png create mode 100644 example-expo-app/assets/splash-icon.png create mode 100644 example-expo-app/index.ts create mode 100644 example-expo-app/package-lock.json create mode 100644 example-expo-app/package.json create mode 100644 example-expo-app/tsconfig.json diff --git a/example-expo-app/.gitignore b/example-expo-app/.gitignore new file mode 100644 index 0000000..d16e1ef --- /dev/null +++ b/example-expo-app/.gitignore @@ -0,0 +1,36 @@ +# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files + +# dependencies +node_modules/ + +# Expo +.expo/ +dist/ +web-build/ +expo-env.d.ts + +# Native +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# local env files +.env*.local + +# typescript +*.tsbuildinfo diff --git a/example-expo-app/App.tsx b/example-expo-app/App.tsx new file mode 100644 index 0000000..fbe5dcc --- /dev/null +++ b/example-expo-app/App.tsx @@ -0,0 +1,50 @@ +import React, { useState } from 'react'; +import { StatusBar } from 'expo-status-bar'; +import { StyleSheet, Text, View, Button } from 'react-native'; +import { useRenderer } from 'react-native-elementary'; +import { el } from '@elemaudio/core'; + +export default function App() { + const { core } = useRenderer(); + const [isPlaying, setIsPlaying] = useState(false); + + const playTone = () => { + if (!core) return; + + setIsPlaying(true); + const tone = el.cycle(el.const({ value: 440 })); + core.render(tone, tone); + }; + + const stopTone = () => { + if (!core) return; + + setIsPlaying(false); + core.render(el.const({ value: 0 }), el.const({ value: 0 })); + }; + + return ( + + Elementary Audio in Expo +