快速集成 uni-app 源码(Vue 3)
更新时间: 2024/08/20 15:45:46
IM uni-app Demo 是基于网易云信 NIM SDK 的一款 uni-app Demo,它提供了一些通用的功能,包含会话、聊天、群组等,您可以基于源码搭建您的 IM 业务逻辑。
界面效果
IM uni-app Demo 的部分界面效果如下:
平台支持
当前 IM uni-app Demo 仅支持 Android、iOS、H5、和微信小程序。
前提条件
开始跑通 Demo 之前,请确保:
-
已 注册网易云信 IM 账号,获取账号 ID 和 token。
-
开发环境满足如下要求:
- HBuilderX
- Vue 3
- TypeScript
- sass(sass-loader 版本 <= 10.1.1)
- node(12.13.0 <= node 版本 <= 17.0.0, 推荐使用 Node.js 官方 LTS 版本 16.17.0)
- npm(版本请与 node 版本匹配)
集成源码
步骤 1:创建 uni-app 项目
创建 uni-app 项目,详情参考 uni-app 官网。
如已创建项目,请忽略本步骤。
步骤 2:下载 NEUIKit 组件
运行以下命令将 NEUIKit GitHub 源码项目 nim-uikit-uniapp.git 下载到 uni-app 项目中:
Bash# 找一个目录,clone 组件项目
git clone https://github.com/netease-kit/nim-uikit-uniapp.git
# 在您的项目根目录下执行以下命令,拷贝组件
mkdir -p ./pages/NEUIKit
# macOS
mv ${组件项目路径}/NEUIKit/* ./pages/NEUIKit
# windows
move ${组件项目路径}/NEUIKit/* .\pages\NEUIKit
下载成功后,目录结构如下图所示:
步骤 3:添加依赖和图片引入
-
在项目的根目录下添加依赖和图片引入。
Bash
npm init -y npm i @xkit-yx/core-kit@0.13.0 @xkit-yx/im-store@0.3.0 @xkit-yx/utils@0.5.6 dayjs@1.11.7 mobx@6.6.1 pinyin@3.1.0 --save
-
在您的项目根目录下执行以下命令,将组件需要的图片复制到
static
目录下,若命令执行不成功,请按照路径手动复制。Bash
mkdir -p static
-
当前静态资源放置在网易对象存储(Netease Object Storage,NOS) 中,您可通过链接的方式在组件中进行访问。
由于访问频率有限制,建议您将静态资源放置在您的 业务服务器 上,然后修改
/pages/NEUIKit/components/Icon.vue
组件中的链接即可。Bash
# macOS cp -r pages/NEUIKit/static static/YX_IMG # windows xcopy /E pages\NEUIKit\static static\YX_IMG
步骤 4:引入并初始化组件
在 App.vue
文件引入 NEUIKit 组件并进行初始化。
JSX<script>
import RootStore from '@xkit-yx/im-store'
import { NimKitCore } from '@xkit-yx/core-kit/dist/uniapp-nim-core'
import { getMsgContentTipByType } from './pages/NEUIKit/utils/msg'
import { getUniPlatform } from './pages/NEUIKit/utils'
// #ifdef APP-PLUS
const nimPushPlugin = uni.requireNativePlugin('NIMUniPlugin-PluginModule')
// #endif
export default {
onLaunch: function () {
const isWeixinApp = getUniPlatform() === 'mp-weixin'
// @ts-ignore
const nim = uni.$UIKitNIM = new NimKitCore({
initOptions: {
"appkey": "", // 请填写您的 appkey
"account": "", // 请填写您的 account
"token": "", // 请填写您的 token
"lbsUrls": isWeixinApp ? [
"https://lbs.netease.im/lbs/wxwebconf.jsp"
] : [
"https://lbs.netease.im/lbs/webconf.jsp"
],
"linkUrl": isWeixinApp ? 'wlnimsc0.netease.im' : 'weblink.netease.im',
"needReconnect": true,
/**
* 使用固定设备 ID,
*/
isFixedDeviceId: true,
// "reconnectionAttempts": 5,
debugLevel: 'debug',
},
platform: 'UniApp',
})
// @ts-ignore
const store = uni.$UIKitStore = new RootStore(nim, {
addFriendNeedVerify: false,
teamBeInviteMode: 'noVerify',
teamJoinMode: 'noVerify',
teamUpdateExtMode: 'all',
teamUpdateTeamMode: 'all',
teamInviteMode: 'all',
sendMsgBefore: async (options, type) => {
const pushContent = getMsgContentTipByType({ body: options.body, type })
const yxAitMsg = options.ext ? options.ext.yxAitMsg : { forcePushIDsList: '[]', needForcePush: false }
// 如果是 at 消息,需要走离线强推
const { forcePushIDsList, needForcePush } = yxAitMsg
// @ts-ignore
? store.msgStore._formatExtAitToPushInfo(yxAitMsg, options.body)
: { forcePushIDsList: '[]', needForcePush: false }
console.log('forcePushIDsList: ', forcePushIDsList)
// 不同产商的推送消息体
const { scene, to } = options
const pushPayload = JSON.stringify({
// oppo
oppoField: {
"click_action_type": 4, // 参考 oppo 官网
"click_action_activity": '', // 各端不一样 TODO
"action_parameters": { "sessionId": scene, "sessionType": to } // 自定义
},
// vivo
vivoField: {
"pushMode": 0 //推送模式 0:正式推送。1:测试推送,不填默认为 0。
},
// huawei
hwField: {
click_action: {
'type': 1,
'action': '' // 各端不一样 TODO
},
androidConfig: {
'category': 'IM',
'data': JSON.stringify({ 'sessionId': to, 'sessionType': scene })
}
},
// 通用
sessionId: to,
sessionType: scene
})
const pushInfo = {
needPush: true,
needPushBadge: true,
pushPayload: '{}',
pushContent,
needForcePush,
forcePushIDsList,
forcePushContent: pushContent,
}
return { ...options, pushInfo }
},
})
// #ifdef APP-PLUS
// 注册推送
nim.getNIM().offlinePush.setOfflinePushConfig({
plugin: nimPushPlugin,
authConfig: {
// xiaomi
xmAppId: "",
xmAppKey: "",
xmCertificateName: "KIT_UNIAPP_MI_PUSH",
// huawei
hwAppId: "",
hwCertificateName: "KIT_UNIAPP_HW_PUSH",
// oppo
oppoAppId: "",
oppoAppKey: "",
oppoAppSecret: "",
oppoCertificateName: "KIT_UNIAPP_OPPO_PUSH",
/**
* 注意 vivo 的 appid 和 appkey 需要同时在此处,以及 manifest.json(即插件参数配置)中配置
*/
vivoAppId: "",
vivoAppKey: "",
vivoCertificateName: "KIT_UNIAPP_VIVO_PUSH",
// fcm
fcmCertificateName: "KIT_UNIAPP_FCM_PUSH",
// meizu
mzAppId: "",
mzAppKey: "",
mzCertificateName: "KIT_UNIAPP_MZ_PUSH",
// iOS
apnsCertificateName: "dis_im_uniapp"
}
})
// #endif
nim.connect()
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
}
}
</script>
<style>
uni-page-body {
height: 100%;
}
uni-page-body > uni-view {
height: 100%;
}
</style>
在初始化 NimKitCore 时,需要根据是否是微信小程序,传入不同的 lbsUrls
和 linkUrl
。
单击查看具体示例。
JavaScriptconst nim = (uni.$UIKitNIM = new NimKitCore({
initOptions: {
appkey: "", // 请填写您的 appkey
account: "", // 请填写您的 account
token: "", // 请填写您的 token
lbsUrls: isWeixinApp
? ["https://lbs.netease.im/lbs/wxwebconf.jsp"]
: ["https://lbs.netease.im/lbs/webconf.jsp"],
linkUrl: isWeixinApp ? "wlnimsc0.netease.im" : "weblink.netease.im",
needReconnect: true,
/**
* 使用固定设备 ID,
*/
isFixedDeviceId: true,
// "reconnectionAttempts": 5,
debugLevel: "debug",
},
platform: "UniApp",
}));
步骤 5:配置路由
在 pages/NEUIKit/utils/customNavigate.ts 中,修改 preUrl:
JavaScriptconst preUrl = '/pages/NEUIKit'
在您项目的 pages.json
文件中的更新 pages
路由:
JSON{
"pages": [
{
"path": "pages/NEUIKit/pages/Conversation/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Login/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Chat/message/p2p-set",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/group-info-edit",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Contact/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Contact/contact-list/group-list",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Contact/contact-list/valid-list",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Contact/contact-list/black-list",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Chat/index",
"style": {
"navigationBarBackgroundColor": "#F6F8FA",
"navigationBarTextStyle": "black",
"navigationStyle": "custom",
"enablePullDownRefresh": false,
"app-plus": {
"softinputNavBar": "none",
"bounce": "none"
}
}
},
{
"path": "pages/NEUIKit/pages/Chat/video-play",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-member/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-create/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-add/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Friend/add-friend/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/user-card/friend/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/user-card/my/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/user-card/my/setting",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/user-card/my-detail/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/user-card/detail-item/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/nick-in-team",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/group-manage",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/transform-team",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/group-manager-list",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Group/group-set/add-group-manager",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/NEUIKit/pages/Chat/forward",
"style": {
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black"
},
"tabBar": {
"backgroundColor": "#F6F8FA",
"color": "#999999",
"selectedColor": "#337EFF",
"height": "60px",
"list": [
{
"text": "消息",
"iconPath": "static/YX_IMG/conversation.png",
"selectedIconPath": "static/YX_IMG/conversation-selected.png",
"pagePath": "pages/NEUIKit/pages/Conversation/index"
},
{
"text": "通讯录",
"iconPath": "static/YX_IMG/contact.png",
"selectedIconPath": "static/YX_IMG/contact-selected.png",
"pagePath": "pages/NEUIKit/pages/Contact/index"
},
{
"text": "我的",
"pagePath": "pages/NEUIKit/pages/user-card/my/index",
"iconPath": "static/YX_IMG/me.png",
"selectedIconPath": "static/YX_IMG/me-selected.png"
}
]
}
}
步骤 6:运行 Demo
在 uni-app IDE 中,运行 Demo:
Demo 源码地址
请前往 网易云信 GitHub 开源代码仓库 获取源码。
自定义开发
API 参考
IM uni-app Demo 基于 UIKitStore 开发,相关 API 详情请参考 UIKitStore。
例如,您想获取 IM uni-app UIKit 的会话未读数,示例代码如下:
JavaScriptconst unRead = store.uiStore.sessionUnread
使用原生 SDK 中的方法
如果您需要自行实现目前 uni-app UIKit 还未实现,但原生的 IM uni-app SDK 已提供的能力。您可以通过调用原生 IM uni-app SDK 中提供的接口来实现。原生 uni-app SDK 中的接口请参考对应的 API 文档。
JavaScriptuni.$UIKitNIM = new NimKitCore({
initOptions: {
appkey: '',
lbsUrls: isWeixinApp
? ['https://lbs.netease.im/lbs/wxwebconf.jsp']
: ['https://lbs.netease.im/lbs/webconf.jsp'],
linkUrl: isWeixinApp ? 'wlnimsc0.netease.im' : 'weblink.netease.im',
needReconnect: true,
/**
* 使用固定设备 ID,
*/
isFixedDeviceId: true,
// "reconnectionAttempts": 5,
debugLevel: 'debug',
...opts,
},
platform: 'UniApp',
})
例如,您想对 IM uni-app UIKit 的消息历史进行全文检索(按时间分页搜索),可以调用原生 SDK 中的 msgFtsInServerByTiming
方法,示例代码如下:
JavaScriptuni.$UIKitNIM.nim.msgFtsInServerByTiming({
keyword: '您好',
})
示例中的 uni.$UIKitNIM.nim
为原生 NIM uni-app SDK 的实例。
常见问题
无法正常打开相册
相册拒绝授权后再次开启授权,由于 uni-app API 兼容问题,部分 Android 机型无法正常打开相册,需要您自行处理。
iOS 低版本构建后无法运行
如果 iOS 低版本构建后无法运行,需在构建出的资源 dist/build/app/app-service.js
文件最前面添加 var globalThis = Function('return this')();
。
uni-app 兼容问题
部分 uni-app 兼容问题,已在代码中说明。
page 结构问题
由于 uni-app 自身的 uni.setNavigationBarTitle 限制,chat 页面的 NavigationBarTitle,需要您自行调整 page 结构设置。
uni-app 推送问题
uni-app 推送相关问题请参考 uni-app 离线推送。
业务登录问题
您业务侧的登录需要结合网易云信 IM 的登录实现。
在您的登录页完成登录后,将您的业务服务器返回的 account、token 传入 app.vue 里的初始化登录 IM 的方法,待 IM 初始化、连接完成后,再重定向到您需要的界面。
无法切换深色模式
目前 Demo 不支持深色模式。如需要深色模式,需要您在业务侧自行适配。
uni_modules 问题
NEUIKit 中使用到的 uni-app 提供的部分组件(例如 uni-popup),如果使用上产生冲突,您需要将 NEUIKit 的 uni-modules 与您使用的 uni-modules 进行合并,然后修改 NEUIkit 中引用的路径即可。
视频/语音模块离线打包问题
参考 uni-app 官网的 离线打包。
H5 断网重连问题
若遇到 H5 断网重连失败的问题,请在 manifest.json
中,修改配置,示例如下:
JSON"optimization" : {
"treeShaking" : {
"enable" : false
}
}