Skip to content

Commit

Permalink
feat: add TurboModule support (#910)
Browse files Browse the repository at this point in the history
Co-authored-by: Shawn Dempsey <shawndempsey@fb.com>
Co-authored-by: Tommy Nguyen <4123478+tido64@users.noreply.github.com>
Co-authored-by: Shawn Dempsey <shawnton@gmail.com>
  • Loading branch information
4 people authored Jul 3, 2023
1 parent f4e5d92 commit 86a7e90
Show file tree
Hide file tree
Showing 19 changed files with 375 additions and 86 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
yarn bundle:ios --dev false
- name: Install Pods
run: |
pod install
RCT_NEW_ARCH_ENABLED=1 pod install
working-directory: example/ios
- name: Boot simulator
run: |
Expand Down Expand Up @@ -109,7 +109,7 @@ jobs:
yarn bundle:macos
- name: Install Pods
run: |
pod install
RCT_NEW_ARCH_ENABLED=1 pod install
working-directory: example/macos
- name: Build
run: |
Expand Down
22 changes: 19 additions & 3 deletions RNCAsyncStorage.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ require 'json'

package = JSON.parse(File.read(File.join(__dir__, 'package.json')))

fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'

Pod::Spec.new do |s|
s.name = "RNCAsyncStorage"
s.version = package['version']
Expand All @@ -10,10 +12,24 @@ Pod::Spec.new do |s|

s.authors = package['author']
s.homepage = package['homepage']
s.platforms = { :ios => "9.0", :tvos => "9.2", :osx => "10.14" }

s.source = { :git => "https://github.com/react-native-async-storage/async-storage.git", :tag => "v#{s.version}" }
s.source_files = "ios/**/*.{h,m}"
s.source_files = "ios/**/*.{h,m,mm}"

if fabric_enabled
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'

s.pod_target_xcconfig = {
'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/boost" "$(PODS_ROOT)/boost-for-react-native" "$(PODS_ROOT)/RCT-Folly"',
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
}
s.platforms = { ios: '13.4', tvos: '11.0', :osx => "10.15" }
s.compiler_flags = folly_compiler_flags + ' -DRCT_NEW_ARCH_ENABLED'

install_modules_dependencies(s)
else
s.platforms = { :ios => "9.0", :tvos => "9.2", :osx => "10.14" }

s.dependency 'React-Core'
s.dependency "React-Core"
end
end
39 changes: 37 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ def getVersionOrDefault(String flagName, String defaultVersion) {
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] : defaultVersion
}

def isNewArchitectureEnabled() {
// To opt-in for the New Architecture, you can either:
// - Set `newArchEnabled` to true inside the `gradle.properties` file
// - Invoke gradle with `-newArchEnabled=true`
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

configurations {
compileClasspath
}
Expand Down Expand Up @@ -73,8 +81,22 @@ if (useNextStorage) {
apply from: './testresults.gradle'
}

if (isNewArchitectureEnabled()) {
apply plugin: "com.facebook.react"
}

android {
compileSdkVersion safeExtGet('compileSdkVersion', 32)
// Used to override the NDK path/version by allowing users to customize
// the NDK path/version from their root project (e.g. for M1 support)
if (rootProject.hasProperty("ndkPath")) {
ndkPath rootProject.ext.ndkPath
}
if (rootProject.hasProperty("ndkVersion")) {
ndkVersion rootProject.ext.ndkVersion
}


defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 23)
targetSdkVersion safeExtGet('targetSdkVersion', 32)
Expand All @@ -94,6 +116,20 @@ android {
}
}
}

sourceSets.main {
java {
if (useNextStorage) {
srcDirs += 'src/kotlinPackage/java'
} else {
srcDirs += 'src/javaPackage/java'
}

if (!isNewArchitectureEnabled()) {
srcDirs += 'src/oldarch/java'
}
}
}
}

repositories {
Expand Down Expand Up @@ -137,6 +173,5 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesTest_version"
}

//noinspection GradleDynamicVersion
implementation 'com.facebook.react:react-native:+' // From node_modules
implementation 'com.facebook.react:react-native:+' // from node_modules
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.reactnativecommunity.asyncstorage;

import com.facebook.react.TurboReactPackage;
import com.facebook.react.ViewManagerOnDemandReactPackage;
import com.facebook.react.bridge.ModuleSpec;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.module.annotations.ReactModuleList;
import com.facebook.react.module.model.ReactModuleInfo;
import com.facebook.react.module.model.ReactModuleInfoProvider;
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
import com.facebook.react.uimanager.ViewManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

@ReactModuleList(
nativeModules = {
AsyncStorageModule.class,
}
)
public class AsyncStoragePackage extends TurboReactPackage {

@Override
protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
return null;
}

@Override
public NativeModule getModule(String name, @Nonnull ReactApplicationContext reactContext) {
switch (name) {
case AsyncStorageModule.NAME:
return new AsyncStorageModule(reactContext);
default:
return null;
}
}

@Override
public ReactModuleInfoProvider getReactModuleInfoProvider() {
try {
Class<?> reactModuleInfoProviderClass =
Class.forName("com.reactnativecommunity.asyncstorage.AsyncStoragePackage$$ReactModuleInfoProvider");
return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
} catch (ClassNotFoundException e) {
// ReactModuleSpecProcessor does not run at build-time. Create this ReactModuleInfoProvider by
// hand.
return new ReactModuleInfoProvider() {
@Override
public Map<String, ReactModuleInfo> getReactModuleInfos() {
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();

Class<? extends NativeModule>[] moduleList =
new Class[] {
AsyncStorageModule.class,
};

for (Class<? extends NativeModule> moduleClass : moduleList) {
ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);

reactModuleInfoMap.put(
reactModule.name(),
new ReactModuleInfo(
reactModule.name(),
moduleClass.getName(),
reactModule.canOverrideExistingModule(),
reactModule.needsEagerInit(),
reactModule.hasConstants(),
reactModule.isCxxModule(),
TurboModule.class.isAssignableFrom(moduleClass)));
}

return reactModuleInfoMap;
}
};
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(
"No ReactModuleInfoProvider for com.reactnativecommunity.asyncstorage.AsyncStoragePackage$$ReactModuleInfoProvider", e);
}
}

// Deprecated in RN 0.47
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
@SuppressWarnings("rawtypes")
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.reactnativecommunity.asyncstorage

import com.facebook.react.TurboReactPackage
import com.facebook.react.ViewManagerOnDemandReactPackage
import com.facebook.react.bridge.ModuleSpec
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
import com.facebook.react.module.annotations.ReactModuleList
import com.facebook.react.module.model.ReactModuleInfo
import com.facebook.react.module.model.ReactModuleInfoProvider
import com.facebook.react.turbomodule.core.interfaces.TurboModule
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
import com.reactnativecommunity.asyncstorage.next.StorageModule

@ReactModuleList(
nativeModules = [
StorageModule::class
]
)
class AsyncStoragePackage : TurboReactPackage() {
override fun getModule(name: String, context: ReactApplicationContext): NativeModule? = when (name) {
StorageModule.NAME -> StorageModule(context)
else -> null
}

override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
try {
val reactModuleInfoProviderClass =
Class.forName("com.reactnativecommunity.asyncstorage.AsyncStoragePackage$\$ReactModuleInfoProvider")
return reactModuleInfoProviderClass.newInstance() as ReactModuleInfoProvider
} catch (e: ClassNotFoundException) {
return ReactModuleInfoProvider {
val reactModule: ReactModule = StorageModule::class.java.getAnnotation(
ReactModule::class.java)!!

mutableMapOf(
StorageModule.NAME to ReactModuleInfo(
reactModule.name,
StorageModule::class.java.name,
reactModule.canOverrideExistingModule,
reactModule.needsEagerInit,
reactModule.hasConstants,
reactModule.isCxxModule,
TurboModule::class.java.isAssignableFrom(StorageModule::class.java)
)
)
}
} catch (e: InstantiationException) {
throw RuntimeException("No ReactModuleInfoProvider for AsyncStoragePackage$\$ReactModuleInfoProvider", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("No ReactModuleInfoProvider for AsyncStoragePackage$\$ReactModuleInfoProvider", e)
}
}

override fun getViewManagers(reactContext: ReactApplicationContext?): MutableList<ModuleSpec>? = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@

@ReactModule(name = AsyncStorageModule.NAME)
public final class AsyncStorageModule
extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable, LifecycleEventListener {
extends NativeAsyncStorageModuleSpec implements ModuleDataCleaner.Cleanable, LifecycleEventListener {

// changed name to not conflict with AsyncStorage from RN repo
public static final String NAME = "RNC_AsyncSQLiteDBStorage";
public static final String NAME = "RNCAsyncStorage";

// SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER:
// https://raw.githubusercontent.com/android/platform_external_sqlite/master/dist/sqlite3.c
Expand Down Expand Up @@ -110,6 +110,7 @@ public void onHostDestroy() {
* (key, null) for the keys that haven't been found.
*/
@ReactMethod
@Override
public void multiGet(final ReadableArray keys, final Callback callback) {
if (keys == null) {
callback.invoke(AsyncStorageErrorUtil.getInvalidKeyError(null), null);
Expand Down Expand Up @@ -183,6 +184,7 @@ protected void doInBackgroundGuarded(Void... params) {
* The insertion will replace conflicting (key, value) pairs.
*/
@ReactMethod
@Override
public void multiSet(final ReadableArray keyValueArray, final Callback callback) {
if (keyValueArray.size() == 0) {
callback.invoke();
Expand Down Expand Up @@ -248,6 +250,7 @@ protected void doInBackgroundGuarded(Void... params) {
* Removes all rows of the keys given.
*/
@ReactMethod
@Override
public void multiRemove(final ReadableArray keys, final Callback callback) {
if (keys.size() == 0) {
callback.invoke();
Expand Down Expand Up @@ -300,6 +303,7 @@ protected void doInBackgroundGuarded(Void... params) {
* of the given keys, if they exist.
*/
@ReactMethod
@Override
public void multiMerge(final ReadableArray keyValueArray, final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
Expand Down Expand Up @@ -362,6 +366,7 @@ protected void doInBackgroundGuarded(Void... params) {
* Clears the database.
*/
@ReactMethod
@Override
public void clear(final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
Expand All @@ -385,6 +390,7 @@ protected void doInBackgroundGuarded(Void... params) {
* Returns an array with all keys from the database.
*/
@ReactMethod
@Override
public void getAllKeys(final Callback callback) {
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
@Override
Expand Down
Loading

0 comments on commit 86a7e90

Please sign in to comment.