微信小程式 實作實時消息與 uniapp 轉碼成微信小程式 實作實時消息兩者是一樣的,差別僅僅是一個是原生小程式一個是 uniapp 轉碼成小程式。
本文主要簡單實作點對點消息與呼叫邀請等相關功能實作。
uniapp轉碼成小程式邏輯與小程式邏輯基本一緻。
引入 RTM SDK
使用 web RTM-SDK 即可,小程式的實時消息與 WEB 的實時消息共用 SDK。
使用 1.0.5 版本,否則轉成小程式時可能會無法正常使用
npm i [email protected]
// 引入 anyRTM
import ArRTM from "ar-rtm-sdk"
代碼封裝
你可以在頁面裡邊直接調用,也可單獨封裝成一個 js。
本人喜歡将 RTM 封裝成一個 js 檔案。
本地存放
const Store = {
// RTM 用戶端
rtmClient: null,
// 主叫邀請執行個體
localInvitation: null,
// 被叫收到的邀請執行個體
remoteInvitation: null,
}
回調封裝
本文僅進行簡單封裝,如需更複雜邏輯請自行更改。
// RTM 監聽事件
const rtmEvent = {
// 主叫:被叫已收到呼叫邀請
localInvitationReceivedByPeer: () => {
uni.hideToast();
uni.showToast({
title: '被叫已收到呼叫邀請',
icon: 'none',
duration: 2000,
mask: true,
});
},
// 主叫:被叫已接受呼叫邀請
localInvitationAccepted: async (response) => {
console.log("主叫:被叫已接受呼叫邀請", response);
uni.hideToast();
uni.showToast({
title: '被叫接受呼叫邀請',
icon: 'none',
duration: 2000,
mask: true,
});
},
// 主叫:被叫拒絕了你的呼叫邀請
localInvitationRefused: (response) => {
console.log("主叫:被叫拒絕了你的呼叫邀請", response);
uni.hideToast();
uni.showToast({
title: '被叫拒絕呼叫邀請',
icon: 'none',
duration: 2000,
mask: true,
});
},
// 主叫:呼叫邀請程序失敗
localInvitationFailure: (response) => {
console.log("主叫:呼叫邀請程序失敗", response);
uni.hideToast();
uni.showToast({
title: '呼叫邀請失敗',
icon: 'error',
duration: 2000,
mask: true,
});
},
// 主叫:呼叫邀請已被成功取消 (主動挂斷)
localInvitationCanceled: () => {
console.log("主叫:呼叫邀請已被成功取消 (主動挂斷)");
},
// 被叫:監聽收到來自主叫的呼叫邀請
RemoteInvitationReceived: async (remoteInvitation) => {
console.log("監聽收到來自主叫的呼叫邀請", remoteInvitation);
// 監聽回調
rtmInternal.inviteProcessing(remoteInvitation)
// 顯示模态彈窗
uni.showModal({
title: '提示',
content: '收到來自主叫的呼叫邀請',
cancelText: '拒絕',
confirmText: '接聽',
success: function(res) {
if (res.confirm) {
console.log('使用者點選确定');
remoteInvitation.accept();
} else if (res.cancel) {
console.log('使用者點選取消');
remoteInvitation.refuse();
}
}
});
},
// 被叫:監聽接受呼叫邀請
RemoteInvitationAccepted: async () => {
console.log("被叫 接受呼叫邀請");
uni.hideToast();
uni.showToast({
title: '接受呼叫邀請',
icon: 'success',
duration: 2000,
mask: true,
});
},
// 被叫:監聽拒絕呼叫邀請
RemoteInvitationRefused: () => {
console.log("被叫 拒絕呼叫邀請");
uni.hideToast();
uni.showToast({
title: '拒絕呼叫邀請',
icon: 'success',
duration: 2000,
mask: true,
});
},
// 被叫:監聽主叫取消呼叫邀請
RemoteInvitationCanceled: () => {
console.log("主叫 取消呼叫邀請");
uni.hideToast();
uni.showToast({
title: '主叫取消呼叫',
icon: 'success',
duration: 2000,
mask: true,
});
},
// 被叫:監聽呼叫邀請程序失敗
RemoteInvitationFailure: () => {
console.log("被叫 呼叫邀請程序失敗");
uni.hideToast();
uni.showToast({
title: '呼叫邀請失敗',
icon: 'error',
duration: 2000,
mask: true,
});
},
// 收到來自對端的點對點消息
MessageFromPeer: (message, peerId) => {
console.log("收到來自對端的點對點消息", message, peerId);
uni.showToast({
title: '收到' + peerId + '的點對點消息:' + message.text,
icon: 'none',
duration: 1000 * 5
})
},
// 通知 SDK 與 RTM 系統的連接配接狀态發生了改變
ConnectionStateChanged: (newState, reason) => {
console.log("系統的連接配接狀态發生了改變", newState);
switch (newState) {
case "CONNECTED":
uni.hideLoading();
// SDK 已登入 RTM 系統
uni.showToast({
title: 'RTM 連接配接成功',
icon: 'success',
mask: true,
})
break;
case "ABORTED":
uni.showToast({
title: 'RTM 停止登入',
icon: 'error',
mask: true,
});
console.log("RTM 停止登入,重新登入");
break;
default:
wx.showLoading({
title: 'RTM 連接配接中',
mask: true,
})
break;
}
}
}
登入 RTM 系統
// 初始化
export const InItRtm = async (Config) => {
// 建立 RTM 用戶端
Store.rtmClient = await ArRTM.createInstance(Config.AppID);
// RTM 版本
console.log("RTM 版本", ArRTM.VERSION);
uni.showLoading({
title: '登入中',
mask: true
})
// 登入 RTM
await Store.rtmClient.login({
token: "",
uid: Config.userId
}).then(() => {
uni.hideLoading();
uni.showToast({
title: '登入成功',
icon: 'success',
duration: 2000
})
console.log("登入成功");
// 監聽收到來自主叫的呼叫邀請
Store.rtmClient.on(
"RemoteInvitationReceived",
rtmEvent.RemoteInvitationReceived
);
// 監聽收到來自對端的點對點消息
Store.rtmClient.on("MessageFromPeer", rtmEvent.MessageFromPeer);
// 通知 SDK 與 RTM 系統的連接配接狀态發生了改變
Store.rtmClient.on(
"ConnectionStateChanged",
rtmEvent.ConnectionStateChanged
);
}).catch((err) => {
Store.userId = "";
uni.hideLoading();
uni.showToast({
icon: 'error',
title: 'RTM 登入失敗',
mask: true,
duration: 2000
});
console.log("RTM 登入失敗", err);
});
}
邏輯方法封裝
// RTM 内部邏輯
export const rtmInternal = {
...
}
查詢呼叫使用者是否線上
// 查詢呼叫使用者是否線上
peerUserQuery: async (uid) => {
const oUserStatus = await Store.rtmClient.queryPeersOnlineStatus([uid]);
if (!oUserStatus[uid]) {
uni.showToast({
title: '使用者不線上',
icon: 'error',
duration: 2000,
mask: true,
});
return false;
}
return true;
},
發起呼叫
// 主叫發起呼叫
inviteSend: async (peerUserId) => {
Store.localInvitation = await Store.rtmClient.createLocalInvitation(
peerUserId
)
// 設定邀請内容
// Store.localInvitation.content = JSON.stringify({});
// 事件監聽
// 監聽被叫已收到呼叫邀請
Store.localInvitation.on(
"LocalInvitationReceivedByPeer",
rtmEvent.localInvitationReceivedByPeer
);
// 監聽被叫已接受呼叫邀請
Store.localInvitation.on(
"LocalInvitationAccepted",
rtmEvent.localInvitationAccepted
);
// 監聽被叫拒絕了你的呼叫邀請
Store.localInvitation.on(
"LocalInvitationRefused",
rtmEvent.localInvitationRefused
);
// 監聽呼叫邀請程序失敗
Store.localInvitation.on(
"LocalInvitationFailure",
rtmEvent.localInvitationFailure
);
// 監聽呼叫邀請已被成功取消
Store.localInvitation.on(
"LocalInvitationCanceled",
rtmEvent.localInvitationCanceled
);
// 發送邀請
Store.localInvitation.send();
},
取消呼叫
callCancel: () => {
if (Store.localInvitation) {
Store.localInvitation.cancel()
}
},
被叫邀請回調綁定
// 被叫收到呼叫邀請處理(給收到的邀請執行個體綁定事件)
inviteProcessing: async (remoteInvitation) => {
// 監聽接受呼叫邀請
remoteInvitation.on(
"RemoteInvitationAccepted",
rtmEvent.RemoteInvitationAccepted
);
// 監聽拒絕呼叫邀請
remoteInvitation.on(
"RemoteInvitationRefused",
rtmEvent.RemoteInvitationRefused
);
// 監聽主叫取消呼叫邀請
remoteInvitation.on(
"RemoteInvitationCanceled",
rtmEvent.RemoteInvitationCanceled
);
// 監聽呼叫邀請程序失敗
remoteInvitation.on(
"RemoteInvitationFailure",
rtmEvent.RemoteInvitationFailure
);
},
點對點消息發送
// 發送消息
sendMessage: (uid, message) => {
console.log("發送消息", uid, message);
Store.rtmClient && Store.rtmClient.sendMessageToPeer({
text: JSON.stringify(message)
}, uid).catch(err => {
console.log("發送消息失敗", err);
});
},
簡單頁面
html
<view class="content">
<view class="">
<text>使用者 ID:{{userId}}</text>
</view>
<view class="">
<!-- 登入 RTM 系統 -->
<button v-if="page === 0" type="primary" @click="loginRTM">登入 RTM 系統</button>
<!-- -->
<view v-else-if="page === 1" class="">
<button type="primary" @click="page=2">呼叫邀請</button>
<button type="primary" @click="page=3">發送消息</button>
</view>
<!-- 呼叫邀請 -->
<view v-else-if="page === 2" class="">
<!-- 遠端使用者 -->
<input class="input_automatic" v-model="peerId" type="text" placeholder="請輸入遠端使用者" />
<button type="primary" @click="invitationCall">發起呼叫</button>
<button type="primary" @click="invitationCallOff">取消呼叫</button>
</view>
<!-- 發送消息 -->
<view v-else class="">
<input type="text" class="input_automatic" v-model="peerId" placeholder="請輸入遠端使用者" />
<input type="text" class="input_automatic" v-model="sendText" placeholder="請輸入消息" />
<button type="primary" @click="sendMessage">發送</button>
</view>
</view>
</view>
js
import {
generateNumber
} from "../../until/until.js"; // 生成随機數
import {
InItRtm,
rtmInternal
} from "../../until/rtm.js"
export default {
data() {
return {
page: 0,
// 本地使用者
userId: '',
// 遠端使用者
peerId: '',
// 發送的資訊
sendText: ''
}
},
created() {
// 使用者 UID
this.userId = generateNumber(4) + ''
},
methods: {
/** 登入 RTM 系統 */
async loginRTM() {
const info = {
/**
* 必填 anyRTC 為 App 開發者簽發的 App ID。每個項目都應該有一個獨一無二的 App ID。
* 如果你的開發包裡沒有 App ID,請從anyRTC官網(https://www.anyrtc.io)申請一個新的 App ID
*/
AppID: '',
userId: this.userId
}
await InItRtm(info);
this.page = 1
},
/** 呼叫邀請 */
async invitationCall() {
if (this.peerId === '') return uni.showToast({
title: '請輸入遠端使用者',
icon: 'error',
});
if (this.peerId === this.userId) return uni.showToast({
title: '禁止遠端使用者與本地使用者一緻',
icon: 'none',
});
// 查詢使用者是否線上
const state = await rtmInternal.peerUserQuery(this.peerId);
if (state) {
rtmInternal.inviteSend(this.peerId)
} else {
return uni.showToast({
title: '使用者不線上',
icon: 'error',
});
}
},
invitationCallOff() {
rtmInternal.callCancel()
},
/** 發送消息 */
async sendMessage() {
if (this.peerId === '') return uni.showToast({
title: '請輸入遠端使用者',
icon: 'error',
});
if (this.peerId === this.userId) return uni.showToast({
title: '禁止遠端使用者與本地使用者一緻',
icon: 'none',
});
if (this.sendText === '') return uni.showToast({
title: '請輸入發送資訊',
icon: 'error',
});
// 查詢使用者是否線上
const state = await rtmInternal.peerUserQuery(this.peerId);
if (state) {
rtmInternal.sendMessage(this.peerId, this.sendText)
} else {
return uni.showToast({
title: '使用者不線上',
icon: 'error',
});
}
}
}
}
style
.input_automatic {
border: 1px solid;
height: 40px;
border-radius: 4px;
padding: 0 12px;
}