-
Notifications
You must be signed in to change notification settings - Fork 41
App Migration from CLI to Expo #482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
App Migration from CLI to Expo #482
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Summary by CodeRabbit
WalkthroughThe changes introduce a large number of new files and modifications across native Android configuration, Expo app configuration, and React Native components. Notable updates include new documentation for the .expo folder, additional gitignore files, extensive Android build and resource configurations, updated activity and application classes, new Expo-based components for authentication and tab navigation, and adjustments to TypeScript and dependency management. A legacy Metro configuration file has also been removed. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant AS as AuthScreen
participant OS as Operating System
participant DL as DeepLinkHandler
participant NS as Navigation
participant ST as AsyncStorage
U->>AS: Tap "Sign In" button
AS->>OS: Open GitHub authentication URL
OS->>DL: Handle deep link callback with token
DL->>AS: Pass token to AuthScreen
AS->>ST: Store the token
AS->>NS: Navigate to ProfileScreen
NS->>AS: Load ProfileScreen UI
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 27
🔭 Outside diff range comments (1)
RDSExpoApp/assets/svgs/github_logo.js (1)
1-21: 🧹 Nitpick (assertive)LGTM – Svg Component Implementation Looks Solid
The
GithubSvgcomponent is implemented cleanly usingreact-native-svg, correctly propagates props via spread ({...props}), and renders the GitHub logo as expected. Optionally, consider adding PropTypes or a TypeScript interface to document the expected props for extra maintainability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
⛔ Files ignored due to path filters (15)
RDSExpoApp/.yarn/install-state.gzis excluded by!**/.yarn/**,!**/*.gzRDSExpoApp/android/app/src/main/res/drawable-hdpi/splashscreen_logo.pngis excluded by!**/*.pngRDSExpoApp/android/app/src/main/res/drawable-mdpi/splashscreen_logo.pngis excluded by!**/*.pngRDSExpoApp/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.pngis excluded by!**/*.pngRDSExpoApp/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.pngis excluded by!**/*.pngRDSExpoApp/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.pngis excluded by!**/*.pngRDSExpoApp/android/gradle/wrapper/gradle-wrapper.jaris excluded by!**/*.jarRDSExpoApp/assets/fonts/SpaceMono-Regular.ttfis excluded by!**/*.ttfRDSExpoApp/assets/images/adaptive-icon.pngis excluded by!**/*.pngRDSExpoApp/assets/images/favicon.pngis excluded by!**/*.pngRDSExpoApp/assets/images/icon.pngis excluded by!**/*.pngRDSExpoApp/assets/images/rdsLogo.pngis excluded by!**/*.pngRDSExpoApp/assets/images/splash-icon.pngis excluded by!**/*.pngRDSExpoApp/yarn.lockis excluded by!**/yarn.lock,!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (42)
.expo/README.md(1 hunks).expo/devices.json(1 hunks)RDSExpoApp/.gitignore(1 hunks)RDSExpoApp/android/.gitignore(1 hunks)RDSExpoApp/android/app/build.gradle(1 hunks)RDSExpoApp/android/app/proguard-rules.pro(1 hunks)RDSExpoApp/android/app/src/debug/AndroidManifest.xml(1 hunks)RDSExpoApp/android/app/src/main/AndroidManifest.xml(1 hunks)RDSExpoApp/android/app/src/main/java/com/abstrctdatyp/RDSExpoApp/MainActivity.kt(1 hunks)RDSExpoApp/android/app/src/main/java/com/abstrctdatyp/RDSExpoApp/MainApplication.kt(1 hunks)RDSExpoApp/android/app/src/main/res/drawable/ic_launcher_background.xml(1 hunks)RDSExpoApp/android/app/src/main/res/drawable/rn_edit_text_material.xml(1 hunks)RDSExpoApp/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml(1 hunks)RDSExpoApp/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml(1 hunks)RDSExpoApp/android/app/src/main/res/values-night/colors.xml(1 hunks)RDSExpoApp/android/app/src/main/res/values/colors.xml(1 hunks)RDSExpoApp/android/app/src/main/res/values/strings.xml(1 hunks)RDSExpoApp/android/app/src/main/res/values/styles.xml(1 hunks)RDSExpoApp/android/build.gradle(1 hunks)RDSExpoApp/android/gradle.properties(1 hunks)RDSExpoApp/android/gradle/wrapper/gradle-wrapper.properties(1 hunks)RDSExpoApp/android/gradlew(1 hunks)RDSExpoApp/android/gradlew.bat(1 hunks)RDSExpoApp/android/settings.gradle(1 hunks)RDSExpoApp/app.json(1 hunks)RDSExpoApp/app/(tabs)/ProfileScreen.tsx(1 hunks)RDSExpoApp/app/(tabs)/_layout.tsx(1 hunks)RDSExpoApp/app/(tabs)/index.tsx(1 hunks)RDSExpoApp/app/_layout.tsx(1 hunks)RDSExpoApp/assets/svgs/github_logo.js(1 hunks)RDSExpoApp/constants/Colors.ts(1 hunks)RDSExpoApp/constants/apiConstant/AuthApi.ts(1 hunks)RDSExpoApp/constants/apiConstant/BaseUrl.ts(1 hunks)RDSExpoApp/package.json(1 hunks)RDSExpoApp/tsconfig.json(1 hunks)android/app/src/main/java/com/rdsapp/MainActivity.kt(2 hunks)android/app/src/main/java/com/rdsapp/MainApplication.kt(4 hunks)android/settings.gradle(1 hunks)ios/Podfile(2 hunks)metro.config.js(0 hunks)package.json(2 hunks)tsconfig.json(1 hunks)
💤 Files with no reviewable changes (1)
- metro.config.js
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
.expo/README.md
1-1: First line in a file should be a top-level heading
null
(MD041, first-line-heading, first-line-h1)
4-4: Lists should be surrounded by blank lines
null
(MD032, blanks-around-lists)
5-5: Lists should be surrounded by blank lines
null
(MD032, blanks-around-lists)
🪛 RuboCop (1.73)
ios/Podfile
[convention] 21-21: Redundant begin block detected.
(Style/RedundantBegin)
🪛 GitHub Check: build (18.x)
RDSExpoApp/app/(tabs)/index.tsx
[failure] 62-62:
React Hook useEffect has a missing dependency: 'handleTokenFromUrl'. Either include it or remove the dependency array
RDSExpoApp/app/(tabs)/_layout.tsx
[warning] 34-34:
Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “TabLayout” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true
[warning] 25-25:
Inline style: { marginBottom: -3 }
[warning] 20-20:
Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “TabLayout” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true
🪛 ESLint
RDSExpoApp/app/(tabs)/index.tsx
[error] 16-16: Replace key with (key)
(prettier/prettier)
[error] 29-32: Replace ⏎····AuthApi.GITHUB_AUTH_API,⏎····queryParams,⏎·· with AuthApi.GITHUB_AUTH_API,·queryParams
(prettier/prettier)
[error] 51-51: Replace "Initial·URL·received:" with 'Initial·URL·received:'
(prettier/prettier)
[error] 58-58: Replace "Deep·link·event·received:" with 'Deep·link·event·received:'
(prettier/prettier)
[error] 65-65: React Hook useEffect has a missing dependency: 'handleTokenFromUrl'. Either include it or remove the dependency array.
(react-hooks/exhaustive-deps)
[error] 68-68: Replace (err with ((err)
(prettier/prettier)
[error] 75-75: Delete ·
(prettier/prettier)
[error] 76-76: Delete ·
(prettier/prettier)
[error] 77-77: Delete ·
(prettier/prettier)
[error] 78-78: Delete ·
(prettier/prettier)
[error] 92-92: Delete ·
(prettier/prettier)
[error] 101-101: Insert ·
(prettier/prettier)
[error] 106-106: Delete ·
(prettier/prettier)
[error] 108-109: Delete ··⏎··
(prettier/prettier)
[error] 113-113: Delete ·
(prettier/prettier)
[error] 122-122: Insert ·
(prettier/prettier)
[error] 123-123: Insert ,
(prettier/prettier)
[error] 129-129: Insert ,
(prettier/prettier)
[error] 131-131: Insert ⏎
(prettier/prettier)
RDSExpoApp/app/(tabs)/_layout.tsx
[error] 13-13: Delete ·
(prettier/prettier)
[error] 14-14: Insert ⏎····
(prettier/prettier)
[error] 20-20: Replace ·name="code"·size={28}·color={color}·style={{·marginBottom:·-3·}} with ⏎··············name="code"⏎··············size={28}⏎··············color={color}⏎··············style={{·marginBottom:·-3·}}⏎···········
(prettier/prettier)
[error] 29-29: Replace ·name="code"·size={28}·color={color}·style={{·marginBottom:·-3·}} with ⏎··············name="code"⏎··············size={28}⏎··············color={color}⏎··············style={{·marginBottom:·-3·}}⏎···········
(prettier/prettier)
[error] 35-35: Insert ⏎
(prettier/prettier)
RDSExpoApp/app/_layout.tsx
[error] 39-40: Delete ⏎··
(prettier/prettier)
[error] 48-48: Insert ⏎
(prettier/prettier)
🪛 GitHub Actions: Continous-Integeration
RDSExpoApp/app/(tabs)/index.tsx
[error] 62-62: React Hook useEffect has a missing dependency: 'handleTokenFromUrl'. Either include it or remove the dependency array.
RDSExpoApp/app/(tabs)/_layout.tsx
[warning] 20-20: Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state. Instead, move this component definition out of the parent component 'TabLayout' and pass data as props.
[warning] 25-25: Inline style: { marginBottom: -3 }
[warning] 34-34: Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state. Instead, move this component definition out of the parent component 'TabLayout' and pass data as props.
[warning] 39-39: Inline style: { marginBottom: -3 }
🔇 Additional comments (68)
ios/Podfile (2)
1-1: Correct integration of Expo autolinking script.This line properly includes the Expo autolinking script, which is a necessary addition when migrating from React Native CLI to Expo.
19-26: Good implementation of Expo modules with error handling.The addition of
use_expo_modules!and the post_integrate block with proper error handling follows Expo's recommended setup. The error trapping ensures that any issues withexpo_patch_react_imports!won't cause the entire build process to fail.🧰 Tools
🪛 RuboCop (1.73)
[convention] 21-21: Redundant
beginblock detected.(Style/RedundantBegin)
RDSExpoApp/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml (1)
1-5: Proper implementation of Android adaptive icon.This file correctly implements Android's adaptive icon format, separating the icon into background and foreground layers as required by modern Android standards. This will ensure your app icon displays properly on Android 8.0 (API 26) and above.
package.json (1)
33-33: Expo Dependency Addition Verified.
The addition of"expo": "^51.0.0"is appropriate for the migration to the Expo framework. Please ensure that this version is compatible with your other dependencies and that you have verified any Expo-specific configuration changes in your project.RDSExpoApp/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml (1)
1-5: Adaptive Icon XML Looks Correct.
The adaptive icon XML is correctly structured with both<background>and<foreground>elements defined. Ensure that the referenced resources (@color/iconBackgroundand@mipmap/ic_launcher_foreground) exist and are properly configured in your project.RDSExpoApp/android/.gitignore (1)
1-17: Android .gitignore Configuration is Appropriate.
The newly added.gitignorefile for the Android directory includes all the necessary patterns to exclude OS-specific files (like.DS_Store), Android build artifacts, and IDE configuration files. This will help maintain a clean repository.RDSExpoApp/app/(tabs)/ProfileScreen.tsx (1)
1-23: ProfileScreen Component is Well Implemented.
The newProfileScreencomponent is simple and clear, using a standard layout and style definition. It meets the requirements for a basic screen. Consider adding accessibility properties (e.g.,accessibilityLabel) if this component is part of the primary navigation to enhance usability.RDSExpoApp/android/app/src/main/res/drawable/ic_launcher_background.xml (1)
1-6: Launcher Background Drawable is Configured Correctly.
Theic_launcher_background.xmlfile utilizes a<layer-list>to combine a background color with a centered logo bitmap, which is a solid approach for creating composite drawables. Please verify that the resources referenced (@color/splashscreen_backgroundand@drawable/splashscreen_logo) are defined and available.RDSExpoApp/constants/apiConstant/BaseUrl.ts (1)
1-3: Good approach using exported constants for API endpoints.This is a clean implementation of base URL constants that centralizes API endpoint configuration. Using separate constants for production and staging environments is a good practice for environment isolation.
android/settings.gradle (1)
6-7: Proper Expo configuration for Android.These additions correctly integrate Expo modules into the Android project, which is essential for the CLI to Expo migration mentioned in the PR objectives. The dynamic resolution of the Expo package path is a standard approach.
RDSExpoApp/constants/Colors.ts (1)
1-19: Well-organized color theme structure.The file properly defines separate color schemes for light and dark modes, which is good practice for theming. Using named constants for repeated values (tint colors) improves maintainability.
RDSExpoApp/tsconfig.json (1)
1-18: Good TypeScript configuration setup for Expo!This configuration extends Expo's base TypeScript settings and includes appropriate compiler options for a React Native project. The path aliasing with "@/*" will simplify imports throughout the application, and strict type checking is enabled to catch potential issues early.
RDSExpoApp/.gitignore (1)
1-36: Comprehensive .gitignore configuration for ExpoThis .gitignore file appropriately excludes all the necessary files and directories for an Expo/React Native project, including node modules, build artifacts, sensitive files, and environment-specific configurations.
RDSExpoApp/android/app/proguard-rules.pro (1)
1-14: Appropriate ProGuard rules for React Native with ReanimatedThe ProGuard configuration correctly preserves classes from Reanimated and React Native's TurboModule system, which is essential for proper functionality when building production Android apps.
RDSExpoApp/android/gradle/wrapper/gradle-wrapper.properties (1)
1-7: Gradle wrapper configured with a recent versionThe Gradle wrapper is properly configured with Gradle 8.10.2, which is a recent version. The file includes all standard properties required for the Gradle wrapper to function correctly.
RDSExpoApp/android/app/src/main/res/drawable/rn_edit_text_material.xml (1)
1-38: XML Drawable Resource for Edit Text is Appropriately ConfiguredThe XML file correctly defines an inset with a selector for handling drawable states. The inline comment clearly explains the rationale for the change to avoid a
NullPointerException. This implementation is clear and adheres to the intended material design adjustments.RDSExpoApp/android/app/src/debug/AndroidManifest.xml (1)
1-8: Debug AndroidManifest Configuration Looks CorrectThe manifest file for the debug build correctly declares the
SYSTEM_ALERT_WINDOWpermission and configures the application tag to allow cleartext traffic. Ensure the allowance for cleartext traffic is intended solely for debugging purposes.RDSExpoApp/android/app/src/main/res/values/styles.xml (3)
1-8: AppTheme style looks correct with a potential issueThe main application theme is properly configured with appropriate settings, including text color, edit text style, and references to custom resources. However, the hardcoded white status bar color might overwrite the
colorPrimaryDarksetting from your colors.xml file.Verify that setting both
colorPrimaryDarkin colors.xml andandroid:statusBarColorin styles.xml isn't redundant. Consider using a reference instead of hardcoding:<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:textColor">@android:color/black</item> <item name="android:editTextStyle">@style/ResetEditText</item> <item name="android:editTextBackground">@drawable/rn_edit_text_material</item> <item name="colorPrimary">@color/colorPrimary</item> - <item name="android:statusBarColor">#ffffff</item> + <item name="android:statusBarColor">@color/colorPrimaryDark</item> </style>
9-13: EditText style correctly implementedThe ResetEditText style properly inherits from the Android EditText widget and customizes padding and text colors appropriately.
14-18: Splash screen configuration looks goodThe Expo splash screen is properly configured with the necessary attributes, including background color, animated icon, and post-splash theme transition.
RDSExpoApp/android/build.gradle (2)
26-41: Repository configuration is properThe repository configuration correctly includes all necessary sources for React Native dependencies, including Google, Maven Central, and JitPack repositories.
3-22:Details
❓ Verification inconclusive
Check Android SDK version compatibility
The build script correctly configures SDK versions, but uses very high version numbers that might not be widely available or stable yet.
🏁 Script executed:
#!/bin/bash # Check if the specified SDK versions are compatible with common device distributions echo "Verifying Android SDK versions used in build.gradle" echo "compileSdkVersion: 35" echo "targetSdkVersion: 34" echo "buildToolsVersion: 35.0.0" echo "minSdkVersion: 24" # Check Android Studio's latest available versions echo -e "\nLatest Android Studio SDK versions according to documentation:" curl -s "https://developer.android.com/studio/releases" | grep -A 5 "Build Tools" | grep -o "Build Tools [0-9]*\.[0-9]*\.[0-9]*" | head -1Length of output: 602
SDK Default Versions Verification – Please Confirm Compatibility
The build script is correctly outputting the default Android SDK settings (compileSdkVersion: 35, targetSdkVersion: 34, buildToolsVersion: 35.0.0, minSdkVersion: 24). However, our automated check didn’t confirm from the Android Studio releases page that these higher version numbers (especially 35.x) are fully supported and stable. Please review the official Android documentation and confirm these defaults match the intended device and ecosystem support. If not, consider using lower, widely accepted versions until you’re confident that these higher versions won’t create compatibility issues.
- File: RDSExpoApp/android/build.gradle (lines 3–22)
RDSExpoApp/android/app/src/main/res/values/strings.xml (1)
1-6:Details
❓ Verification inconclusive
String resources properly defined for Expo
The string resources are correctly defined for the Expo application, including the application name and Expo configuration options.
Verify that 'RDSExpoApp' is the intended app name when showing on the device, as it appears different from the component name 'RDSApp' in MainActivity.kt:
🏁 Script executed:
#!/bin/bash # Check for potential inconsistency between app name and component name echo "Application name in strings.xml: RDSExpoApp" echo "Main component name in MainActivity.kt: RDSApp" # Find any other occurrences of either name to determine which is correct echo -e "\nOccurrences of RDSExpoApp in project:" fd -t f -e java -e kt -e xml -e json -e js -e jsx -e ts -e tsx | xargs grep -l "RDSExpoApp" | wc -l echo -e "\nOccurrences of RDSApp in project:" fd -t f -e java -e kt -e xml -e json -e js -e jsx -e ts -e tsx | xargs grep -l "RDSApp" | wc -lLength of output: 803
Action: Verify Naming Consistency Between App Name and Component Name
The Expo string resources are correctly defined in RDSExpoApp/android/app/src/main/res/values/strings.xml. However, our verification shows that while the app name is set to "RDSExpoApp" (appearing in 4 locations), the main component in MainActivity.kt is registered as "RDSApp" (found in 3 locations). Please confirm that this discrepancy is intentional to ensure the displayed app name on the device is as expected and that there’s no unintended mismatch.
- File:
RDSExpoApp/android/app/src/main/res/values/strings.xml–app_nameis "RDSExpoApp".- File:
MainActivity.kt– main component name is "RDSApp".- Verification: Occurrence counts indicate a naming discrepancy (4 vs 3).
android/app/src/main/java/com/rdsapp/MainActivity.kt (2)
2-2: Added Expo modules importThe import for
expo.modules.ReactActivityDelegateWrapperis correctly added to integrate Expo with the React Native application.
21-22:Details
❓ Verification inconclusive
Integrated Expo wrapper for React Activity Delegate
The
createReactActivityDelegatemethod has been correctly modified to use Expo'sReactActivityDelegateWrapper, which is essential for the CLI to Expo migration.However, there's an inconsistency in component names. The
MainActivityuses "RDSApp" as the main component name, but the string resource in strings.xml is "RDSExpoApp". This might cause issues when the app starts.
🏁 Script executed:
#!/bin/bash # Check for potential app name inconsistencies in JS files echo "Searching for component/app name in JavaScript files..." # Look for registerComponent calls echo -e "\nSearching for registerComponent calls:" rg "registerComponent\(" -A 2 -g "*.{js,jsx,ts,tsx}" # Look for specific app names echo -e "\nOccurrences of 'RDSApp':" rg "'RDSApp'" -g "*.{js,jsx,ts,tsx}" echo -e "\nOccurrences of 'RDSExpoApp':" rg "'RDSExpoApp'" -g "*.{js,jsx,ts,tsx}"Length of output: 572
Action: Resolve main component naming mismatch
The update to use Expo's
ReactActivityDelegateWrapperincreateReactActivityDelegateis correctly implemented for the CLI to Expo migration. However, there is still a naming inconsistency: theMainActivityreferences the main component as"RDSApp"while the string resource inandroid/app/src/main/res/values/strings.xmlis set to"RDSExpoApp". This discrepancy might lead to runtime issues if the expected component name does not match across configurations.
- Verify that the intended main component name is uniformly used in both the native code (MainActivity) and the string resources.
- If the difference is intentional (e.g., as part of the Expo migration), please add a comment to explain the rationale.
RDSExpoApp/android/settings.gradle (6)
4-4: Plugin Declaration:
The declaration of thecom.facebook.react.settingsplugin is clear and appropriately placed.
24-24: Root Project Name:
Setting the root project name to 'RDSExpoApp' is standard practice.
26-32: Dynamic Version Catalog Loading:
Using Node to resolve the path for yourlibs.versions.tomlfile is clever. Ensure that this dynamic resolution is consistently reliable across all development and CI environments, particularly when paths or package versions change.
34-36: Expo Modules Integration:
Applying the external Gradle script from the Expo package and then invokinguseExpoModules()cleanly integrates Expo modules into the Android build. Double-check that the relative path resolution remains valid across updates to Expo packages.
37-39: Module Inclusion:
The inclusion of modules viainclude ':app'and a secondaryincludeBuildwith a dynamic path is fine. Just ensure any changes in the underlying paths do not break this resolution mechanism.
6-22:Details
❓ Verification inconclusive
Conditional Autolinking Configuration:
Theextensions.configureblock effectively chooses between community autolinking and a custom command based on theEXPO_USE_COMMUNITY_AUTOLINKINGenvironment variable. Verify that the constructed command (lines 10–19) behaves as expected on all target environments.
Action Required: Verify Autolinking Command Behavior Across Environments
The conditional configuration correctly toggles between community autolinking and a custom command based on the
EXPO_USE_COMMUNITY_AUTOLINKINGenvironment variable. However, please ensure that:
- In environments where
EXPO_USE_COMMUNITY_AUTOLINKINGis not set to'1', the custom command (lines 10–19) reliably resolves and executes the Expo modules autolinking logic.- The Node.js call using
--no-warningsand the inline evaluation of the Expo modules autolinking script behaves consistently across all target environments.A thorough runtime test or manual verification on all supported environments would help confirm that the custom command functions as expected.
tsconfig.json (1)
23-31: Extending Expo's TypeScript Base Configuration:
Adding"extends": "expo/tsconfig.base"centralizes common TypeScript settings provided by Expo, which is ideal for an Expo-managed project. Ensure any project-specific overrides are maintained separately if required.RDSExpoApp/package.json (6)
1-4: Project Metadata:
The basic metadata (name, main entry point, version) is set correctly. Using"expo-router/entry"as the main entry aligns with your Expo migration strategy.
5-11: Scripts Configuration:
The scripts for starting the app on different platforms (start, android, ios, web) and for running tests are well-aligned with Expo CLI conventions. Make sure your README or documentation is updated to reflect these commands.
12-14: Jest Preset Usage:
Configuring Jest with the"jest-expo"preset is appropriate for testing Expo projects. Confirm that test cases cover key application behaviors post-migration.
15-35: Dependencies Overview:
The dependency list includes essential Expo libraries, React, and React Native components. It’s important to regularly verify that these version constraints (e.g., for Expo, React Native, etc.) are compatible with one another and reflect your project's requirements.
36-43: DevDependencies Check:
The devDependencies look comprehensive for an Expo and React Native project. Ensure that the tooling versions (Babel, TypeScript, Jest) remain compatible with any upgrades you choose to perform in the future.
44-46: Project Privacy:
Marking the project as private is standard for internal apps.RDSExpoApp/android/gradlew (5)
1-20: Gradle Wrapper Script Header:
The header provides required licensing information and usage instructions, adhering to Gradle wrapper conventions.
121-144: Java Command Resolution:
The logic to determine which Java executable to use—including handling IBM’s JDK on AIX—is robust. The error messaging is clear and should help users diagnose configuration issues quickly.
146-163: File Descriptor Limit Handling:
Attempting to increase the file descriptor limit is a good practice where system constraints permit it. The fallback warnings are useful for diagnosing issues on systems that might not support the change.
165-202: Argument Processing for Cross-Platform Compatibility:
The script’s handling of command-line arguments—especially for Cygwin/MSYS environments—is comprehensive and helps ensure that paths are correctly formatted. This detailed processing increases the chances of cross-platform compatibility.
205-253:Details
❓ Verification inconclusive
JVM Options and Execution:
Default JVM options are set and command-line arguments are carefully collated before invoking Java. The use ofevalandxargsintroduces some complexity; ensure that environment variables (DEFAULT_JVM_OPTS,JAVA_OPTS,GRADLE_OPTS) do not contain unexpected characters that could lead to security issues.
Security Review: Validate
evalHandling in Gradle WrapperThe script in
RDSExpoApp/android/gradlew(lines 205–253) uses a combination ofxargs,sed, andevalto process and sanitize JVM options from environment variables. The sed command ensures that characters outside of a defined safe set are escaped, which helps reduce the risk of shell injection. However, note that the approach assumes these variables won’t contain newlines or unmatched quotes. Please verify that:
- The environment variables (
DEFAULT_JVM_OPTS,JAVA_OPTS,GRADLE_OPTS) are tightly controlled and cannot include unexpected shell fragments.- There is sufficient assurance that any user-provided inputs adhere to the expected format, so as to prevent potential execution issues.
RDSExpoApp/android/gradlew.bat (8)
1-18: Gradle Wrapper Batch Script Header:
The header with licensing and usage instructions meets standard conventions for Windows batch scripts.
19-27: Local Scope and Environment Setup:
The use ofsetlocalensures that variables do not leak into the global environment on Windows, and the initialization of directory variables is correctly handled.
29-37: APP_HOME Resolution in Batch:
The method of resolvingAPP_HOMEusing%~dp0and a FOR loop is standard and should work reliably on Windows systems.
38-40: Default JVM Options:
Setting default memory options for the JVM helps ensure a consistent runtime environment. Double-check that the allocated memory (-Xmx64m -Xms64m) is adequate for your Gradle tasks in the context of an Expo project.
41-55: Java Executable Resolution:
The logic to locatejava.exeby first checkingJAVA_HOMEand then falling back to the system’s PATH is robust. The error messages provide clear instructions to the user in case of misconfiguration.
56-69: JAVA_HOME Validation:
Stripping quotes fromJAVA_HOMEand verifying the existence ofjava.exereinforces the script’s robustness in handling common user errors.
70-78: Executing the Gradle Wrapper:
The construction and execution of the Gradle command with the proper JVM options and classpath is well done, ensuring that the build process will be initiated correctly on Windows using the batch script.
79-95: Exit Handling:
Proper termination of the script using local scope cleanup and detailed exit code management ensures that errors in Gradle execution are correctly reported.RDSExpoApp/android/gradle.properties (1)
1-56: Configuration looks good for the Expo migration.The gradle.properties file has been properly configured with standard React Native and Expo settings, including memory allocation, architecture targets, and enabling key features like the new architecture and Hermes engine.
RDSExpoApp/app/_layout.tsx (1)
16-17: Best practice use of splash screen.Good implementation of splash screen management by preventing auto-hiding until fonts are loaded.
RDSExpoApp/android/app/src/main/AndroidManifest.xml (2)
43-57: Good deep linking configuration.The deep linking setup is well-structured with specific filters for OAuth redirects and a general scheme handler. This allows the app to properly receive authentication callbacks.
25-27:Details
❓ Verification inconclusive
Verify Expo updates configuration.
The Expo updates feature is explicitly disabled (
ENABLEDset tofalse), but other update settings are configured. This seems inconsistent.Check if this is intentional or if updates should be enabled for this app:
🏁 Script executed:
#!/bin/bash # Search for other Expo update configurations in the codebase grep -r "expo.modules.updates" --include="*.json" --include="*.js" --include="*.ts" .Length of output: 3293
Action Required: Confirm Expo Updates Configuration
The grep results show that all occurrences of Expo updates configuration come from Expo’s default config plugins (in the node_modules folder), with no additional custom override in user code. The AndroidManifest.xml still includes update-related keys despite disabling updates via
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>. Please verify whether this mix is intentional—if you’re purposely disabling updates, consider whether the extra keys (EXPO_UPDATES_CHECK_ON_LAUNCH and EXPO_UPDATES_LAUNCH_WAIT_MS) are needed or can be removed to avoid future confusion.
- Location: RDSExpoApp/android/app/src/main/AndroidManifest.xml (Lines 25-27)
- Reference: No custom Expo updates configuration was found outside of Expo’s node_modules.
RDSExpoApp/android/app/build.gradle (2)
5-63: Good Expo integration configurationThe React Native configuration is properly set up for Expo integration. The use of Expo CLI for bundling and the correct path resolution for entry files are essential for the migration to work properly.
149-176: Well-structured conditional dependenciesThe conditional inclusion of GIF and WebP support based on properties is a good practice that keeps the app size minimal when these features aren't needed.
android/app/src/main/java/com/rdsapp/MainApplication.kt (4)
20-34: Good implementation of ReactNativeHostWrapperThe switch to
ReactNativeHostWrappercorrectly integrates Expo with the React Native host, which is essential for the Expo migration.
36-37: Correct implementation of reactHost getterThe update to use
ReactNativeHostWrapper.createReactHostinstead ofgetDefaultReactHostis necessary for proper Expo integration.
46-46: Important Expo lifecycle integrationAdding
ApplicationLifecycleDispatcher.onApplicationCreate(this)is essential for proper Expo lifecycle management.
49-52: Proper configuration change handlingThe addition of
onConfigurationChangedoverride withApplicationLifecycleDispatcherintegration is necessary for handling configuration changes in Expo applications.RDSExpoApp/android/app/src/main/java/com/abstrctdatyp/RDSExpoApp/MainActivity.kt (3)
15-24: Proper splash screen integrationThe splash screen integration is implemented correctly with
SplashScreenManager.registerOnActivity(this). Passingnulltosuper.onCreate()is an intentional pattern to avoid recreating the JavaScript context on configuration changes.
36-45: Good setup for new architectureThe implementation of
createReactActivityDelegate()correctly usesReactActivityDelegateWrapperwith the appropriate architecture flags from BuildConfig, ensuring compatibility with React Native's new architecture when enabled.
52-64: Excellent back button handlingThe back button handling is well-implemented with proper Android version checks, following the recommended pattern for handling back navigation differently on Android R and below versus Android S and above.
RDSExpoApp/android/app/src/main/java/com/abstrctdatyp/RDSExpoApp/MainApplication.kt (4)
21-38: Proper Expo integration for React Native hostThe
reactNativeHostimplementation correctly usesReactNativeHostWrapperto integrate Expo functionality with React Native.
31-31: Correct Expo entry pointSetting the JS main module name to
.expo/.virtual-metro-entryis required for Expo's metro configuration and bundling to work properly.
43-51: Proper initialization with Expo lifecycle integrationThe
onCreatemethod correctly initializes SoLoader withOpenSourceMergedSoMappingand integratesApplicationLifecycleDispatcherfor proper Expo lifecycle management.
53-56: Configuration change handling for ExpoThe implementation of
onConfigurationChangedwithApplicationLifecycleDispatcherintegration is necessary for proper handling of configuration changes in Expo applications.
.expo/devices.json
Outdated
| { | ||
| "devices": [] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Standard Expo devices tracking file.
This is a standard configuration file created by Expo to track devices that connect to your development server. The structure is correct.
Consider adding the .expo directory to your .gitignore file if not already there, as this contains machine-specific information that shouldn't be committed to version control.
| @@ -0,0 +1 @@ | |||
| <resources/> No newline at end of file | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Empty night mode colors file needs values.
Adding a night-specific colors.xml file follows Android best practices, but it's currently empty. Without night mode color definitions, your app may not display optimally when users have dark theme enabled.
Consider defining night mode variations of your app's colors in this file to ensure proper dark theme support. At minimum, you should define night mode versions of the main colors defined in your regular colors.xml file (such as splashscreen_background, iconBackground, etc.).
<resources>
<color name="splashscreen_background">#121212</color>
<color name="iconBackground">#121212</color>
<color name="colorPrimary">[dark_value]</color>
<color name="colorPrimaryDark">[dark_value]</color>
</resources>| tabBarIcon: ({ color }) => ( | ||
| <FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} /> | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extract icon components to avoid re-creation during renders.
Components defined during render cause performance issues as React creates new instances on every render.
+// Define tab icons outside of the component
+const TabBarIcon = (props: {
+ name: React.ComponentProps<typeof FontAwesome>['name'];
+ color: string;
+}) => <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
export default function TabLayout() {
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme].tint,
headerShown: false,
}}>
<Tabs.Screen
name="index"
options={{
title: 'index',
tabBarIcon: ({ color }) => (
- <FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} />
+ <TabBarIcon name="code" color={color} />
),
}}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| tabBarIcon: ({ color }) => ( | |
| <FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} /> | |
| ), | |
| // Define tab icons outside of the component | |
| const TabBarIcon = (props: { | |
| name: React.ComponentProps<typeof FontAwesome>['name']; | |
| color: string; | |
| }) => <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />; | |
| export default function TabLayout() { | |
| return ( | |
| <Tabs | |
| screenOptions={{ | |
| tabBarActiveTintColor: Colors[colorScheme].tint, | |
| headerShown: false, | |
| }}> | |
| <Tabs.Screen | |
| name="index" | |
| options={{ | |
| title: 'index', | |
| tabBarIcon: ({ color }) => ( | |
| <TabBarIcon name="code" color={color} /> | |
| ), | |
| }} | |
| /> | |
| </Tabs> | |
| ); | |
| } |
🧰 Tools
🪛 GitHub Check: build (18.x)
[warning] 20-20:
Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “TabLayout” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true
🪛 ESLint
[error] 20-20: Replace ·name="code"·size={28}·color={color}·style={{·marginBottom:·-3·}} with ⏎··············name="code"⏎··············size={28}⏎··············color={color}⏎··············style={{·marginBottom:·-3·}}⏎···········
(prettier/prettier)
🪛 GitHub Actions: Continous-Integeration
[warning] 20-20: Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state. Instead, move this component definition out of the parent component 'TabLayout' and pass data as props.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yesyash The issue isn't with creating a component that returns a FontAwesome icon, but where it's being created. When you define an inline component function like this:
tabBarIcon: ({ color }) => (
<FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} />
)React creates a new function instance on every render of the parent component. This is problematic because:
- React uses reference equality (
===) to check if components have changed - New function instances are treated as different components
- This can cause React to unmount and remount the entire subtree instead of just updating props
By defining the component outside the render method:
const TabBarIcon = (props) => <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;The function reference remains stable between renders, allowing React to properly update the component instead of recreating it, which improves performance.
This is why ESLint is showing the warning: "Do not define components during render."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yesyash I understand your question! This is about React's rendering optimization, not just creating a component.
When you define a function inside the render method like this:
tabBarIcon: ({ color }) => (
<FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} />
)React creates a brand new function instance on every render of the parent component. React uses reference equality (===) to check if components have changed, so these new functions are treated as completely different components each time.
When you move the component definition outside:
// Outside component, defined once
const TabBarIcon = (props) => <FontAwesome size={28} style={{ marginBottom: -3 }} {...props} />;
// Inside component, reference stays stable between renders
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />The TabBarIcon function is created once and its reference remains stable, while we're still passing the dynamic color prop. This helps React optimize re-renders and can prevent unnecessary DOM manipulations.
This is a recommended React performance pattern, which is why ESLint is warning about component definitions during render.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@coderabbitai we're just creating a component that returns the FontAwesome icon how will this fix the issue you're suggesting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
| <Tabs.Screen | ||
| name="ProfileScreen" | ||
| options={{ | ||
| title: 'ProfileScreen', | ||
| tabBarIcon: ({ color }) => ( | ||
| <FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} /> | ||
| ), | ||
| }} | ||
| /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use distinct icons for different tabs and fix component recreation issue.
Both tabs currently use the same "code" icon, which can be confusing for users. Also, this tab has the same issue with component recreation during render.
<Tabs.Screen
name="ProfileScreen"
options={{
title: 'ProfileScreen',
tabBarIcon: ({ color }) => (
- <FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} />
+ <TabBarIcon name="user" color={color} />
),
}}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Tabs.Screen | |
| name="ProfileScreen" | |
| options={{ | |
| title: 'ProfileScreen', | |
| tabBarIcon: ({ color }) => ( | |
| <FontAwesome name="code" size={28} color={color} style={{ marginBottom: -3 }} /> | |
| ), | |
| }} | |
| /> | |
| <Tabs.Screen | |
| name="ProfileScreen" | |
| options={{ | |
| title: 'ProfileScreen', | |
| tabBarIcon: ({ color }) => ( | |
| <TabBarIcon name="user" color={color} /> | |
| ), | |
| }} | |
| /> |
🧰 Tools
🪛 GitHub Check: build (18.x)
[warning] 25-25:
Inline style: { marginBottom: -3 }
🪛 ESLint
[error] 29-29: Replace ·name="code"·size={28}·color={color}·style={{·marginBottom:·-3·}} with ⏎··············name="code"⏎··············size={28}⏎··············color={color}⏎··············style={{·marginBottom:·-3·}}⏎···········
(prettier/prettier)
🪛 GitHub Actions: Continous-Integeration
[warning] 25-25: Inline style: { marginBottom: -3 }
| screenOptions={{ | ||
| tabBarActiveTintColor: Colors[colorScheme].tint, | ||
| headerShown: false, | ||
| }}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix formatting issues flagged by ESLint.
There are several formatting issues that caused pipeline failures.
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme].tint,
- headerShown: false,
+ headerShown: false,
}}>Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 ESLint
[error] 13-13: Delete ·
(prettier/prettier)
[error] 14-14: Insert ⏎····
(prettier/prettier)
| const [loaded, error] = useFonts({ | ||
| SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Consider adding more fonts if needed.
Currently, only SpaceMono font is loaded. Consider if additional font weights or styles are needed for the app.
| function RootLayoutNav() { | ||
|
|
||
| return ( | ||
| <ThemeProvider value={DefaultTheme}> | ||
| <Stack> | ||
| <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> | ||
| <Stack.Screen name="modal" options={{ presentation: 'modal' }} /> | ||
| </Stack> | ||
| </ThemeProvider> | ||
| ); | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Remove unnecessary whitespace and follow consistent formatting.
There's unnecessary whitespace in the RootLayoutNav function that should be removed.
function RootLayoutNav() {
-
return (
<ThemeProvider value={DefaultTheme}>
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
</ThemeProvider>
);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function RootLayoutNav() { | |
| return ( | |
| <ThemeProvider value={DefaultTheme}> | |
| <Stack> | |
| <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> | |
| <Stack.Screen name="modal" options={{ presentation: 'modal' }} /> | |
| </Stack> | |
| </ThemeProvider> | |
| ); | |
| } | |
| function RootLayoutNav() { | |
| return ( | |
| <ThemeProvider value={DefaultTheme}> | |
| <Stack> | |
| <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> | |
| <Stack.Screen name="modal" options={{ presentation: 'modal' }} /> | |
| </Stack> | |
| </ThemeProvider> | |
| ); | |
| } |
🧰 Tools
🪛 ESLint
[error] 39-40: Delete ⏎··
(prettier/prettier)
[error] 48-48: Insert ⏎
(prettier/prettier)
| <uses-permission android:name="android.permission.INTERNET"/> | ||
| <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||
| <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | ||
| <uses-permission android:name="android.permission.VIBRATE"/> | ||
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Review necessary permissions for modern Android.
Some permissions might be unnecessary or could be replaced with more modern alternatives.
🌐 Web query:
What are the modern alternatives to READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions in Android?
💡 Result:
Android has shifted from broad storage permissions like READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE to more granular, privacy-focused alternatives. Here are the modern approaches developers should adopt:
Key Modern Alternatives
1. Granular Media Permissions (Android 13+)
READ_MEDIA_IMAGES: Access images viaMediaStore[2][10].READ_MEDIA_VIDEO: Access videos viaMediaStore[2][10].READ_MEDIA_AUDIO: Access audio files viaMediaStore[2][10].
These replace READ_EXTERNAL_STORAGE for media access. Apps must request these at runtime and only for the specific media types needed.
2. MediaStore API
Use MediaStore APIs to interact with shared media files (images, videos, audio) without requiring broad permissions:
- Query media files using
ContentResolver[3][10]. - Direct file paths can now be used with
FileAPIs or native libraries (Android 11+) for media files your app owns [4][10].
Example:
val resolver = context.contentResolver
resolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ...)3. Scoped Storage Best Practices
-
App-Specific Storage:
UsegetExternalFilesDir()orgetExternalCacheDir()to store private files without permissions [3][4]. -
Legacy Compatibility:
For apps supporting Android 10 and below, use conditional logic:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Use MediaStore } else { // Request READ_EXTERNAL_STORAGE (deprecated post-Android 10) }
4. Storage Access Framework (SAF)
For non-media files (e.g., PDFs) or user-selected directories:
- Use
ACTION_OPEN_DOCUMENTorACTION_CREATE_DOCUMENTintents [10][11]. - Grants temporary access to specific files/folders without permissions.
5. Special Cases: MANAGE_EXTERNAL_STORAGE
- Required for file managers or backup apps needing full storage access [2][4].
- Requires Play Store approval and strict justification [2][4].
Deprecated Permissions
READ_EXTERNAL_STORAGE: Ignored for apps targeting Android 13+; replaced by granular media permissions [2][10].WRITE_EXTERNAL_STORAGE: No effect on Android 11+ for shared storage. Use app-specific directories orMediaStorefor writes [3][4][10].
Common Challenges & Solutions
| Challenge | Solution |
|---|---|
| Legacy app migration | Refactor to use MediaStore and app-specific directories [1][4]. |
| Backward compatibility | Use Build.VERSION.SDK_INT checks [1][4]. |
| Large media queries | Optimize with pagination or LOAD_ONLY_METADATA [1]. |
| User permission confusion | Explain why permissions are needed during runtime requests [1]. |
Testing & Compliance
- Test on Android 10–15 to ensure compatibility [1][6].
- Use Android 15’s enhanced logging for file access errors [1].
- Avoid
MANAGE_EXTERNAL_STORAGEunless absolutely necessary [2][4].
By adopting these alternatives, developers align with Android’s privacy-first approach while ensuring functionality across devices.
Citations:
- 1: https://itnext.io/navigating-the-challenges-of-scoped-storage-lessons-for-modern-android-apps-b5fd8318a02c
- 2: https://developer.datalogic.com/mobile-computers/news/a13_new_permissions_for_file_access
- 3: https://developer.android.com/training/data-storage
- 4: https://developer.android.com/about/versions/11/privacy/storage
- 5: https://godotforums.org/d/27239-work-arounds-for-new-scoped-storage-in-android
- 6: https://www.b4x.com/android/forum/threads/write_external_storage-and-read_external_storage-permissions-in-android-sdk-33-13.149145/
- 7: https://techcommunity.microsoft.com/discussions/microsoft-intune/application-configuration-policy-for-android---missing-permission-options/3800060
- 8: https://love2d.org/forums/viewtopic.php?t=94334
- 9: Storage permissions are unnecessarily required kiwix/kiwix-android#3265
- 10: https://developer.android.com/training/data-storage/shared/media
- 11: Android - READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are set to max sdk 28 by core NativeScript/NativeScript#10341
Update Permissions for Modern Android
File: RDSExpoApp/android/app/src/main/AndroidManifest.xml (Lines 2–6)
The manifest still includes legacy storage permissions that modern Android no longer requires or recommends. In Android 11 and later:
READ_EXTERNAL_STORAGEis deprecated in favor of granular media permissions introduced in Android 13:- Use
READ_MEDIA_IMAGES,READ_MEDIA_VIDEO, andREAD_MEDIA_AUDIOfor accessing specific media types.
- Use
WRITE_EXTERNAL_STORAGEis effectively a no-op on Android 11+ when using shared storage. Instead, consider using:- App-specific storage directories (via
getExternalFilesDir()orgetExternalCacheDir()), or - The
MediaStoreAPI for media file operations.
- App-specific storage directories (via
Action Items:
-
Reevaluate Storage Permissions:
- Update or remove
READ_EXTERNAL_STORAGEandWRITE_EXTERNAL_STORAGEbased on your target SDK and the type of media/data your app accesses. - If your app targets Android 13 or later, replace broad media access with the granular permissions (
READ_MEDIA_*).
- Update or remove
-
Confirm Necessity of Other Permissions:
- Verify that permissions such as
INTERNET,SYSTEM_ALERT_WINDOW, andVIBRATEare still required for your app’s functionality.
- Verify that permissions such as
Please update your manifest accordingly and add conditional runtime checks if supporting backward compatibility.
| namespace 'com.abstrctdatyp.RDSExpoApp' | ||
| defaultConfig { | ||
| applicationId 'com.abstrctdatyp.RDSExpoApp' | ||
| minSdkVersion rootProject.ext.minSdkVersion | ||
| targetSdkVersion rootProject.ext.targetSdkVersion | ||
| versionCode 1 | ||
| versionName "1.0.0" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Check package name consistency with original app
The namespace and applicationId are set to com.abstrctdatyp.RDSExpoApp, but I noticed the original app package was com.rdsapp. Ensure this change is intentional and that references to the package name are updated consistently throughout the codebase to avoid any runtime issues.
🏁 Script executed:
#!/bin/bash
# Check for references to old package name that might need updating
echo "Searching for references to old package name..."
rg -i "com\.rdsapp" --type java --type kotlin --type xmlLength of output: 310
Action Required: Update Package Name for Consistency
The build.gradle file now sets the namespace and applicationId to com.abstrctdatyp.RDSExpoApp, but we still found references to the old package name com.rdsapp in the following files:
- android/app/src/main/java/com/rdsapp/MainApplication.kt
- android/app/src/main/java/com/rdsapp/MainActivity.kt
Please verify whether the package name change is intentional. If so, update these files to use com.abstrctdatyp.RDSExpoApp to ensure consistency and avoid potential runtime issues.
| release { | ||
| // Caution! In production, you need to generate your own keystore file. | ||
| // see https://reactnative.dev/docs/signed-apk-android. | ||
| signingConfig signingConfigs.debug | ||
| shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) | ||
| minifyEnabled enableProguardInReleaseBuilds | ||
| proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" | ||
| crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Production signing config needs attention
The release build configuration is using the debug signing config, which is not suitable for production releases. For a production app, you should generate a proper signing keystore and configure it appropriately.
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
- signingConfig signingConfigs.debug
+ // TODO: Configure a proper release signing config before publishing
+ // signingConfig signingConfigs.release
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| release { | |
| // Caution! In production, you need to generate your own keystore file. | |
| // see https://reactnative.dev/docs/signed-apk-android. | |
| signingConfig signingConfigs.debug | |
| shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) | |
| minifyEnabled enableProguardInReleaseBuilds | |
| proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" | |
| crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) | |
| } | |
| release { | |
| // Caution! In production, you need to generate your own keystore file. | |
| // see https://reactnative.dev/docs/signed-apk-android. | |
| // TODO: Configure a proper release signing config before publishing | |
| // signingConfig signingConfigs.release | |
| shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false) | |
| minifyEnabled enableProguardInReleaseBuilds | |
| proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" | |
| crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true) | |
| } |
Date: 18-01-2025
Developer Name: Aditi Shinde
Issue Ticket Number
Description
Migrated existing CLI app to Expo
Documentation Updated?
Under Feature Flag
Database Changes
Breaking Changes
Development Tested?
Screenshots
Screenshot 1
RDS_Test6.mp4
Test Coverage
Screenshot 1
Additional Notes