天天看點

uni-app技術分享| uni-app轉小程式-實時消息

微信小程式 實作實時消息與 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;

	}
           

繼續閱讀