Building a React Native App Without Expo: A Comprehensive Guide
Why Build a React Native App Without Expo?
While Expo provides a streamlined environment for React Native development, it also abstracts a lot of the underlying configurations. This can be both a blessing and a curse. By not using Expo, you gain several advantages:Full Control Over Native Modules
Expo simplifies many tasks, but it also limits your ability to access and modify native code directly. For instance, if you want to integrate custom native modules or third-party libraries that require native code modifications, using Expo can be restrictive. Building without Expo allows you to have full control over native modules, enabling you to add features that may not be supported by Expo.Better Performance
For large-scale applications, the overhead introduced by Expo can sometimes lead to performance bottlenecks. Expo apps tend to include a lot of pre-configured features that, while useful, may not be necessary for your specific app. By bypassing Expo, you can strip down your app to only include the features you need, resulting in faster load times and more efficient resource management.No Dependency on Expo SDK Versions
Expo regularly updates its SDK, and while this ensures that you have access to the latest features, it can also be a limitation. If you need to use a version of React Native that is not yet supported by the latest Expo SDK, you’re stuck waiting for Expo to catch up. By building your app without Expo, you have the freedom to update React Native and other dependencies as soon as new versions are released. Also read: React Native app targeting mobile, web, desktop with expo tauri.Setting Up the Development Environment
Before you start building your React Native app without Expo, it’s essential to have the right development environment set up. Here’s a detailed guide to getting your environment ready:Step 1: Install Node.js and npm/yarn
React Native relies on Node.js, a JavaScript runtime built on Chrome’s V8 JavaScript engine. npm (Node Package Manager) or yarn will help you manage your project’s dependencies. To install Node.js, visit the official Node.js website and download the latest stable version. Once Node.js is installed, npm will be installed automatically. If you prefer using yarn, you can install it globally using npm: npm install -g yarnStep 2: Install React Native CLI
The React Native CLI is a command-line tool that enables you to initialize and manage React Native projects without relying on Expo. You can install it globally using npm or yarn: npm install -g react-native-cli This CLI will be your primary tool for creating new projects, running your app, and managing other development tasks.Step 3: Install Java Development Kit (JDK)
If you’re developing for Android, you’ll need to install the Java Development Kit (JDK). The JDK provides the necessary tools for compiling and running Java code, which is essential for Android development. You can download the JDK from the Oracle website or use an open-source alternative like OpenJDK. After installation, ensure that the JDK is properly set up by adding it to your system’s PATH environment variable. This allows your system to recognize Java commands from the terminal.Step 4: Set Up Android Studio
Android Studio is the official Integrated Development Environment (IDE) for Android development. It includes the Android SDK, which provides the necessary tools to build, test, and debug Android apps. Download and install Android Studio from the official website. After installation, open Android Studio and follow the setup wizard to install the necessary components, including the Android SDK, Android Virtual Device (AVD), and any additional tools required for your development needs. You will also need to set up the Android SDK location in your system environment variables:- Windows: Go to System Properties > Environment Variables, and add a new variable named ANDROID_HOME pointing to the Android SDK directory.
- macOS/Linux: Add the following line to your .bash_profile, .zshrc, or equivalent:
|
1 2 3 4 5 6 7 8 9 |
export ANDROID_HOME=$HOME/Library/Android/sdk export PATH=$PATH:$ANDROID_HOME/emulator export PATH=$PATH:$ANDROID_HOME/tools export PATH=$PATH:$ANDROID_HOME/tools/bin export PATH=$PATH:$ANDROID_HOME/platform-tools |
Step 5: Install Xcode (For iOS Development)
If you’re targeting iOS, Xcode is an essential tool. Xcode is the official IDE for iOS app development services and includes the necessary tools to build, test, and debug iOS apps. You can download Xcode from the Mac App Store. After installing Xcode, open it and agree to the terms and conditions. You may also need to install additional components, such as command-line tools, which Xcode will prompt you to install when you first run it. Ensure that you have the latest version of Xcode, as older versions may not support the latest iOS features or may cause compatibility issues with React Native.Initializing the React Native Project
With your environment set up, you’re ready to build and deploy a React Native project. Unlike Expo, where everything is handled behind the scenes, creating a project without Expo gives you full control over the process.Step 1: Create a New Project
To create a new React Native project, use the React Native CLI: react-native init MyApp Replace MyApp with your desired project name. The react-native init command generates a new React Native project with all the necessary files and configurations. This includes native directories (android/ and ios/), JavaScript files, and the basic structure needed to start building your app.Step 2: Understanding the Directory Structure
Once the project is initialized, you’ll notice a different directory structure compared to an Expo project. Here’s an overview of the key directories and files:- android/: This directory contains Android-specific code and configurations. You’ll find Gradle build files, AndroidManifest.xml, and Java files for your Android app.
- ios/: This directory contains iOS-specific code and configurations. It includes Xcode project files, Info.plist, and Swift or Objective-C files for your iOS app.
- src/: Although this directory is not created by default, it’s a good practice to create a src/ directory for your application’s main code. This helps keep your project organized and separates your app logic from platform-specific code.
- App.js: This is the main entry point for your React Native application. You can start building your UI and logic here.
- node_modules/: This directory contains all the dependencies your project needs, installed via npm or yarn.
Managing Dependencies
One of the significant differences when building a React Native app without Expo is that you’ll need to manage dependencies manually. This offers greater flexibility but requires a deeper understanding of how React Native and its libraries work.Step 1: Installing Libraries
Without Expo, you can install any library directly using npm or yarn. For example, if you want to add a library for navigation, you can install it like this: npm install @react-navigation/native After installing the navigation library, you may need to install additional dependencies and set up your project to use them: npm install react-native-screens react-native-safe-area-context For libraries that involve native code, additional steps may be required. React Native CLI automates much of this through auto-linking, but in some cases, you might need to manually link the library: react-native link some-libraryStep 2: Customizing the Build Process
When using Expo, the build process is handled for you. However, without Expo, you’ll need to manage your build configurations, especially if you want to customize the build process for Android or iOS. For Android, you can modify the build.gradle files to customize how your app is built. This might involve setting different build types (e.g., debug, release), configuring ProGuard for code obfuscation, or setting up multi-APK support. For iOS, you can modify the Xcode project settings. This might involve setting up different schemes for development and production, configuring the app’s signing and provisioning profiles, or optimizing the build settings for performance.Running the App
With your dependencies installed and the build process configured, you’re ready to run your app. The process varies slightly depending on whether you’re targeting Android or iOS.Step 1: Running on Android
To run your app on an Android device or emulator, use the following command: react-native run-android Before running this command, make sure you have an Android emulator running or a physical Android device connected to your computer via USB. The React Native CLI will handle the build process and automatically launch your app on the device. Also read: How to create an MVP Android app in React Native frameworkStep 2: Running on iOS
To run your app on an iOS device or simulator, use the following command: react-native run-ios This command will open the iOS Simulator and launch your app. If you want to run the app on a specific device or simulator, you can specify the device name: react-native run-ios –device “iPhone 12” For deployment to a physical iOS device, ensure that your Xcode project is configured with the correct signing and provisioning profiles. You may also need to trust the developer certificate on your iOS device.Adding Native Modules
One of the main reasons to avoid Expo is the ability to add custom native modules. This is particularly useful when you need to access device features that Expo does not support or when you want to optimize performance by writing custom native code.Step 1: Understanding Native Modules
Native modules are pieces of code written in platform-specific languages (Java/Kotlin for Android, Swift/Objective-C for iOS) that allow you to access device features or integrate with third-party services. For example, if you want to access a device’s camera or GPS, you might need to write or integrate a native module for cybersecurity risk. For example, if you want to access a device’s camera or GPS, you might need to write or integrate a native module.Step 2: Adding a Native Module
To add a native module, you’ll need to modify the code in the android/ or ios/ directories. Here’s a high-level overview of the steps: Android:- Navigate to the android/ directory and open the appropriate Java file in the app/src/main/java/com/myapp/ directory.
- Create a new Java class for your native module and extend it from ReactContextBaseJavaModule.
- Implement the methods you need and register the module with React Native.
- Navigate to the ios/ directory and open the appropriate Swift or Objective-C file.
- Create a new class for your native module, ensuring it conforms to the RCTBridgeModule protocol.
- Implement the methods you need and register the module with React Native.
Step 3: Linking the Native Module
After creating the native module, you’ll need to link it with your React Native project. This step involves updating the MainApplication.java (for Android) or AppDelegate.m (for iOS) files to include the new module. For Android, add the following to your MainApplication.java:|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new YourNativeModulePackage() // Add your module here ); } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#import <YourNativeModule.h> // Import your module - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"MyApp" initialProperties:nil]; // Additional setup code return YES; } |
Handling Updates and Dependencies
Without Expo managing your environment, keeping your app up-to-date is your responsibility. Regularly updating your dependencies is crucial to ensure your app remains secure, performant, and compatible with the latest versions of React Native and its libraries.Step 1: Updating Dependencies
To check for updates to your dependencies, you can use the npm-check-updates tool. This tool compares your current dependencies with the latest versions available and updates your package.json accordingly. First, install npm-check-updates globally: npm install -g npm-check-updates Then, check for updates: ncu -u This command updates your package.json with the latest versions of your dependencies. To install the updated dependencies, run: npm installStep 2: Updating React Native
Updating React Native itself can be more involved, as it may require you to update both JavaScript and native code. The React Native community provides a React Native Upgrade Helper tool that guides you through the upgrade process. To update React Native, follow these steps:- Update the react-native version in your package.json to the desired version.
- Run npm install or yarn install to install the updated version.
- Use the React Native Upgrade Helper to manually update any necessary files in the android/ and ios/ directories.
Debugging and Testing
Debugging and testing are essential parts of the development process. Without Expo, you’ll need to rely on different tools and techniques to ensure your app is bug-free and performs well across different devices and platforms.Step 1: Debugging Tools
React Native provides several tools for debugging:- React Developer Tools: A standalone app that allows you to inspect the React component hierarchy, view props and state, and debug the app’s UI.
- Chrome Developer Tools: You can use the Chrome DevTools to debug your JavaScript code. To do this, run your app in development mode and press Cmd+D (iOS) or Cmd+M (Android) to open the developer menu. Then, select “Debug” to open Chrome DevTools.
- Flipper: A desktop app for debugging mobile apps. It provides a wide range of tools, including network inspection, layout inspection, and performance monitoring.
Step 2: Unit Testing
Unit testing ensures that individual components of your app work as expected. You can use testing libraries like Jest, which comes pre-configured with React Native projects. To write a unit test, create a test file in the __tests__/ directory and write your test cases using Jest syntax. For example:|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import React from 'react'; import { render } from '@testing-library/react-native'; import MyComponent from '../src/MyComponent'; test('renders correctly', () => { const { getByText } = render(<MyComponent />); expect(getByText('Hello, World!')).toBeTruthy(); }); |