更新记录

1.0.1(2026-06-16) 下载此版本

cf-uniwebview 接入说明

cf-uniwebview 用来在 App 内打开原生 WebView,并向页面注入一层统一的 JSBridge,方便 H5 和宿主 App 双向通信。

当前插件只支持:

  • APP-IOS
  • APP-ANDROID

目录结构

说明:

  • webview-bridge.js 是 H5 侧 helper,内部仍然依赖原生在页面加载时注入到 window 的 bridge。
  • 普通浏览器 / 普通 H5 环境里如果没有原生注入,helper 会返回 bridge_unavailable

插件导出

插件本体目前只导出两个方法:

isSupported() : boolean
openWebUrlWithOptions(
  options : WebViewOpenOptions,
  callback : (result : WebViewBridgePayload) => void
) : boolean

类型定义见 interface.uts

export type WebViewBridgePayload = {
  action ?: string | null
  data ?: any | null
  message ?: string | null
}

export type WebViewOpenOptions = {
  platformName ?: string | null
  platformCode ?: string | null
  linkUrl ?: string | null
  token ?: string | null
  customUserAgent ?: string | null
  channel ?: string | null
  openMode ?: string | null
  origin ?: boolean | null
  animated ?: boolean | null
  fullscreen ?: boolean | null
  topBarHidden ?: boolean | null
  applyDialogWindowConfig ?: boolean | null
  patchChooseImage ?: boolean | null
}

其中当前代码里已经实际生效的字段主要是:

  • platformName
  • platformCode
  • linkUrl
  • token
  • customUserAgent
  • openMode
  • animated
  • fullscreen
  • topBarHidden
  • applyDialogWindowConfig:仅 Android 生效
  • patchChooseImage:仅 Android 生效

当前版本里 channelorigin 还没有在原生实现中实际使用,建议视为保留字段。

App 侧用法

推荐像当前项目一样,业务层不要直接四处调用插件本体,而是加一层自己的包装。

当前项目包装层在:

它已经帮业务做了这些事情:

  • 自动补 platformName
  • 自动补 platformCode
  • 自动补 token
  • 相对路径自动拼接 AUTH_BASE_URL
  • 对运行环境做了可用性判断

当前项目调用示例

import { openNativeWebView } from '@/services/native/webview-plugin.uts'

openNativeWebView({
  linkUrl: '/h5/order/detail?id=123',
  customUserAgent: 'your-ua',
  topBarHidden: false,
  openMode: 'present',
  animated: true,
  fullscreen: true,
  applyDialogWindowConfig: true,
  patchChooseImage: true
}, (res : any) => {
  console.log('webview callback =', res)
})

直接调用插件示例

import { isSupported, openWebUrlWithOptions } from '@/uni_modules/cf-uniwebview'
import { WebViewOpenOptions, WebViewBridgePayload } from '@/uni_modules/cf-uniwebview/utssdk/interface.uts'

export function openNativeWebView(
  options : WebViewOpenOptions,
  callback : ((result : WebViewBridgePayload) => void) | null = null
) : boolean {
  if (!isSupported()) {
    return false
  }
  return openWebUrlWithOptions(
    options,
    callback == null
      ? (_ : WebViewBridgePayload) : void => {}
      : callback
  )
}

参数说明

  • linkUrl:打开的网页地址,不能为空
  • platformName:传给 H5 的平台名称
  • platformCode:传给 H5 的平台编码
  • token:传给 H5 的 token
  • customUserAgent:附加到 WebView UA 的自定义标识
  • openModepresentpush
  • animated:是否带打开/关闭动画
  • fullscreenpresent 模式下是否全屏
  • topBarHidden:是否隐藏原生顶部栏
  • applyDialogWindowConfig:Android 下是否套用弹窗 window 配置
  • patchChooseImage:Android 下是否接管 H5 内的 uni.chooseImage()

打开结果回调

H5 调 plugWebView() 主动关闭并回传:

{
  action: 'plugWebView',
  data: {
    success: true,
    orderId: '123456'
  }
}

H5 调 postMessageToApp() 持续发消息:

{
  action: 'postMessage',
  data: {
    type: 'stepChange',
    step: 2
  }
}

用户主动点关闭:

{
  action: 'dismiss'
}

打开失败或原生错误:

{
  action: 'error',
  message: 'invalid_url'
}

H5 侧用法

推荐直接引用:

import Bridge, {
  getPlugData,
  getDeviceInfo,
  getLocation,
  getLoaction,
  openAppSettings,
  openNativeUrl,
  postMessageToApp,
  copyText,
  getImageFromPhotoLibrary,
  takePhoto,
  saveImageToLibrary,
  callPhone,
  plugWebView
} from '@/uni_modules/cf-uniwebview/utssdk/webview-bridge.js'

webview-bridge.js 内部仍然依赖原生注入到 window 的这些全局方法:

  • window.WebViewJavascriptBridge
  • window.setupWebViewJavascriptBridge
  • window.getPlugData
  • window.getDeviceInfo
  • window.getLocation
  • window.getLoaction
  • window.openAppSettings
  • window.postMessageToApp
  • window.copyText
  • window.getImageFromPhotoLibrary
  • window.takePhoto
  • window.saveImageToLibrary
  • window.callPhone
  • window.plugWebView
  • window.openNativeUrl

最直接的用法示例:

window.getDeviceInfo(function (info) {
  console.log('deviceInfo =', info)
})

也可以走标准 bridge 形式:

window.WebViewJavascriptBridge.callHandler('getPlugData', null, function (data) {
  console.log('plugData =', data)
})

说明:

  • 当前原生注入层本身是 callback 风格。
  • 如果业务想用 Promise,建议在 H5 项目里自行封一层 helper。

一个最小 Promise 包装示例

function callBridge(name, data) {
  return new Promise(function (resolve) {
    if (!window.WebViewJavascriptBridge) {
      resolve({ success: false, message: 'bridge_unavailable' })
      return
    }
    window.WebViewJavascriptBridge.callHandler(name, data || null, function (res) {
      resolve(res)
    })
  })
}

const plugData = await callBridge('getPlugData')

H5 能力清单

1. 获取 App 注入参数

window.getPlugData(function (plugData) {
  console.log(plugData)
})

通常会包含:

  • platformName
  • platformCode
  • linkUrl
  • token
  • openMode
  • animated
  • fullscreen
  • topBarHidden
  • applyDialogWindowConfig:Android 会带上
  • patchChooseImage:Android 会带上

2. 获取设备信息

window.getDeviceInfo(function (deviceInfo) {
  console.log(deviceInfo)
})

3. 获取定位

window.getLocation(function (res) {
  console.log(res)
})

兼容旧拼写:

window.getLoaction(function (res) {
  console.log(res)
})

成功示例:

{
  success: true,
  locationSuccess: true,
  errorMsg: '',
  latitude: 31.2304,
  longitude: 121.4737,
  accuracy: 35,
  location: {
    latitude: '31.2304',
    longitude: '121.4737'
  }
}

常见失败值:

  • location_permission_denied
  • location_provider_disabled
  • location_timeout
  • location_busy

4. 打开系统设置

window.openAppSettings(function (res) {
  console.log(res)
})

5. 打开外部链接

window.openNativeUrl({
  url: 'weixin://',
  fallbackUrl: 'https://weixin.qq.com/'
}, function (res) {
  console.log(res)
})

支持这些字段:

  • url
  • fallbackUrl
  • failOpenUrl
  • backupUrl

6. 给 App 发消息但不关闭页面

window.postMessageToApp({
  type: 'progress',
  value: 50
}, function (res) {
  console.log(res)
})

7. 关闭页面并回传数据

window.plugWebView({
  success: true,
  orderId: '123456'
})

8. 复制文本

window.copyText({ text: 'abc123' }, function (res) {
  console.log(res)
})

也支持直接传字符串:

window.copyText('abc123', function (res) {
  console.log(res)
})

9. 从相册选图

window.getImageFromPhotoLibrary(function (res) {
  console.log(res)
})

需要 base64 时:

window.getImageFromPhotoLibrary({
  returnBase64: true
}, function (res) {
  console.log(res)
})

返回示例:

{
  success: true,
  fileName: 'image.jpg',
  mimeType: 'image/jpeg',
  size: 12345,
  tempFilePath: '/.../cache/xxx-image.jpg',
  base64: 'data:image/jpeg;base64,...'
}

10. 拍照

window.takePhoto(function (res) {
  console.log(res)
})

需要 base64 时:

window.takePhoto({
  returnBase64: true
}, function (res) {
  console.log(res)
})

返回结构和 getImageFromPhotoLibrary() 对齐。

11. 保存图片到相册

window.saveImageToLibrary({
  url: 'https://example.com/test.jpg'
}, function (res) {
  console.log(res)
})

支持这些输入:

  • 远程图片 URL
  • data:image/...;base64,...
  • content://...
  • file://...
  • 本地绝对路径

成功示例:

{
  success: true,
  savedUri: 'content://...',
  fileName: 'image.jpg',
  mimeType: 'image/jpeg',
  size: 12345
}

12. 拨打电话

window.callPhone({
  phoneNumber: '13800138000'
}, function (res) {
  console.log(res)
})

也支持:

window.callPhone('13800138000', function (res) {})
window.callPhone({ mobile: '13800138000' }, function (res) {})
window.callPhone({ tel: '13800138000' }, function (res) {})
window.callPhone({ phone: '13800138000' }, function (res) {})

直接使用 JSBridge

如果不走全局快捷方法,也可以直接调用:

window.WebViewJavascriptBridge.callHandler('getPlugData', null, cb)
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, cb)
window.WebViewJavascriptBridge.callHandler('getLocation', null, cb)
window.WebViewJavascriptBridge.callHandler('openAppSettings', null, cb)
window.WebViewJavascriptBridge.callHandler('openUrl', { url: 'weixin://' }, cb)
window.WebViewJavascriptBridge.callHandler('postMessageToApp', { type: 'x' }, cb)
window.WebViewJavascriptBridge.callHandler('copyText', { text: 'abc123' }, cb)
window.WebViewJavascriptBridge.callHandler('getImageFromPhotoLibrary', { returnBase64: true }, cb)
window.WebViewJavascriptBridge.callHandler('takePhoto', { returnBase64: true }, cb)
window.WebViewJavascriptBridge.callHandler('saveImageToLibrary', { url: 'https://example.com/test.jpg' }, cb)
window.WebViewJavascriptBridge.callHandler('callPhone', { phoneNumber: '13800138000' }, cb)
window.WebViewJavascriptBridge.callHandler('plugWebView', { success: true }, cb)

平台差异

Android

  • 使用 WebViewClient URL 拦截形式实现 bridge
  • customUserAgent 会和系统默认 UA 合并
  • applyDialogWindowConfig 仅 Android 生效
  • patchChooseImage: true 时会显式 patch uni.chooseImage()
  • 已接通:定位、相册选图、拍照、保存到相册、拨号、Web 媒体权限处理
  • 自带加载态和失败态页面

iOS

  • 使用注入脚本 + 轮询信号形式实现 bridge
  • 支持 presentpush
  • fullscreen 控制模态展示样式
  • tel: / uni.makePhoneCall 做了 bridge 接管
  • 已接通:定位、相册选图、拍照、保存到相册、打开设置、拨号

常见错误码

通用

  • bridge_unavailable
  • invalid_url
  • activity_unavailable
  • unsupported

定位

  • location_permission_denied
  • location_provider_disabled
  • location_timeout
  • location_busy
  • location_unavailable

相册 / 图片

  • picker_busy
  • picker_unavailable
  • invalid_image
  • image_permission_denied
  • cancel

拍照

  • camera_permission_denied
  • camera_unavailable
  • camera_busy

保存图片

  • invalid_image_url
  • save_permission_denied
  • save_failed
  • save_busy

拨号

  • invalid_phone_number
  • call_permission_denied
  • call_unavailable
  • call_busy

权限说明

Android Manifest

当前插件声明了这些权限:

  • android.permission.INTERNET
  • android.permission.CALL_PHONE
  • android.permission.CAMERA
  • android.permission.RECORD_AUDIO
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.READ_MEDIA_IMAGES
  • android.permission.READ_EXTERNAL_STORAGE
  • android.permission.WRITE_EXTERNAL_STORAGE maxSdkVersion="28"

文件位置:

新增权限后,需要重新打自定义基座或重新打包,纯热更新不会生效。

iOS

iOS 侧涉及:

  • 定位权限
  • 相册读取权限
  • 相册写入权限
  • 相机权限

如果目标项目要独立复用这个插件,记得同步补齐对应的 Info.plist 权限文案。

其他项目复用建议

如果要在别的 uni-app x 项目复用,建议最少做这几步:

  1. 复制整个 uni_modules/cf-uniwebview 目录。
  2. 在目标项目新建自己的包装层,不要让业务代码直接依赖插件本体。
  3. 在包装层里补默认的域名、平台标识、token、UA。
  4. 按目标项目实际情况补齐 Android 权限和 iOS 权限描述。
  5. 如果 H5 侧想使用 Promise,再在 H5 项目里封一层自己的 helper。

1.0.0(2026-06-13) 下载此版本

cf-uniwebview 接入说明

cf-uniwebview 用来在 App 内打开原生 WebView,并给 H5 提供一层统一 JSBridge。

当前仓库里它分成两部分:

原生实现位置:

App 侧用法

打开网页

import { openNativeWebView } from '@/services/native/webview-plugin.uts'

openNativeWebView({
  linkUrl: 'https://example.com',
  platformName: 'xxxxxx',
  platformCode: 'accountbutler',
  customUserAgent: 'your-ua',
  topBarHidden: false,
  openMode: 'present',
  animated: true,
  fullscreen: true
}, (res : any) => {
  console.log('webview callback =', res)
})

参数说明

  • linkUrl: 打开的地址
  • platformName: 传给 H5 的平台名
  • platformCode: 传给 H5 的平台编码
  • token: 传给 H5 的 token
  • customUserAgent: 自定义 UA
  • topBarHidden: 是否隐藏原生导航栏
  • openMode: 'present''push'
  • animated: 是否带动画
  • fullscreen: 是否全屏模态展示
  • origin: 原样透传给 H5 的扩展字段

App 回调

H5 关闭并回传:

{
  action: 'plugWebView',
  data: {
    success: true,
    orderId: '123456'
  }
}

H5 持续发消息:

{
  action: 'postMessage',
  data: {
    type: 'stepChange',
    step: 2
  }
}

用户主动关闭:

{
  action: 'dismiss'
}

H5 侧用法

推荐直接使用:

import {
  getPlugData,
  getDeviceInfo,
  getLocation,
  getLoaction,
  openAppSettings,
  openNativeUrl,
  postMessageToApp,
  copyText,
  getImageFromPhotoLibrary,
  takePhoto,
  saveImageToLibrary,
  callPhone,
  plugWebView
} from '@/uni_modules/cf-uniwebview/utssdk/webview-bridge.js'

这些方法同时支持:

  • Promise 风格
  • callback 风格

例如:

const info = await getDeviceInfo()
getDeviceInfo((info) => {
  console.log(info)
})

H5 能力清单

获取 App 传参

const plugData = await getPlugData()

通常会返回:

  • platformName
  • platformCode
  • linkUrl
  • token
  • topBarHidden
  • fullscreen
  • openMode
  • animated
  • origin

获取设备信息

const deviceInfo = await getDeviceInfo()

获取定位

const location = await getLocation()

兼容旧拼写:

const location = await getLoaction()

成功示例:

{
  success: true,
  locationSuccess: true,
  errorMsg: '',
  latitude: 31.2304,
  longitude: 121.4737,
  accuracy: 35,
  location: {
    latitude: '31.2304',
    longitude: '121.4737'
  }
}

常见失败值:

  • location_permission_denied
  • location_provider_disabled
  • location_timeout
  • location_busy

打开系统设置页

await openAppSettings()

打开外部链接

await openNativeUrl({
  url: 'weixin://',
  fallbackUrl: 'https://weixin.qq.com/'
})

支持:

  • url
  • fallbackUrl
  • failOpenUrl
  • backupUrl

给 App 发消息但不关闭页面

await postMessageToApp({
  type: 'progress',
  value: 50
})

关闭页面并回传

await plugWebView({
  success: true,
  orderId: '123456'
})

复制文本

await copyText('abc123')

从相册选图

const image = await getImageFromPhotoLibrary()

需要 base64

const image = await getImageFromPhotoLibrary({
  returnBase64: true
})

返回示例:

{
  success: true,
  fileName: 'image.jpg',
  mimeType: 'image/jpeg',
  size: 12345,
  tempFilePath: '/.../cache/xxx-image.jpg',
  base64: 'data:image/jpeg;base64,...'
}

拍照

const photo = await takePhoto()

需要 base64

const photo = await takePhoto({
  returnBase64: true
})

返回结构和 getImageFromPhotoLibrary() 对齐。

保存图片到相册

await saveImageToLibrary({
  url: 'https://example.com/test.jpg'
})

支持这些输入:

  • 远程图片 URL
  • data:image/...;base64,...
  • content://...
  • file://...
  • 本地绝对路径

成功示例:

{
  success: true,
  savedUri: 'content://...',
  fileName: 'image.jpg',
  mimeType: 'image/jpeg',
  size: 12345
}

拨打电话

await callPhone({
  phoneNumber: '***'
})

也支持:

await callPhone('***')
await callPhone({ mobile: '***' })
await callPhone({ tel: '***' })
await callPhone({ phone: '***' })

直接使用 JSBridge

如果不想引入 webview-bridge.js,也可以直接调用:

window.WebViewJavascriptBridge.callHandler('getPlugData', null, cb)
window.WebViewJavascriptBridge.callHandler('getDeviceInfo', null, cb)
window.WebViewJavascriptBridge.callHandler('getLocation', null, cb)
window.WebViewJavascriptBridge.callHandler('openAppSettings', null, cb)
window.WebViewJavascriptBridge.callHandler('openUrl', { url: 'weixin://' }, cb)
window.WebViewJavascriptBridge.callHandler('postMessageToApp', { type: 'x' }, cb)
window.WebViewJavascriptBridge.callHandler('copyText', { text: 'abc123' }, cb)
window.WebViewJavascriptBridge.callHandler('getImageFromPhotoLibrary', { returnBase64: true }, cb)
window.WebViewJavascriptBridge.callHandler('takePhoto', { returnBase64: true }, cb)
window.WebViewJavascriptBridge.callHandler('saveImageToLibrary', { url: 'https://example.com/test.jpg' }, cb)
window.WebViewJavascriptBridge.callHandler('callPhone', { phoneNumber: '***' }, cb)
window.WebViewJavascriptBridge.callHandler('plugWebView', { success: true }, cb)

平台说明

Android

  • 使用 WebView URL 拦截形式实现桥接
  • getLocation() 已接通,并带权限申请
  • getImageFromPhotoLibrary() 已接通
  • takePhoto() 已接通
  • saveImageToLibrary() 已接通
  • callPhone() 已接通
  • 内嵌 H5 的 uni.chooseImage() 已做原生兜底

iOS

  • 使用注入脚本 + 轮询信号形式实现桥接
  • openNativeUrl({ url: 'tel://' }) 可用于拨号
  • callPhone() 内部也是复用 openNativeUrl 打开 tel://
  • 图片、定位、保存图片等能力已接通

常见错误码

通用

  • bridge_unavailable: 当前不在原生 WebView 环境,或桥尚未注入完成
  • invalid_url: 传入的链接无效
  • activity_unavailable: 当前原生页面或宿主上下文不可用

定位

  • location_permission_denied: 定位权限被拒绝
  • location_provider_disabled: 系统定位服务未开启
  • location_timeout: 定位超时
  • location_busy: 已有一个定位请求正在进行
  • location_unavailable: 当前设备无法提供定位能力

相册 / 图片

  • picker_busy: 已有一个选图流程正在进行
  • picker_unavailable: 当前设备无法拉起系统选图
  • invalid_image: 图片读取失败或返回内容无效
  • image_permission_denied: 图片读取兜底权限被拒绝
  • cancel: 用户取消了选图

拍照

  • camera_permission_denied: 相机权限被拒绝
  • camera_unavailable: 当前设备无法拉起系统相机
  • camera_busy: 已有一个拍照流程正在进行

保存图片

  • invalid_image_url: 图片地址为空或格式不支持
  • save_permission_denied: 保存图片权限被拒绝
  • save_failed: 保存到系统相册失败
  • save_busy: 已有一个保存流程正在进行

拨号

  • invalid_phone_number: 手机号为空或格式无效
  • call_permission_denied: 电话权限被拒绝
  • call_unavailable: 当前设备无法发起拨号
  • call_busy: 已有一个拨号流程正在进行

权限说明

Android Manifest

当前插件会用到这些权限:

  • android.permission.INTERNET
  • android.permission.CALL_PHONE
  • android.permission.CAMERA
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.READ_MEDIA_IMAGES
  • android.permission.READ_EXTERNAL_STORAGE
  • android.permission.WRITE_EXTERNAL_STORAGE maxSdkVersion="28"

新增权限后,需要重新打自定义基座或重新打安装包,纯热更新不会生效。

iOS

图片、相机、定位、电话能力都依赖系统本身的权限或能力状态,请同步检查宿主工程的权限说明文案。


平台兼容性

uni-app x(4.21)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × 7.0 13 - ×

隐私、权限声明

1. 本插件需要申请的系统权限列表:

存储,相册,定位,电话,麦克风

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。