Skip to content

Commit 86a7e90

Browse files
j-piaseckiShawn Dempseytido64Shawn Dempsey
authored
feat: add TurboModule support (#910)
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>
1 parent f4e5d92 commit 86a7e90

File tree

19 files changed

+375
-86
lines changed

19 files changed

+375
-86
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
yarn bundle:ios --dev false
7373
- name: Install Pods
7474
run: |
75-
pod install
75+
RCT_NEW_ARCH_ENABLED=1 pod install
7676
working-directory: example/ios
7777
- name: Boot simulator
7878
run: |
@@ -109,7 +109,7 @@ jobs:
109109
yarn bundle:macos
110110
- name: Install Pods
111111
run: |
112-
pod install
112+
RCT_NEW_ARCH_ENABLED=1 pod install
113113
working-directory: example/macos
114114
- name: Build
115115
run: |

RNCAsyncStorage.podspec

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ require 'json'
22

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

5+
fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
6+
57
Pod::Spec.new do |s|
68
s.name = "RNCAsyncStorage"
79
s.version = package['version']
@@ -10,10 +12,24 @@ Pod::Spec.new do |s|
1012

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

1516
s.source = { :git => "https://github.com/react-native-async-storage/async-storage.git", :tag => "v#{s.version}" }
16-
s.source_files = "ios/**/*.{h,m}"
17+
s.source_files = "ios/**/*.{h,m,mm}"
18+
19+
if fabric_enabled
20+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
21+
22+
s.pod_target_xcconfig = {
23+
'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/boost" "$(PODS_ROOT)/boost-for-react-native" "$(PODS_ROOT)/RCT-Folly"',
24+
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17',
25+
}
26+
s.platforms = { ios: '13.4', tvos: '11.0', :osx => "10.15" }
27+
s.compiler_flags = folly_compiler_flags + ' -DRCT_NEW_ARCH_ENABLED'
28+
29+
install_modules_dependencies(s)
30+
else
31+
s.platforms = { :ios => "9.0", :tvos => "9.2", :osx => "10.14" }
1732

18-
s.dependency 'React-Core'
33+
s.dependency "React-Core"
34+
end
1935
end

android/build.gradle

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ def getVersionOrDefault(String flagName, String defaultVersion) {
2929
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] : defaultVersion
3030
}
3131

32+
def isNewArchitectureEnabled() {
33+
// To opt-in for the New Architecture, you can either:
34+
// - Set `newArchEnabled` to true inside the `gradle.properties` file
35+
// - Invoke gradle with `-newArchEnabled=true`
36+
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
37+
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
38+
}
39+
3240
configurations {
3341
compileClasspath
3442
}
@@ -73,8 +81,22 @@ if (useNextStorage) {
7381
apply from: './testresults.gradle'
7482
}
7583

84+
if (isNewArchitectureEnabled()) {
85+
apply plugin: "com.facebook.react"
86+
}
87+
7688
android {
7789
compileSdkVersion safeExtGet('compileSdkVersion', 32)
90+
// Used to override the NDK path/version by allowing users to customize
91+
// the NDK path/version from their root project (e.g. for M1 support)
92+
if (rootProject.hasProperty("ndkPath")) {
93+
ndkPath rootProject.ext.ndkPath
94+
}
95+
if (rootProject.hasProperty("ndkVersion")) {
96+
ndkVersion rootProject.ext.ndkVersion
97+
}
98+
99+
78100
defaultConfig {
79101
minSdkVersion safeExtGet('minSdkVersion', 23)
80102
targetSdkVersion safeExtGet('targetSdkVersion', 32)
@@ -94,6 +116,20 @@ android {
94116
}
95117
}
96118
}
119+
120+
sourceSets.main {
121+
java {
122+
if (useNextStorage) {
123+
srcDirs += 'src/kotlinPackage/java'
124+
} else {
125+
srcDirs += 'src/javaPackage/java'
126+
}
127+
128+
if (!isNewArchitectureEnabled()) {
129+
srcDirs += 'src/oldarch/java'
130+
}
131+
}
132+
}
97133
}
98134

99135
repositories {
@@ -137,6 +173,5 @@ dependencies {
137173
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesTest_version"
138174
}
139175

140-
//noinspection GradleDynamicVersion
141-
implementation 'com.facebook.react:react-native:+' // From node_modules
176+
implementation 'com.facebook.react:react-native:+' // from node_modules
142177
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.reactnativecommunity.asyncstorage;
9+
10+
import com.facebook.react.TurboReactPackage;
11+
import com.facebook.react.ViewManagerOnDemandReactPackage;
12+
import com.facebook.react.bridge.ModuleSpec;
13+
import com.facebook.react.bridge.JavaScriptModule;
14+
import com.facebook.react.bridge.NativeModule;
15+
import com.facebook.react.bridge.ReactApplicationContext;
16+
import com.facebook.react.module.annotations.ReactModule;
17+
import com.facebook.react.module.annotations.ReactModuleList;
18+
import com.facebook.react.module.model.ReactModuleInfo;
19+
import com.facebook.react.module.model.ReactModuleInfoProvider;
20+
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
21+
import com.facebook.react.uimanager.ViewManager;
22+
import java.util.Collections;
23+
import java.util.HashMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
import javax.annotation.Nonnull;
28+
import javax.annotation.Nullable;
29+
30+
@ReactModuleList(
31+
nativeModules = {
32+
AsyncStorageModule.class,
33+
}
34+
)
35+
public class AsyncStoragePackage extends TurboReactPackage {
36+
37+
@Override
38+
protected List<ModuleSpec> getViewManagers(ReactApplicationContext reactContext) {
39+
return null;
40+
}
41+
42+
@Override
43+
public NativeModule getModule(String name, @Nonnull ReactApplicationContext reactContext) {
44+
switch (name) {
45+
case AsyncStorageModule.NAME:
46+
return new AsyncStorageModule(reactContext);
47+
default:
48+
return null;
49+
}
50+
}
51+
52+
@Override
53+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
54+
try {
55+
Class<?> reactModuleInfoProviderClass =
56+
Class.forName("com.reactnativecommunity.asyncstorage.AsyncStoragePackage$$ReactModuleInfoProvider");
57+
return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
58+
} catch (ClassNotFoundException e) {
59+
// ReactModuleSpecProcessor does not run at build-time. Create this ReactModuleInfoProvider by
60+
// hand.
61+
return new ReactModuleInfoProvider() {
62+
@Override
63+
public Map<String, ReactModuleInfo> getReactModuleInfos() {
64+
final Map<String, ReactModuleInfo> reactModuleInfoMap = new HashMap<>();
65+
66+
Class<? extends NativeModule>[] moduleList =
67+
new Class[] {
68+
AsyncStorageModule.class,
69+
};
70+
71+
for (Class<? extends NativeModule> moduleClass : moduleList) {
72+
ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
73+
74+
reactModuleInfoMap.put(
75+
reactModule.name(),
76+
new ReactModuleInfo(
77+
reactModule.name(),
78+
moduleClass.getName(),
79+
reactModule.canOverrideExistingModule(),
80+
reactModule.needsEagerInit(),
81+
reactModule.hasConstants(),
82+
reactModule.isCxxModule(),
83+
TurboModule.class.isAssignableFrom(moduleClass)));
84+
}
85+
86+
return reactModuleInfoMap;
87+
}
88+
};
89+
} catch (InstantiationException | IllegalAccessException e) {
90+
throw new RuntimeException(
91+
"No ReactModuleInfoProvider for com.reactnativecommunity.asyncstorage.AsyncStoragePackage$$ReactModuleInfoProvider", e);
92+
}
93+
}
94+
95+
// Deprecated in RN 0.47
96+
public List<Class<? extends JavaScriptModule>> createJSModules() {
97+
return Collections.emptyList();
98+
}
99+
100+
@Override
101+
@SuppressWarnings("rawtypes")
102+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
103+
return Collections.emptyList();
104+
}
105+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.reactnativecommunity.asyncstorage
2+
3+
import com.facebook.react.TurboReactPackage
4+
import com.facebook.react.ViewManagerOnDemandReactPackage
5+
import com.facebook.react.bridge.ModuleSpec
6+
import com.facebook.react.bridge.NativeModule
7+
import com.facebook.react.bridge.ReactApplicationContext
8+
import com.facebook.react.module.annotations.ReactModule
9+
import com.facebook.react.module.annotations.ReactModuleList
10+
import com.facebook.react.module.model.ReactModuleInfo
11+
import com.facebook.react.module.model.ReactModuleInfoProvider
12+
import com.facebook.react.turbomodule.core.interfaces.TurboModule
13+
import com.facebook.react.uimanager.ReactShadowNode
14+
import com.facebook.react.uimanager.ViewManager
15+
import com.reactnativecommunity.asyncstorage.next.StorageModule
16+
17+
@ReactModuleList(
18+
nativeModules = [
19+
StorageModule::class
20+
]
21+
)
22+
class AsyncStoragePackage : TurboReactPackage() {
23+
override fun getModule(name: String, context: ReactApplicationContext): NativeModule? = when (name) {
24+
StorageModule.NAME -> StorageModule(context)
25+
else -> null
26+
}
27+
28+
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
29+
try {
30+
val reactModuleInfoProviderClass =
31+
Class.forName("com.reactnativecommunity.asyncstorage.AsyncStoragePackage$\$ReactModuleInfoProvider")
32+
return reactModuleInfoProviderClass.newInstance() as ReactModuleInfoProvider
33+
} catch (e: ClassNotFoundException) {
34+
return ReactModuleInfoProvider {
35+
val reactModule: ReactModule = StorageModule::class.java.getAnnotation(
36+
ReactModule::class.java)!!
37+
38+
mutableMapOf(
39+
StorageModule.NAME to ReactModuleInfo(
40+
reactModule.name,
41+
StorageModule::class.java.name,
42+
reactModule.canOverrideExistingModule,
43+
reactModule.needsEagerInit,
44+
reactModule.hasConstants,
45+
reactModule.isCxxModule,
46+
TurboModule::class.java.isAssignableFrom(StorageModule::class.java)
47+
)
48+
)
49+
}
50+
} catch (e: InstantiationException) {
51+
throw RuntimeException("No ReactModuleInfoProvider for AsyncStoragePackage$\$ReactModuleInfoProvider", e)
52+
} catch (e: IllegalAccessException) {
53+
throw RuntimeException("No ReactModuleInfoProvider for AsyncStoragePackage$\$ReactModuleInfoProvider", e)
54+
}
55+
}
56+
57+
override fun getViewManagers(reactContext: ReactApplicationContext?): MutableList<ModuleSpec>? = null
58+
}

android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@
3434

3535
@ReactModule(name = AsyncStorageModule.NAME)
3636
public final class AsyncStorageModule
37-
extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable, LifecycleEventListener {
37+
extends NativeAsyncStorageModuleSpec implements ModuleDataCleaner.Cleanable, LifecycleEventListener {
3838

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

4242
// SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER:
4343
// https://raw.githubusercontent.com/android/platform_external_sqlite/master/dist/sqlite3.c
@@ -110,6 +110,7 @@ public void onHostDestroy() {
110110
* (key, null) for the keys that haven't been found.
111111
*/
112112
@ReactMethod
113+
@Override
113114
public void multiGet(final ReadableArray keys, final Callback callback) {
114115
if (keys == null) {
115116
callback.invoke(AsyncStorageErrorUtil.getInvalidKeyError(null), null);
@@ -183,6 +184,7 @@ protected void doInBackgroundGuarded(Void... params) {
183184
* The insertion will replace conflicting (key, value) pairs.
184185
*/
185186
@ReactMethod
187+
@Override
186188
public void multiSet(final ReadableArray keyValueArray, final Callback callback) {
187189
if (keyValueArray.size() == 0) {
188190
callback.invoke();
@@ -248,6 +250,7 @@ protected void doInBackgroundGuarded(Void... params) {
248250
* Removes all rows of the keys given.
249251
*/
250252
@ReactMethod
253+
@Override
251254
public void multiRemove(final ReadableArray keys, final Callback callback) {
252255
if (keys.size() == 0) {
253256
callback.invoke();
@@ -300,6 +303,7 @@ protected void doInBackgroundGuarded(Void... params) {
300303
* of the given keys, if they exist.
301304
*/
302305
@ReactMethod
306+
@Override
303307
public void multiMerge(final ReadableArray keyValueArray, final Callback callback) {
304308
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
305309
@Override
@@ -362,6 +366,7 @@ protected void doInBackgroundGuarded(Void... params) {
362366
* Clears the database.
363367
*/
364368
@ReactMethod
369+
@Override
365370
public void clear(final Callback callback) {
366371
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
367372
@Override
@@ -385,6 +390,7 @@ protected void doInBackgroundGuarded(Void... params) {
385390
* Returns an array with all keys from the database.
386391
*/
387392
@ReactMethod
393+
@Override
388394
public void getAllKeys(final Callback callback) {
389395
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
390396
@Override

0 commit comments

Comments
 (0)