React Native

MAC Develop tools

ENV setup

Running on Device with Expo

# create app
npx create-expo-app@latest
# start app
npx expo start
# or
pnpm run android
# or
yarn android --mode release
# This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
pnpm run reset-project
# deploy to testflight
npx testflight

Build App

๐Ÿ“‹ Expo ๅทฅไฝœๆต็จ‹ๅ…จๆ™ฏๅ›พ

ๆญๅปบ่„šๆ‰‹ๆžถ โ†’ ้กน็›ฎ้…็ฝฎ โ†’ ๆœฌๅœฐๅผ€ๅ‘ โ†’ ้ข„ๆž„ๅปบ โ†’ ๆ‰“ๅŒ… APK โ†’ ๅ‘ๅธƒ

// package.json
{
  "dependencies": {
    // === Expo ๆ ธๅฟƒ ===
    "expo": "~53.0.0", // Expo SDK ๆ ธๅฟƒ
    "expo-status-bar": "~2.2.0", // ็Šถๆ€ๆ 

    // === React ็”Ÿๆ€ ===
    "react": "19.0.0", // React ๆ ธๅฟƒ
    "react-native": "0.79.5", // RN ๆ ธๅฟƒ

    // === ่ทฏ็”ฑ๏ผˆๅฆ‚ๆžœไฝฟ็”จ Expo Router๏ผ‰===
    "expo-router": "~5.1.0", // ๆ–‡ไปถ็ณป็ปŸ่ทฏ็”ฑ
    "expo-linking": "~7.1.0", // Deep Linking
    "expo-splash-screen": "~0.30.0", // ๅฏๅŠจๅฑๅน•

    // === ๅผ€ๅ‘ๅทฅๅ…ท ===
    "expo-dev-client": "~5.2.0" // ่‡ชๅฎšไน‰ๅผ€ๅ‘ๅฎขๆˆท็ซฏ
  },
  "devDependencies": {
    "@babel/core": "^7.28.0", // Babel ๆ ธๅฟƒ
    "@expo/cli": "^0.24.0", // Expo CLI ๅทฅๅ…ท
    "@types/react": "~19.0.0", // TS ็ฑปๅž‹ๅฎšไน‰
    "typescript": "^5.9.0" // TypeScript
  }
}
// eas.json
{
  "cli": {
    "version": ">= 5.0.0"
  },
  "build": {
    // === ๅผ€ๅ‘ๆž„ๅปบ ===
    "development": {
      "developmentClient": true, // ๅผ€ๅ‘ๅฎขๆˆท็ซฏ
      "distribution": "internal",
      "android": {
        "gradleCommand": ":app:assembleDebug",
        "buildType": "apk"
      }
    },

    // === ้ข„่งˆๆž„ๅปบ๏ผˆๆต‹่ฏ•็Žฏๅขƒ๏ผ‰===
    "preview": {
      "distribution": "internal",
      "android": {
        "buildType": "apk" // ็”Ÿๆˆ APK
      },
      "env": {
        "EXPO_PUBLIC_ENV": "staging"
      }
    },

    // === ็”Ÿไบงๆž„ๅปบ ===
    "production": {
      "android": {
        "buildType": "aab" // ็”Ÿๆˆ AAB๏ผˆGoogle Play๏ผ‰
      },
      "env": {
        "EXPO_PUBLIC_ENV": "production"
      }
    }
  },

  "submit": {
    "production": {
      "android": {
        "serviceAccountKeyPath": "./path/to/key.json"
      }
    }
  }
}
// app.json
{
  "ios": {
    "bundleIdentifier": "com.yourcompany.yourapp"
  }
}

Metro Bundler ๅšไป€ไนˆ๏ผŸ

ๆบไปฃ็  (.tsx/.ts)
    โ†“ Babel ่ฝฌ่ฏ‘
JavaScript Bundle
    โ†“ Metro ๆ‰“ๅŒ…
index.bundle
    โ†“ ้€š่ฟ‡ HTTP ๆœๅŠก
App ๅŠ ่ฝฝ่ฟ่กŒ

Prebuild stage

  1. ่ฏปๅ–้…็ฝฎ๏ผš่งฃๆž app.json ๅ’Œๆ’ไปถ้…็ฝฎ
  2. ็”ŸๆˆๅŽŸ็”Ÿไปฃ็ ๏ผš
  1. ้“พๆŽฅๅŽŸ็”Ÿๆจกๅ—๏ผšExpo Autolinking๏ผˆ็ฑปไผผ React Native CLI ็š„ autolinking๏ผ‰
  2. ๅบ”็”จๆ’ไปถไฟฎๆ”น๏ผšๆ‰ง่กŒ้…็ฝฎๆ’ไปถ๏ผˆConfig Plugins๏ผ‰
# Install expo-dev-client
npx expo install expo-dev-client
# Install Cli
npm install -g eas-cli && eas login

# bulild android develop
eas build --platform android --profile development
# build android product
eas build --platform android --profile production

# build ios develop
eas build --platform ios --profile development
# build production
eas build --platform ios --profile production
# submit to ios store
eas submit --platform ios

# submit to Google Play Store
https://docs.expo.dev/deploy/submit-to-app-stores/#google-play-store

# Android ็ญพๅๅฏ†้’ฅ๏ผˆEAS ไผš่‡ชๅŠจ็ฎก็†๏ผ‰
eas credentials

# ๆˆ–ๆ‰‹ๅŠจ็”Ÿๆˆ
keytool -genkeypair -v \
  -storetype PKCS12 \
  -keystore my-release-key.keystore \
  -alias my-key-alias \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000


# ๆŸฅ็œ‹ๆž„ๅปบๅˆ—่กจ
eas build:list

# ไธ‹่ฝฝๆœ€ๆ–ฐๆž„ๅปบ
eas build:download --platform android --latest

EAS Build ๅทฅไฝœๆต๏ผš

  1. ไธŠไผ ไปฃ็ ๅˆฐ EAS ๆœๅŠกๅ™จ
  2. ๅœจไบ‘็ซฏ่ฟ่กŒ prebuild
  3. ๅฎ‰่ฃ…ไพ่ต– (npm install)
  4. ๆ‰ง่กŒ Gradle ๆž„ๅปบ
  5. ็ญพๅ APK/AAB
  6. ไธŠไผ ๆž„ๅปบไบง็‰ฉๅˆฐ CDN
  7. ่ฟ”ๅ›žไธ‹่ฝฝ้“พๆŽฅ

Without Expo

# macOS ้œ€่ฆๅฎ‰่ฃ…
# 1. Android Studio
# 2. JDK 17
# 3. Android SDK (API 34+)
# 4. ้…็ฝฎ็Žฏๅขƒๅ˜้‡

# Install jdk21 https://www.oracle.com/java/technologies/downloads/#java21
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
export PATH="$JAVA_HOME/bin:$PATH"


export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin

# ้ชŒ่ฏ็Žฏๅขƒ
adb --version
sdkmanager --list

# create app
npx @react-native-community/cli@latest init AwesomeProject

# ้ข„ๆž„ๅปบ
npx expo prebuild --platform android --clean

# ๆฃ€ๆŸฅ็”Ÿๆˆ็š„ๆ–‡ไปถ
ls -la android/

# build local pkg for development
npx expo run:android

# ๆœฌๅœฐๆž„ๅปบ APK
# ๆ–นๆณ• 1๏ผšไฝฟ็”จ Expo CLI๏ผˆๆŽจ่๏ผ‰
npx expo run:android --variant release

# ๆ–นๆณ• 2๏ผš็›ดๆŽฅไฝฟ็”จ Gradle
cd android
./gradlew assembleRelease        # ็”Ÿๆˆ APK
./gradlew bundleRelease          # ็”Ÿๆˆ AAB

# APK ไฝ็ฝฎ
# android/app/build/outputs/apk/release/app-release.apk

# start metro in one terminal
yarn start
# start app in the other terminal
yarn android --port 8080 --verbose
# check status
npx react-native doctor
# find the id for the process that is listening on port
sudo lsof -i :8081
# kill process
kill -9 <PID>

็ญพๅ APK

# 1. ๅˆ›ๅปบ็ญพๅ้…็ฝฎๆ–‡ไปถ
# android/app/build.gradle
android {
  signingConfigs {
    release {
      storeFile file("my-release-key.keystore")
      storePassword System.getenv("KEYSTORE_PASSWORD")
      keyAlias System.getenv("KEY_ALIAS")
      keyPassword System.getenv("KEY_PASSWORD")
    }
  }

  buildTypes {
    release {
      signingConfig signingConfigs.release
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
}

# 2. ่ฎพ็ฝฎ็Žฏๅขƒๅ˜้‡
export KEYSTORE_PASSWORD="your_password"
export KEY_ALIAS="your_alias"
export KEY_PASSWORD="your_key_password"

# 3. ๆž„ๅปบ็ญพๅ APK
cd android
./gradlew assembleRelease

Build Optimization

# ๅ‡ๅฐ APK ไฝ“็งฏ
// android/app/build.gradle
android {
  // ๅฏ็”จ ProGuard/R8 ไปฃ็ ๆททๆท†
  buildTypes {
    release {
      minifyEnabled true
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
    }
  }

  // ๆ‹†ๅˆ† APK๏ผˆๆŒ‰ๆžถๆž„๏ผ‰
  splits {
    abi {
      enable true
      reset()
      include "armeabi-v7a", "arm64-v8a"
      universalApk false
    }
  }
}
// app.json
// ๅฏ็”จ Hermes ๅผ•ๆ“Ž
{
  "expo": {
    "jsEngine": "hermes", // ้ป˜่ฎคๅทฒๅฏ็”จ
    "android": {
      "enableProguardInReleaseBuilds": true,
      "enableShrinkResourcesInReleaseBuilds": true
    }
  }
}

ๅฎŒๆ•ดๆž„ๅปบๆต็จ‹

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     Expo ้กน็›ฎๆบไปฃ็                           โ”‚
โ”‚  (TypeScript/JSX + app.json + eas.json)                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                         โ”‚
                         โ–ผ
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚   npx expo prebuild            โ”‚
        โ”‚   (็”ŸๆˆๅŽŸ็”Ÿไปฃ็ )                โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                     โ”‚
         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ–ผ                       โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  android/      โ”‚      โ”‚  ios/          โ”‚
โ”‚  (Java/Kotlin) โ”‚      โ”‚  (Obj-C/Swift) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                       โ”‚
         โ–ผ                       โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Gradle Build  โ”‚      โ”‚  Xcode Build   โ”‚
โ”‚  ./gradlew     โ”‚      โ”‚  xcodebuild    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                       โ”‚
         โ–ผ                       โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  APK / AAB     โ”‚      โ”‚  IPA           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Troubleshooting

# ้—ฎ้ข˜ 1๏ผšMetro Bundler ็ผ“ๅญ˜้”™่ฏฏ
rm -rf node_modules/.cache .expo
npx expo start -c

# Android Gradle ๆž„ๅปบๅคฑ่ดฅ
## ๆธ…็† Gradle ็ผ“ๅญ˜
cd android
./gradlew clean
cd ..

## ้‡ๆ–ฐ็”ŸๆˆๅŽŸ็”Ÿไปฃ็ 
npx expo prebuild --clean

# ไพ่ต–ๅ†ฒ็ช
rm -rf node_modules pnpm-lock.yaml
pnpm install

## ๆˆ–ไฝฟ็”จ Expo ไฟฎๅคๅทฅๅ…ท
npx expo install --fix

# ๆŸฅ็œ‹ Android ๆ—ฅๅฟ—
adb logcat | grep ReactNative
# RN ๆ—ฅๅฟ—
npx react-native log-android

Expo

# Check Expo Version Compatibility
npx expo install --fix
npx expo prebuild --clean
npx expo run:android

clean and reinstall dependencies

rm -rf node_modules 
rm -rf .expo
pnpm install
npx expo install <pkg-name> 

builds

npx expo build:android
eas build --platform android --profile production --local

ADB

# list devices
adb devices -l
List of devices attached
emulator-5554          device product:sdk_gphone64_x86_64 model:sdk_gphone64_x86_64 device:emu64xa transport_id:2
5EGBB22511208006       device product:KATHY-AN00 model:Hera_BD00 device:TS-KATHY-Q transport_id:1

Page Source