# 条件编译处理多端差异

# 为什么选择条件编译处理跨端兼容

uni-app 已将常用的组件、API封装到框架中,开发者按照 uni-app 规范开发即可保证多平台兼容,大部分业务均可直接满足。

Each platform has its own characteristics, so there will be some situations that can not be cross-platform.

  • Writing a lot of if else may cause low performance in code execution and management confusion.
  • 编译到不同的工程后二次修改,会让后续升级变的很麻烦。
  • 为每个平台重写,明明主业务逻辑又一样

在 C 语言中,通过 #ifdef#ifndef 的方式,为 Windows、Mac 等不同 OS 编译不同的代码。

uni-app 团队参考这个思路,为 uni-app 提供了条件编译手段,在一个工程里优雅的完成了平台个性化实现。

# Conditional compilation

Conditional compilation is marked with special comments which are the basic of compiling the code inside these comments to different platforms during compilation.

# 使用方法

#ifdef#ifndef%PLATFORM% 开头,以 #endif 结尾。

  • #ifdef:if defined 仅在某平台存在
  • #ifndef:if not defined 除了某平台均存在
  • %PLATFORM%:平台名称
条件编译写法说明
#ifdef APP-PLUS
需条件编译的代码
#endif
仅出现在 App 平台下的代码
#ifndef H5
需条件编译的代码
#endif
除了 H5 平台,其它平台均存在的代码(注意if后面有个n)
#ifdef H5 || MP-WEIXIN
需条件编译的代码
#endif
在 H5 平台或微信小程序平台存在的代码(这里只有||,不可能出现&&,因为没有交集)

%PLATFORM% 可取值:

生效条件 版本支持
VUE3 uni-app js引擎版用于区分vue2和3,详情 HBuilderX 3.2.0+
VUE2 uni-app js引擎版用于区分vue2和3,详情
UNI-APP-X 用于区分是否是uni-app x项目 详情 HBuilderX 3.9.0+
APP App
APP-PLUS uni-app js引擎版编译为App时
APP-PLUS-NVUE或APP-NVUE App nvue 页面
APP-ANDROID App Android 平台 详情
APP-IOS App iOS 平台 详情
H5 H5(推荐使用 WEB
WEB web(同H5 HBuilderX 3.6.3+
MP-WEIXIN 微信小程序
MP-ALIPAY 支付宝小程序
MP-BAIDU 百度小程序
MP-TOUTIAO 抖音小程序
MP-LARK 飞书小程序
MP-QQ QQ小程序
MP-KUAISHOU 快手小程序
MP-JD 京东小程序
MP-360 360小程序
MP 微信小程序/支付宝小程序/百度小程序/抖音小程序/飞书小程序/QQ小程序/360小程序
QUICKAPP-WEBVIEW 快应用通用(包含联盟、华为)
QUICKAPP-WEBVIEW-UNION 快应用联盟
QUICKAPP-WEBVIEW-HUAWEI 快应用华为

支持的文件:

  • .vue/.nvue/.uvue
  • .js/.uts
  • .css
  • pages.json
  • Precompiled language files, such as .scss, .less, .stylus, .ts, .pug

注意:

  • 条件编译是利用注释实现的,在不同语法里注释写法不一样,js/uts使用 // 注释、css 使用 /* 注释 */、vue/nvue/uvue 模板里使用 <!-- 注释 -->

  • 条件编译APP-PLUS包含APP-NVUE和APP-VUE,APP-PLUS-NVUE和APP-NVUE没什么区别,为了简写后面出了APP-NVUE ;

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

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

    JSON 错误示例

    JSON 正确示例

    {
      "key": "a",
      // #ifdef MP-WEIXIN
      "key": "b"
      // #endif
    }
    

    JS 错误示例

    JS 正确示例

    // #ifdef MP-WEIXIN
    import a from 'a/wx'
    // #endif
    // #ifndef MP-WEIXIN
    import a from 'a/index'
    // #endif
    
  • VUE3 需要在项目的 manifest.json 文件根节点配置 "vueVersion" : "3"

# Conditional compilation of API

// #ifdef  %PLATFORM%
...
// #endif

For example, the following codes only appear on App:

For example, the following codes will not appear on the H5 platform:

In addition to conditional compilation on a single platform, it also supports simultaneous compilation on multiple platforms. Use || to separate the platform names.

For example, the following codes will appear on App and H5 platforms:

# 组件的条件编译

<!--  #ifdef  %PLATFORM% -->
...
<!--  #endif -->

For example, the following public account follow components will only appear in WeChat Mini Programs:

<view>
    <view>微信公众号关注组件</view>
    <view>
        <!-- #ifdef MP-WEIXIN -->
		        <official-account></official-account>
		    <!-- #endif -->
    </view>
</view>

# 样式的条件编译

/*  #ifdef  %PLATFORM%  */
...
/*  #endif  */

Notice: For style conditional compilation, whether it is css or sass/scss/less/stylus and other pre-compiled languages, you must use the wording of /*Comments*/.

Correct writing

Wrong writing

# pages.json 的条件编译

The following pages will only be compiled when running to App.

The unique functions under different platforms, as well as the subcontracting of the applet platform, can be better realized through the conditional compilation of pages.json. In this way, redundant resources will not be generated on other platforms, thereby reducing the package size.

For conditional compilation of json, if the key names of different platforms are the same, the verifiers installed by developers under cli project will report errors, and the verification rules of these verifiers for the same key of json need to be closed by themselves. If the verifier of HBuilderX is used, there is no need to care about this problem, because the syntax verifier of HBuilderX has been optimized for this purpose.

# static 目录的条件编译

这里也解释了 static 内的哪些目录是特殊的。

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

目录名称 说明 版本支持
app app uni-app 3.9+
web web uni-app 3.9+
mp-weixin 微信小程序
mp-alipay 支付宝小程序
mp-baidu 百度小程序
mp-qq QQ小程序
mp-toutiao 抖音小程序
mp-lark 飞书小程序
mp-kuaishou 快手小程序
mp-jd 京东小程序

Static resources in a dedicated directory will only be compiled on a specific platform.

As shown in the following directory structure, a.png will only be compiled in the WeChat applet platform, and b.png will be compiled in all platforms.

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

注意

  • 自HBuilderX3.9+起,App平台static目录同时支持app、app-plus目录,Web平台static目录同时支持web、h5目录
  • 自HBuilderX3.98+起,编译时增加 static 下被忽略的非当前平台专有目录提示信息,如static下同时存在app、web,运行到web时,会提示static/app已被忽略

# Conditional compilation of whole directories

If you want to separate the page files of each platform more thoroughly, you can also create a platforms directory in the root directory of the uni-app project, and then further create app-plus, mp-weixin and other subdirectories below to store different Platform documentation.

Notice

  • platforms目录下只支持放置页面文件(即页面vue文件),如果需要对其他资源条件编译,建议使用static 目录的条件编译

# uts 的条件编译

对于APP-ANDROIDAPP-IOS两个平台,

  • 在uni-app项目中,仅uts文件中支持(通常是uts插件里使用)
  • 在uni-app x项目中,只要是条件编译支持的文件,均可以使用
// #ifdef  %PLATFORM%
Platform-specific API implementation
// #endif

# uni-app x项目的条件编译

使用UNI-APP-X条件编译,来区分uni-app x项目和uni-app项目。

uni-app x项目

uni-app项目

// #ifdef UNI-APP-X
代码会生效
// #endif
// #ifndef UNI-APP-X
代码不会生效
// #endif

# 版本的条件编译

HBuilderX 3.9+

插件作者的插件,需要适配各种插件使用者,使用者的uni-app版本,可能有很多。

有些问题可以在运行期判断适配,有些则需要在编译器处理,尤其是不处理可能会导致低版本编译失败的情况。

为此,uni-app的条件编译新增了uniVersion。在uni-app和uni-app x中均可使用。

// #ifdef  uniVersion > 3.9
编译器版本大于3.9时生效
// #endif

注意,从HBuilderX 3.9起,版本号将由三段式字符串改为小数。

即HBuilderX 3.9.1,将改为 3.91。

这样条件编译判断时,仅需输入一个数字即可。

注意低于3.9版本的HBuilderX的条件编译不识别uniVersion

# HBuilderX support

HBuilderX provides rich support for conditional compilation of uni-app:

Code block support

When developing uni-app in HBuilderX, you can quickly generate conditionally compiled code snippets by typing ifdef

Syntax highlighting

HBuilderX provides syntax highlighting for the code comment part of conditional comments, which can distinguish whether the writing mode is correct or not, making the code clearer (For standalone js files, you need to switch the javascript es6+ editor in the lower right corner of the editor. Standalone css files do not support highlighting, which does not affect the use effect)

Correct comment and quick selection

In HBuilderX, ctrl+alt+/ can generate correct comments (js: // Comments, css: /* Comments */, vue/nvue template: <!-- Comments -->).

Click ifdef or endif to quickly select the conditional compilation part; Click the folding icon on the left to collapse part of the conditional compilation code.

# 注意

  • It is not supported to distinguish Android and iOS platforms through conditional compilation. If you need to distinguish them, please call uni.getSystemInfo to get the platform information. Supports ifios, ifAndroid code blocks, which is convenient for writing and judging.
  • Some cross-end tools can provide conditional compilation or polymorphism of js, but this is far from enough for actual development. uni-app not only deals with js, but any code can be compiled conditionally on multiple terminals, so as to truly solve the cross-terminal problem of the actual project. In addition, the so-called polymorphism will cause a lot of redundant code in actual development, which is not conducive to reuse and maintenance. For example, the theme color of WeChat applet is green, and the Baidu Alipay applet is blue. If your application wants to adapt to the color of the platform, only conditional compilation is the least code amount and the easiest to maintain.
  • Some companies operate their products with different requirements for different platforms, but that is no reason to reject uni-App. The key lies in whether there is more reusable code or more personalized code in the project. Normally, there shall be more reusable codes, so it should still be multi-side. Personalized codes are placed in directories of different platforms for differentiated maintenance.