386 lines
11 KiB
Markdown
386 lines
11 KiB
Markdown
# Expo(React Native 工具链)
|
||
|
||
[Expo](https://docs.expo.dev/) 是一个基于 React Native 的框架,旨在简化移动应用开发。它提供了一套工具和服务,让开发者可以更快速地构建、测试和发布 React Native 应用。
|
||
|
||
## 初始化项目
|
||
```bash
|
||
pnpm create expo-app@latest --template blank-typescript
|
||
```
|
||
|
||
[官网模板](https://docs.expo.dev/more/create-expo/) 如下:
|
||
|
||
| 模板名称 | 描述 |
|
||
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||
| [`default`](https://github.com/expo/expo/tree/main/templates/expo-template-default) | 默认模板,用于构建多页面应用。包含推荐工具,如 **Expo CLI**、**Expo Router** 路由库,并启用 **TypeScript** 配置。适合大多数应用。 |
|
||
| [`blank`](https://github.com/expo/expo/tree/main/templates/expo-template-blank) | 最简模板,仅安装最基本依赖,不包含导航配置。 |
|
||
| [`blank-typescript`](https://github.com/expo/expo/tree/main/templates/expo-template-blank-typescript) | 空白模板,但启用了 **TypeScript** 支持。 |
|
||
| [`tabs`](https://github.com/expo/expo/tree/main/templates/expo-template-tabs) | 启用基于文件的路由系统(Expo Router),并默认使用 **TypeScript**,适合多标签页结构的应用。 |
|
||
| [`bare-minimum`](https://github.com/expo/expo/tree/main/templates/expo-template-bare-minimum) | 带有原生目录(`android` 与 `ios`)的空白模板,创建时会自动运行 [`npx expo prebuild`](https://docs.expo.dev/workflow/prebuild)。适合需要直接修改原生代码的项目。 |
|
||
|
||
**启动项目:**
|
||
|
||
```bash
|
||
npx expo start
|
||
```
|
||
|
||
## 打包发布
|
||
### 本地打包
|
||
#### 1. 安装 [Android Studio]( https://developer.android.com/?hl=zh-cn)
|
||
|
||
1. 下载安装
|
||
|
||
- 按照官网提示依次安装 SDK 工具和必要组件。
|
||
|
||
- 安装完成后,记住 SDK 的安装路径(例如:`D:\data\sdk`,默认位置是:`C:\Users\<你的用户名>\AppData\Local\Android\Sdk`),后续需要用到。
|
||
|
||
2. 配置环境变量
|
||
|
||
- 打开 **系统属性 → 高级 → 环境变量**。
|
||
|
||
- 在 **系统变量** 中新增:
|
||
|
||
```
|
||
变量名:ANDROID_HOME
|
||
变量值:D:\data\sdk
|
||
```
|
||
|
||
- 在 **Path** 中新增:
|
||
|
||
```bash
|
||
%ANDROID_HOME%\platform-tools
|
||
%ANDROID_HOME%\tools
|
||
%ANDROID_HOME%\tools\bin
|
||
```
|
||
|
||
- 保存设置。
|
||
|
||
3. 验证安装
|
||
|
||
- 打开命令行,执行:
|
||
|
||
```
|
||
echo %ANDROID_HOME%
|
||
```
|
||
|
||
- 如果输出 SDK 路径,则说明配置成功。
|
||
|
||
|
||
|
||
#### 2. 安装 [jdk17](https://adoptium.net/zh-CN/temurin/releases?version=8&os=any&arch=any)
|
||
|
||
1. 下载安装
|
||
|
||
- 下载对应版本解压即可。
|
||
- 安装成功后,记住 jdk 的安装路径,后续需要用到。
|
||
|
||
2. 配置环境变量
|
||
|
||
- 打开 **系统属性 → 高级 → 环境变量**。
|
||
|
||
- 在 **系统变量** 中新增:
|
||
|
||
```bash
|
||
变量名:JAVA_HOME
|
||
变量值:D:\devtool\jdk\jdk-17.0.16+8
|
||
```
|
||
|
||
- 在 **Path** 中新增:
|
||
|
||
```bash
|
||
%JAVA_HOME%\bin
|
||
```
|
||
|
||
- 保存设置。
|
||
|
||
3. 验证安装
|
||
|
||
- 打开命令行,执行:
|
||
|
||
```bash
|
||
java --version
|
||
```
|
||
|
||
- 如果输出 jdk 的信息,则说明配置成功。
|
||
|
||
|
||
|
||
#### 3. Expo 项目启用 [Prebuild](https://docs.expo.dev/workflow/prebuild/)
|
||
|
||
1. 生成原生项目
|
||
|
||
```bash
|
||
npx expo prebuild
|
||
```
|
||
|
||
然后执行完毕后,会生成 `android` 目录。
|
||
|
||
2. 清除并重新生成原生项目
|
||
|
||
```bash
|
||
npx expo prebuild --clean
|
||
```
|
||
|
||
会删除已有的 `android` 和 `ios` 目录,然后重新生成。
|
||
|
||
#### 4. 配置 Keystore
|
||
##### 4.1 生成密钥
|
||
|
||
```bash
|
||
keytool -genkey -v -keystore android-release.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
|
||
```
|
||
说明:
|
||
|
||
- `my-release-key.keystore`:生成的密钥文件名,可自定义路径
|
||
- `my-key-alias`:密钥别名
|
||
- `RSA`:加密算法
|
||
- `2048`:密钥长度
|
||
- `10000`:有效期(天)
|
||
|
||
##### 4.2 手动配置
|
||
|
||
修改 `android/app/build.gradle` 文件
|
||
|
||
1. 修改 `signingConfigs`
|
||
|
||
```bash
|
||
signingConfigs {
|
||
release {
|
||
storeFile file('android-release.keystore') // keystore 文件路径
|
||
storePassword '你的Keystore密码' // keystore 密码
|
||
keyAlias '你的KeyAlias' // 密钥别名
|
||
keyPassword '你的Key密码' // key 密码
|
||
}
|
||
|
||
debug {
|
||
storeFile file('debug.keystore')
|
||
storePassword 'android'
|
||
keyAlias 'androiddebugkey'
|
||
keyPassword 'android'
|
||
}
|
||
}
|
||
```
|
||
|
||
2. 在 `buildTypes` 中设置 release 使用 release 签名
|
||
|
||
```bash
|
||
buildTypes {
|
||
release {
|
||
signingConfig signingConfigs.release
|
||
}
|
||
|
||
debug {
|
||
signingConfig signingConfigs.debug
|
||
}
|
||
}
|
||
```
|
||
|
||
##### 4.3 脚本配置(推荐)
|
||
|
||
1. 在 expo 项目根目录下新增 `plugins\withAndroidSignature.js` 文件,内容如下:
|
||
|
||
```js
|
||
// plugins/withAndroidSignature.js
|
||
|
||
const { withAppBuildGradle } = require("@expo/config-plugins");
|
||
const fs = require("fs");
|
||
const path = require("path");
|
||
|
||
module.exports = function withAndroidSignature(config) {
|
||
return withAppBuildGradle(config, config => {
|
||
if (config.modResults.language === "groovy") {
|
||
config.modResults.contents = setAndroidSignature(config.modResults.contents);
|
||
} else {
|
||
throw new Error("如果不是 groovy,则无法在 app/build.gradle 中设置 signingConfigs");
|
||
}
|
||
return config;
|
||
});
|
||
};
|
||
|
||
function setAndroidSignature(appBuildGradle) {
|
||
if (!fs.existsSync(path.resolve(__dirname, "../credentials.json"))) {
|
||
console.warn("警告:没有设置正式版本的 Android Keystore 文件,因为 credentials.json 不存在。");
|
||
return appBuildGradle;
|
||
}
|
||
const info = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../credentials/credentials.json"), { encoding: "utf8" }));
|
||
|
||
// 使用正则表达式插入签名信息
|
||
let output = appBuildGradle.replace(
|
||
/(signingConfigs\s*\{)/,
|
||
`$1
|
||
release {
|
||
storeFile file(${JSON.stringify(path.resolve(__dirname, "../credentials/android-release.keystore"))})
|
||
storePassword ${JSON.stringify(info.android.keystore.keystorePassword)}
|
||
keyAlias ${JSON.stringify(info.android.keystore.keyAlias)}
|
||
keyPassword ${JSON.stringify(info.android.keystore.keyPassword)}
|
||
}`,
|
||
);
|
||
|
||
// 使用正则表达式替换 signingConfig
|
||
output = output.replace(
|
||
/(release\s*\{)[^}]*?signingConfig\s+signingConfigs\.debug/s,
|
||
`$1
|
||
signingConfig signingConfigs.release
|
||
`,
|
||
);
|
||
|
||
return output;
|
||
}
|
||
```
|
||
|
||
2. 在 expo 项目根目录下新增 `/credentials/credentials.json` 文件(该文件主要是 Keystore 的信息):
|
||
|
||
```json
|
||
{
|
||
"android": {
|
||
"keystore": {
|
||
"keystorePath": "credentials/android-release.keystore", // Android keystore 文件路径
|
||
"keystorePassword": "123456", // keystore 密码
|
||
"keyAlias": "my-key-alias", // Key 别名
|
||
"keyPassword": "123456" // Key 密码
|
||
}
|
||
},
|
||
"ios": {
|
||
"provisioningProfilePath": "ios/certs/profile.mobileprovision", // iOS 描述文件路径
|
||
"distributionCertificate": {
|
||
"path": "ios/certs/dist-cert.p12", // iOS 分发证书路径
|
||
"password": "password" // 证书密码
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
3. 在 `app.json` 中指定这个项目级插件:
|
||
|
||
```json
|
||
{
|
||
"expo": {
|
||
"plugins": [
|
||
"./plugins/withAndroidSignature"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5. 打包
|
||
|
||
- 编译成 Google Play 商店用的 .aab 文件
|
||
|
||
```bash
|
||
./gradlew bundleRelease
|
||
```
|
||
|
||
- 直接安装的 .apk 文件
|
||
|
||
```bash
|
||
./gradlew assembleRelease
|
||
```
|
||
|
||
**注意**:这个时候可能会下载 `gradle` 、`apk` 等资源,网络速度可能过慢。
|
||
|
||
**解决方法**:在 `android/gradle.properties` 添加网络代理:
|
||
|
||
```bash
|
||
systemProp.http.proxyHost=127.0.0.1
|
||
systemProp.http.proxyPort=7890
|
||
systemProp.https.proxyHost=127.0.0.1
|
||
systemProp.https.proxyPort=7890
|
||
```
|
||
|
||
打包结果在 `android/app/build/outputs/apt/release` 包下。
|
||
|
||
### 云打包
|
||
1. 安装 EAS CLI
|
||
|
||
```bash
|
||
npm install -g eas-cli
|
||
```
|
||
|
||
2. 注册并登录 Expo 账户
|
||
|
||
- 访问 https://expo.dev/ 注册账户,然后命令行登录:
|
||
|
||
```bash
|
||
expo login
|
||
```
|
||
|
||
3. 配置项目构建
|
||
|
||
- 输入以下命令,选择 Android 平台即可。
|
||
|
||
```bash
|
||
eas build:configure
|
||
```
|
||
|
||
4. 构建 Android 包
|
||
|
||
- 默认构建 AAB 包(上传 Google Play):
|
||
|
||
```bash
|
||
eas build --platform android
|
||
```
|
||
|
||
- 构建 APK(可直接安装):
|
||
|
||
```bash
|
||
eas build -p android --profile preview
|
||
```
|
||
### 安装包体积优化
|
||
|
||
#### 方法1(简单)
|
||
找到 `android/gradle.properties` 文件,找到 `reactNativeArchitectures` ,根据需要删除即可
|
||
|
||
```properties
|
||
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||
```
|
||
|
||
保留 `arm64-v8a` 常用的即可
|
||
|
||
#### 方法2(原生方法 选择更多)
|
||
在 `android/app/build.gradle` 文件中添加或修改以下配置:
|
||
|
||
```
|
||
android {
|
||
// 其他配置...
|
||
|
||
splits {
|
||
abi {
|
||
enable true // 启用按 CPU 架构拆分
|
||
reset() // 重置默认架构列表
|
||
include 'arm64-v8a', 'armeabi-v7a'
|
||
universalApk false // 是否生成包含所有架构的通用 APK(false 表示只生成分架构的独立包)
|
||
// 还有一个 exclude 配置是排除指定架构的
|
||
}
|
||
}
|
||
|
||
// 其他配置...
|
||
}
|
||
```
|
||
|
||
**说明:**
|
||
|
||
- `enable true`:启用架构拆分功能。
|
||
- `reset()`:清空默认的架构配置,避免重复。
|
||
- `include`:指定要生成的架构包,比如只打 `arm64-v8a` 和 `armeabi-v7a`。
|
||
- `universalApk false`:不生成通用包(即包含所有架构的 APK)。
|
||
|
||
**举例:**
|
||
|
||
执行打包命令后,将生成多个包,例如:
|
||
|
||
```
|
||
app-arm64-v8a-release.apk
|
||
app-armeabi-v7a-release.apk
|
||
```
|
||
|
||
每个 APK 只包含对应架构的二进制文件,体积更小。
|
||
|
||
如果把 `universalApk` 设置为 `true`,则只会生成一个:
|
||
|
||
```
|
||
app-universal-release.apk
|
||
```
|
||
|
||
这个包能在 `arm64-v8a` 和 `armeabi-v7a` 架构的设备上运行,但体积最大。
|
||
|
||
## 工具库
|