react-native-universal-keyboard-aware-scrollview 1.0.0

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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +387 -0
  3. package/android/app/build.gradle +182 -0
  4. package/android/app/debug.keystore +0 -0
  5. package/android/app/proguard-rules.pro +14 -0
  6. package/android/app/src/debug/AndroidManifest.xml +7 -0
  7. package/android/app/src/debugOptimized/AndroidManifest.xml +7 -0
  8. package/android/app/src/main/AndroidManifest.xml +25 -0
  9. package/android/app/src/main/java/com/anonymous/reactnativeuniversalkeyboardawarescrollview/MainActivity.kt +61 -0
  10. package/android/app/src/main/java/com/anonymous/reactnativeuniversalkeyboardawarescrollview/MainApplication.kt +56 -0
  11. package/android/app/src/main/res/drawable/ic_launcher_background.xml +6 -0
  12. package/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  13. package/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png +0 -0
  14. package/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png +0 -0
  15. package/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png +0 -0
  16. package/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png +0 -0
  17. package/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png +0 -0
  18. package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  19. package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  20. package/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  21. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp +0 -0
  22. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  23. package/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  24. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp +0 -0
  25. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  26. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  27. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp +0 -0
  28. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  29. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  30. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp +0 -0
  31. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  32. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  33. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp +0 -0
  34. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  35. package/android/app/src/main/res/values/colors.xml +6 -0
  36. package/android/app/src/main/res/values/strings.xml +5 -0
  37. package/android/app/src/main/res/values/styles.xml +11 -0
  38. package/android/app/src/main/res/values-night/colors.xml +1 -0
  39. package/android/build.gradle +89 -0
  40. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  41. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  42. package/android/gradle.properties +65 -0
  43. package/android/gradlew +251 -0
  44. package/android/gradlew.bat +94 -0
  45. package/android/settings.gradle +39 -0
  46. package/android/src/main/AndroidManifest.xml +3 -0
  47. package/android/src/main/java/com/universalkeyboard/UniversalKeyboardModule.kt +349 -0
  48. package/android/src/main/java/com/universalkeyboard/UniversalKeyboardPackage.kt +21 -0
  49. package/ios/.xcode.env +11 -0
  50. package/ios/Podfile +60 -0
  51. package/ios/Podfile.lock +2001 -0
  52. package/ios/Podfile.properties.json +5 -0
  53. package/ios/UniversalKeyboard.h +24 -0
  54. package/ios/UniversalKeyboard.m +413 -0
  55. package/ios/reactnativeuniversalkeyboardawarescrollview/AppDelegate.swift +70 -0
  56. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
  57. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/AppIcon.appiconset/Contents.json +14 -0
  58. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/Contents.json +6 -0
  59. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/SplashScreenBackground.colorset/Contents.json +20 -0
  60. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/SplashScreenLegacy.imageset/Contents.json +23 -0
  61. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/SplashScreenLegacy.imageset/image.png +0 -0
  62. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/SplashScreenLegacy.imageset/image@2x.png +0 -0
  63. package/ios/reactnativeuniversalkeyboardawarescrollview/Images.xcassets/SplashScreenLegacy.imageset/image@3x.png +0 -0
  64. package/ios/reactnativeuniversalkeyboardawarescrollview/Info.plist +76 -0
  65. package/ios/reactnativeuniversalkeyboardawarescrollview/PrivacyInfo.xcprivacy +48 -0
  66. package/ios/reactnativeuniversalkeyboardawarescrollview/SplashScreen.storyboard +48 -0
  67. package/ios/reactnativeuniversalkeyboardawarescrollview/Supporting/Expo.plist +12 -0
  68. package/ios/reactnativeuniversalkeyboardawarescrollview/reactnativeuniversalkeyboardawarescrollview-Bridging-Header.h +3 -0
  69. package/ios/reactnativeuniversalkeyboardawarescrollview/reactnativeuniversalkeyboardawarescrollview.entitlements +5 -0
  70. package/ios/reactnativeuniversalkeyboardawarescrollview.xcodeproj/project.pbxproj +540 -0
  71. package/ios/reactnativeuniversalkeyboardawarescrollview.xcodeproj/xcshareddata/xcschemes/reactnativeuniversalkeyboardawarescrollview.xcscheme +88 -0
  72. package/ios/reactnativeuniversalkeyboardawarescrollview.xcworkspace/contents.xcworkspacedata +10 -0
  73. package/package.json +61 -0
  74. package/react-native-universal-keyboard-aware-scrollview.podspec +32 -0
  75. package/react-native.config.js +18 -0
  76. package/src/NativeModule.ts +61 -0
  77. package/src/components/KeyboardAwareScrollView.tsx +388 -0
  78. package/src/components/index.ts +5 -0
  79. package/src/hooks/index.ts +2 -0
  80. package/src/hooks/useKeyboard.ts +360 -0
  81. package/src/index.ts +27 -0
  82. package/src/types.ts +87 -0
  83. package/src/utils/KeyboardController.ts +112 -0
  84. package/src/utils/index.ts +1 -0
@@ -0,0 +1,349 @@
1
+ package com.universalkeyboard
2
+
3
+ import android.app.Activity
4
+ import android.graphics.Rect
5
+ import android.os.Build
6
+ import android.util.DisplayMetrics
7
+ import android.view.View
8
+ import android.view.ViewTreeObserver
9
+ import android.view.WindowInsets
10
+ import android.view.WindowManager
11
+ import com.facebook.react.bridge.*
12
+ import com.facebook.react.modules.core.DeviceEventManagerModule
13
+ import java.lang.ref.WeakReference
14
+
15
+ /**
16
+ * UniversalKeyboardModule - Native Android module for detecting keyboard height changes.
17
+ *
18
+ * This module provides reliable keyboard detection that works in:
19
+ * - Normal React Native screens
20
+ * - React Native Modal components
21
+ * - BottomSheet components
22
+ * - Any overlay/dialog scenarios
23
+ *
24
+ * It uses the GlobalLayoutListener approach which is the most reliable method
25
+ * for detecting keyboard visibility on Android, as it measures the actual
26
+ * visible window frame.
27
+ */
28
+ class UniversalKeyboardModule(private val reactContext: ReactApplicationContext) :
29
+ ReactContextBaseJavaModule(reactContext), LifecycleEventListener {
30
+
31
+ companion object {
32
+ const val MODULE_NAME = "UniversalKeyboard"
33
+ const val EVENT_KEYBOARD_DID_SHOW = "keyboardDidShow"
34
+ const val EVENT_KEYBOARD_DID_HIDE = "keyboardDidHide"
35
+ const val EVENT_KEYBOARD_HEIGHT_CHANGED = "keyboardHeightChanged"
36
+
37
+ // Threshold for keyboard detection (200dp is a reasonable minimum keyboard height)
38
+ private const val KEYBOARD_MIN_HEIGHT_DP = 100
39
+ }
40
+
41
+ private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
42
+ private var rootView: WeakReference<View>? = null
43
+ private var lastKeyboardHeight = 0
44
+ private var isKeyboardVisible = false
45
+ private var hasListeners = false
46
+ private var screenHeight = 0
47
+
48
+ override fun getName(): String = MODULE_NAME
49
+
50
+ override fun initialize() {
51
+ super.initialize()
52
+ reactContext.addLifecycleEventListener(this)
53
+ }
54
+
55
+ override fun invalidate() {
56
+ removeKeyboardListener()
57
+ reactContext.removeLifecycleEventListener(this)
58
+ super.invalidate()
59
+ }
60
+
61
+ // Lifecycle events
62
+ override fun onHostResume() {
63
+ if (hasListeners) {
64
+ setupKeyboardListener()
65
+ }
66
+ }
67
+
68
+ override fun onHostPause() {
69
+ // Keep listener active during pause for modals
70
+ }
71
+
72
+ override fun onHostDestroy() {
73
+ removeKeyboardListener()
74
+ }
75
+
76
+ /**
77
+ * Start listening for keyboard events.
78
+ * This method MUST be called from JS before keyboard events will be emitted.
79
+ */
80
+ @ReactMethod
81
+ fun startListening(promise: Promise) {
82
+ hasListeners = true
83
+
84
+ UiThreadUtil.runOnUiThread {
85
+ try {
86
+ setupKeyboardListener()
87
+ promise.resolve(true)
88
+ } catch (e: Exception) {
89
+ promise.reject("ERROR", "Failed to start keyboard listener: ${e.message}")
90
+ }
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Stop listening for keyboard events.
96
+ * Call this when the component unmounts to prevent memory leaks.
97
+ */
98
+ @ReactMethod
99
+ fun stopListening(promise: Promise) {
100
+ hasListeners = false
101
+
102
+ UiThreadUtil.runOnUiThread {
103
+ try {
104
+ removeKeyboardListener()
105
+ promise.resolve(true)
106
+ } catch (e: Exception) {
107
+ promise.reject("ERROR", "Failed to stop keyboard listener: ${e.message}")
108
+ }
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Get the current keyboard height synchronously.
114
+ */
115
+ @ReactMethod
116
+ fun getKeyboardHeight(promise: Promise) {
117
+ promise.resolve(lastKeyboardHeight.toDouble() / getScreenDensity())
118
+ }
119
+
120
+ /**
121
+ * Check if the keyboard is currently visible.
122
+ */
123
+ @ReactMethod
124
+ fun isKeyboardVisible(promise: Promise) {
125
+ promise.resolve(isKeyboardVisible)
126
+ }
127
+
128
+ /**
129
+ * Force dismiss the keyboard.
130
+ */
131
+ @ReactMethod
132
+ fun dismissKeyboard(promise: Promise) {
133
+ UiThreadUtil.runOnUiThread {
134
+ try {
135
+ val activity = currentActivity
136
+ if (activity != null) {
137
+ val view = activity.currentFocus
138
+ if (view != null) {
139
+ val imm = activity.getSystemService(Activity.INPUT_METHOD_SERVICE) as android.view.inputmethod.InputMethodManager
140
+ imm.hideSoftInputFromWindow(view.windowToken, 0)
141
+ }
142
+ }
143
+ promise.resolve(true)
144
+ } catch (e: Exception) {
145
+ promise.reject("ERROR", "Failed to dismiss keyboard: ${e.message}")
146
+ }
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Get the screen density for converting pixels to density-independent pixels.
152
+ */
153
+ private fun getScreenDensity(): Float {
154
+ return reactContext.resources.displayMetrics.density
155
+ }
156
+
157
+ /**
158
+ * Get the minimum keyboard height in pixels based on screen density.
159
+ */
160
+ private fun getMinKeyboardHeightPx(): Int {
161
+ return (KEYBOARD_MIN_HEIGHT_DP * getScreenDensity()).toInt()
162
+ }
163
+
164
+ /**
165
+ * Sets up the global layout listener to detect keyboard visibility changes.
166
+ * This is the core mechanism for reliable keyboard detection on Android.
167
+ */
168
+ private fun setupKeyboardListener() {
169
+ val activity = currentActivity ?: return
170
+
171
+ // Get the root decorView
172
+ val decorView = activity.window.decorView
173
+ val contentView = decorView.findViewById<View>(android.R.id.content) ?: return
174
+
175
+ rootView = WeakReference(contentView)
176
+
177
+ // Store the full screen height
178
+ val displayMetrics = DisplayMetrics()
179
+ @Suppress("DEPRECATION")
180
+ activity.windowManager.defaultDisplay.getMetrics(displayMetrics)
181
+ screenHeight = displayMetrics.heightPixels
182
+
183
+ // Remove any existing listener
184
+ removeKeyboardListener()
185
+
186
+ globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
187
+ measureKeyboardHeight()
188
+ }
189
+
190
+ contentView.viewTreeObserver.addOnGlobalLayoutListener(globalLayoutListener)
191
+ }
192
+
193
+ /**
194
+ * Measures the keyboard height by comparing the visible window frame
195
+ * with the root view's height.
196
+ */
197
+ private fun measureKeyboardHeight() {
198
+ val view = rootView?.get() ?: return
199
+ val activity = currentActivity ?: return
200
+
201
+ val visibleFrame = Rect()
202
+ view.getWindowVisibleDisplayFrame(visibleFrame)
203
+
204
+ val keyboardHeight: Int
205
+
206
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
207
+ // Android 11+ uses WindowInsets for more accurate keyboard detection
208
+ val rootWindowInsets = view.rootWindowInsets
209
+ if (rootWindowInsets != null) {
210
+ val imeInsets = rootWindowInsets.getInsets(WindowInsets.Type.ime())
211
+ val navigationBarInsets = rootWindowInsets.getInsets(WindowInsets.Type.navigationBars())
212
+
213
+ // The keyboard height is the IME inset minus the navigation bar
214
+ // because IME insets include the navigation bar
215
+ keyboardHeight = imeInsets.bottom - if (imeInsets.bottom > 0) 0 else navigationBarInsets.bottom
216
+ } else {
217
+ keyboardHeight = calculateKeyboardHeightLegacy(view, visibleFrame)
218
+ }
219
+ } else {
220
+ keyboardHeight = calculateKeyboardHeightLegacy(view, visibleFrame)
221
+ }
222
+
223
+ handleKeyboardHeightChange(keyboardHeight)
224
+ }
225
+
226
+ /**
227
+ * Legacy method for calculating keyboard height on Android < 11.
228
+ */
229
+ private fun calculateKeyboardHeightLegacy(view: View, visibleFrame: Rect): Int {
230
+ val activity = currentActivity ?: return 0
231
+
232
+ // Get the screen height including system bars
233
+ val displayMetrics = DisplayMetrics()
234
+ @Suppress("DEPRECATION")
235
+ activity.windowManager.defaultDisplay.getRealMetrics(displayMetrics)
236
+ val screenHeight = displayMetrics.heightPixels
237
+
238
+ // The keyboard height is the difference between screen height and visible frame bottom
239
+ // We need to account for the navigation bar as well
240
+ val navBarHeight = getNavigationBarHeight()
241
+
242
+ // Calculate content height difference
243
+ val heightDiff = screenHeight - visibleFrame.bottom
244
+
245
+ // If the difference is greater than our threshold, keyboard is visible
246
+ return if (heightDiff > getMinKeyboardHeightPx()) {
247
+ heightDiff - navBarHeight
248
+ } else {
249
+ 0
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Get the navigation bar height for proper keyboard height calculation.
255
+ */
256
+ private fun getNavigationBarHeight(): Int {
257
+ val activity = currentActivity ?: return 0
258
+
259
+ val resourceId = reactContext.resources.getIdentifier(
260
+ "navigation_bar_height",
261
+ "dimen",
262
+ "android"
263
+ )
264
+
265
+ return if (resourceId > 0) {
266
+ reactContext.resources.getDimensionPixelSize(resourceId)
267
+ } else {
268
+ 0
269
+ }
270
+ }
271
+
272
+ /**
273
+ * Handles keyboard height changes and emits appropriate events.
274
+ */
275
+ private fun handleKeyboardHeightChange(keyboardHeightPx: Int) {
276
+ val density = getScreenDensity()
277
+ val keyboardHeightDp = (keyboardHeightPx / density).toInt()
278
+
279
+ val minHeight = KEYBOARD_MIN_HEIGHT_DP
280
+ val keyboardNowVisible = keyboardHeightDp >= minHeight
281
+
282
+ // Always emit height change if it's different
283
+ if (keyboardHeightPx != lastKeyboardHeight) {
284
+ lastKeyboardHeight = keyboardHeightPx
285
+ sendEvent(EVENT_KEYBOARD_HEIGHT_CHANGED, createKeyboardEventData(keyboardHeightDp))
286
+ }
287
+
288
+ // Emit show/hide events
289
+ if (keyboardNowVisible && !isKeyboardVisible) {
290
+ isKeyboardVisible = true
291
+ sendEvent(EVENT_KEYBOARD_DID_SHOW, createKeyboardEventData(keyboardHeightDp))
292
+ } else if (!keyboardNowVisible && isKeyboardVisible) {
293
+ isKeyboardVisible = false
294
+ lastKeyboardHeight = 0
295
+ sendEvent(EVENT_KEYBOARD_DID_HIDE, createKeyboardEventData(0))
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Creates the event data payload for keyboard events.
301
+ */
302
+ private fun createKeyboardEventData(keyboardHeight: Int): WritableMap {
303
+ val params = Arguments.createMap()
304
+ params.putDouble("height", keyboardHeight.toDouble())
305
+ params.putBoolean("isVisible", keyboardHeight > 0)
306
+ params.putDouble("screenHeight", screenHeight / getScreenDensity().toDouble())
307
+ params.putDouble("timestamp", System.currentTimeMillis().toDouble())
308
+ return params
309
+ }
310
+
311
+ /**
312
+ * Sends an event to JavaScript.
313
+ */
314
+ private fun sendEvent(eventName: String, params: WritableMap) {
315
+ if (!hasListeners) return
316
+
317
+ reactContext
318
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
319
+ ?.emit(eventName, params)
320
+ }
321
+
322
+ /**
323
+ * Removes the global layout listener to prevent memory leaks.
324
+ */
325
+ private fun removeKeyboardListener() {
326
+ globalLayoutListener?.let { listener ->
327
+ rootView?.get()?.viewTreeObserver?.let { observer ->
328
+ if (observer.isAlive) {
329
+ observer.removeOnGlobalLayoutListener(listener)
330
+ }
331
+ }
332
+ }
333
+ globalLayoutListener = null
334
+ rootView = null
335
+ }
336
+
337
+ /**
338
+ * Required for TurboModule support - indicates this module requires main queue setup.
339
+ */
340
+ @ReactMethod
341
+ fun addListener(eventName: String) {
342
+ // Required for RN built-in event emitter
343
+ }
344
+
345
+ @ReactMethod
346
+ fun removeListeners(count: Int) {
347
+ // Required for RN built-in event emitter
348
+ }
349
+ }
@@ -0,0 +1,21 @@
1
+ package com.universalkeyboard
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ /**
9
+ * React Native Package that registers the UniversalKeyboard native module.
10
+ * This package is automatically linked by React Native's autolinking feature.
11
+ */
12
+ class UniversalKeyboardPackage : ReactPackage {
13
+
14
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
15
+ return listOf(UniversalKeyboardModule(reactContext))
16
+ }
17
+
18
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
19
+ return emptyList()
20
+ }
21
+ }
package/ios/.xcode.env ADDED
@@ -0,0 +1,11 @@
1
+ # This `.xcode.env` file is versioned and is used to source the environment
2
+ # used when running script phases inside Xcode.
3
+ # To customize your local environment, you can create an `.xcode.env.local`
4
+ # file that is not versioned.
5
+
6
+ # NODE_BINARY variable contains the PATH to the node executable.
7
+ #
8
+ # Customize the NODE_BINARY variable here.
9
+ # For example, to use nvm with brew, add the following line
10
+ # . "$(brew --prefix nvm)/nvm.sh" --no-use
11
+ export NODE_BINARY=$(command -v node)
package/ios/Podfile ADDED
@@ -0,0 +1,60 @@
1
+ require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
2
+ require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
3
+
4
+ require 'json'
5
+ podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {}
6
+
7
+ def ccache_enabled?(podfile_properties)
8
+ # Environment variable takes precedence
9
+ return ENV['USE_CCACHE'] == '1' if ENV['USE_CCACHE']
10
+
11
+ # Fall back to Podfile properties
12
+ podfile_properties['apple.ccacheEnabled'] == 'true'
13
+ end
14
+
15
+ ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false'
16
+ ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR']
17
+ ENV['RCT_USE_RN_DEP'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false'
18
+ ENV['RCT_USE_PREBUILT_RNCORE'] ||= '1' if podfile_properties['ios.buildReactNativeFromSource'] != 'true' && podfile_properties['newArchEnabled'] != 'false'
19
+ platform :ios, podfile_properties['ios.deploymentTarget'] || '15.1'
20
+
21
+ prepare_react_native_project!
22
+
23
+ target 'reactnativeuniversalkeyboardawarescrollview' do
24
+ use_expo_modules!
25
+
26
+ if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
27
+ config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
28
+ else
29
+ config_command = [
30
+ 'npx',
31
+ 'expo-modules-autolinking',
32
+ 'react-native-config',
33
+ '--json',
34
+ '--platform',
35
+ 'ios'
36
+ ]
37
+ end
38
+
39
+ config = use_native_modules!(config_command)
40
+
41
+ use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
42
+ use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
43
+
44
+ use_react_native!(
45
+ :path => config[:reactNativePath],
46
+ :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
47
+ # An absolute path to your application root.
48
+ :app_path => "#{Pod::Config.instance.installation_root}/..",
49
+ :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
50
+ )
51
+
52
+ post_install do |installer|
53
+ react_native_post_install(
54
+ installer,
55
+ config[:reactNativePath],
56
+ :mac_catalyst_enabled => false,
57
+ :ccache_enabled => ccache_enabled?(podfile_properties),
58
+ )
59
+ end
60
+ end