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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Vijay Kishan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,387 @@
1
+ # react-native-universal-keyboard-aware-scrollview
2
+
3
+ [![npm version](https://img.shields.io/npm/v/react-native-universal-keyboard-aware-scrollview.svg)](https://www.npmjs.com/package/react-native-universal-keyboard-aware-scrollview)
4
+ [![license](https://img.shields.io/npm/l/react-native-universal-keyboard-aware-scrollview.svg)](https://github.com/AetherTechDev/react-native-universal-keyboard-aware-scrollview/blob/main/LICENSE)
5
+ [![platform](https://img.shields.io/badge/platform-iOS%20%7C%20Android-lightgrey.svg)](https://reactnative.dev/)
6
+
7
+ A **universal keyboard-aware ScrollView** for React Native that **works correctly** in:
8
+ - ✅ Normal screens
9
+ - ✅ React Native Modal
10
+ - ✅ BottomSheet components
11
+ - ✅ Any overlay or dialog scenario
12
+
13
+ This package uses **native keyboard listeners** on both Android and iOS for reliable keyboard detection, solving the common issues that plague other keyboard-aware libraries.
14
+
15
+ ## 🎯 Why This Package?
16
+
17
+ Existing keyboard-aware solutions often fail in these scenarios:
18
+
19
+ | Issue | Other Libraries | This Package |
20
+ |-------|----------------|--------------|
21
+ | Keyboard overlaps input in Modal | ❌ | ✅ |
22
+ | Glitchy animations on Android | ❌ | ✅ |
23
+ | Incorrect height inside BottomSheet | ❌ | ✅ |
24
+ | Race conditions with keyboard events | ❌ | ✅ |
25
+ | Inconsistent behavior iOS vs Android | ❌ | ✅ |
26
+
27
+ ### How We Solve These Issues
28
+
29
+ 1. **Native Keyboard Detection**: Instead of relying solely on React Native's JavaScript keyboard events, we use platform-native APIs:
30
+ - **iOS**: `UIKeyboardWillChangeFrameNotification` for accurate keyboard frame tracking
31
+ - **Android**: `ViewTreeObserver.OnGlobalLayoutListener` with visible window frame measurement
32
+
33
+ 2. **Modal-Aware Architecture**: Our native implementations measure keyboard height relative to the actual visible window, not the root activity/view controller. This means keyboard detection works correctly even when views are presented modally.
34
+
35
+ 3. **Unified Event System**: Events are emitted from native → JavaScript through a consistent interface, eliminating timing issues and race conditions.
36
+
37
+ ## 📦 Installation
38
+
39
+ ```bash
40
+ # Using npm
41
+ npm install react-native-universal-keyboard-aware-scrollview
42
+
43
+ # Using yarn
44
+ yarn add react-native-universal-keyboard-aware-scrollview
45
+ ```
46
+
47
+ ### iOS Setup
48
+
49
+ ```bash
50
+ cd ios && pod install
51
+ ```
52
+
53
+ ### Android Setup
54
+
55
+ No additional setup required. The native module is automatically linked.
56
+
57
+ ## 🚀 Quick Start
58
+
59
+ ### Basic Usage
60
+
61
+ ```tsx
62
+ import React from 'react';
63
+ import { TextInput, View, StyleSheet } from 'react-native';
64
+ import { KeyboardAwareScrollView } from 'react-native-universal-keyboard-aware-scrollview';
65
+
66
+ function MyForm() {
67
+ return (
68
+ <KeyboardAwareScrollView style={styles.container}>
69
+ <TextInput placeholder="Name" style={styles.input} />
70
+ <TextInput placeholder="Email" style={styles.input} />
71
+ <TextInput placeholder="Phone" style={styles.input} />
72
+ <TextInput
73
+ placeholder="Message"
74
+ style={[styles.input, styles.multiline]}
75
+ multiline
76
+ />
77
+ </KeyboardAwareScrollView>
78
+ );
79
+ }
80
+
81
+ const styles = StyleSheet.create({
82
+ container: {
83
+ flex: 1,
84
+ },
85
+ input: {
86
+ borderWidth: 1,
87
+ borderColor: '#ccc',
88
+ borderRadius: 8,
89
+ padding: 12,
90
+ marginBottom: 16,
91
+ marginHorizontal: 16,
92
+ },
93
+ multiline: {
94
+ height: 100,
95
+ textAlignVertical: 'top',
96
+ },
97
+ });
98
+ ```
99
+
100
+ ### Usage Inside Modal
101
+
102
+ ```tsx
103
+ import React, { useState } from 'react';
104
+ import { Modal, TextInput, View, Button, StyleSheet } from 'react-native';
105
+ import { KeyboardAwareScrollView } from 'react-native-universal-keyboard-aware-scrollview';
106
+
107
+ function ModalForm() {
108
+ const [visible, setVisible] = useState(false);
109
+
110
+ return (
111
+ <>
112
+ <Button title="Open Form" onPress={() => setVisible(true)} />
113
+
114
+ <Modal visible={visible} animationType="slide">
115
+ <View style={styles.modalContainer}>
116
+ <KeyboardAwareScrollView
117
+ insideModal={true}
118
+ extraScrollHeight={20}
119
+ >
120
+ <TextInput placeholder="Name" style={styles.input} />
121
+ <TextInput placeholder="Email" style={styles.input} />
122
+ <TextInput
123
+ placeholder="Message"
124
+ style={[styles.input, styles.multiline]}
125
+ multiline
126
+ />
127
+ </KeyboardAwareScrollView>
128
+
129
+ <Button title="Close" onPress={() => setVisible(false)} />
130
+ </View>
131
+ </Modal>
132
+ </>
133
+ );
134
+ }
135
+ ```
136
+
137
+ ### Using the Hook Directly
138
+
139
+ ```tsx
140
+ import React from 'react';
141
+ import { View, TextInput, StyleSheet } from 'react-native';
142
+ import { useKeyboard } from 'react-native-universal-keyboard-aware-scrollview';
143
+
144
+ function CustomKeyboardHandling() {
145
+ const {
146
+ keyboardHeight,
147
+ isKeyboardVisible,
148
+ dismissKeyboard
149
+ } = useKeyboard({
150
+ onKeyboardDidShow: (event) => {
151
+ console.log('Keyboard shown with height:', event.height);
152
+ },
153
+ onKeyboardDidHide: () => {
154
+ console.log('Keyboard hidden');
155
+ },
156
+ });
157
+
158
+ return (
159
+ <View style={[styles.container, { paddingBottom: keyboardHeight }]}>
160
+ <TextInput placeholder="Type here..." style={styles.input} />
161
+ {isKeyboardVisible && (
162
+ <Button title="Dismiss Keyboard" onPress={dismissKeyboard} />
163
+ )}
164
+ </View>
165
+ );
166
+ }
167
+ ```
168
+
169
+ ## 📖 API Reference
170
+
171
+ ### `KeyboardAwareScrollView`
172
+
173
+ A ScrollView that automatically adjusts for the keyboard.
174
+
175
+ #### Props
176
+
177
+ | Prop | Type | Default | Description |
178
+ |------|------|---------|-------------|
179
+ | `enableOnAndroid` | `boolean` | `true` | Enable keyboard handling on Android |
180
+ | `enableOnIOS` | `boolean` | `true` | Enable keyboard handling on iOS |
181
+ | `extraScrollHeight` | `number` | `20` | Extra scroll space above keyboard |
182
+ | `extraHeight` | `number` | `75` | Extra space for focused element |
183
+ | `enableAnimation` | `boolean` | `true` | Animate height changes |
184
+ | `animationDuration` | `number` | `250` | Animation duration in ms |
185
+ | `enableAutoScrollToFocused` | `boolean` | `true` | Auto-scroll when keyboard shows |
186
+ | `resetScrollToCoords` | `{x, y} \| null` | `null` | Reset scroll position on keyboard hide |
187
+ | `keyboardShouldPersistTaps` | `string` | `'handled'` | Keyboard dismiss behavior |
188
+ | `insideModal` | `boolean` | `false` | Optimize for modal usage |
189
+ | `enableKeyboardSpacer` | `boolean` | `true` | Use spacer view approach |
190
+ | `useContentInset` | `boolean` | `true` (iOS) | Use content inset vs padding |
191
+
192
+ #### Ref Methods
193
+
194
+ ```tsx
195
+ const scrollViewRef = useRef<KeyboardAwareScrollViewRef>(null);
196
+
197
+ // Available methods:
198
+ scrollViewRef.current?.scrollTo({ x: 0, y: 100, animated: true });
199
+ scrollViewRef.current?.scrollToEnd({ animated: true });
200
+ scrollViewRef.current?.scrollToFocusedInput(inputRef);
201
+ scrollViewRef.current?.getScrollResponder();
202
+ scrollViewRef.current?.dismissKeyboard();
203
+ ```
204
+
205
+ ### `useKeyboard` Hook
206
+
207
+ A hook for tracking keyboard state.
208
+
209
+ #### Options
210
+
211
+ ```tsx
212
+ const keyboard = useKeyboard({
213
+ enableOnAndroid: true, // Enable on Android
214
+ enableOnIOS: true, // Enable on iOS
215
+ useNativeEvents: true, // Use native module events
216
+ animated: true, // Animate height changes
217
+ onKeyboardWillShow: (e) => {}, // iOS only
218
+ onKeyboardWillHide: (e) => {}, // iOS only
219
+ onKeyboardDidShow: (e) => {},
220
+ onKeyboardDidHide: (e) => {},
221
+ onKeyboardHeightChange: (h) => {},
222
+ });
223
+ ```
224
+
225
+ #### Return Value
226
+
227
+ ```tsx
228
+ interface UseKeyboardReturn {
229
+ keyboardHeight: number; // Current keyboard height
230
+ isKeyboardVisible: boolean; // Is keyboard visible
231
+ isAnimating: boolean; // Is keyboard animating
232
+ dismissKeyboard: () => Promise<void>;
233
+ screenHeight: number; // Screen height
234
+ animationDuration: number; // Animation duration
235
+ safeAreaBottom: number; // Safe area inset (iOS)
236
+ }
237
+ ```
238
+
239
+ ### `KeyboardController`
240
+
241
+ Static utility class for keyboard control.
242
+
243
+ ```tsx
244
+ import { KeyboardController } from 'react-native-universal-keyboard-aware-scrollview';
245
+
246
+ // Dismiss keyboard
247
+ await KeyboardController.dismiss();
248
+
249
+ // Get keyboard height
250
+ const height = await KeyboardController.getHeight();
251
+
252
+ // Check visibility
253
+ const isVisible = await KeyboardController.isVisible();
254
+
255
+ // Check if native module is available
256
+ const hasNative = KeyboardController.isNativeModuleAvailable();
257
+ ```
258
+
259
+ ## 🔧 Expo Support
260
+
261
+ This package works with Expo, but **requires a development build** (not Expo Go).
262
+
263
+ ### Expo Bare Workflow
264
+
265
+ Works out of the box. Install and use normally.
266
+
267
+ ### Expo Managed Workflow
268
+
269
+ 1. Install the package:
270
+ ```bash
271
+ npx expo install react-native-universal-keyboard-aware-scrollview
272
+ ```
273
+
274
+ 2. Create a development build:
275
+ ```bash
276
+ npx expo prebuild
277
+ npx expo run:ios # or run:android
278
+ ```
279
+
280
+ 3. Use in your app as normal.
281
+
282
+ > **Note**: This package contains native code, so it cannot run in Expo Go. You must use a development build or EAS Build.
283
+
284
+ ## 🏗 Architecture
285
+
286
+ ### Native Implementation Details
287
+
288
+ #### Android (Kotlin)
289
+
290
+ ```
291
+ ┌─────────────────────────────────────┐
292
+ │ UniversalKeyboardModule │
293
+ ├─────────────────────────────────────┤
294
+ │ ViewTreeObserver │
295
+ │ OnGlobalLayoutListener │
296
+ │ ↓ │
297
+ │ getWindowVisibleDisplayFrame() │
298
+ │ ↓ │
299
+ │ Calculate keyboard height │
300
+ │ ↓ │
301
+ │ Emit via DeviceEventEmitter │
302
+ └─────────────────────────────────────┘
303
+ ```
304
+
305
+ The Android implementation uses `ViewTreeObserver.OnGlobalLayoutListener` to detect layout changes. When the keyboard appears, the visible display frame shrinks. We calculate the keyboard height by comparing the visible frame with the full screen height.
306
+
307
+ This approach works in modals because we attach the listener to the content view, which is always affected by keyboard appearance regardless of the view hierarchy.
308
+
309
+ #### iOS (Objective-C)
310
+
311
+ ```
312
+ ┌─────────────────────────────────────┐
313
+ │ UniversalKeyboard │
314
+ ├─────────────────────────────────────┤
315
+ │ NSNotificationCenter │
316
+ │ UIKeyboardWillChangeFrameNotification│
317
+ │ ↓ │
318
+ │ Extract keyboard frame from userInfo│
319
+ │ ↓ │
320
+ │ Calculate height from screen bottom │
321
+ │ ↓ │
322
+ │ Emit via RCTEventEmitter │
323
+ └─────────────────────────────────────┘
324
+ ```
325
+
326
+ The iOS implementation uses `UIKeyboardWillChangeFrameNotification`, which provides the most accurate keyboard frame information. This notification fires for all keyboard changes including interactive dismiss gestures.
327
+
328
+ We calculate keyboard height as `screenHeight - keyboardFrame.origin.y`, which works correctly in all presentation contexts including modals.
329
+
330
+ ## 🐛 Troubleshooting
331
+
332
+ ### "Native module not found" Error
333
+
334
+ This usually means the native module isn't linked:
335
+
336
+ **iOS:**
337
+ ```bash
338
+ cd ios && pod install --repo-update
339
+ ```
340
+
341
+ **Android:**
342
+ Clean and rebuild:
343
+ ```bash
344
+ cd android && ./gradlew clean
345
+ cd .. && npx react-native run-android
346
+ ```
347
+
348
+ ### Keyboard still overlaps in Modal
349
+
350
+ Make sure you set `insideModal={true}`:
351
+
352
+ ```tsx
353
+ <KeyboardAwareScrollView insideModal={true}>
354
+ {/* content */}
355
+ </KeyboardAwareScrollView>
356
+ ```
357
+
358
+ ### Animation is jumpy on Android
359
+
360
+ Try adjusting the animation settings:
361
+
362
+ ```tsx
363
+ <KeyboardAwareScrollView
364
+ enableAnimation={true}
365
+ animationDuration={300}
366
+ >
367
+ ```
368
+
369
+ Or disable animation entirely:
370
+
371
+ ```tsx
372
+ <KeyboardAwareScrollView enableAnimation={false}>
373
+ ```
374
+
375
+ ## 📄 License
376
+
377
+ MIT © [Vijay Kishan](https://github.com/AetherTechDev)
378
+
379
+ ## 🤝 Contributing
380
+
381
+ Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) first.
382
+
383
+ ## 📞 Support
384
+
385
+ - 🐛 [Report bugs](https://github.com/AetherTechDev/react-native-universal-keyboard-aware-scrollview/issues)
386
+ - 💡 [Request features](https://github.com/AetherTechDev/react-native-universal-keyboard-aware-scrollview/issues)
387
+ - 📧 Email: vijay@aethertech.dev
@@ -0,0 +1,182 @@
1
+ apply plugin: "com.android.application"
2
+ apply plugin: "org.jetbrains.kotlin.android"
3
+ apply plugin: "com.facebook.react"
4
+
5
+ def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
6
+
7
+ /**
8
+ * This is the configuration block to customize your React Native Android app.
9
+ * By default you don't need to apply any configuration, just uncomment the lines you need.
10
+ */
11
+ react {
12
+ entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
13
+ reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
14
+ hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
15
+ codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
16
+
17
+ enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean()
18
+ // Use Expo CLI to bundle the app, this ensures the Metro config
19
+ // works correctly with Expo projects.
20
+ cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
21
+ bundleCommand = "export:embed"
22
+
23
+ /* Folders */
24
+ // The root of your project, i.e. where "package.json" lives. Default is '../..'
25
+ // root = file("../../")
26
+ // The folder where the react-native NPM package is. Default is ../../node_modules/react-native
27
+ // reactNativeDir = file("../../node_modules/react-native")
28
+ // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
29
+ // codegenDir = file("../../node_modules/@react-native/codegen")
30
+
31
+ /* Variants */
32
+ // The list of variants to that are debuggable. For those we're going to
33
+ // skip the bundling of the JS bundle and the assets. By default is just 'debug'.
34
+ // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
35
+ // debuggableVariants = ["liteDebug", "prodDebug"]
36
+
37
+ /* Bundling */
38
+ // A list containing the node command and its flags. Default is just 'node'.
39
+ // nodeExecutableAndArgs = ["node"]
40
+
41
+ //
42
+ // The path to the CLI configuration file. Default is empty.
43
+ // bundleConfig = file(../rn-cli.config.js)
44
+ //
45
+ // The name of the generated asset file containing your JS bundle
46
+ // bundleAssetName = "MyApplication.android.bundle"
47
+ //
48
+ // The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
49
+ // entryFile = file("../js/MyApplication.android.js")
50
+ //
51
+ // A list of extra flags to pass to the 'bundle' commands.
52
+ // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
53
+ // extraPackagerArgs = []
54
+
55
+ /* Hermes Commands */
56
+ // The hermes compiler command to run. By default it is 'hermesc'
57
+ // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
58
+ //
59
+ // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
60
+ // hermesFlags = ["-O", "-output-source-map"]
61
+
62
+ /* Autolinking */
63
+ autolinkLibrariesWithApp()
64
+ }
65
+
66
+ /**
67
+ * Set this to true in release builds to optimize the app using [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization).
68
+ */
69
+ def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean()
70
+
71
+ /**
72
+ * The preferred build flavor of JavaScriptCore (JSC)
73
+ *
74
+ * For example, to use the international variant, you can use:
75
+ * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
76
+ *
77
+ * The international variant includes ICU i18n library and necessary data
78
+ * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
79
+ * give correct results when using with locales other than en-US. Note that
80
+ * this variant is about 6MiB larger per architecture than default.
81
+ */
82
+ def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
83
+
84
+ android {
85
+ ndkVersion rootProject.ext.ndkVersion
86
+
87
+ buildToolsVersion rootProject.ext.buildToolsVersion
88
+ compileSdk rootProject.ext.compileSdkVersion
89
+
90
+ namespace 'com.anonymous.reactnativeuniversalkeyboardawarescrollview'
91
+ defaultConfig {
92
+ applicationId 'com.anonymous.reactnativeuniversalkeyboardawarescrollview'
93
+ minSdkVersion rootProject.ext.minSdkVersion
94
+ targetSdkVersion rootProject.ext.targetSdkVersion
95
+ versionCode 1
96
+ versionName "1.0.0"
97
+
98
+ buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
99
+ }
100
+ signingConfigs {
101
+ debug {
102
+ storeFile file('debug.keystore')
103
+ storePassword 'android'
104
+ keyAlias 'androiddebugkey'
105
+ keyPassword 'android'
106
+ }
107
+ }
108
+ buildTypes {
109
+ debug {
110
+ signingConfig signingConfigs.debug
111
+ }
112
+ release {
113
+ // Caution! In production, you need to generate your own keystore file.
114
+ // see https://reactnative.dev/docs/signed-apk-android.
115
+ signingConfig signingConfigs.debug
116
+ def enableShrinkResources = findProperty('android.enableShrinkResourcesInReleaseBuilds') ?: 'false'
117
+ shrinkResources enableShrinkResources.toBoolean()
118
+ minifyEnabled enableMinifyInReleaseBuilds
119
+ proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
120
+ def enablePngCrunchInRelease = findProperty('android.enablePngCrunchInReleaseBuilds') ?: 'true'
121
+ crunchPngs enablePngCrunchInRelease.toBoolean()
122
+ }
123
+ }
124
+ packagingOptions {
125
+ jniLibs {
126
+ def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false'
127
+ useLegacyPackaging enableLegacyPackaging.toBoolean()
128
+ }
129
+ }
130
+ androidResources {
131
+ ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
132
+ }
133
+ }
134
+
135
+ // Apply static values from `gradle.properties` to the `android.packagingOptions`
136
+ // Accepts values in comma delimited lists, example:
137
+ // android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
138
+ ["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
139
+ // Split option: 'foo,bar' -> ['foo', 'bar']
140
+ def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
141
+ // Trim all elements in place.
142
+ for (i in 0..<options.size()) options[i] = options[i].trim();
143
+ // `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
144
+ options -= ""
145
+
146
+ if (options.length > 0) {
147
+ println "android.packagingOptions.$prop += $options ($options.length)"
148
+ // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
149
+ options.each {
150
+ android.packagingOptions[prop] += it
151
+ }
152
+ }
153
+ }
154
+
155
+ dependencies {
156
+ // The version of react-native is set by the React Native Gradle Plugin
157
+ implementation("com.facebook.react:react-android")
158
+
159
+ def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
160
+ def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
161
+ def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
162
+
163
+ if (isGifEnabled) {
164
+ // For animated gif support
165
+ implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}")
166
+ }
167
+
168
+ if (isWebpEnabled) {
169
+ // For webp support
170
+ implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}")
171
+ if (isWebpAnimatedEnabled) {
172
+ // Animated webp support
173
+ implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}")
174
+ }
175
+ }
176
+
177
+ if (hermesEnabled.toBoolean()) {
178
+ implementation("com.facebook.react:hermes-android")
179
+ } else {
180
+ implementation jscFlavor
181
+ }
182
+ }
Binary file
@@ -0,0 +1,14 @@
1
+ # Add project specific ProGuard rules here.
2
+ # By default, the flags in this file are appended to flags specified
3
+ # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4
+ # You can edit the include path and order by changing the proguardFiles
5
+ # directive in build.gradle.
6
+ #
7
+ # For more details, see
8
+ # http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+ # react-native-reanimated
11
+ -keep class com.swmansion.reanimated.** { *; }
12
+ -keep class com.facebook.react.turbomodule.** { *; }
13
+
14
+ # Add any project specific keep options here:
@@ -0,0 +1,7 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ xmlns:tools="http://schemas.android.com/tools">
3
+
4
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
5
+
6
+ <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
7
+ </manifest>
@@ -0,0 +1,7 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ xmlns:tools="http://schemas.android.com/tools">
3
+
4
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
5
+
6
+ <application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
7
+ </manifest>
@@ -0,0 +1,25 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ <uses-permission android:name="android.permission.INTERNET"/>
3
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
4
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
5
+ <uses-permission android:name="android.permission.VIBRATE"/>
6
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
7
+ <queries>
8
+ <intent>
9
+ <action android:name="android.intent.action.VIEW"/>
10
+ <category android:name="android.intent.category.BROWSABLE"/>
11
+ <data android:scheme="https"/>
12
+ </intent>
13
+ </queries>
14
+ <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:enableOnBackInvokedCallback="false">
15
+ <meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
16
+ <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
17
+ <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
18
+ <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
19
+ <intent-filter>
20
+ <action android:name="android.intent.action.MAIN"/>
21
+ <category android:name="android.intent.category.LAUNCHER"/>
22
+ </intent-filter>
23
+ </activity>
24
+ </application>
25
+ </manifest>