🚀 Expo 现代化医疗应用项目搭建指南

从零开始搭建基于 Expo + React Native 的现代化移动应用,完整的环境配置、依赖安装和项目初始化流程。

📋 目录

🛠️ 环境准备

1. 系统要求

Windows:

  • Windows 10 或更高版本

  • PowerShell 5.0 或更高版本

macOS:

  • macOS 10.15 或更高版本

  • Xcode 12 或更高版本(iOS 开发)

Linux:

  • Ubuntu 18.04 或更高版本

2. 必要软件安装


# 1. 安装 Node.js (推荐 18.x 或 20.x LTS 版本)

# 访问 https://nodejs.org 下载安装



# 2. 验证 Node.js 安装

node --version  # 应该显示 v18.x.x 或 v20.x.x

npm --version   # 应该显示 9.x.x 或更高



# 3. 安装 Yarn (推荐使用)

npm install -g yarn

yarn --version



# 4. 安装 Expo CLI

npm install -g @expo/cli

expo --version

3. 移动端开发环境


# Android 开发环境

# 1. 安装 Android Studio

# 2. 配置 Android SDK

# 3. 设置环境变量 ANDROID_HOME



# iOS 开发环境 (仅 macOS)

# 1. 安装 Xcode

# 2. 安装 Xcode Command Line Tools

xcode-select --install

🎯 项目初始化

1. 创建 Expo 项目


# 使用 Expo CLI 创建项目

npx create-expo-app@latest MedicalApp --template



# 选择模板:选择 "Blank (TypeScript)" 或 "Navigation (TypeScript)"

# 推荐选择 Navigation 模板,包含基础导航结构



# 进入项目目录

cd MedicalApp

2. 升级到 Expo Router


# 安装 Expo Router

npx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar



# 修改 package.json 中的 main 字段

# "main": "expo-router/entry"

3. 项目基础结构


# 创建基础目录结构

mkdir -p app/{login,\(tabs\),patient,reservation,search}

mkdir -p components/{ui,business,forms,layout,navigation}

mkdir -p stores

mkdir -p utils/{storage,permissions}

mkdir -p assets/{images,fonts,svg}

mkdir -p constants

mkdir -p hooks

mkdir -p types

mkdir -p docs

📦 核心依赖安装

1. 路由和导航


# Expo Router (已安装)

# 底部导航

yarn add @react-navigation/bottom-tabs @react-navigation/native @react-navigation/elements



# 导航相关工具

npx expo install react-native-gesture-handler react-native-reanimated

2. 状态管理


# Zustand - 轻量级状态管理

yarn add zustand



# React Query - 服务端状态管理

yarn add @tanstack/react-query



# 数据持久化

npx expo install @react-native-async-storage/async-storage

3. UI 组件库


# Ant Design React Native

yarn add @ant-design/react-native @ant-design/icons-react-native



# 图标库

yarn add react-native-vector-icons

npx expo install @expo/vector-icons



# 其他 UI 组件

yarn add @react-native-segmented-control/segmented-control

yarn add react-native-calendars

yarn add react-native-swiper

4. 样式和主题


# NativeWind - Tailwind CSS for React Native

yarn add nativewind

yarn add --dev tailwindcss@3.3.2



# 线性渐变

npx expo install expo-linear-gradient

yarn add react-native-linear-gradient

5. 表单处理


# React Hook Form

yarn add react-hook-form @hookform/resolvers



# 表单验证

yarn add yup



# 日期处理

yarn add date-fns dayjs

6. 网络和数据


# HTTP 客户端和工具

yarn add uuid react-native-get-random-values



# WebView

npx expo install react-native-webview



# 图片处理

npx expo install expo-image



# SVG 支持

npx expo install react-native-svg react-native-svg-transformer

7. 设备功能


# 设备信息和功能

npx expo install expo-device expo-application expo-haptics

npx expo install expo-secure-store expo-web-browser expo-blur

npx expo install expo-font expo-splash-screen expo-system-ui

8. 开发工具


# TypeScript 支持

yarn add --dev typescript @types/react @types/react-native-vector-icons



# 代码规范

yarn add --dev eslint eslint-config-expo prettier prettier-plugin-tailwindcss



# 环境变量管理

yarn add --dev cross-env



# API 类型生成

yarn add --dev openapi-ts-request

9. Storybook (可选)


# Storybook for React Native

yarn add --dev @storybook/react-native @storybook/addon-ondevice-actions @storybook/addon-ondevice-backgrounds @storybook/addon-ondevice-controls @storybook/addon-ondevice-notes @storybook/addon-actions



# 其他 Storybook 插件

yarn add --dev @react-native-community/datetimepicker @react-native-community/slider @gorhom/bottom-sheet

⚙️ 基础配置

1. 配置 TypeScript

创建 tsconfig.json:


{

  "extends": "expo/tsconfig.base",

  "compilerOptions": {

    "strict": true,

    "baseUrl": ".",

    "paths": {

      "@/*": ["./src/*"],

      "@/components/*": ["./components/*"],

      "@/utils/*": ["./utils/*"],

      "@/stores/*": ["./stores/*"],

      "@/types/*": ["./types/*"],

      "@/constants/*": ["./constants/*"],

      "@/assets/*": ["./assets/*"]

    }

  },

  "include": [

    "**/*.ts",

    "**/*.tsx",

    ".expo/types/**/*.ts",

    "expo-env.d.ts"

  ]

}

2. 配置 NativeWind

创建 tailwind.config.js:


/** @type {import('tailwindcss').Config} */

module.exports = {

  content: [

    "./app/**/*.{js,jsx,ts,tsx}",

    "./components/**/*.{js,jsx,ts,tsx}"

  ],

  theme: {

    extend: {

      colors: {

        primary: {

          50: '#f0fdf4',

          500: '#22c55e',

          600: '#16a34a',

          700: '#15803d',

        }

      }

    },

  },

  plugins: [],

}

创建 global.css:


@tailwind base;

@tailwind components;

@tailwind utilities;

创建 nativewind-env.d.ts:


/// <reference types="nativewind/types" />

3. 配置 Expo 应用

更新 app.config.ts:


import { ExpoConfig } from "expo/config";



export default ({ config }: { config: ExpoConfig }) => {

  const environment = process.env.NODE_ENV || 'development';



  return {

    ...config,

    name: "医疗管理应用",

    slug: "medical-app",

    version: "1.0.0",

    orientation: "portrait",

    icon: "./assets/images/icon.png",

    userInterfaceStyle: "automatic",

    splash: {

      image: "./assets/images/splash-icon.png",

      resizeMode: "contain",

      backgroundColor: "#ffffff"

    },

    assetBundlePatterns: [

      "**/*"

    ],

    ios: {

      supportsTablet: true,

      bundleIdentifier: "com.yourcompany.medicalapp"

    },

    android: {

      adaptiveIcon: {

        foregroundImage: "./assets/images/adaptive-icon.png",

        backgroundColor: "#ffffff"

      },

      package: "com.yourcompany.medicalapp"

    },

    web: {

      bundler: "metro",

      output: "static",

      favicon: "./assets/images/favicon.png"

    },

    plugins: [

      "expo-router"

    ],

    experiments: {

      typedRoutes: true,

    },

    extra: {

      // 环境变量

      EXPO_PUBLIC_API_BASE_URL_DEV: process.env.EXPO_PUBLIC_API_BASE_URL_DEV || 'http://localhost:3000',

      EXPO_PUBLIC_API_BASE_URL_PROD: process.env.EXPO_PUBLIC_API_BASE_URL_PROD || 'https://your-api-domain.com',

      EXPO_PUBLIC_ENV: environment,

     

      // EAS 配置

      eas: {

        projectId: "your-project-id-here"

      }

    },

  };

};

4. 配置 Metro

更新 metro.config.js:


const { getDefaultConfig } = require('expo/metro-config');

const { withNativeWind } = require('nativewind/metro');



const config = getDefaultConfig(__dirname);



// NativeWind 配置

config.transformer = {

  ...config.transformer,

  babelTransformerPath: require.resolve('react-native-svg-transformer'),

};



config.resolver = {

  ...config.resolver,

  assetExts: config.resolver.assetExts.filter((ext) => ext !== 'svg'),

  sourceExts: [...config.resolver.sourceExts, 'svg'],

};



module.exports = withNativeWind(config, { input: './global.css' });

5. 配置 Babel

更新 babel.config.js:


module.exports = function (api) {

  api.cache(true);

  return {

    presets: [

      ["babel-preset-expo", { jsxImportSource: "nativewind" }]

    ],

    plugins: [

      // Reanimated 插件 (必须放在最后)

      'react-native-reanimated/plugin',

    ],

  };

};

🏗️ 项目结构搭建

1. 创建基础 Layout

创建 app/_layout.tsx:


import { Stack } from 'expo-router';

import { StatusBar } from 'expo-status-bar';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import '../global.css';



const queryClient = new QueryClient({

  defaultOptions: {

    queries: {

      staleTime: 5 * 60 * 1000, // 5 分钟

      retry: 2,

    },

  },

});



export default function RootLayout() {

  return (

    <QueryClientProvider client={queryClient}>

      <Stack>

        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />

        <Stack.Screen name="login" options={{ headerShown: false }} />

      </Stack>

      <StatusBar style="auto" />

    </QueryClientProvider>

  );

}

2. 创建 Tab 导航

创建 app/(tabs)/_layout.tsx:


import { Tabs } from 'expo-router';

import { Ionicons } from '@expo/vector-icons';



export default function TabLayout() {

  return (

    <Tabs

      screenOptions={{

        tabBarActiveTintColor: '#22c55e',

        tabBarInactiveTintColor: '#6b7280',

        headerShown: false,

      }}>

      <Tabs.Screen

        name="index"

        options={{

          title: '首页',

          tabBarIcon: ({ color, focused }) => (

            <Ionicons name={focused ? 'home' : 'home-outline'} size={24} color={color} />

          ),

        }}

      />

      <Tabs.Screen

        name="ai"

        options={{

          title: 'AI助手',

          tabBarIcon: ({ color, focused }) => (

            <Ionicons name={focused ? 'chatbubble' : 'chatbubble-outline'} size={24} color={color} />

          ),

        }}

      />

      <Tabs.Screen

        name="message"

        options={{

          title: '消息',

          tabBarIcon: ({ color, focused }) => (

            <Ionicons name={focused ? 'mail' : 'mail-outline'} size={24} color={color} />

          ),

        }}

      />

      <Tabs.Screen

        name="profile"

        options={{

          title: '我的',

          tabBarIcon: ({ color, focused }) => (

            <Ionicons name={focused ? 'person' : 'person-outline'} size={24} color={color} />

          ),

        }}

      />

    </Tabs>

  );

}

3. 创建基础 Store

创建 stores/appStore.ts:


import { create } from 'zustand';

import { persist, createJSONStorage } from 'zustand/middleware';

import AsyncStorage from '@react-native-async-storage/async-storage';



interface AppState {

  theme: 'light' | 'dark' | 'auto';

  language: 'zh-CN' | 'en-US';

  isFirstLaunch: boolean;

  setTheme: (theme: 'light' | 'dark' | 'auto') => void;

  setLanguage: (language: 'zh-CN' | 'en-US') => void;

  setFirstLaunch: (isFirst: boolean) => void;

}



export const useAppStore = create<AppState>()(

  persist(

    (set) => ({

      theme: 'auto',

      language: 'zh-CN',

      isFirstLaunch: true,

      setTheme: (theme) => set({ theme }),

      setLanguage: (language) => set({ language }),

      setFirstLaunch: (isFirst) => set({ isFirstLaunch: isFirst }),

    }),

    {

      name: 'app-storage',

      storage: createJSONStorage(() => AsyncStorage),

    }

  )

);

4. 创建工具函数

创建 utils/request.ts:


interface RequestConfig {

  baseURL: string;

  timeout: number;

  headers: Record<string, string>;

}



class RequestClient {

  private config: RequestConfig;



  constructor(config: RequestConfig) {

    this.config = config;

  }



  async get<T>(url: string, options?: RequestInit): Promise<T> {

    return this.request<T>(url, { ...options, method: 'GET' });

  }



  async post<T>(url: string, data?: any, options?: RequestInit): Promise<T> {

    return this.request<T>(url, {

      ...options,

      method: 'POST',

      body: data ? JSON.stringify(data) : undefined,

    });

  }



  private async request<T>(url: string, options: RequestInit): Promise<T> {

    const fullUrl = `${this.config.baseURL}${url}`;

   

    const response = await fetch(fullUrl, {

      ...options,

      headers: {

        'Content-Type': 'application/json',

        ...this.config.headers,

        ...options.headers,

      },

    });



    if (!response.ok) {

      throw new Error(`HTTP error! status: ${response.status}`);

    }



    return response.json();

  }

}



export const request = new RequestClient({

  baseURL: process.env.EXPO_PUBLIC_API_BASE_URL_DEV || 'http://localhost:3000',

  timeout: 10000,

  headers: {},

});

📱 启动项目

1. 更新 package.json scripts


{

  "scripts": {

    "start": "expo start --dev-client",

    "start:prod": "cross-env NODE_ENV=production expo start --dev-client",

    "android": "expo run:android",

    "ios": "expo run:ios",

    "web": "expo start --web",

    "lint": "expo lint",

    "type-check": "tsc --noEmit",

    "storybook": "cross-env WITH_STORYBOOK=true expo start --dev-client"

  }

}

2. 开发环境启动


# 安装开发客户端

npx expo install expo-dev-client



# 构建开发版本 (首次运行)

npx expo run:android  # Android

npx expo run:ios      # iOS (仅 macOS)



# 后续开发启动

yarn start



# 或者直接在模拟器中运行

yarn android  # Android

yarn ios      # iOS

3. 验证安装

创建简单的测试页面 app/(tabs)/index.tsx:


import { View, Text, ScrollView } from 'react-native';

import { useAppStore } from '@/stores/appStore';



export default function HomeScreen() {

  const { theme, setTheme } = useAppStore();



  return (

    <ScrollView className="flex-1 bg-gray-50">

      <View className="p-4">

        <Text className="text-2xl font-bold text-gray-800 mb-4">

          欢迎使用医疗管理应用

        </Text>

       

        <View className="bg-white rounded-lg p-4 shadow-sm">

          <Text className="text-lg text-gray-600">

            当前主题: {theme}

          </Text>

         

          <Text className="text-base text-gray-500 mt-2">

            ✅ Expo Router 已配置

          </Text>

          <Text className="text-base text-gray-500">

            ✅ NativeWind 样式正常

          </Text>

          <Text className="text-base text-gray-500">

            ✅ Zustand 状态管理工作中

          </Text>

          <Text className="text-base text-gray-500">

            ✅ TypeScript 类型检查正常

          </Text>

        </View>

      </View>

    </ScrollView>

  );

}

🔧 常见问题解决

1. Metro 相关问题


# 清除 Metro 缓存

npx expo start --clear



# 重置 npm/yarn 缓存

npm start -- --reset-cache

# 或

yarn start --reset-cache

2. 依赖版本冲突


# 检查依赖版本兼容性

npx expo doctor



# 修复版本冲突

npx expo install --fix

3. 原生模块问题


# 重新构建原生代码

npx expo run:android --clear

npx expo run:ios --clear

4. TypeScript 错误


# 类型检查

yarn type-check



# 生成类型定义

npx expo customize tsconfig.json

📚 下一步

  1. 配置 Storybook - 组件文档化

  2. 集成推送服务 - JPush 或 Expo Notifications

  3. 添加原生模块 - 根据业务需求

  4. 配置 EAS Build - 生产环境构建

  5. 设置 CI/CD - 自动化部署流程

📝 总结

现在您已经拥有一个完整的 Expo 项目架构,包含:

  • 现代化技术栈 - Expo SDK 53 + React Native 0.79

  • 状态管理 - Zustand + React Query

  • UI 体系 - NativeWind + Ant Design

  • 开发工具 - TypeScript + ESLint + Prettier

  • 项目结构 - 清晰的目录组织

  • 配置完整 - 开发和生产环境配置

接下来可以根据具体业务需求添加功能模块和定制化配置!


💡 提示: 建议按步骤逐个配置,每完成一个步骤就测试一下,确保没有问题再继续下一步。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐