@bmsuisse/app-inative
BMS 应用的 Web 应用侧: 打入呼叫 window.BMSNative,该
app注入到每个网络应用中——有浏览器倒回,所以同一页
也运行在应用程序之外。 没有依赖关系, 不需要反应 .
后端对应 : bmsdna-app-native
(毕. 每个专题的详细指南: docs/,用于当地形式和
内容 土地平面导线(md)。 。 。 .
安装
npm install @bmsuisse/app-native
# or
bun add @bmsuisse/app-native
实例
import {
isNativeApp,
can,
on,
setChrome,
toast,
haptic,
share,
biometricConfirm,
scanBarcode,
scanBarcodes,
scanText,
setWidgets,
getAccessToken,
navigate,
addReminder,
saveContact,
callPhone,
toIsoWithOffset,
canShowNativeForms,
isNativeSurfaceUnsupported,
showForm,
showContent,
} from '@bmsuisse/app-native'
// Is the page running in the app? Does it have a given capability?
if (isNativeApp() && can('customChrome')) {
setChrome({
scope: 'route',
menu: [{ items: [{ id: 'new-order', label: 'New order', icon: 'plus' }] }],
actionButtons: [{ id: 'search', icon: 'magnifyingglass' }],
})
}
// Taps in the native menu — instead of setting window.onNativeMenuSelect yourself
const off = on('menuSelect', (id) => navigate(`/${id}`))
// Feedback
toast('Saved', 'success')
haptic('success')
// Share: app → native share sheet, browser → Web Share API / clipboard
await share({ title: 'Order 123', url: location.href })
// Face ID before a critical action (UX only, no proof for the backend)
const { ok } = await biometricConfirm('Approve order?')
// Scan a barcode; the result arrives as an event
on('barcodeScanned', (value) => lookup(value))
await scanBarcode()
// Or let the promise carry the result: several codes, or text from a label
// (docs/scan-guide.md). Keep a way to type the value in.
const codes = await scanBarcodes({ formats: ['ean13', 'qr'], max: 20 })
const serial = await scanText({ pattern: '[A-Z]{2}-\d{4,}' })
// Widgets on the native dashboard
await setWidgets([{ id: 'open-orders', kind: 'kpi', title: 'Open', data: { value: 12 } }])
// Entra token of the app's sign-in. Only needed where the browser cannot set a
// header (WebSocket, EventSource, …): fetch/XHR to your own backend get it automatically.
const session = await getAccessToken()
if (session.ok) socket.send(JSON.stringify({ token: session.token }))
// Other apps on the iPhone: route, reminder, contact, phone call
await navigate({ destination: { name: 'Müller AG', address: 'Industriestrasse 5, 4600 Olten' } })
await addReminder({ title: 'Call Mr. Meier back', due: toIsoWithOffset(new Date(2026, 9, 2, 9)) })
await saveContact({ givenName: 'Anna', organization: 'Müller AG', phones: ['+41 44 000 00 00'] })
await callPhone({ number: '+41 44 000 00 00' })
// Native form (an iOS sheet). The form stays open until your handler settles:
// `{ fieldErrors }` or a thrown error marks fields and lets the user correct.
if (canShowNativeForms()) {
const res = await showForm(
{
id: 'new-customer',
title: 'New customer',
fields: [
{ id: 'name', type: 'text', label: 'Company name', required: true },
{ id: 'email', type: 'email', label: 'Email', required: true },
{ id: 'card', type: 'photo', label: 'Business card', max: 1 },
],
},
{ onSubmit: async (values) => await api.createCustomer(values) }
)
if (!res.ok && isNativeSurfaceUnsupported(res)) openWebForm() // old app, no capability
} else {
openWebForm()
}
// Native content: info with blocks and buttons
const shown = await showContent({
title: 'Miller Ltd',
blocks: [
{ type: 'facts', items: [{ label: 'Phone', value: '+41 44 000 00 00', kind: 'phone' }] },
],
actions: [{ id: 'new-order', label: 'New order', style: 'primary' }],
})
应用程序外的行为
| 函数 | 浏览器 |
|---|---|
toast, (中文(简体) ), haptic, (中文(简体) ), setBadge, (中文(简体) ), setChrome | 无所作为 |
share | Web 共享 API, 否则剪贴板('copied'(中文(简体) ) |
openExternal | 新建标签 |
biometricConfirm | { ok: true } (网络流量继续) |
navigate | 在新标签中的 Google 地图 |
callPhone | tel: 链接 |
showForm, (中文(简体) ), showContent, (中文(简体) ), closeSurface | { ok: false, error: 'unavailable' } - 保持您的网络用户界面canShowNativeForms()(中文(简体) ) |
所有其他(setWidgets, (中文(简体) ), startLiveActivity, (中文(简体) ), scanDocument, (...) (中文(简体) ) | { ok: false, error: 'unavailable' } |
答复和错误
有回复的呼叫 { ok: true, … } 或者说 { ok: false, error }。 。 。 .
常见错误 : capability (该应用程序尚未赋予该能力)
网络应用程序, invalid, (中文(简体) ), cancelled, (中文(简体) ), unavailable, (中文(简体) ), notConfigured; 用于
getAccessToken (单位:千美元) forbidden 财务报告和审定财务报表 notSignedIn; 设备动作
denied; 用于 showForm编号 :showContent (单位:千美元) forbidden, (中文(简体) ), busy 财务报告和审定财务报表 tooLarge。 。 。 .
一个在呼叫答案之前的应用程序 unknownAction: 对待它像 unavailable。 。 。 .
can(capability) 但应用程序总是检查它的
拥有的.
概览
| 区域 | 职能 | 能力 |
|---|---|---|
| 检测 | isNativeApp, (中文(简体) ), nativeInfo, (中文(简体) ), can | – 说吧 – |
| 活动 | on('menuSelect' | 'actionButtonTap' | 'bottomBarTap' | 'barcodeScanned' | 'barcodesScanned' | 'textScanned', …) | – 说吧 – |
| 颜色 | setChrome, (中文(简体) ), centerProminentEntry | customChrome, (中文(简体) ), customBottomBar |
| 反馈 | toast, (中文(简体) ), haptic, (中文(简体) ), setBadge | – 说吧 – |
| 系统 | share, (中文(简体) ), openExternal, (中文(简体) ), biometricConfirm | – 说吧 – |
| 相机 | scanDocument, (中文(简体) ), scanBarcode, (中文(简体) ), scanBarcodes, (中文(简体) ), scanText, (中文(简体) ), canScan (单位:千美元)指南(中文(简体) ) | camera |
| 部件 | setWidgets, (中文(简体) ), updateWidget, (中文(简体) ), removeWidgets, (中文(简体) ), refreshWidgets | dashboardWidgets |
| 现场活动 | startLiveActivity, (中文(简体) ), updateLiveActivity, (中文(简体) ), endLiveActivity, (中文(简体) ), getLiveActivities | liveActivities |
| 核准 | refreshApprovals | approvals |
| 签名 | getAccessToken | identity |
| 其他应用程序 | navigate, (中文(简体) ), callPhone, (中文(简体) ), addReminder, (中文(简体) ), saveContact, (中文(简体) ), toIsoWithOffset | deviceApps (警报,联系) |
| 土著形式 | showForm, (中文(简体) ), canShowNativeForms, (中文(简体) ), formLimitWarnings | nativeForms (+ 数) camera (用于相机字段) |
| 原生内容 | showContent, (中文(简体) ), canShowNativeContent, (中文(简体) ), contentLimitWarnings | nativeContent (+ 数) deviceApps 页:1 saveContact编号 :addReminder 步骤) |
| 表面 | closeSurface, (中文(简体) ), surfaceResult, (中文(简体) ), isNativeSurfaceUnsupported, (中文(简体) ), on('surfaceAction', …), (中文(简体) ), onSurfaceAction | nativeForms 或者说 nativeContent |
| 测试 | sendTestNotification | notifications |
| 原始接入 | call, (中文(简体) ), post, (中文(简体) ), send | – 说吧 – |