# provider机制介绍

uni-app的API,统一了多平台的差异。但某个API,可以由很多三方SDK来支撑,所以提供了provider机制用于抹平SDK之间的差异。

比如

  • 支付API:有支付宝支持、微信支付
  • 定位API:有系统定位、腾讯定位

不同的SDK,本身的API是完全不同的,甚至同一个SDK的Android和iOS的API也不一样。

uni-app 通过 provider 机制来统一不同的SDK,屏蔽他们的差异。

同一个功能的不同的SDK,都被称为该功能的 provider,即供应商。

比如对于支付模块,有 支付宝 和 微信 这2个 provider 供应商。

由于这些模块和SDK在打包时是可选的,那么在运行时可以通过 uni.getProvider,来获取到本App包中包含的provider清单。

注意

我们要把SDK和App的概念区分清楚。对于支付的2个provider,支付宝和微信,它们除了有SDK外,也有各自的主App。

uni.getProviders,只是动态获取开发者的App包中的provider清单,即打包了哪些SDK。但本API不负责判断这些provider的主App是否安装在同一台手机上。

但微信比较特殊,如果没有微信App,微信支付无法完成。并且Appstore审核要求本机未安装微信时,不能显示微信的登录支付。这就要求开发者必须判断本机是否安装了微信。

所以微信的SDK,自身提供了获取微信主App是否安装的API,那么这个API也被封装到了provider返回的对象里。

除微信外,其他SDK无此特殊情况。

# 自注册provider

除了官方提供的provider,uni-app x 于 4.24版开放了provider自注册机制,允许三方插件注册provider。

注意

  • 标准基座android需要在manifest.json中配置才能获取到对应的provider,ios不需要。自定义基座都需要配置
  • 自定义的provider不要在构造函数中写逻辑,因为现在provider会预先实例化,如果在构造函数中写逻辑,会导致代码在应用启动的时候就被执行

# uni.getProvider(options)

获取服务供应商 已废弃,4.25及以后版本请使用getProviderSync()方法代替

# getProvider 兼容性

Web Android iOS
x 4.11 4.18

# 参数

名称 类型 必填 默认值 兼容性 描述
options GetProviderOptions - -
名称 类型 必备 默认值 兼容性 描述
service string -
服务类型:支付 (payment)
合法值 兼容性 描述
payment
支付 (alipay、wxpay)
oauth
授权登录
success (result: GetProviderSuccess) => void -
接口调用成功的回调
fail (result: IGetProviderFail) => void -
接口调用失败的回调函数
complete (result: any) => void -
接口调用结束的回调函数(调用成功、失败都会执行)

# GetProviderSuccess 的属性值

名称 类型 必备 默认值 兼容性 描述
service string -
服务类型:支付 (payment)
合法值 兼容性 描述
payment
支付 (alipay、wxpay)
oauth
授权登录
provider Array<string> -
得到的服务供应商
providers Array<UniProvider> -
得到的服务供应商服务对象

# IGetProviderFail 的属性值

名称 类型 必备 默认值 兼容性 描述
errCode number - - 错误码:
110600:服务类型参数无效。
errSubject string - - 统一错误主题(模块)名称
data any - - 错误信息中包含的数据
cause Error - - 源错误信息,可以包含多个错误,详见SourceError
errMsg string - - -

uni.getProvider 返回顺序说明:

  1. 目前标准基座中注册的 provider 返回顺序如下: 支付: 微信支付、支付宝; 定位: 系统定位、腾讯定位

  2. 相同 service 下,其他的自注册 provider,返回顺序在官方预置的 provider 之后

  3. 自注册的 provider 无法保障顺序, 请不要依赖自注册 provider 的顺序

  4. 如果自定义的 service 与 provider 配置与内置的一样,优先采用自定义的

  5. 如果自定义的 service 下存在多个同名的 provider,编译器会报错

# 参见

# uni.getProviderSync(options)

getProvider的同步方法

# getProviderSync 兼容性

Web Android iOS
x 4.25 4.25

# 参数

名称 类型 必填 默认值 兼容性 描述
options GetProviderSyncOptions - -
名称 类型 必备 默认值 兼容性 描述
service string -
服务类型
合法值 兼容性 描述
payment
支付 (alipay、wxpay)
location
定位 (system、tencent)
oauth
授权登录

# 返回值

类型
GetProviderSyncSuccess
名称 类型 必备 默认值 兼容性 描述
service string -
服务类型
合法值 兼容性 描述
payment
支付 (alipay、wxpay)
location
定位 (system、tencent)
oauth
授权登录
providerIds Array<string> -
得到的服务供应商
providerObjects Array<UniProvider> -
得到的服务供应商服务对象

# 参见

# UniProvider说明文档链接

# UniProvider

服务供应商

# UniProvider 的属性值

名称 类型 必备 默认值 兼容性 描述
id string - - 服务供应商标识
description string - - 服务供应商描述
isAppExist boolean - - 判断服务供应商依赖的App是否安装(仅支持微信支付)

# UniProvider 兼容性

Web Android iOS
- 4.18 4.18

# 示例

hello uni-app x

该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验

扫码体验(手机浏览器跳转到App直达页)
<template>
  <!-- #ifdef APP -->
  <scroll-view class="page-scroll-view">
  <!-- #endif -->
    <view class="page">
      <page-head :title="title"></page-head>
      <view class="service-item" v-for="(item, index) in serviceList" :key="index">
        <text class="service-name">{{item.name}}:</text>
        <view class="provider-list">
          <text class="provider-item" v-for="(item2, index2) in item.provider" :key="index2">
            {{item2}}
            {{item.providerObj.length > 0 ? ':' + JSON.stringify(item.providerObj[index2]) : '' }}
          </text>
        </view>
      </view>
      <button class="btn-get-provider" type="primary" @click="getProvider">getProviderSync</button>
    </view>
  <!-- #ifdef APP -->
  </scroll-view>
  <!-- #endif -->
</template>

<script>
  type ProviderItem = {
    service : string,
    name : string,
    provider : string[],
    providerObj : UniProvider[]
  }

  export default {
    data() {
      return {
        title: 'provider',
        flag: false,
        serviceList: [
          { service: "payment", name: "支付", provider: [], providerObj: [] },
          { service: "location", name: "定位", provider: [], providerObj: [] }
        ] as ProviderItem[],
        //自动化测试使用
        providerIds: [] as string[],

        providerObjects: [] as UniProvider[],
      }
    },
    methods: {
      getProvider() {
        this.serviceList.forEach((item : ProviderItem) => {
          var provider = uni.getProviderSync({
            service: item.service,
          } as GetProviderSyncOptions)
          provider.providerIds.forEach((value) => {
            this.providerIds.push(value)
          })
          this.updateProvider(item.service, provider.providerIds, provider.providerObjects);
        })
      },
      updateProvider(service : string, provider : string[] | null, uniProvider : UniProvider[]) {
        //这里需要从新从serviceList 获取item,不能直接用forEach 里面的item,目前存在bug,后续会解决这个问题
        const item : ProviderItem | null = this.serviceList.find((item : ProviderItem) : boolean => {
          return item.service == service
        });

        if (item != null && provider != null) {
          item.provider = provider
          item.providerObj = uniProvider
          item.providerObj.forEach((obj) => {
            this.providerObjects.push(obj)
          })
        }

      }
    }
  }
</script>

<style>
  .page {
    padding: 15px;
  }

  .service-item {
    margin-top: 10px;
  }

  .service-name {
    font-weight: bold;
  }

  .provider-list {
    margin-left: 32px;
  }

  .provider-item {
    line-height: 1.5;
  }

  .btn-get-provider {
    margin-top: 30px;
  }
</style>

# 通用类型

# GeneralCallbackResult

名称 类型 必备 默认值 兼容性 描述
errMsg string - - 错误信息