expo-modules-core 0.4.9 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/CHANGELOG.md +33 -2
  2. package/android/build.gradle +30 -2
  3. package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +42 -5
  4. package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +49 -5
  5. package/android/src/main/java/expo/modules/core/BasePackage.java +6 -0
  6. package/android/src/main/java/expo/modules/core/ModulePriorities.kt +25 -0
  7. package/android/src/main/java/expo/modules/core/interfaces/ActivityEventListener.java +3 -1
  8. package/android/src/main/java/expo/modules/core/interfaces/Package.java +4 -0
  9. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.java +21 -0
  10. package/android/src/main/java/expo/modules/core/interfaces/ReactActivityLifecycleListener.java +23 -0
  11. package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +14 -0
  12. package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
  13. package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
  14. package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
  15. package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
  16. package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +24 -0
  17. package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
  18. package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
  19. package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
  20. package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
  21. package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
  22. package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
  23. package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
  24. package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
  25. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
  26. package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
  27. package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
  28. package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
  29. package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
  30. package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
  31. package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
  32. package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
  33. package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
  34. package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
  35. package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
  36. package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
  37. package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
  38. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
  39. package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
  40. package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
  41. package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
  42. package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
  43. package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
  44. package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
  45. package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
  46. package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
  47. package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
  48. package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
  49. package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
  50. package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
  51. package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
  52. package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
  53. package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
  54. package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
  55. package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
  56. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +41 -0
  57. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
  58. package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
  59. package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
  60. package/build/NativeModulesProxy.native.d.ts +4 -0
  61. package/build/NativeModulesProxy.native.js +14 -1
  62. package/build/NativeModulesProxy.native.js.map +1 -1
  63. package/build/NativeModulesProxy.types.d.ts +3 -0
  64. package/build/NativeModulesProxy.types.js.map +1 -1
  65. package/build/NativeViewManagerAdapter.native.js +1 -1
  66. package/build/NativeViewManagerAdapter.native.js.map +1 -1
  67. package/ios/AppDelegates/EXAppDelegateWrapper.h +19 -0
  68. package/ios/AppDelegates/EXAppDelegateWrapper.m +45 -0
  69. package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
  70. package/ios/AppDelegates/EXAppDelegatesLoader.m +30 -0
  71. package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
  72. package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
  73. package/ios/AppDelegates/ExpoAppDelegate.swift +282 -0
  74. package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
  75. package/ios/EXAppDefines.h +26 -0
  76. package/ios/EXAppDefines.m +61 -0
  77. package/ios/ExpoModulesCore.podspec +8 -3
  78. package/ios/JSI/ExpoModulesProxySpec.h +24 -0
  79. package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
  80. package/ios/JSI/JSIConversions.h +42 -0
  81. package/ios/JSI/JSIConversions.mm +164 -0
  82. package/ios/JSI/JSIInstaller.h +19 -0
  83. package/ios/JSI/JSIInstaller.mm +22 -0
  84. package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
  85. package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
  86. package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +63 -17
  87. package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.h +16 -0
  88. package/ios/ReactDelegates/EXRCTBridgeDelegateInterceptor.m +49 -0
  89. package/ios/ReactDelegates/EXReactDelegateWrapper+Private.h +18 -0
  90. package/ios/ReactDelegates/EXReactDelegateWrapper.h +25 -0
  91. package/ios/ReactDelegates/EXReactDelegateWrapper.m +40 -0
  92. package/ios/ReactDelegates/ExpoReactDelegate.swift +37 -0
  93. package/ios/ReactDelegates/ExpoReactDelegateHandler.swift +52 -0
  94. package/ios/ReactDelegates/ModulePriorities.swift +20 -0
  95. package/ios/Services/EXReactNativeEventEmitter.h +6 -0
  96. package/ios/Services/EXReactNativeEventEmitter.m +15 -0
  97. package/ios/Swift/AppContext.swift +14 -1
  98. package/ios/Swift/Arguments/AnyArgument.swift +14 -0
  99. package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
  100. package/ios/Swift/Arguments/ArgumentType.swift +24 -0
  101. package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
  102. package/ios/Swift/Arguments/Convertibles.swift +107 -0
  103. package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
  104. package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
  105. package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
  106. package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
  107. package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
  108. package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
  109. package/ios/Swift/Conversions.swift +199 -7
  110. package/ios/Swift/EventListener.swift +37 -5
  111. package/ios/Swift/Functions/AnyFunction.swift +42 -0
  112. package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
  113. package/ios/Swift/ModuleHolder.swift +86 -20
  114. package/ios/Swift/ModuleRegistry.swift +19 -8
  115. package/ios/Swift/Modules/AnyModule.swift +8 -8
  116. package/ios/Swift/Modules/Module.swift +11 -0
  117. package/ios/Swift/Modules/ModuleDefinition.swift +55 -15
  118. package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
  119. package/ios/Swift/Modules/ModuleDefinitionComponents.swift +149 -54
  120. package/ios/Swift/ModulesProvider.swift +19 -0
  121. package/ios/Swift/Promise.swift +1 -1
  122. package/ios/Swift/Records/Field.swift +1 -1
  123. package/ios/Swift/Records/Record.swift +8 -1
  124. package/ios/Swift/SwiftInteropBridge.swift +46 -17
  125. package/ios/Swift/Views/AnyViewProp.swift +2 -2
  126. package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
  127. package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
  128. package/ios/Swift.h +9 -0
  129. package/ios/Tests/ArgumentTypeSpec.swift +145 -0
  130. package/ios/Tests/ConstantsSpec.swift +36 -0
  131. package/ios/Tests/ConvertiblesSpec.swift +265 -0
  132. package/ios/Tests/EXAppDefinesTest.m +99 -0
  133. package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
  134. package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
  135. package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
  136. package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
  137. package/ios/Tests/ModuleRegistrySpec.swift +4 -7
  138. package/package.json +3 -3
  139. package/src/NativeModulesProxy.native.ts +22 -2
  140. package/src/NativeModulesProxy.types.ts +8 -0
  141. package/src/NativeViewManagerAdapter.native.tsx +1 -1
  142. package/ios/EXAppDelegateWrapper.h +0 -13
  143. package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
  144. package/ios/Swift/Methods/AnyMethod.swift +0 -31
  145. package/ios/Swift/Methods/AnyMethodArgument.swift +0 -13
package/CHANGELOG.md CHANGED
@@ -10,13 +10,44 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
- ## 0.4.9 — 2021-12-08
13
+ ## 0.6.2 — 2021-12-15
14
14
 
15
15
  ### 🎉 New features
16
16
 
17
+ - Add `onNewIntent` and `onBackPressed` support to `ReactActivityLifecycleListener`. ([#15550](https://github.com/expo/expo/pull/15550) by [@Kudo](https://github.com/Kudo))
18
+
19
+ ## 0.6.1 — 2021-12-08
20
+
21
+ _This version does not introduce any user-facing changes._
22
+
23
+ ## 0.6.0 — 2021-12-03
24
+
25
+ ### 🎉 New features
26
+
27
+ - Made `Foundation.URL` a convertible type to consistently normalize file paths to file URLs. ([#15278](https://github.com/expo/expo/pull/15278) by [@tsapeta](https://github.com/tsapeta))
17
28
  - Improve external Android handlers or listeners backward compatibility by Java 8 interface default method. ([#15421](https://github.com/expo/expo/pull/15421) by [@kudo](https://github.com/kudo))
18
29
 
19
- ## 0.4.8 — 2021-11-11
30
+ ### 💡 Others
31
+
32
+ - Add parameter to `ReactNativeHostHandler.onDidCreateReactInstanceManager` on Android. ([#15221](https://github.com/expo/expo/pull/15221) by [@esamelson](https://github.com/esamelson))
33
+ - Make the no-argument module initializer unavailable — `onCreate` definition component should be used instead. ([#15262](https://github.com/expo/expo/pull/15262) by [@tsapeta](https://github.com/tsapeta))
34
+
35
+ ## 0.5.0 — 2021-11-17
36
+
37
+ ### 🎉 New features
38
+
39
+ - Method calls on iOS now can go through the JSI instead of the bridge (opt-in feature). ([#14626](https://github.com/expo/expo/pull/14626) by [@tsapeta](https://github.com/tsapeta))
40
+ - `AppDelegateWrapper` is now written in Swift and is independent of the singleton modules. ([#14867](https://github.com/expo/expo/pull/14867) by [@tsapeta](https://github.com/tsapeta))
41
+ - Implemented sending native events to JavaScript in Sweet API on iOS. ([#14958](https://github.com/expo/expo/pull/14958) by [@tsapeta](https://github.com/tsapeta))
42
+ - [Sweet API] Introduced Convertibles on iOS — a way to use custom types as method arguments if they can be converted from JavaScript values. Provided implementation for some common CoreGraphics types. ([#14988](https://github.com/expo/expo/pull/14988) by [@tsapeta](https://github.com/tsapeta))
43
+ - Introduce `ReactActivityHandler` and support `createReactRootView` hook. ([#14883](https://github.com/expo/expo/pull/14883) by [@kudo](https://github.com/kudo))
44
+ - [Sweet API] Added support for array types in method arguments on iOS. ([#15042](https://github.com/expo/expo/pull/15042) by [@tsapeta](https://github.com/tsapeta))
45
+ - [Sweet API] Added support for optional types in method arguments on iOS. ([#15068](https://github.com/expo/expo/pull/15068) by [@tsapeta](https://github.com/tsapeta))
46
+ - [Sweet API] Added support for enums in method arguments on iOS. ([#15129](https://github.com/expo/expo/pull/15129) by [@tsapeta](https://github.com/tsapeta))
47
+ - [Sweet API] Automatic conversion is now available for view props setters. ([#15132](https://github.com/expo/expo/pull/15132) by [@tsapeta](https://github.com/tsapeta))
48
+ - [Sweet API] Added experimental implementation of the new API in Kotlin. (by [@lukmccall](https://github.com/lukmccall))
49
+ - Introduce EXAppDefines to get app building configurations. ([#14428](https://github.com/expo/expo/pull/14428) by [@kudo](https://github.com/kudo))
50
+ - Introduce React Native bridge delegate handlers on iOS. ([#15138](https://github.com/expo/expo/pull/15138) by [@kudo](https://github.com/kudo))
20
51
 
21
52
  ### 🐛 Bug fixes
22
53
 
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '0.4.9'
6
+ version = '0.6.2'
7
7
 
8
8
  buildscript {
9
9
  // Simple helper that allows the root project to override versions declared by this library.
@@ -58,7 +58,7 @@ android {
58
58
  targetSdkVersion safeExtGet("targetSdkVersion", 30)
59
59
  consumerProguardFiles 'proguard-rules.pro'
60
60
  versionCode 1
61
- versionName "0.4.9"
61
+ versionName "0.6.2"
62
62
  }
63
63
  lintOptions {
64
64
  abortOnError false
@@ -66,10 +66,23 @@ android {
66
66
  kotlinOptions {
67
67
  jvmTarget = JavaVersion.VERSION_1_8
68
68
  }
69
+
70
+ testOptions {
71
+ unitTests.all {
72
+ testLogging {
73
+ outputs.upToDateWhen { false }
74
+ events "passed", "failed", "skipped", "standardError"
75
+ showCauses true
76
+ showExceptions true
77
+ showStandardStreams true
78
+ }
79
+ }
80
+ }
69
81
  }
70
82
 
71
83
  dependencies {
72
84
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${safeExtGet('kotlinVersion', '1.4.21')}"
85
+ implementation "org.jetbrains.kotlin:kotlin-reflect:${safeExtGet('kotlinVersion', '1.4.21')}"
73
86
  implementation 'androidx.annotation:annotation:1.2.0'
74
87
 
75
88
  // used only in `expo.modules.core.errors.ModuleDestroyedException` for API export
@@ -77,4 +90,19 @@ dependencies {
77
90
 
78
91
  //noinspection GradleDynamicVersion
79
92
  implementation 'com.facebook.react:react-native:+'
93
+
94
+ testImplementation 'androidx.test:core:1.4.0'
95
+ testImplementation 'junit:junit:4.13.1'
96
+ testImplementation 'io.mockk:mockk:1.10.6'
97
+ testImplementation "com.google.truth:truth:1.1.2"
98
+ }
99
+
100
+ /**
101
+ * To make the users of annotations @OptIn and @RequiresOptIn aware of their experimental status,
102
+ * the compiler raises warnings when compiling the code with these annotations:
103
+ * This class can only be used with the compiler argument '-Xopt-in=kotlin.RequiresOptIn'
104
+ * To remove the warnings, we add the compiler argument -Xopt-in=kotlin.RequiresOptIn.
105
+ */
106
+ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
107
+ kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
80
108
  }
@@ -5,14 +5,18 @@ import com.facebook.react.bridge.NativeModule;
5
5
  import com.facebook.react.bridge.ReactApplicationContext;
6
6
  import com.facebook.react.uimanager.ViewManager;
7
7
 
8
+ import java.util.ArrayList;
9
+ import java.util.List;
10
+ import java.util.Objects;
11
+
8
12
  import expo.modules.adapters.react.views.SimpleViewManagerAdapter;
9
13
  import expo.modules.adapters.react.views.ViewGroupManagerAdapter;
10
14
  import expo.modules.core.ModuleRegistry;
11
15
  import expo.modules.core.interfaces.InternalModule;
12
16
  import expo.modules.core.interfaces.Package;
13
-
14
- import java.util.ArrayList;
15
- import java.util.List;
17
+ import expo.modules.kotlin.KotlinInteropModuleRegistry;
18
+ import expo.modules.kotlin.ModulesProvider;
19
+ import expo.modules.kotlin.views.ViewWrapperDelegateHolder;
16
20
 
17
21
  /**
18
22
  * An adapter over {@link ModuleRegistry}, compatible with React (implementing {@link ReactPackage}).
@@ -21,7 +25,11 @@ import java.util.List;
21
25
  */
22
26
  public class ModuleRegistryAdapter implements ReactPackage {
23
27
  protected ReactModuleRegistryProvider mModuleRegistryProvider;
28
+ protected ModulesProvider mModulesProvider;
24
29
  protected ReactAdapterPackage mReactAdapterPackage = new ReactAdapterPackage();
30
+ private NativeModulesProxy mModulesProxy;
31
+ // We need to save all view holders to update them when the new kotlin module registry will be created.
32
+ private List<ViewWrapperDelegateHolder> mWrapperDelegateHolders = null;
25
33
 
26
34
  public ModuleRegistryAdapter(List<Package> packageList) {
27
35
  mModuleRegistryProvider = new ReactModuleRegistryProvider(packageList, null);
@@ -31,6 +39,11 @@ public class ModuleRegistryAdapter implements ReactPackage {
31
39
  mModuleRegistryProvider = moduleRegistryProvider;
32
40
  }
33
41
 
42
+ public ModuleRegistryAdapter(ReactModuleRegistryProvider moduleRegistryProvider, ModulesProvider modulesProvider) {
43
+ mModuleRegistryProvider = moduleRegistryProvider;
44
+ mModulesProvider = modulesProvider;
45
+ }
46
+
34
47
  @Override
35
48
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
36
49
  ModuleRegistry moduleRegistry = mModuleRegistryProvider.get(reactContext);
@@ -39,13 +52,20 @@ public class ModuleRegistryAdapter implements ReactPackage {
39
52
  moduleRegistry.registerInternalModule(internalModule);
40
53
  }
41
54
 
42
- return getNativeModulesFromModuleRegistry(reactContext, moduleRegistry);
55
+ List<NativeModule> nativeModules = getNativeModulesFromModuleRegistry(reactContext, moduleRegistry);
56
+ if (mWrapperDelegateHolders != null) {
57
+ KotlinInteropModuleRegistry kotlinInteropModuleRegistry = mModulesProxy.getKotlinInteropModuleRegistry();
58
+ kotlinInteropModuleRegistry.updateModuleHoldersInViewManagers(mWrapperDelegateHolders);
59
+ }
60
+
61
+ return nativeModules;
43
62
  }
44
63
 
45
64
  protected List<NativeModule> getNativeModulesFromModuleRegistry(ReactApplicationContext reactContext, ModuleRegistry moduleRegistry) {
46
65
  List<NativeModule> nativeModulesList = new ArrayList<>(2);
47
66
 
48
- nativeModulesList.add(new NativeModulesProxy(reactContext, moduleRegistry));
67
+ mModulesProxy = createNativeModulesProxy(reactContext, moduleRegistry);
68
+ nativeModulesList.add(mModulesProxy);
49
69
 
50
70
  // Add listener that will notify expo.modules.core.ModuleRegistry when all modules are ready
51
71
  nativeModulesList.add(new ModuleRegistryReadyNotifier(moduleRegistry));
@@ -73,6 +93,23 @@ public class ModuleRegistryAdapter implements ReactPackage {
73
93
  break;
74
94
  }
75
95
  }
96
+
97
+ // We assume that `createNativeModules` was called first.
98
+ NativeModulesProxy modulesProxy = Objects.requireNonNull(mModulesProxy);
99
+ KotlinInteropModuleRegistry kotlinInteropModuleRegistry = modulesProxy.getKotlinInteropModuleRegistry();
100
+ List<ViewManager<?, ?>> kViewManager = kotlinInteropModuleRegistry.exportViewManagers();
101
+ // Saves all holders that needs to be in sync with module registry
102
+ mWrapperDelegateHolders = kotlinInteropModuleRegistry.extractViewManagersDelegateHolders(kViewManager);
103
+ viewManagerList.addAll(kViewManager);
104
+
76
105
  return viewManagerList;
77
106
  }
107
+
108
+ private NativeModulesProxy createNativeModulesProxy(ReactApplicationContext reactContext, ModuleRegistry moduleRegistry) {
109
+ if (mModulesProvider != null) {
110
+ return new NativeModulesProxy(reactContext, moduleRegistry, mModulesProvider);
111
+ } else {
112
+ return new NativeModulesProxy(reactContext, moduleRegistry);
113
+ }
114
+ }
78
115
  }
@@ -14,13 +14,19 @@ import expo.modules.core.ExportedModule;
14
14
  import expo.modules.core.ModuleRegistry;
15
15
  import expo.modules.core.ViewManager;
16
16
  import expo.modules.core.interfaces.ExpoMethod;
17
+ import expo.modules.kotlin.ExpoModulesHelper;
18
+ import expo.modules.kotlin.KotlinInteropModuleRegistry;
19
+ import expo.modules.kotlin.KPromiseWrapper;
20
+ import expo.modules.kotlin.ModulesProvider;
17
21
 
22
+ import java.lang.ref.WeakReference;
18
23
  import java.lang.reflect.Method;
19
24
  import java.util.ArrayList;
20
25
  import java.util.Collection;
21
26
  import java.util.HashMap;
22
27
  import java.util.List;
23
28
  import java.util.Map;
29
+ import java.util.Objects;
24
30
 
25
31
  import javax.annotation.Nullable;
26
32
 
@@ -45,12 +51,36 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
45
51
  private ModuleRegistry mModuleRegistry;
46
52
  private Map<String, Map<String, Integer>> mExportedMethodsKeys;
47
53
  private Map<String, SparseArray<String>> mExportedMethodsReverseKeys;
54
+ private KotlinInteropModuleRegistry mKotlinInteropModuleRegistry;
48
55
 
49
56
  public NativeModulesProxy(ReactApplicationContext context, ModuleRegistry moduleRegistry) {
50
57
  super(context);
51
58
  mModuleRegistry = moduleRegistry;
52
59
  mExportedMethodsKeys = new HashMap<>();
53
60
  mExportedMethodsReverseKeys = new HashMap<>();
61
+
62
+ mKotlinInteropModuleRegistry = new KotlinInteropModuleRegistry(
63
+ Objects.requireNonNull(ExpoModulesHelper.Companion.getModulesProvider()),
64
+ moduleRegistry,
65
+ new WeakReference<>(context)
66
+ );
67
+ }
68
+
69
+ public NativeModulesProxy(ReactApplicationContext context, ModuleRegistry moduleRegistry, ModulesProvider modulesProvider) {
70
+ super(context);
71
+ mModuleRegistry = moduleRegistry;
72
+ mExportedMethodsKeys = new HashMap<>();
73
+ mExportedMethodsReverseKeys = new HashMap<>();
74
+
75
+ mKotlinInteropModuleRegistry = new KotlinInteropModuleRegistry(
76
+ Objects.requireNonNull(modulesProvider),
77
+ moduleRegistry,
78
+ new WeakReference<>(context)
79
+ );
80
+ }
81
+
82
+ public KotlinInteropModuleRegistry getKotlinInteropModuleRegistry() {
83
+ return mKotlinInteropModuleRegistry;
54
84
  }
55
85
 
56
86
  @Override
@@ -79,11 +109,19 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
79
109
  exportedMethodsMap.put(moduleName, exportedMethods);
80
110
  }
81
111
 
112
+ modulesConstants.putAll(mKotlinInteropModuleRegistry.exportedModulesConstants());
113
+ exportedMethodsMap.putAll(mKotlinInteropModuleRegistry.exportMethods((name, info) -> {
114
+ assignExportedMethodsKeys(name, (List<Map<String, Object>>) info);
115
+ return null;
116
+ }));
117
+
82
118
  for (ViewManager viewManager : viewManagers) {
83
119
  viewManagersNames.add(viewManager.getName());
84
120
  }
85
121
 
86
- Map<String, Object> constants = new HashMap<>(2);
122
+ viewManagersNames.addAll(mKotlinInteropModuleRegistry.exportedViewManagersNames());
123
+
124
+ Map<String, Object> constants = new HashMap<>(3);
87
125
  constants.put(MODULES_CONSTANTS_KEY, modulesConstants);
88
126
  constants.put(EXPORTED_METHODS_KEY, exportedMethodsMap);
89
127
  constants.put(VIEW_MANAGERS_NAMES_KEY, viewManagersNames);
@@ -110,6 +148,11 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
110
148
  return;
111
149
  }
112
150
 
151
+ if (mKotlinInteropModuleRegistry.hasModule(moduleName)) {
152
+ mKotlinInteropModuleRegistry.callMethod(moduleName, methodName, arguments, new KPromiseWrapper(promise));
153
+ return;
154
+ }
155
+
113
156
  try {
114
157
  List<Object> nativeArguments = getNativeArgumentsForMethod(arguments, mModuleRegistry.getExportedModule(moduleName).getExportedMethodInfos().get(methodName));
115
158
  nativeArguments.add(new PromiseWrapper(promise));
@@ -121,9 +164,9 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
121
164
  promise.reject(UNEXPECTED_ERROR, "Encountered an exception while calling native method: " + e.getMessage(), e);
122
165
  } catch (NoSuchMethodException e) {
123
166
  promise.reject(
124
- UNDEFINED_METHOD_ERROR,
125
- "Method " + methodName + " of Java module " + moduleName + " is undefined.",
126
- e
167
+ UNDEFINED_METHOD_ERROR,
168
+ "Method " + methodName + " of Java module " + moduleName + " is undefined.",
169
+ e
127
170
  );
128
171
  }
129
172
  }
@@ -157,7 +200,7 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
157
200
  * Returns methodInfo Map (a Map containing a value for key argumentsCount).
158
201
  */
159
202
  private Map<String, Object> getMethodInfo(String name, Method method) {
160
- Map<String, Object> info = new HashMap<>(1);
203
+ Map<String, Object> info = new HashMap<>(2);
161
204
  info.put(METHOD_INFO_NAME, name);
162
205
  info.put(METHOD_INFO_ARGUMENTS_COUNT, method.getParameterTypes().length - 1); // - 1 is for the Promise
163
206
  return info;
@@ -200,5 +243,6 @@ public class NativeModulesProxy extends ReactContextBaseJavaModule {
200
243
  @Override
201
244
  public void onCatalystInstanceDestroy() {
202
245
  mModuleRegistry.onDestroy();
246
+ mKotlinInteropModuleRegistry.onDestroy();
203
247
  }
204
248
  }
@@ -5,6 +5,7 @@ import android.content.Context;
5
5
  import expo.modules.core.interfaces.ApplicationLifecycleListener;
6
6
  import expo.modules.core.interfaces.InternalModule;
7
7
  import expo.modules.core.interfaces.Package;
8
+ import expo.modules.core.interfaces.ReactActivityHandler;
8
9
  import expo.modules.core.interfaces.ReactActivityLifecycleListener;
9
10
  import expo.modules.core.interfaces.ReactNativeHostHandler;
10
11
  import expo.modules.core.interfaces.SingletonModule;
@@ -49,4 +50,9 @@ public class BasePackage implements Package {
49
50
  public List<ReactActivityLifecycleListener> createReactActivityLifecycleListeners(Context activityContext) {
50
51
  return Collections.emptyList();
51
52
  }
53
+
54
+ @Override
55
+ public List<ReactActivityHandler> createReactActivityHandlers(Context activityContext) {
56
+ return Collections.emptyList();
57
+ }
52
58
  }
@@ -0,0 +1,25 @@
1
+ package expo.modules.core
2
+
3
+ /**
4
+ * This class determines the order of the following handlers/listeners
5
+ * - {@link ReactNativeHostHandler}
6
+ * - {@link ApplicationLifecycleListener}
7
+ * - {@link ReactActivityLifecycleListener}
8
+ * - {@link ReactActivityHandler}
9
+ *
10
+ * The priority is only for internal use and we maintain a pre-defined {@link SUPPORTED_MODULES} map.
11
+ */
12
+ object ModulePriorities {
13
+ fun get(packageName: String?): Int {
14
+ return packageName?.let {
15
+ return SUPPORTED_MODULES[it] ?: 0
16
+ } ?: 0
17
+ }
18
+
19
+ private val SUPPORTED_MODULES = mapOf(
20
+ // {key} to {value}
21
+ // key: full qualified class name
22
+ // value: priority value, the higher value takes precedence
23
+ "expo.modules.updates.UpdatesPackage" to 10,
24
+ )
25
+ }
@@ -3,8 +3,10 @@ package expo.modules.core.interfaces;
3
3
  import android.app.Activity;
4
4
  import android.content.Intent;
5
5
 
6
+ import androidx.annotation.Nullable;
7
+
6
8
  public interface ActivityEventListener {
7
- public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data);
9
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, @Nullable Intent data);
8
10
 
9
11
  // Called when a new intent is passed to the activity
10
12
  public void onNewIntent(Intent intent);
@@ -43,4 +43,8 @@ public interface Package {
43
43
  default List<? extends ReactActivityLifecycleListener> createReactActivityLifecycleListeners(Context activityContext) {
44
44
  return Collections.emptyList();
45
45
  }
46
+
47
+ default List<? extends ReactActivityHandler> createReactActivityHandlers(Context activityContext) {
48
+ return Collections.emptyList();
49
+ }
46
50
  }
@@ -0,0 +1,21 @@
1
+ package expo.modules.core.interfaces;
2
+
3
+ import android.app.Activity;
4
+ import com.facebook.react.ReactRootView;
5
+
6
+ import androidx.annotation.Nullable;
7
+
8
+ /**
9
+ * A handler API for modules to override default ReactActivity behaviors.
10
+ * Used by {@link ReactActivityDelegateWrapper}
11
+ */
12
+ public interface ReactActivityHandler {
13
+ /**
14
+ * Given modules a chance to override the default {@link ReactRootView}
15
+ * @return the override ReactRootView instance or null if not to override
16
+ */
17
+ @Nullable
18
+ default ReactRootView createReactRootView(Activity activity) {
19
+ return null;
20
+ }
21
+ }
@@ -1,6 +1,7 @@
1
1
  package expo.modules.core.interfaces;
2
2
 
3
3
  import android.app.Activity;
4
+ import android.content.Intent;
4
5
  import android.os.Bundle;
5
6
 
6
7
  public interface ReactActivityLifecycleListener {
@@ -11,4 +12,26 @@ public interface ReactActivityLifecycleListener {
11
12
  default void onPause(Activity activity) {}
12
13
 
13
14
  default void onDestroy(Activity activity) {}
15
+
16
+ /**
17
+ * Called when {@link com.facebook.react.ReactActivity} received `onNewIntent`
18
+ * Every listener will receive this callback.
19
+ * `ReactActivityDelegateWrapper.onNewIntent` will get `true` if there's some module returns `true`
20
+ *
21
+ * @return true if this module wants to return `true` from `ReactActivityDelegateWrapper.onNewIntent`
22
+ */
23
+ default boolean onNewIntent(Intent intent) {
24
+ return false;
25
+ }
26
+
27
+ /**
28
+ * Called when {@link com.facebook.react.ReactActivity} received `onBackPressed`
29
+ * Every listener will receive this callback.
30
+ * `ReactActivityDelegateWrapper.onBackPressed` will get `true` if there's some module returns `true`
31
+ *
32
+ * @return true if this module wants to return `true` from `ReactActivityDelegateWrapper.onBackPressed`
33
+ */
34
+ default boolean onBackPressed() {
35
+ return false;
36
+ }
14
37
  }
@@ -42,6 +42,8 @@ public interface ReactNativeHostHandler {
42
42
  return null;
43
43
  }
44
44
 
45
+ //region event listeners
46
+
45
47
  /**
46
48
  * Given chance for JSI modules to register, e.g. for react-native-reanimated
47
49
  *
@@ -53,4 +55,16 @@ public interface ReactNativeHostHandler {
53
55
  boolean useDeveloperSupport
54
56
  ) {
55
57
  }
58
+
59
+ /**
60
+ * Callback before {@link ReactInstanceManager} creation
61
+ */
62
+ default void onWillCreateReactInstanceManager(boolean useDeveloperSupport) {}
63
+
64
+ /**
65
+ * Callback after {@link ReactInstanceManager} creation
66
+ */
67
+ default void onDidCreateReactInstanceManager(ReactInstanceManager reactInstanceManager, boolean useDeveloperSupport) {}
68
+
69
+ //endregion
56
70
  }
@@ -0,0 +1,23 @@
1
+ package expo.modules.core.utilities
2
+
3
+ /**
4
+ * Returns receiver, or block result if the receiver is `null`
5
+ *
6
+ * A more semantic equivalent to: `nullable ?: run { ... }`:
7
+ * ```
8
+ * val nonNullable1 = sthNullable.ifNull { ... }
9
+ * val nonNullable2 = sthNullable ?: run { ... }
10
+ * ```
11
+ */
12
+ inline fun <T> T?.ifNull(block: () -> T): T = this ?: block()
13
+
14
+ /**
15
+ * If the receiver is instance of `T`, returns the receiver, otherwise returns `null`
16
+ *
17
+ * Works the same as the `as?` operator, but allows method chaining without parentheses:
18
+ * ```
19
+ * val x = a.b.takeIfInstanceOf<Number>?.someMethod()
20
+ * val y = (a.b as? Number)?.someMethod() // same, but needs parenthesis
21
+ * ```
22
+ */
23
+ inline fun <reified T> Any?.takeIfInstanceOf(): T? = if (this is T) this else null
@@ -0,0 +1,166 @@
1
+ package expo.modules.kotlin
2
+
3
+ import android.app.Activity
4
+ import android.content.Context
5
+ import android.content.Intent
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import expo.modules.core.interfaces.ActivityProvider
8
+ import expo.modules.core.interfaces.services.EventEmitter
9
+ import expo.modules.interfaces.barcodescanner.BarCodeScannerInterface
10
+ import expo.modules.interfaces.camera.CameraViewInterface
11
+ import expo.modules.interfaces.constants.ConstantsInterface
12
+ import expo.modules.interfaces.filesystem.FilePermissionModuleInterface
13
+ import expo.modules.interfaces.font.FontManagerInterface
14
+ import expo.modules.interfaces.imageloader.ImageLoaderInterface
15
+ import expo.modules.interfaces.permissions.Permissions
16
+ import expo.modules.interfaces.sensors.SensorServiceInterface
17
+ import expo.modules.interfaces.taskManager.TaskManagerInterface
18
+ import expo.modules.kotlin.events.EventName
19
+ import expo.modules.kotlin.events.KEventEmitterWrapper
20
+ import expo.modules.kotlin.events.OnActivityResultPayload
21
+ import expo.modules.kotlin.modules.Module
22
+ import java.lang.ref.WeakReference
23
+
24
+ class AppContext(
25
+ modulesProvider: ModulesProvider,
26
+ val legacyModuleRegistry: expo.modules.core.ModuleRegistry,
27
+ private val reactContextHolder: WeakReference<ReactApplicationContext>
28
+ ) {
29
+ val registry = ModuleRegistry(WeakReference(this)).register(modulesProvider)
30
+ private val reactLifecycleDelegate = ReactLifecycleDelegate(this)
31
+
32
+ init {
33
+ requireNotNull(reactContextHolder.get()) {
34
+ "The app context should be created with valid react context."
35
+ }.apply {
36
+ addLifecycleEventListener(reactLifecycleDelegate)
37
+ addActivityEventListener(reactLifecycleDelegate)
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Returns a legacy module implementing given interface.
43
+ */
44
+ inline fun <reified Module> legacyModule(): Module? {
45
+ return try {
46
+ legacyModuleRegistry.getModule(Module::class.java)
47
+ } catch (_: Exception) {
48
+ null
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Provides access to app's constants from the legacy module registry.
54
+ */
55
+ val constants: ConstantsInterface?
56
+ get() = legacyModule()
57
+
58
+ /**
59
+ * Provides access to the file system manager from the legacy module registry.
60
+ */
61
+ val filePermission: FilePermissionModuleInterface?
62
+ get() = legacyModule()
63
+
64
+ /**
65
+ * Provides access to the permissions manager from the legacy module registry
66
+ */
67
+ val permissions: Permissions?
68
+ get() = legacyModule()
69
+
70
+ /**
71
+ * Provides access to the image loader from the legacy module registry
72
+ */
73
+ val imageLoader: ImageLoaderInterface?
74
+ get() = legacyModule()
75
+
76
+ /**
77
+ * Provides access to the bar code scanner manager from the legacy module registry
78
+ */
79
+ val barcodeScanner: BarCodeScannerInterface?
80
+ get() = legacyModule()
81
+
82
+ /**
83
+ * Provides access to the camera view manager from the legacy module registry
84
+ */
85
+ val camera: CameraViewInterface?
86
+ get() = legacyModule()
87
+
88
+ /**
89
+ * Provides access to the font manager from the legacy module registry
90
+ */
91
+ val font: FontManagerInterface?
92
+ get() = legacyModule()
93
+
94
+ /**
95
+ * Provides access to the sensor manager from the legacy module registry
96
+ */
97
+ val sensor: SensorServiceInterface?
98
+ get() = legacyModule()
99
+
100
+ /**
101
+ * Provides access to the task manager from the legacy module registry
102
+ */
103
+ val taskManager: TaskManagerInterface?
104
+ get() = legacyModule()
105
+
106
+ /**
107
+ * Provides access to the activity provider from the legacy module registry
108
+ */
109
+ val activityProvider: ActivityProvider?
110
+ get() = legacyModule()
111
+
112
+ /**
113
+ * Provides access to the react application context
114
+ */
115
+ val reactContext: Context?
116
+ get() = reactContextHolder.get()
117
+
118
+ /**
119
+ * Provides access to the event emitter
120
+ */
121
+ fun eventEmitter(module: Module): EventEmitter? {
122
+ val legacyEventEmitter = legacyModule<EventEmitter>() ?: return null
123
+ return KEventEmitterWrapper(
124
+ requireNotNull(registry.getModuleHolder(module)) {
125
+ "Cannot create an event emitter for the module that isn't present in the module registry."
126
+ },
127
+ legacyEventEmitter
128
+ )
129
+ }
130
+
131
+ fun onDestroy() {
132
+ reactContextHolder.get()?.removeLifecycleEventListener(reactLifecycleDelegate)
133
+ registry.post(EventName.MODULE_DESTROY)
134
+ }
135
+
136
+ fun onHostResume() {
137
+ registry.post(EventName.ACTIVITY_ENTERS_FOREGROUND)
138
+ }
139
+
140
+ fun onHostPause() {
141
+ registry.post(EventName.ACTIVITY_ENTERS_BACKGROUND)
142
+ }
143
+
144
+ fun onHostDestroy() {
145
+ registry.post(EventName.ACTIVITY_DESTROYS)
146
+ }
147
+
148
+ fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
149
+ registry.post(
150
+ EventName.ON_ACTIVITY_RESULT,
151
+ activity,
152
+ OnActivityResultPayload(
153
+ requestCode,
154
+ resultCode,
155
+ data
156
+ )
157
+ )
158
+ }
159
+
160
+ fun onNewIntent(intent: Intent?) {
161
+ registry.post(
162
+ EventName.ON_NEW_INTENT,
163
+ intent
164
+ )
165
+ }
166
+ }
@@ -0,0 +1,9 @@
1
+ package expo.modules.kotlin
2
+
3
+ import com.facebook.react.bridge.Dynamic
4
+
5
+ inline fun <T> Dynamic.recycle(block: Dynamic.() -> T): T {
6
+ val result = block(this)
7
+ this.recycle()
8
+ return result
9
+ }