Bootstrap

uni-app 玩转条件编译:自定义平台的条件编译实战详解

一. 条件编译支持的场景

uni-app 的条件编译能支持以下几种场景,具体如图所示:

1. API 的条件编译

简言之,同一功能实现,可能有不同的逻辑处理,比如:在 js 文件中,或者在 Vue 文件中的 script 代码中有不同的逻辑处理方式,使用方式如下:

// #ifdef  %PLATFORM%
该平台特有的API实现;
// #endif

2. 组件的条件编译

在 template 模版中,可能会在不同的平台展示不同的组件,或者是展示效果不同,或者是在某一平台不需要展示,使用方式如下:

<!--  #ifdef  %PLATFORM% -->
该平台特有的组件
<!--  #endif -->

3. 样式的条件编译

在不同的平台下有差异性的样式处理,使用方式如下:

/*  #ifdef  %PLATFORM%  */
该平台特有的样式
/*  #endif  */

4. pages.json 的条件编译

不同平台下的特有功能,以及小程序平台的分包,都可以通过 pages.json 的条件编译来更好地实现。这样,就不会在其它平台产生多余的资源,进而减小包体积。

例如:在 pages.json 中配置 pages 页面路由,在 H5 平台下编译 “测试 1” 页面,在微信小程序页面下编译 “测试 2” 页面

"pages": [
    // #ifdef H5
    {
      "path": "pages/test1",
      "style": {
        "navigationBarTitleText": "测试1"
      }
    },
    // #endif
    // #ifdef MP-WEIXIN
    {
      "path": "pages/test2",
      "style": {
        "navigationBarTitleText": "测试2"
      }
    },
    // #endif
]

特别注意:json 的条件编译,一定要注意最后","分隔符的所属问题,不能有多余的逗号,可能会出现异常情况,导致编译失败!

5. static 目录的条件编译

在不同平台,引用的静态资源可能也存在差异,通过 static 的条件编译可以解决此问题,static 目录下新建不同平台的专有目录,目录名称均为小写,专有目录下的静态资源只有在特定平台才会编译进去。

如以下目录结构,a.png 只有在微信小程序平台才会编译进去,b.png 在所有平台都会被编译,合理的利用 static 目录的条件编译能够大大的减小包体积,在微信小程序的分包实践中尤为重要!

┌─static
│  ├─mp-weixin
│  │  └─a.png
│  └─b.png
├─main.js
├─App.vue
├─manifest.json
└─pages.json

二. 注意事项

关于条件编译,有以下几个注意事项需要在编程的过程中重点关注一下:

  1. 条件编译 APP-PLUS 包含 APP-NVUE 和 APP-VUE ;

  2. 对于未定义平台名称,可能是名称写错了,也可能是低版本 HBuilderX 没有这个平台,此时的条件编译,#ifdef 中的代码不会生效,而 #ifndef 中的代码会生效;

  3. 使用条件编译请保证编译前和编译后文件的语法正确性,即要保障无论条件编译是否生效都能通过语法校验。比如:json 文件中不能有多余的逗号,js 中不能重复导入;

  4. Android 和 iOS 平台不支持通过条件编译来区分,如果需要区分 Android、iOS 平台,请通过调用 uni.getSystemInfo 来获取平台信息。支持 ifiosifAndroid 代码块,可方便编写判断。

三. 自定义条件编译平台

1. 背景(我为什么要进行自定义平台)

在开发 Web 时,可能有时候需要将同一套代码编译发布到不同的站点,比如多个不同的微信 h5 站,这些站点可能有不同的差异性处理。在开发小程序时,也经常有扩展小程序平台,比如同一套代码,我需要发布到多个小程序,可能这些小程序之间少许有些差异。因此,uni-app 通过在 package.json 文件中增加 uni-app 扩展节点,可实现自定义条件编译平台。

在我之前开发的实际项目中,同一套代码需要部署多个平台,大概有 10 个平台,而且这几个平台可能有 90% 以上的代码是相同的,因此我就没有必要重新开发一套代码了。这多个平台的含义是:在微信小程序有多个平台,在 H5 网站有多个平台,可能在 APP 中也有多个平台,在这些平台之间,可能有或多或少的差异,比如:

  • 功能的差异性,页面展示不同,tabbar 数量等

  • 请求 API 的差异性,对应的后端服务 API 不同

  • 全局变量的差异性,主题配色变量,默认语言等

因此,以上这些差异就会要求在代码中处理不同平台之间的差异性,以下是我的实际项目中的自定义平台:

除此之外,还有两个 APP 平台,但是目前 uni-app 不支持自定义 APP 的基准平台!

如何增加 uni-app 扩展节点,总结一下有以下几个步骤可以快速完成一个全新平台的编译:

  • 声明配置,添加新平台

  • 在代码中使用新平台条件编译

  • 编译到新平台

2. 第一步: 声明配置,添加新平台

在 package.json 中添加 uni-app 节点,添加以下配置,使新定义的平台生效:

   "uni-app": {
    "scripts": {
      "custom-h5": {
        "title": "自定义H5平台",
      "browser": "chrome",
        "env": {
          "UNI_PLATFORM": "h5"
        },
        "define": {
          "CUSTOM-H5": true
        }
      },
      "custom-mp": {
        "title": "自定义小程序平台",
        "env": {
          "UNI_PLATFORM": "mp-weixin"
        },
        "define": {
          "CUSTOM-MP": true
        }
      }
    }
  }

参数说明:

正确的结构就是如上所示,下面说一下这几个参数的具体含义

  • title:自定义扩展名称, 在 HBuilderX 中会显示在 运行/发行 菜单中

  • browser:运行到的目标浏览器,仅当 UNI_PLATFORM 为 h5 时有效

  • env:环境变量
    • UNI_PLATFORM:基准平台

    • MY_TEST:其他自定义环境变量

  • define:自定义条件编译
    • CUSTOM-H5:自定义条件编译常量,建议为大写

注意事项:

  • 只能扩展 web 和小程序平台,不能扩展 app 平台。并且扩展小程序平台时只能基于指定的基准平台扩展子平台,不能扩展基准平台。也就是说 UNI_PLATFORM 仅支持填写 uni-app 默认支持的基准平台,目前仅限如下枚举值:h5mp-weixinmp-alipaymp-baidump-toutiaomp-qq

  • browser 仅在 UNI_PLATFORM 为 h5 时有效,目前仅限如下枚举值:chrome、firefox、ie、edge、safari、hbuilderx。

  • package.json 文件中不允许出现注释,否则扩展配置无效。

3. 第二步:在代码中使用条件编译

接下来,可以在代码里使用自定义的条件编译,为这个新平台编写专用代码:

// 新的自定义微信小程序平台
// #ifdef CUSTOM-MP
/**
 * 微信小程序 代码
 */
// #endif

// 新的自定义H5平台
// #ifdef CUSTOM-H5
/**
 * H5 代码
 */
// #endif

4. 第三步:编译到新平台

运行时可以执行面向新平台的编译运行,发行时可以执行面向新平台的编译发行。如下图所示,我们点击运行和发行,已经都有了我们刚才已经自定义好的平台名称。

四. 总结

关于你是否需要自定义平台,关键在于项目里复用的代码多还是个性的代码多,如果都是复用的代码多,并且对应的服务端是一致的,所以仍然可以自定义平台多端部署,而个性的代码放到不同平台的目录下,进行差异化维护。

五. 资源文档

;