目录
5.1.1 .env.development / .env.production
5.1.2 修改 vite.config.ts,增加 base
5.2.1 如何使用 Live Server,测试打包效果?
5.3.1.1 打包时,依赖解析失败,会导致添加 android 平台失败
5.3.2 构建、同步原生app资源,打开 Android Studio
5.3.2.3 执行 ionic cap sync 后 在 Android Studio 中报错
5.3.2.4 升级完 Android Studio 后,找不到相关依赖
5.4.1 打包报错 vue-tsc 解决方案,调整 package.json 打包配置,删除 vue-tsc
5.4.4 打包后,图片地址能单独打开,但是在页面里又不显示
5.4.7 添加 file-transfer 插件后,打包报错乱码
5.4.8 解决 android.support.v4.app.CoreComponent... 插件版本不匹配的问题
解决方案一(使用 jetifier 将项目中的 android.support.v4 代码转换成 androidx)
5.4.9 解决 Android SDK 版本 和 打包工具版本 不匹配导致的报错
为什么要尽量保持 compileSdkVersion 和 buildToolsVersion 版本一致?
Android SDK Build Tools 打包工具安装
查看 Andorid Studio 中的虚拟机 所用的 Android 版本信息
解决 cordova-camera 插件点击拍照后,app闪退、报错非法参数的问题
为什么在 org.apache.cordova 中,找不到 imagepicker 插件?
1.环境搭建
1.1 安装 node 16+ 版本
nvm install 16.20.2
1.2 安装 ionic7
npminstall -g @ionic/cli@latest
ps:某个平常的清晨,我的 ionic 自动从7掉到了6,导致我 7 的项目运行不起来了,而且还装不上7,最后重启就自动恢复成7了,so...遇事别慌,重启试试
1.3 创建 vue 项目
ionic start weihai-patrol-app tabs --type vue
2.index.html
之前的 ionic 项目,index.html 都是在 public 下面的
最新版的 ionic7,因为采用 vite,所以 index.html 在根目录下,而不是 public 下
新建 config.js 用于存放 ip,该文件需要在 index.html 中引入
- 开发过程中,读取的是 public 下的 config.js
- 打包后的成品,读取的是 根目录下的 config.js
目前两个 config.js 缺一不可,需要保持一致
3.main.ts
3.1 如何默认使用 ios 样式?
之所以要全局设置,是因为项目运行起来后,默认展示 Android 样式,刷新后才展示 IOS 样式
在 Ionic 7 + Vue 3 + Vite 项目中
- 打开 src/main.ts 文件
- 在 createApp 函数中,使用 IonicVue 插件,并传入 mode: 'ios' 选项
import { createApp } from 'vue';
import { IonicVue } from '@ionic/vue';
import App from './App.vue';
import router from './router';
const app = createApp(App)
.use(IonicVue, { mode: 'ios' }) // 设置默认全局使用 iOS 样式
.use(router);
router.isReady().then(() => {
app.mount('#app');
});
3.2 如何使用 ElmentPlus 国际化?
使用原因:日历组件默认展示英文
// 添加 elementplus 国际化
import ElementPlus from 'element-plus';
import zhCn from 'element-plus/dist/locale/zh-cn.mjs';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
const app = createApp(App)
.use(ElementPlus, {
locale: zhCn,
});
为啥我不用 ionic 的日历组件呢?
- 使用 ionic7 中的日历组件,两个及以上,只会渲染一个,暂时没来的及排查原因 ion-datetime-button: Ionic Input for Datetime Picker
- ionic7 之前的日历组件,跨年跨月选择很费劲,都是滚轮的
4.router/xxx
路由,虽然我很想拆分,但打包 h5 的时候:
- 在 vite 里遍历文件导入,不能使用 require
- 用 import await 打包又会报错禁止使用顶层 await
- 使用 vite 插件解决了顶层 await 路由页面又白屏,移除插件也白屏
- 移除插件并且使用 hash 路由,才正常显示(划重点,记笔记,打 h5 包一般使用 hash 路由解决白屏问题)
- 就很难搞……目前就是合并成一个文件了
这一节可以结合下面的打包遇到的问题一块看
如果有大佬可以帮忙解决这个问题,请联系我,感恩的心
import { createRouter, createWebHashHistory, createWebHistory } from '@ionic/vue-router';
// 可以使用 require 时,才能用下面的方法
// // 自动添加router目录下的所有ts路由模块
// const files = require.context('./', false, /\.ts$/);
// files.keys().forEach((route) => {
// // 如果是根目录的 index.js、 不做任何处理
// if (route.startsWith('./index')) {
// return;
// }
// const routerModule = files(route);
// // 兼容 import export 和 require module.export 两种规范 ES modules commonjs
// routes.push(...(routerModule.default || routerModule));
// });
/**
* 接所有路由文件导出的内容
* @description 不能使用 require 时,采用此方法
* @param routeFiles 路由文件对象数组
* @returns
*/
const importAll = async (routeFiles: any) => {
// console.log('路由文件对象数组 ---', routeFiles);
// 拼接好的最终路由配置
const routes = [];
// 遍历路由配置文件
for (const path in routeFiles) {
// console.log('path 路由文件名', path);
const routeModule = await routeFiles[path]();
console.log('routeModule 路由文件导出内容', routeModule);
const route = routeModule?.default || routeModule;
// 将导出的数组填充到最终数组中
route.forEach((elem: any) => routes.push(elem));
}
return routes;
};
// 使用动态导入来导入所有路由文件
const routeFilesArr = import.meta.glob('./*.ts');
// 拼接所有路由文件导出的内容
const routes = await importAll(routeFilesArr);
// 创建路由实例(Hash 路由)
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
routes,
});
export default router;
5.打包二三事
打包分为两种,一种是 h5 包,一种是移动端
5.1 添加打包相关文件
5.1.1 .env.development / .env.production
注意事项:
- 这两个文件名字是固定的
- 打 h5包 时需要新增,打 移动端包 时需要移除
patrol-app\.env.development
NODE_ENV=development
VITE_BASE_PATH='/'
patrol-app\.env.production
NODE_ENV=production
BASE_URL=/weihai-patrol/
5.1.2 修改 vite.config.ts,增加 base
注意事项:
- h5 改成 /weihai-patrol/
- 移动端改成 ./
/**
* 判断是否是生产环境
* @returns {boolean}
*/
function isProd() {
return process.env.NODE_ENV === 'production';
}
base: '/weihai-patrol/',
// 解决打包不知道干啥的
build: {
minify: 'terser',
terserOptions: {
compress: {
// drop_console: true,
drop_debugger: true,
},
},
},
5.2 打包 h5
添加完打包相关的文件后(注意在 vite.config.js 中使用的 base 相对路径),直接执行 yarn build 就行
5.2.1 如何使用 Live Server,测试打包效果?
将生成的 dist 目录,cv 到当前打开的 vscode 里,和当前项目同级
把 dist 改名成 weihai-patrol,右击 index.html,使用 live server 打开
5.3 打包移动端
添加完打包相关的文件后(注意在 vite.config.js 中使用的 base 相对路径),还要执行下面的操作
5.3.1 添加 android 平台
ionic capacitor add android
添加成功是这种感觉:
执行完毕后:
- package.json 中会自动添加依赖:"@capacitor/android": "5.4.1",
- 项目根目录中,会新增 android 文件夹
5.3.1.1 打包时,依赖解析失败,会导致添加 android 平台失败
解决方案:这个包是用来进行 vue 单元测试的,直接移除安装吧
npm uninstall @vue/cli-plugin-unit-jest
5.3.2 构建、同步原生app资源,打开 Android Studio
ionic cap sync
构建成功是这种感觉:
此时,会自动打开 android studio,自动执行 gradle 下载
5.3.2.1 gradle 是个啥
Gradle 是一个开源的构建自动化工具,它被广泛用于 Android 开发中,用于构建和管理 Android 应用程序的构建过程
在 Android 开发中,Gradle 被用作 Android 项目的构建工具。它可以编译源代码、处理资源文件、打包生成 APK 文件,并支持多种构建变体和构建类型。通过 Gradle,你可以轻松地管理和配置你的 Android 项目的构建过程,包括添加第三方库、处理多渠道打包、配置签名等
5.3.2.2 如何解决 gradle 下载不下来的问题?
修改下载源
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
5.3.2.3 执行 ionic cap sync 后 在 Android Studio 中报错
Cannot convert string value 'UNIFIED_TEST_PLATFORM' to an enum value of type 'com.android.builder.model.AndroidGradlePluginProjectFlags$BooleanFlag' (valid case insensitive values: APPLICATION_R_CLASS_CONSTANT_IDS, TEST_R_CLASS_CONSTANT_IDS, TRANSITIVE_R_CLASS, JETPACK_COMPOSE, ML_MODEL_BINDING)
升级 Android Studio 版本就行
5.3.2.4 升级完 Android Studio 后,找不到相关依赖
根据下面的报错信息:下载源找不到相关路径,因此,我把下载源切回了 google,然后打包正常了
也可能是因为多注释了:mavenCentral()
5.3.2.5 在线测试 chrome://inspect
5.4 打包遇到的其它问题
5.4.1 打包报错 vue-tsc 解决方案,调整 package.json 打包配置,删除 vue-tsc
5.4.2 打包后,页面一片空白,没有报错
这个问题我是玄学解决的,我不懂为啥……,把 history 路由改成 hash 就好了
一般打包成 h5 都需要替换成 hash 路由
// 创建路由实例
const router = createRouter({
// history: createWebHistory(import.meta.env.BASE_URL),
history: createWebHashHistory(import.meta.env.BASE_URL), // 使用哈希路由模式
routes,
});
5.4.3 打包报错 顶层 await 解决方案
出现原因:
- 为了将路由分类,我在路由 index 里写了一个方法:循环遍历 router 下的 ts 文件,把他们的 export default 给拼接到一个数组里
- 由于读取文件是异步操作,因此使用了 await,导致打包报错
const importAll = async (routeFiles: any) => {
// console.log('路由文件对象数组 ---', routeFiles);
// 拼接好的最终路由配置
const routes = [];
// 遍历路由配置文件
for (const path in routeFiles) {
// console.log('path 路由文件名', path);
const routeModule = await routeFiles[path]();
// console.log('routeModule 路由文件导出内容', routeModule);
const route = routeModule.default || routeModule;
// 将导出的数组填充到最终数组中
route.forEach((elem: any) => routes.push(elem));
}
return routes;
};
解决方案一(目前使用的)
不用路由分组,不用 await
解决方案二(看似优雅但是毫无卵用)
npm install vite-plugin-top-level-await -D --force
vite-plugin-top-level-await - npm
解决 vite build打包报错Top-level await is not available in the configured target environment - 简书
使用了这个插件之后,打包确实不报错了,但是打包后预览:
- 白屏了,路由入口中的打印没打印出来
- 控制台没有任何报错,文件也顺利请求到了
5.4.4 打包后,图片地址能单独打开,但是在页面里又不显示
检查是不是使用了 IonImg 标签,并且没有 import,没 import 就会把他当成 html 标签处理,自然无法解析
5.4.5 打包后,静态资源不全
项目中应该有两份 assets、config.js
第一份在 public 下面
第二份在 根目录下面放个 config.js、在 src/assets 下面放静态资源
二者保持一致,缺一不可,一个是打包的时候会读取,一个是运行项目的时候会读取
5.4.6 部署到 nginx 上后,页面网络请求失败
把下面的删了就行
5.4.7 添加 file-transfer 插件后,打包报错乱码
解决方案:https://www.cnblogs.com/dndt/p/17133266.html
// import org.apache.cordova.Whitelist;
import org.apache.cordova.AllowList;
// Whitelist whitelist = (Whitelist)gwl.invoke(webView);
// shouldAllowRequest = whitelist.isUrlWhiteListed(source);
AllowList whitelist = (AllowList)gwl.invoke(webView);
shouldAllowRequest = whitelist.isUrlAllowListed(source);
5.4.8 解决 android.support.v4.app.CoreComponent... 插件版本不匹配的问题
解决方案一(使用 jetifier 将项目中的 android.support.v4 代码转换成 androidx)
在项目中,按顺序执行下方命令:
npm install jetifier
npx jetifynpx cap sync android
此时代码已经同步到 Android Studio 中了,不需要再执行 ionic cap sync 了
但是这种方法可能转换失败,转换无效,就要考虑第二种方法了
解决方案二(使用 Android 自带的转换工具转换)
- 右击项目,选择 Refactor-Migrate to AndoridX
- 然后 Android Studio 会自动扫描项目中不符合需求的代码,经检查,是 cordova-plugin-ths-webviewpage 这个插件中存在问题
- 接着 Android Studio 会在终端中,询问是否转换该插件代码,选择是即可
- 转换成功后,即可顺利打包
5.4.9 解决 Android SDK 版本 和 打包工具版本 不匹配导致的报错
基本概念
Andorid SDK Buid Tools —— 是一组用于构建和打包 Android 应用程序的工具集合。它提供了一系列的命令行工具和构建脚本,用于编译、打包和签名Android应用程序。
compile sdk —— 在 Android Studio 中,compileSdkVersion 是指定你的应用程序编译时使用的Android SDK版本的设置。它决定了你的应用程序可以使用的 Android API 级别和功能。
为什么要尽量保持 compileSdkVersion 和 buildToolsVersion 版本一致?
- 兼容性:compileSdkVersion 和 buildToolsVersion 之间的版本一致性,可以确保 构建工具 和 编译时使用的SDK版本之间 的兼容性。这有助于 避免由于版本不匹配,而导致的编译错误或其他问题。
- 最新功能和修复:构建工具版本通常会包含对特定SDK版本的修复和改进。通过保持 buildToolsVersion 与compileSdkVersion 一致,你可以确保你的应用程序能够受益于最新的功能和修复。
- 一致性和稳定性:保持 compileSdkVersion 和 buildToolsVersion 一致可以提供一致的构建环境和稳定的构建过程。这有助于减少构建过程中的潜在问题,并确保应用程序的一致性。
总之,尽量保持 compileSdkVersion 和 buildToolsVersion 版本一致可以确保构建工具和编译时使用的SDK版本之间的兼容性,并提供一致性、稳定性和最新功能的好处。
Android SDK Build Tools 打包工具安装
点击这里,会列出所有可以安装的版本
比如下面,可以选择安装 Andorid SDK Buid Tools34 版本的,每个版本差不多几百兆
Android 平台版本安装
再比如下面,可以选择安装 Android 12 版本的,有了这个,就可以使用指定版本的 虚拟机了
查看 Andorid Studio 中的虚拟机 所用的 Android 版本信息
修改项目模块 Modules,保持版本一致性
右键点击项目 android,选择 Modules,如下图所示,会列出当前项目拆分的不同模块,可以这么理解:
- 中间这一栏列出了项目涉及的所有模块
- 他们的关系类似于 微前端的基座应用、微应用的关系,app 相当于基座应用,剩下的相当于微应用
- 可以针对每个模块,单独设置 ① Compile sdk 版本 ② build tools 版本 ③ jdk 版本
- 我们在上面说了,要尽量保持 Compile sdk 和 build tools 的版本一致性,能避免错误(此处由于我没有安装更高版本的 build Tools,所以我用的版本不一致,但是没报错,我也就没改)
解决 cordova-camera 插件点击拍照后,app闪退、报错非法参数的问题
问就是升级插件版本,立马解决这种抽象报错
打断点调试 cordova.camera 的经历
首先是在 node_modules 里,搜索了上面的非法参数报错,找到了他在 CameraLauncher.java 文件里
在 Andorid Studio 中找到这个文件:找 org.apache.cordova 这个包,下面很轻松就看到 camera 了
在代码里行号旁边,点一下,出现一个红点,表示断点
点击下图右上角,小虫子,表示开启调试,此时链接手机后,会自动安装app
点击执行断点的地方,比如拍照按钮,就会进入这个方法,这个过程会比较卡
点击下面终端的红框内第一个按钮,表示进入方法,逐行调试
为什么在 org.apache.cordova 中,找不到 imagepicker 插件?
这个 org.apache.cordova 是个包名,是作者可以自定义的东西,所以他不一定按照规范来
虽然在 node_modules 中,这个插件看起来好像是 cordova 的插件
但是,他的真实包名,可以看 node_modules 下的 plugin.xml 文件
随便找个文件,target-dir 标识了作者写的包名
在 android 包里,也顺利的找到了
修改 ImagePicker 图片选择插件 的中文名字
xml 文件,在 cordova 里通常用于放一些 常量配置,比如国际化语言啊之类的
找到 node_modules 里面的这个插件,寻找 xml 文件,修改遇到问题的文字
node_modules 和 android 是啥关系
当执行 ionic cap sync 的时候,会把 node_modules 编译到 android 文件夹下面,两者内容有相似的地方(比如 java 文件,可以进行调试),也有不同的地方
一般情况下:
- 修改 cordova 插件源码,直接改 node_modules 就行,比如 file-transfer 的 whitelist(每次重新安装依赖都需要修改,也可以使用脚本)
- 调试插件bug,直接在 Android Studio 里,展开 android 文件夹,打断点进行调试,详见下面