im2-link-jssdk 是 H5 小程序与宿主 App/WebView 之间的通信 SDK。Web 侧通过统一 API 请求宿主完成支付
、导航、系统分享、下载、网络请求等原生能力;SDK 负责平台识别、消息封装和回调分发。
本 README 以当前源码为准:公开方法、参数类型、消息类型和回调协议均与
src/index.ts、src/types/common.ts保持一致。
以上地址指向 npm 当前已发布版本的类型文档。仓库中的最新改动会在下次发布后同步到这两个地址。
npm install im2-link-jssdk
SDK 同时提供 ESM、CommonJS 和 TypeScript 类型声明。
import IMSDK from 'im2-link-jssdk';
const sdk = new IMSDK({
id: 'your-app-id',
token: 'your-app-token',
debug: false
});
sdk.share({
type: 'system',
param: {
title: '分享标题',
text: '分享描述',
shareUrl: 'https://example.com?share_source=tg',
imageUrl: 'https://example.com/share.png'
}
});
初始化参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string |
是 | 小程序 App ID |
token |
string |
是 | 小程序 App Token |
debug |
boolean |
否 | 是否打印 SDK 调试日志,默认 false |
window.location.hash 承载。index.html。window 和 navigator,不要在 SSR 服务端执行初始化。| API | 宿主消息类型 | 用途 |
|---|---|---|
platform |
- | 获取当前运行平台 |
callPayment |
payment |
拉起原生支付 |
callBack |
back |
通知宿主返回 |
callConversation |
conversation |
打开指定用户会话 |
callNavigate |
navigate |
调用宿主导航 |
permissions |
permissions |
请求宿主权限能力 |
callOpenMiniProgram |
openminiapp |
打开其他小程序 |
callSetBarColor |
barcolor |
设置状态栏颜色 |
callPopup |
popup |
拉起原生弹框 |
requestApi |
requireAPI |
由宿主发起网络请求 |
requestApp |
requireAPP |
与宿主交换业务数据 |
adjustInputBoxHeight |
inputBoxHeight |
调整输入框高度 |
switchLandscape |
landscape |
切换横屏状态 |
share |
share |
业务分享或系统分享 |
download |
download |
请求宿主下载视频 |
behaviorCaptcha |
behaviorCaptcha |
发送行为验证码结果 |
getCaptchaAccount |
captchaAccount |
索取登录页账号与区号 |
vibrate |
vibrate |
触发宿主系统振动 |
const platform = sdk.platform;
返回值为:
type Platform = 'win' | 'mac' | 'unix' | 'linux' | 'android' | 'ios' | 'unknown';
import { IMChainCurrencyEnum } from 'im2-link-jssdk';
sdk.callPayment(
{
amount: '99.00',
consumeType: 'goods',
chainCurrencyType: IMChainCurrencyEnum.CNY,
productOrderNo: 'ORDER-20260828-001',
productName: '商品名称',
quantity: '1'
},
(isSuccess) => {
console.log('支付是否成功:', isSuccess);
}
);
chainCurrencyType 可选值:CNY = 1、KKC = 2、VNC = 3。
支付参数可以省略;省略时表示只校验支付密码:
sdk.callPayment(undefined, (isSuccess) => {
console.log('支付密码校验结果:', isSuccess);
});
当初始化的 id 不等于字符串 '0' 时,SDK 会先校验 App ID 和 App Token,再向宿主发送支付消息。校验
失败只会输出 callPayment error,不会继续拉起支付。
callPayment 是当前唯一返回 Promise<void> 的公开方法。等待该 Promise 只表示前置校验和消息发送结束
,支付最终结果仍以回调为准。
sdk.callBack(() => {
console.log('宿主已处理返回');
});
sdk.callConversation('target-user-open-id', () => {
console.log('宿主已处理会话请求');
});
sdk.callNavigate(
{
actionType: 'external',
params: {
route: 'https://example.com'
}
},
() => {
console.log('宿主已处理导航请求');
}
);
当前约定的 actionType 包括:
| 值 | 用途 |
|---|---|
home |
首页 |
channel |
超级群,params 中传 channelId |
trad |
交易页面 |
inner |
内部链接,params 中传 route |
external |
外部链接,params 中传 route |
invite |
邀请页面 |
share |
系统分享入口 |
shortVideoSearch |
短视频搜索 |
customerService |
客服页面 |
actionType 在当前类型定义中是 string,表格列出的是宿主已约定的业务值。
sdk.permissions(
{
actionType: 'camera'
},
(result) => {
console.log('权限结果:', result);
}
);
params 当前使用 IMNavigateParams 结构,实际 actionType 及返回数据由宿主约定。
sdk.callOpenMiniProgram(
'miniapp://target-app',
{
source: 'current-app',
scene: 'detail'
},
() => {
console.log('宿主已处理打开请求');
}
);
第二个参数为可选的透传对象。若不需要透传参数,可传 undefined:
sdk.callOpenMiniProgram('miniapp://target-app', undefined, () => {
console.log('宿主已处理打开请求');
});
sdk.callSetBarColor(
{
titleColor: '#FFFFFF',
backgroundColor: '#1677FF'
},
() => {
console.log('颜色设置完成');
}
);
titleColor 和 backgroundColor 均为可选字符串,颜色格式由宿主解析。
sdk.callPopup(
{
url: 'https://example.com/popup',
ratio: 0.75,
popupType: 2
},
() => {
console.log('弹框已处理');
}
);
popupType:
| 值 | 展示方式 |
|---|---|
1 |
带标题栏 |
2 |
居中弹出 |
3 |
从底部向上覆盖 |
interface UserProfile {
id: string;
nickname: string;
}
sdk.requestApi<UserProfile>(
{
type: 'core',
url: '/v1/user/profile',
method: 'GET',
param: {
userId: '10001'
}
},
(data) => {
console.log(data.nickname);
}
);
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
'core' | 'wallet' |
否 | 请求服务类型,默认 'core' |
url |
string |
是 | 请求地址 |
method |
string |
是 | 请求方法,例如 GET、POST |
param |
Record<string, any> |
否 | 请求参数 |
sdk.requestApp<{ url: string }>(
{
method: 'h5-register',
param: {
locale: 'zh-CN'
}
},
(data) => {
console.log('注册页面:', data.url);
}
);
method 和 param 由 Web 与宿主共同约定;当前已记录的方法为 h5-register。
sdk.adjustInputBoxHeight(320, (result) => {
console.log('调整结果:', result);
});
高度单位和结果数据由宿主约定。
sdk.switchLandscape(true, (result) => {
console.log('切换结果:', result);
});
第一个参数默认值为 true;传 false 表示取消横屏。
share 通过 type 区分短视频、棋牌游戏和系统分享。
sdk.share(
{
type: 'shortVideo',
param: {
cover_url: 'https://example.com/cover.jpg',
description: '视频描述',
title: '视频标题',
user_id: '10001',
video_id: 'video-001'
}
},
(result) => {
console.log('分享结果:', result);
}
);
sdk.share(
{
type: 'cardGame',
param: {
show_type: 3,
game_path: '/room/10001',
game_preview_width: 375,
game_preview_height: 667,
game_preview_url: 'https://example.com/game-preview',
currencySource: 'CNY',
subGameName: {
ch: '游戏名称',
en: 'Game name'
}
}
},
(result) => {
console.log('分享结果:', result);
}
);
show_type 的含义:0 为默认旧样式,1 为不带链接的棋牌游戏样式,2 为带链接的棋牌游戏样式,3
为游戏预览。
sdk.share({
type: 'system',
param: {
title: '分享标题',
text: '分享描述',
shareUrl: 'https://example.com?share_source=tg',
imageUrl: 'https://example.com/share.png'
}
});
所有字段均为必填字符串:
| 字段 | 说明 |
|---|---|
title |
分享标题 |
text |
分享描述 |
shareUrl |
分享链接;游戏分享来源参数 share_source=tg 拼在此链接中 |
imageUrl |
分享图片 URL;宿主下载图片后用于图文分享 |
宿主收到的消息如下:
{
"type": "share",
"params": {
"type": "system",
"param": {
"title": "分享标题",
"text": "分享描述",
"shareUrl": "https://example.com?share_source=tg",
"imageUrl": "https://example.com/share.png"
}
},
"appid": "your-app-id",
"apptoken": "your-app-token"
}
系统分享与其他 share 类型一样,可以传入可选回调。
sdk.download(
{
fileType: 'video',
url: 'https://example.com/video.mp4'
},
(result) => {
console.log('下载结果:', result);
}
);
当前 fileType 仅支持 'video'。
sdk.behaviorCaptcha(
{
token: 'captcha-result-token'
},
() => {
console.log('验证码结果已发送给宿主');
}
);
此 API 用于 H5 完成滑动验证后,将验证码 token 透传给宿主。
验证码 token 获取失败时,也可沿用同一通道透传上游业务响应;SDK 不解析业务码或文案:
sdk.behaviorCaptcha({
code: 1038,
msg: '由业务服务返回的提示',
data: {}
});
成功结果仍保持 { token },以兼容既有 App。宿主可通过是否存在 params.token 区分成功与业务失败。
H5 通过 vibrate 通知宿主调用设备系统振动 / 触觉反馈。未传参数时按短振动处理。
// 默认短振动
sdk.vibrate();
// 短振动,指定强度
sdk.vibrate({ type: 'short', style: 'heavy' });
// 长振动
sdk.vibrate({ type: 'long' }, (isSuccess) => {
console.log('振动是否已触发:', isSuccess);
});
// 指定时长(毫秒),宿主按系统能力执行
sdk.vibrate({ duration: 200 });
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
'short' | 'long' |
否 | 振动类型,默认 'short' |
style |
'light' | 'medium' | 'heavy' |
否 | 短振动强度,仅 type 为 'short' 时生效 |
duration |
number |
否 | 振动时长(毫秒)。与 type 同时存在时,宿主优先按 duration 执行 |
宿主收到的消息如下:
{
"type": "vibrate",
"params": {
"type": "short",
"style": "heavy"
},
"appid": "your-app-id",
"apptoken": "your-app-token"
}
iOS 建议将 short + style 映射为 UIImpactFeedbackGenerator,long 映射为系统振动;Android 建议使用 VibrationEffect。桌面端和无振动能力的设备可直接回 isSuccess: 0。
本节供 iOS、Android、桌面端和 H5 容器开发者实现消息桥接。
| API | Web 侧收到的回调值 |
|---|---|
requestApi、requestApp |
宿主返回的业务数据 |
permissions |
宿主返回的权限数据 |
| 其他带回调的 API | isSuccess === 1 时为 true,否则为 false |
部分历史 API 的 TypeScript 回调签名为 () => void,调用方可以只把它当作完成通知;SDK 运行时仍会传入
上述布尔结果。
interface SDKMessage {
type: MessageTypeEnum;
params?: unknown;
callback?: string;
appid: string;
apptoken: string;
}
type:原生能力标识,见“API 概览”。params:对应 API 的业务参数。callback:调用方传入回调时由 SDK 生成;无回调时不发送该字段。appid、apptoken:初始化 SDK 时传入的身份信息。| 环境 | SDK 调用的宿主通道 | 消息形式 |
|---|---|---|
| iOS | window.webkit.messageHandlers.JSParent.postMessage(message) |
对象 |
| Android | window.JSParent.postMessage(JSON.stringify(message)) |
JSON 字符串 |
| Windows / Unix / Linux | window.miniJSParent.postMessage(message) |
对象 |
| macOS | 优先使用 webkit.messageHandlers.JSParent,否则使用 miniJSParent |
对象 |
| H5 iframe | window.parent.postMessage(message, '*') |
对象 |
消息带有 callback 时,原生宿主处理完成后应调用对应的全局回调:
// 普通原生能力:payment、navigate、share 等
window.IMCallBack[callback](
JSON.stringify({
isSuccess: 1,
callback
})
);
// requestApi、requestApp
window.receiveData[callback](JSON.stringify(responseData));
// permissions
window.permissions[callback](JSON.stringify(permissionData));
IMCallBack 中 isSuccess 为 1 时,Web 回调接收 true;其他值接收 false。receiveData 和
permissions 的数据会先经过安全 JSON 解析,以避免大整数精度丢失。
父页面通过 postMessage 返回:
iframeWindow.postMessage(
{
type: 'IMCallBack',
callback: message.callback,
data: {
isSuccess: 1
}
},
'*'
);
type 与调用类型的对应关系:
| SDK 调用 | 回调 type |
|---|---|
requestApi、requestApp |
receiveData |
permissions |
permissions |
| 其他带回调的 API | IMCallBack |
H5 宿主需要在父级 window 上注入:
window['h5-app-version'] = '宿主版本号';
跨域 iframe 无法读取父页面字段时,SDK 会按 H5 容器处理。SDK 只接收 event.source === window.parent
的标准浏览器消息;source === null 的回包会被拒绝,网页宿主应通过 IMSDK.web.createHost 绑定真实
iframe WindowProxy。
requestApi 回调在 30 秒后仍未收到响应时会被清理。SDK 面向 App WebView 和宿主 iframe。在普通浏览器顶层页面中,如果不存在原生桥且未注入
h5-app-version,调用不会发送给宿主;传入回调时,SDK 会以 undefined 调用该回调。
除默认导出的 IMSDK 外,包还导出:
MessageTypeEnum、IMSDKConfig、IMPaymentParams、IMNavigateParams、IMRequestParams、IMRequestAppParams、IMPopupParams、IMShareParams、IMSystemShareParams、IMDownLoadParams、IMBehaviorCaptchaParams、IMVibrateParams、IMChainCurrencyEnum
等。safeJSONParse、uuidv4、getOS、Md5。大整数 JSON 解析示例:
import { safeJSONParse } from 'im2-link-jssdk';
const data = safeJSONParse('[123456789123456789123456789, 2.3]');
// 超出 JavaScript 安全整数范围的数字以字符串形式保留
npm install
npm run build
npm run doc
npm run build:生成 ESM、CommonJS 和类型声明到 dist/。npm run doc:根据源码类型和注释生成 TypeDoc 到 docs/。>= 22.0.0。发布流程见 PUBLISH.md。
web网页容器可以直接使用 IMSDK.web.createHost(也可 import { web }),不需要创建游戏端 SDK 实例或传入 app token。该入口没有自动监听副作用,也不会改动 iOS/Android/PC 的原生桥。
import IMSDK from 'im2-link-jssdk';
const host = IMSDK.web.createHost({
getTarget: () => iframe.contentWindow ? {
source: iframe.contentWindow,
origin: new URL(iframe.src).origin,
key: `${currentAccountId}:${currentAppId}:${iframe.src}`
} : null,
onMessage: async (request) => {
if (request.message.type !== 'share') return;
// params 为 { type: 'cardGame', param: { show_type, game_path, ... } }。
// 宿主必须校验 message.appid 与当前 iframe 的可信应用资料,然后让用户选会话。
const accepted = await selectAndShare(request.message.params, request.signal);
request.reply('IMCallBack', { isSuccess: accepted ? 1 : 0 });
}
});
host.listen();
// iframe 关闭/重新加载、切账号和卸载时:
host.stop();
getTarget 必须来自宿主 iframe,不得用收到的 event.origin 或消息里的 appid 生成信任规则。origin 必须精确匹配,禁止 *。显式绑定 origin: 'null' 才接受 opaque iframe,此时回包使用浏览器要求的 *,仍严格绑定 WindowProxy。key 标识当前应用/账号/页面。异步工作前使用 request.isCurrent();重新加载同一地址时也应 stop() 后 listen(),中止旧业务。监听只校验窗口来源,不代替宿主的 app token/权限验证。reply('IMCallBack' | 'receiveData' | 'permissions', data) 自动带上原 callback,只能回复一次。停止或目标变化后的回复返回 false。业务回调 share(params, cb) 继续收到 boolean,不改变旧 API。onMessage 的 Promise 拒绝时回 {isSuccess:0,error:'HOST_ERROR'};可用 onError 接入宿主诊断,不应输出完整请求凭据。不支持的业务应由宿主明确回失败。additionalMessageTypes 注册;normalizeMessage 只用于拆开宿主已有扩展包装,执行前已经校验 source/origin。handleMessage(event);不要同时再把同一事件交给自己的业务处理器。web.parseMessage(value) 只做对象/JSON 结构解析,不做来源或权限验证。h5-app-version。原生环境仍优先现有原生桥。没有原生桥、没有标记的顶层独立页仍不冒充宿主。H5 游戏分享宿主将 isSuccess:1 定义为用户确认后,所有选中目标均被 IM 发送 API 接受;这不代表送达/已读。取消、忙碌、不可用及部分失败回 0,原始响应附带 status/sent/failed。iOS 现有分享没有实现结果回包,不应把“已弹出选择器”写为它的成功合同。