Skip to main content
Version: 3.x

跨平台开发

Taro 的设计初衷就是为了统一跨平台的开发方式,并且已经尽力通过运行时框架、组件、API 去抹平多端差异,但是由于不同的平台之间还是存在一些无法消除的差异,所以为了更好的实现跨平台开发,Taro 中提供了如下的解决方案。

内置环境变量

Taro 在编译时提供了一些内置的环境变量来帮助用户做一些特殊处理。

process.env.TARO_ENV

用于判断当前的编译平台类型。

取值:weapp / swan / alipay / tt / qq / jd / h5 / rn

可以通过这个变量来区分不同环境,从而使用不同的逻辑。在编译阶段,会移除不属于当前编译类型的代码,只保留当前编译类型下的代码,例如:

1. 在微信小程序和 H5 端分别引用不同资源:

/** 源码 */
if (process.env.TARO_ENV === 'weapp') {
require('path/to/weapp/name')
} else if (process.env.TARO_ENV === 'h5') {
require('path/to/h5/name')
}

/** 编译后(微信小程序)*/
if (true) {
require('path/to/weapp/name')
}
/** 编译后(H5)*/
if (true) {
require('path/to/h5/name')
}

2. 决定不同端要加载的组件

/** 源码(React JSX) */
<View>
{process.env.TARO_ENV === 'weapp' && <ScrollViewWeapp />}
{process.env.TARO_ENV === 'h5' && <ScrollViewH5 />}
</View>

/** 编译后(微信小程序)*/
<View>
{true && <ScrollViewWeapp />}
</View>
/** 编译后(H5)*/
<View>
{true && <ScrollViewH5 />}
</View>
note

不要解构 process.env 来获取环境变量,请直接以完整书写的方式(process.env.TARO_ENV)来进行使用。

// 正确写法
if (process.env.TARO_ENV === 'weapp') {}

// 错误写法
const { TARO_ENV = 'weapp' } = process.env
if (TARO_ENV === 'weapp') {}

统一接口的多端文件

内置环境变量虽然可以解决大部分跨端的问题,但是会让代码中充斥着逻辑判断的代码,影响代码的可维护性,而且也让代码变得愈发丑陋。为了解决这种问题,Taro 提供了另外一种跨端开发的方式作为补充。

开发者可以通过使用统一接口的多端文件,来解决跨端差异的功能。针对一项功能,如果多个端之间都有差异,那么开发者可以通过将文件修改成 原文件名 + 端类型 的命名形式(端类型对应着 process.env.TARO_ENV 的取值),不同端的文件代码对外保持统一接口,而引用的时候仍然是 import 原文件名的文件。Taro 在编译时,会跟根据当前的编译平台类型,将加载的文件变更为带有对应端类型文件名的文件,从而达到不同的端加载对应文件的目的。

使用要点

统一接口的多端文件这一跨平台兼容写法有如下三个使用要点:

  • 不同端的对应文件一定要统一接口和调用方式
  • 引用文件的时候,只需要写默认文件名,不用带文件后缀
  • 最好有一个平台无关的默认文件,这样在使用 TS 的时候也不会出现报错。

通常有以下三种使用场景:

多端组件

假如有一个 Test 组件存在微信小程序、百度小程序和 H5 三个不同版本,那么就可以像如下组织代码:

├── test.js                Test 组件默认的形式,编译到微信小程序、百度小程序和 H5 之外的端使用的版本
├── test.weapp.js Test 组件的微信小程序版本
├── test.swan.js Test 组件的百度小程序版本
└── test.h5.js Test 组件的 H5 版本

四个文件,对外暴露的是统一的接口,它们接受一致的参数,只是内部有针对各自平台的代码实现。

而使用 Test 组件的时候,引用的方式依然和之前保持一致。import 的是不带端类型的文件名,在编译的时候会自动识别并添加端类型后缀:

import Test from '../../components/test'

<Test argA={1} argA={2} />

多端脚本逻辑

与多端组件类似,假如有需要针对不同的端写不同的脚本逻辑代码,我们也可以类似的进行处理,遵守的唯一原则就是多端文件对外的接口保持一致

例如微信小程序上使用 Taro.setNavigationBarTitle 来设置页面标题,H5 则是使用 document.title。那么我们可以封装一个 setTitle 方法来抹平两个平台的差异。

  1. 编写 set_title.weapp.js
set_title.weapp.js
import Taro from '@tarojs/taro'
export default function setTitle (title) {
Taro.setNavigationBarTitle({
title
})
}
  1. 编写 set_title.h5.js
set_title.h5.js
export default function setTitle (title) {
document.title = title
}
  1. 调用:
import setTitle from '../utils/set_title'

setTitle('页面标题')

多端页面路由

可以根据不同平台,设置不同的路由规则。例如:

app.config.js
let pages = []

if (process.env.TARO_ENV === 'weapp') {
pages = [
'/pages/index/index'
]
}

if (process.env.TARO_ENV === 'swan') {
pages = [
'/pages/indexswan/indexswan'
]
}

export default {
pages
}

解析 node_modules 内的多端文件

小程序 & H5

Taro 3 里的多端文件由 MultiPlatformPlugin 插件进行解析。

它是一个 enhanced-resolve 插件,Taro 内部会默认加载它。但为了提高解析效率,插件默认不解析 node_modules 中的文件

假设我们需要解析 NPM 包 taro-mobile 里面的多端文件,可以利用 WebpackChain 为 MultiPlatformPlugin 插件添加 include 配置:

config/index.js
// mini 也可改为 h5,分别对应小程序与 h5 端配置
mini: {
webpackChain (chain) {
// Taro 3.1 & 3.2
chain.resolve.plugin('MultiPlatformPlugin')
.tap(args => {
return [...args, {
include: ['@taro-mobile']
}]
})

// Taro 3.3+
chain.resolve.plugin('MultiPlatformPlugin')
.tap(args => {
args[2]["include"] = ['@taro-mobile']
return args
})
}
}

React Native

RN 端没有使用 Webpack,因此单独增加了一个配置支持:

config/index.js
rn: {
resolve: {
include: ['taro-mobile'],
}
}

参考案例

Taro Playground 项目支持 RN、微信小程序、web 可供参考。

AndroidiOSWebMini Program
https://github.com/wuba/taro-playground/releaseshttps://apps.apple.com/cn/app/taro-playground/id1576830673https://wuba.github.io/taro-playground/https://github.com/wuba/taro-playground

同时该项目集成了Github Workflows,实现了安卓、iOS、微信小程序、web的自动化发布。