likes
comments
collection
share

我就要在非HBuilderX环境下编译uniapp运行Android端

作者站长头像
站长
· 阅读数 12

uniapp开发过小程序H5App的小伙伴们肯定都用过HBuilderX吧;它的强大我就不提了。当前如果你遇到过哪些坑,欢迎在留言区讨论吐槽一下,也希望它能更加好用~ 毕竟它还是帮你解决了很多问题的,是吧?

本文主要跟大家分享一下,如何在非【HBuilderX】编辑器下编译 uniapp 并运行 Android apk。如果你有这样的想法,或者有更好的方法,望不吝赐教~

最近我用的GitHub Copilot嗝屁了... 这里给大家推荐一下:CodeGeex。 先简单开个小G。

我就要在非HBuilderX环境下编译uniapp运行Android端

前言

首先阅读本文前,希望你已经大概清楚或了解过以下工具、语言基础

  • vscode (编辑器)
  • java、uniapp离线打包 (原生 Android 开发)
  • gradle (构建apk工具 / 包管理工具)
  • adb (Android 调试工具)
  • nodejs(语言/打包、构建工具)
  • uni cli(uniapp 脚手架)
  • 系统环境变量、命令行/shell

如果你不清楚,没关系,只要你的网络正常,那么请自行上网科普~

1.uni cli 项目初体验

cli文档链接:uniapp.dcloud.net.cn/quickstart-…

小手动起来~

# 可能无法正常创建 跟网络环境有关!!
npx degit dcloudio/uni-preset-vue#vite unicli-vue3-demo

注意:有时 npm 版本过老(node 版本),也可能无法正常创建的。我这里使用的 npm 9.5.1正常。 没有什么是一成不变的... 不行就换换方式😂

你将得如下结构的一个项目

我就要在非HBuilderX环境下编译uniapp运行Android端

使用VSCODE打开此项目,然后打开package.json,你会发现:

我就要在非HBuilderX环境下编译uniapp运行Android端

顾名思义,相信你看到这些应该知道怎么运行H5看看效果了吧。

当前第一步肯定是【npm install】安装依赖啊~~ 不然... 啥也不是

# 调试运行 H5
npm run dev:h5
# 调试运行 app
npm run dev:app

2.它说打开“HBuilderX”

当你使用npm run dev:app运行后,你将清晰的看到:

我就要在非HBuilderX环境下编译uniapp运行Android端

咳咳~ 虽然你很好,但是我就是想用用其他编辑器运行到 Android 端。

熟悉/了解 uniapp Android 离线打包的小伙伴们,应该知道,每次手动 “生成本地打包App资源” 的而后复制、打包的一系列过程。

我就要在非HBuilderX环境下编译uniapp运行Android端

🤔思考:如何能自动去处理这一系列操作?关键点是什么呢?

我想不用我多说,很多小伙伴已经知道了大致方向:

  1. 监听文件变化,去执行复制打包所需的资源
  2. 执行 gradle 命令打包,并使用adb安装到设备

🎉监听文件变化这也是我初次的想法,但是后来我抛弃了它,因为想到了个更简单的方法:

nodejs 执行子进程 监听原有命令输出日志

监听文件变化虽然【复杂一点】,但是它可以【做到更细化】的文件复制替换。 当然两者结合更棒啦~

3.初探【紫荆城】

nodejs线程/子进程 相关的知识,这里就不多说了,反正大家网络是畅通的。

在项目根目录新增scripts文件夹,,并创建watch.js文件:

我就要在非HBuilderX环境下编译uniapp运行Android端

如图所示,仅需导入内置的几个包。来处理路径、文件、进程。

小试牛刀🚀, 在 watch.js 文件中 编辑以下代码,执行子进程

// xxx 省略导包 

console.log("开始执行");
const app = spawn("npm run dev:app", { shell: process.platform === 'win32' });
app.stdout.on("data", (data) => {
  const log = Buffer.from(data).toString("utf8");
  console.log(log);
  // 编译成功
  if (log.includes("DONE  Build complete.")) {
    console.log("🎉🎉编译成功🎉🎉");
  }
});
app.stderr.on("data", (data) => {
  console.log("stderr-->");
  const log = Buffer.from(data).toString("utf8").replace(/\n/g, "");
  console.log(log);
});
app.on("error", (err) => {
  console.log("子进程 error:");
  console.log(err);
});
app.on("exit", (code) => {
  console.log(`子进程 exit: ${code}`);
});

保存,在终端中输入: node scripts/watch.js

我就要在非HBuilderX环境下编译uniapp运行Android端

啊哈~ 成功监听到了,并输出了:🎉🎉编译成功🎉🎉

去修改点项目源代码,像main.jsApp.vue这些文件保存😁试试水,🌈nice! 成功触发:

我就要在非HBuilderX环境下编译uniapp运行Android端

🤔思考:如果此时Ctrl + C关闭了当前终端运行的node scripts/watch.js,这个npm run dev:app子进程它退出了么?为什么?

4.复制App打包资源

当控制台输出 🎉🎉编译成功🎉🎉 的时候, dist/dev/app 已经成功出世啦~ 它就是 uniapp 离线打包需要的 关键资源。

此时应该怎么通知可以进行复制操作呢?还是直接接着写代码?

恰好nodejs内置提供了events包,方便线程之间通信。 真是太棒了~~

watch.js 中添加 以下代码:

// xxx 省略
// 进程间通信
const EventEmitter = require('events');
const event = new EventEmitter();
// 避免 魔法 字符串
const EVENTS = {
    COPY: 'COPY', // 构建成功后,复制资源
};

// 资源路径
// 当前项目 dev:app 构建出来的 资源目录
const RUN_DIR = path.resolve(__dirname, '../dist/dev/app'); 
// uniapp Android 离线打包 资源目录
const ANDROID_ASSETS_DIR = 'F:\\uniapp_offline_android\\app\\src\\main\\assets\\apps\\__UNI__XXXXXX\\www'; 

// 复制文件夹方法
const copyFolderSync = (source, target) => {
  // 创建目标文件夹
  if (!fs.existsSync(target)) {
    fs.mkdirSync(target);
  }
  // 遍历源文件夹中的每个文件或子文件夹
  fs.readdirSync(source).forEach((file) => {
    // 构造源文件/文件夹的完整路径
    const sourcePath = path.join(source, file);
    // 构造目标文件/文件夹的完整路径
    const targetPath = path.join(target, file);
    // 获取文件/文件夹的详细信息
    const stat = fs.statSync(sourcePath);
    if (stat.isFile()) {
        // 如果是文件,则直接复制文件
        fs.copyFileSync(sourcePath, targetPath);
    } else if (stat.isDirectory()) {
        // 如果是文件夹,则递归复制文件夹
        copyFolderSync(sourcePath, targetPath);
    }
  });
});

// 复制资源
const autoCopy = () => {
    console.log('-----> autoCopy');
    // 文件夹是否存在,否则创建
    copyFolderSync(RUN_DIR, ANDROID_ASSETS_DIR);
    console.log('复制成功');
    event.emit(EVENTS.RUN);
};
// 监听事件
event.on(EVENTS.COPY, autoCopy);

// xxx 省略
// 编译成功
if (log.includes("DONE  Build complete.")) {
  console.log("🎉🎉编译成功🎉🎉");
  // 传递消息 !!!!!
  event.emit(EVENTS.COPY);
}
// xxx 省略

OK~ 通了,通啦! 可以自动复制打包用的App资源啦~

5.执行 gradle 命令

如果你不熟悉,原生 Android 的打包/运行;那么请自行网络科普一下: gradle 命令

为了方便nodejs执行对应的命令请先配置一些环境变量

  • java
  • adb

环境变量在各个系统中,配置方式不一,作用都是一样的,就像任意门一样,让你能在任何地方,能够执行命令工具:

我就要在非HBuilderX环境下编译uniapp运行Android端

本次的主角:installDebug

我就要在非HBuilderX环境下编译uniapp运行Android端

顾名思义,就是安装debug包

AndroidStudio里,我们通常双击运行这个,那么它怎么在命令行里面执行呢?

不知道?科普一下咯~

命令行试试水:

我就要在非HBuilderX环境下编译uniapp运行Android端

sh gradlew installDebug

以上是以 sh(shell) 执行的 gradlew installDebug

nodejs中,当然同样可以执行

const { spawn } = require("child_process");
// cd 移动到 Android 工程跟目录; 然后 执行 gradle 命令
const installProcess = spawn('cd /xxxx/HBuilder-Integrate-AS && gradlew installDevDebug', { shell: process.platform === 'win32' });

🤔思考 执行 spawn 时,为什么要添加参数 { shell: process.platform === 'win32' }, 它的作用是什么呢?

ok,完善一下代码:


// xxx 省略
const EVENTS = {
    COPY: 'COPY', // 构建成功后,复制资源
    RUN: 'RUN' // 复制成功后,安装
};
const autoCopy = () => {
  // xxx 省略
  console.log('复制成功');
  // 添加
  event.emit(EVENTS.RUN);
};
// 安装 APK
const autoRun = () => {
  console.log('-----> autoRun');
  const installProcess = spawn('cd F:\\uniapp_offline_android && gradlew installDebug', { shell: process.platform === 'win32' });
  installProcess.stdout.on('data', (data) => {
      console.log('stdout-->');
      const log = Buffer.from(data).toString('utf8');
      console.log(log);
      if (log.includes('BUILD SUCCESSFUL')) {
          // 这里可以 使用 adb 判断 是否已经安装了,执行打开应用等等...
          console.log('安装成功!');
      }
  });
  installProcess.stderr.on('data', (data) => {
      const log = Buffer.from(data).toString('utf8');
      console.log(log);
  });
  installProcess.on('error', (err) => {
      console.log('子进程 error:');
      console.log(err);
  });
};
// 监听事件
event.on(EVENTS.COPY, autoCopy);
event.on(EVENTS.RUN, autoRun);
// xxx 省略

🤔思考:除了installDebug命令,还可以怎样去安装应用呢? 可以怎么去优化这个功能? 它能直接启动应用的某个activity页面不呢?


6.高级的 adb 命令

adb不仅可以查看连接的设备,还可以,安装/卸载应用检查安装的应用列表模拟点击获取手机信息执行shell命令等等。高级! 当然,它需要你手机打开开发者模式,并开启 USB 调试

先来看看连接的设备列表吧:

adb devices

我就要在非HBuilderX环境下编译uniapp运行Android端

列出安装的第三方(非系统)的应用(包名)列表:

adb shell pm list packages -3

我就要在非HBuilderX环境下编译uniapp运行Android端

安装本电脑上的apk:

adb install /xxx/base.apk

我就要在非HBuilderX环境下编译uniapp运行Android端

至此,我相信你已经知道,可以怎么优化自动安装应用了吧


总结

有时候,大胆发散一下你的思维,这个功能/需求能不能做!怎么去做,它是怎么个流程,原理是什么。或许并没有想像中的那么难! 动动手,实践一下!

  1. CodeGeex等AI工具,可以根据我们的思路快速提供一段代码 demo;以便我们进一步思索;当然别拿着代码就运行! 万一有个 rm -rf
  2. uni cli 脚手架,可以在非【HBuilderX】编辑器下,进行愉快编码,但是需要我们自行扩展功能;比如:自动开发微信开发者工具、自动发布小程序等等。
  3. 任何一门语言,都有它对应的工具、依赖、社区;作为一名开发者,多了解一些知识总归是有些用处的

欢迎各位码友分享转发评论区高见,辛苦各位点个赞收藏在看咯~