Skip to content

工业插件开发注意项

本页面介绍为工业机器人开发插件时需要注意的兼容性问题和最佳实践。

环境限制

alert 和 confirm 函数不可用

在工业机器人的插件环境中,原生的 alert()confirm()prompt() 函数无法使用。

问题说明

示教器的 WebView 环境禁用了这些阻塞式的对话框函数,直接调用会导致:

  • alert() - 无响应或静默失败
  • confirm() - 无法获取用户确认
  • prompt() - 无法获取用户输入

推荐解决方案

我们强烈建议直接使用 UI 框架(如 Element UI、Ant Design 等)或运行时 API 来实现通知和对话框功能,而不是使用浏览器原生的 alert / confirm / prompt 函数。

运行时 API 提供了完整的通知和对话框功能:

使用运行时 API(推荐):

运行时 API 的使用方式取决于你的开发方式:

  • 传统方式(直接在 HTML 中引入 script 标签):使用全局对象 gbtExtension

    将运行时库下载到本地项目,下载方式:

    bash
    # 方式1:通过npm安装后复制
    npm add @agilebot/extension-runtime
    cp ./node_modules/@agilebot/extension-runtime/dist/browser.js ./static/extension-runtime.js
    
    # 方式2:直接从unpkg下载到项目
    curl -o ./static/extension-runtime.js https://unpkg.com/@agilebot/extension-runtime/dist/browser.js
    # 或使用 wget
    wget -O ./static/extension-runtime.js https://unpkg.com/@agilebot/extension-runtime/dist/browser.js
  • 模块化方式(使用构建工具和模块化开发):使用 import 语法

    ts
    import { 
    rtmNotification
    ,
    rtmMessageBox
    } from '@agilebot/extension-runtime';
    // 显示通知
    rtmNotification
    .
    success
    ('操作成功!');
    rtmNotification
    .
    error
    ('操作失败');
    rtmNotification
    .
    info
    ('提示信息');
    // 显示确认对话框
    rtmMessageBox
    .
    confirm
    ('确定要删除吗?')
    .
    then
    (() =>
    console
    .
    log
    ('用户确认'))
    .
    catch
    (() =>
    console
    .
    log
    ('用户取消'));
    // 获取用户输入
    rtmMessageBox
    .
    prompt
    ('请输入名字:')
    .
    then
    ((
    result
    ) =>
    console
    .
    log
    ('用户输入:',
    result
    ))
    .
    catch
    (() =>
    console
    .
    log
    ('用户取消'));

    现代构建工具(如 Vite、Webpack)会自动将依赖打包到最终文件中,无需额外处理。

更多运行时 API 的详细说明,请参考 Web 小程序的运行库

备选方案:兼容原生 alert/confirm

仅在必要时使用

只有当你的项目已经大量使用了原生的 alert() / confirm() 函数,且无法重构时,才需要使用以下兼容方案。

对于新项目或可以重构的项目,请直接使用上述推荐的运行时 API 或 UI 框架。

如果你必须保持对原生 alert() / confirm() 的兼容,可以封装一层兼容代码:

传统方式兼容示例

js
// 判断当前环境是否运行在插件中
const isExtension = gbtExtension.isInExtension();

// 兼容 alert
const alertSuccess = !isExtension
  ? alert
  : gbtExtension.rtmNotification.success;

const alertError = !isExtension
  ? alert
  : gbtExtension.rtmNotification.error;

const alertInfo = !isExtension
  ? alert
  : gbtExtension.rtmNotification.info;

// 兼容 confirm(异步形式)
const myConfirm = function(message) {
  if (!isExtension) {
    return Promise.resolve(confirm(message));
  }
  return new Promise((resolve) => {
    gbtExtension.rtmMessageBox.confirm(message)
      .then(() => resolve(true))
      .catch(() => resolve(false));
  });
};

// 使用示例
alertSuccess('操作成功!');

async function deleteItem() {
  const confirmed = await myConfirm('确定要删除吗?');
  if (confirmed) {
    console.log('用户确认删除');
  }
}

模块化方式兼容示例

ts
import { 
isInExtension
,
rtmNotification
,
rtmMessageBox
} from '@agilebot/extension-runtime';
const
isExtension
=
isInExtension
();
// 兼容 alert const
alertSuccess
= !
isExtension
?
alert
:
rtmNotification
.
success
;
const
alertError
= !
isExtension
?
alert
:
rtmNotification
.
error
;
const
alertInfo
= !
isExtension
?
alert
:
rtmNotification
.
info
;
// 兼容 confirm(异步形式) const
myConfirm
= function(
message
: string) {
if (!
isExtension
) {
return
Promise
.
resolve
(
confirm
(
message
));
} return new
Promise
((
resolve
) => {
rtmMessageBox
.
confirm
(
message
)
.
then
(() =>
resolve
(true))
.
catch
(() =>
resolve
(false));
}); };

注意事项

使用兼容方案时需要注意:

  • confirm 的替代方法是异步的(返回 Promise),必须使用 await.then() 处理
  • 原生 confirm() 是同步的,封装后变为异步,可能需要调整代码结构
  • alert 替代为通知消息,显示效果与原生对话框不同
  • 建议在项目入口文件中统一封装这些函数,避免重复代码

代码转义配置

为什么需要转义

插件的前端页面运行在不同设备的 WebView 环境中:

  • 工业机器人:由于示教器搭载的 Android 系统 (如 Android 13) 的 WebView 可能不支持 ES6 + 的新特性 (如箭头函数、async/await、可选链等),因此需要配置转义,将现代 JavaScript 代码转义 (transpile) 为 ES5 兼容代码。

  • 协作机器人:协作机器人搭载较新版本的 Android 系统,WebView 对现代 JavaScript 特性有良好支持,通常不需要配置转义

提示

如果你是为工业机器人开发插件,那就需要按照本文档配置转义。如果是为协作机器人开发插件,那么大概率不需要转义配置,可以直接使用现代 JavaScript 语法。

场景一:使用 Babel 转义 (传统方式)

如果你使用传统方式开发,即不使用现代构建工具,而是直接编写原生 JavaScript,那么可以使用 Babel 来转义代码。

配置示例

以下是一个完整的 package.json 配置示例:

package.json
json
{
  "name": "my-extension",
  "private": true,
  "scripts": {
    "build": "babel ./static/script.js --out-file=./static/script-compiled.js"
  },
  "devDependencies": {
    "@babel/cli": "^7.27.0",
    "@babel/core": "^7.26.10",
    "@babel/preset-env": "^7.26.9"
  },
  "babel": {
    "presets": [
      [
        "@babel/preset-env",
        {
          "modules": false,
          "targets": {
            "android": "13",
            "chrome": "80"
          }
        }
      ]
    ]
  }
}

关键配置说明

  1. 依赖安装:

    • @babel/cli : Babel 命令行工具
    • @babel/core : Babel 核心库
    • @babel/preset-env : 智能预设,根据目标环境自动转换
  2. 转义配置:

    json
    "babel": {
      "presets": [
        [
          "@babel/preset-env",
          {
            "modules": false,
            "targets": {
              "android": "13",
              "chrome": "80"
            }
          }
        ]
      ]
    }
  3. 构建脚本:

    bash
    pnpm build

    这将把 ./static/script.js 转义为 ./static/script-compiled.js

使用示例

假设你有以下现代 JavaScript 代码:

static/script.js
js
// 使用箭头函数和async/await
const fetchData = async () => {
  const response = await fetch('/api/data');
  const data = await response.json();
  return data?.results ?? [];
};

// 使用可选链和空值合并
const getUserName = (user) => {
  return user?.profile?.name ?? 'Anonymous';
};

运行 pnpm build 后,Babel 会将其转义为 ES5 兼容代码:

static/script-compiled.js
js
// 转义后的代码(示例)
var fetchData = function fetchData() {
  return regeneratorRuntime.async(function fetchData$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return regeneratorRuntime.awrap(fetch('/api/data'));
        case 2:
          response = _context.sent;
          // ...
      }
    }
  });
};

然后在 HTML 中引用转义后的文件:

html
<script src="./static/script-compiled.js"></script>

场景二:使用 Vite Legacy 插件 (模块化方式)

如果你使用 Vite、Webpack 等现代构建工具,可以使用相应的 Legacy 插件来处理转义。

Vite 配置示例

  1. 安装插件:

    bash
    pnpm add -D @vitejs/plugin-legacy
  2. 配置 vite.config.ts:

    vite.config.ts
    ts
    import { 
    fileURLToPath
    ,
    URL
    } from 'node:url'
    import {
    defineConfig
    } from 'vite'
    import
    vue
    from '@vitejs/plugin-vue'
    import
    legacy
    from '@vitejs/plugin-legacy'
    export default
    defineConfig
    ({
    base
    : './',
    plugins
    : [
    vue
    (),
    legacy
    ({
    targets
    : ['android >= 13', 'chrome >= 80'],
    modernPolyfills
    : true,
    }), ],
    resolve
    : {
    alias
    : {
    '@':
    fileURLToPath
    (new
    URL
    ('./src', import.meta.
    url
    ))
    }, }, })
  3. 构建项目:

    bash
    pnpm build

Legacy 插件的作用

@vitejs/plugin-legacy 会自动完成以下工作:

  1. 生成两个版本的代码:

    • 现代版本 (ES 模块,供新浏览器使用)
    • Legacy 版本 (ES5,供旧浏览器使用)
  2. 注入 polyfills (如 Promise、Array.from 等)

  3. 根据浏览器能力自动加载对应版本

构建后,Vite 会生成类似这样的 HTML:

html
<!-- 现代浏览器加载 -->
<script type="module" src="./assets/index-abc123.js"></script>

<!-- 旧浏览器加载 -->
<script nomodule src="./assets/legacy-polyfills-def456.js"></script>
<script nomodule src="./assets/index-legacy-ghi789.js"></script>

其他构建工具

Webpack 配置示例

如果使用 Webpack,可以通过 babel-loader 配置:

webpack.config.js
js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', {
                targets: {
                  android: '13',
                  chrome: '80'
                }
              }]
            ]
          }
        }
      }
    ]
  }
};

验证转义效果

构建完成后,建议在示教器上测试:

  1. 将插件安装到目标设备
  2. 打开插件页面
  3. 验证所有功能是否正常工作