当前位置:   article > 正文

Unity之webgl端通过vue3接入腾讯云联络中心SDK_unity sendmsgtovue

unity sendmsgtovue

腾讯云联络中心SDK:云联络中心 Web-SDK 开发指南-文档中心-腾讯云 (tencent.com)

1 首先下载Demo

 1.1 对其进行解压

 1.2根据文档操作

查看README.md,根据说明设置server下的dev.js里的相关参数。

然后打开电脑终端,cd到项目的路径:

安装依赖

 

运行

​ 

1.3 运行demo

复制http://127.0.0.1:5173/在浏览器里输入,这时候会显示如下画面:

输入电话号码,点击拨打就会把电话打出去。

​ 

 2 在Unity端的操作

2.1 创建Unity工程

 新建一个Unity工程,在Assets/Plugins/WebGl下创建一个后缀为jslib的文件,记事本打开编写脚本如下:

  1. mergeInto(LibraryManager.library, {
  2. ReportReady: function () {
  3. window.ReportReady()
  4. },
  5. TellPhone:function(typeName, phone){
  6. SendPhone(UTF8ToString(typeName), UTF8ToString(phone))
  7. }
  8. });

 2.2 编写挂载对象UIPanel上的脚本

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using UnityEngine;
  5. using UnityEngine.UI;
  6. using TMPro;
  7. public class UIPanel : MonoBehaviour
  8. {
  9. [DllImport("__Internal")]
  10. private static extern string ReportReady();
  11. [DllImport("__Internal")]
  12. private static extern string TellPhone(string type,string phone);
  13. public TextMeshProUGUI text;
  14. public TMP_InputField inputField;
  15. void Start()
  16. {
  17. ReportReady();//向vue报告脚本初始化完成
  18. }
  19. public void OpenPhone()
  20. {
  21. TellPhone("tellphone",inputField.text);
  22. }
  23. public void receiveMsgFromVue(string token) {
  24. text.text = token;
  25. Debug.Log("接受来自vue的消息 == " + token);
  26. }
  27. }

2.3 Unity的UI界面

2.4最后打包webgl的包

放在tccc-demo-vue\src\路径下,如下图所示:

 

2.5改写index.html

打开index.html:

SendPhone是Unity发送给网页的方法,sendMsgToUnity方法是网页发送个Unity的方法。

index.html完整代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en-us">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6. <title>Unity WebGL Player | Web731</title>
  7. <link rel="shortcut icon" href="TemplateData/favicon.ico">
  8. <link rel="stylesheet" href="TemplateData/style.css">
  9. </head>
  10. <body>
  11. <div id="unity-container" class="unity-desktop">
  12. <canvas id="unity-canvas" width=1920 height=1080></canvas>
  13. <div id="unity-loading-bar">
  14. <div id="unity-logo"></div>
  15. <div id="unity-progress-bar-empty">
  16. <div id="unity-progress-bar-full"></div>
  17. </div>
  18. </div>
  19. <div id="unity-warning"> </div>
  20. <div id="unity-footer">
  21. <div id="unity-webgl-logo"></div>
  22. <div id="unity-fullscreen-button"></div>
  23. <div id="unity-build-title">Web731</div>
  24. </div>
  25. </div>
  26. <script>
  27. var container = document.querySelector("#unity-container");
  28. var canvas = document.querySelector("#unity-canvas");
  29. var loadingBar = document.querySelector("#unity-loading-bar");
  30. var progressBarFull = document.querySelector("#unity-progress-bar-full");
  31. var fullscreenButton = document.querySelector("#unity-fullscreen-button");
  32. var warningBanner = document.querySelector("#unity-warning");
  33. // Shows a temporary message banner/ribbon for a few seconds, or
  34. // a permanent error message on top of the canvas if type=='error'.
  35. // If type=='warning', a yellow highlight color is used.
  36. // Modify or remove this function to customize the visually presented
  37. // way that non-critical warnings and error messages are presented to the
  38. // user.
  39. function unityShowBanner(msg, type) {
  40. function updateBannerVisibility() {
  41. warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
  42. }
  43. var div = document.createElement('div');
  44. div.innerHTML = msg;
  45. warningBanner.appendChild(div);
  46. if (type == 'error') div.style = 'background: red; padding: 10px;';
  47. else {
  48. if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
  49. setTimeout(function() {
  50. warningBanner.removeChild(div);
  51. updateBannerVisibility();
  52. }, 5000);
  53. }
  54. updateBannerVisibility();
  55. }
  56. var buildUrl = "Build";
  57. var loaderUrl = buildUrl + "/web0803.loader.js";
  58. var config = {
  59. dataUrl: buildUrl + "/web0803.data.unityweb",
  60. frameworkUrl: buildUrl + "/web0803.framework.js.unityweb",
  61. codeUrl: buildUrl + "/web0803.wasm.unityweb",
  62. streamingAssetsUrl: "StreamingAssets",
  63. companyName: "DefaultCompany",
  64. productName: "Web731",
  65. productVersion: "0.1",
  66. showBanner: unityShowBanner,
  67. };
  68. // By default Unity keeps WebGL canvas render target size matched with
  69. // the DOM size of the canvas element (scaled by window.devicePixelRatio)
  70. // Set this to false if you want to decouple this synchronization from
  71. // happening inside the engine, and you would instead like to size up
  72. // the canvas DOM size and WebGL render target sizes yourself.
  73. // config.matchWebGLToCanvasSize = false;
  74. if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
  75. container.className = "unity-mobile";
  76. // Avoid draining fillrate performance on mobile devices,
  77. // and default/override low DPI mode on mobile browsers.
  78. config.devicePixelRatio = 1;
  79. unityShowBanner('WebGL builds are not supported on mobile devices.');
  80. } else {
  81. canvas.style.width = "1920px";
  82. canvas.style.height = "1080px";
  83. }
  84. loadingBar.style.display = "block";
  85. var script = document.createElement("script");
  86. script.src = loaderUrl;
  87. script.onload = () => {
  88. createUnityInstance(canvas, config, (progress) => {
  89. progressBarFull.style.width = 100 * progress + "%";
  90. }).then((unityInstance) => {
  91. loadingBar.style.display = "none";
  92. fullscreenButton.onclick = () => {
  93. unityInstance.SetFullscreen(1);
  94. };
  95. unityInstanceV = unityInstance;
  96. }).catch((message) => {
  97. alert(message);
  98. });
  99. };
  100. document.body.appendChild(script);
  101. var unityInstanceV;
  102. function ReportReady() {
  103. window.parent.postMessage({guid:"",event:"ReportReady"}, "*");
  104. }
  105. function SendPhone(_type,_phone)
  106. {
  107. // alert(s);
  108. if (_type == "tellphone"){
  109. window.parent.postMessage({guid:"",event:_type,phone:_phone}, "*");
  110. }else {
  111. window.parent.postMessage({guid:_type,event:"guid"}, "*");
  112. }
  113. }
  114. function sendMsgToUnity(obj) {
  115. unityInstanceV.SendMessage('UIPanel','receiveMsgFromVue',JSON.stringify(obj))
  116. }
  117. </script>
  118. </body>
  119. </html>

2.6 修改Container.vue脚本

增加和Unity交互的方法

 把原先显示的界面代码删除掉<div class="container"> </div>

 style 部分也删掉

对Vue不熟悉,我的理解是这样的(理解不对请留言指正)

其中 

  1. onMounted(()=>{
  2.         window.addEventListener('message', unityWatch,true)
  3.     })

是事件,对Unity发送来的消息进行监听。

  1. function  vueSendToUnity(){
  2.       console.log(statusMap[status.value])
  3.       unityIframe.value.contentWindow.sendMsgToUnity({userId:'****',状态:status.value|| '加载中...'})  
  4. }

是vue把消息发送到Unity端。

  1. <template>
  2. <div >
  3. <iframe id="iframe" ref="unityIframe" src="/src/unity/index.html" style="width:100%;height:100vh" frameborder="0" scrolling="auto" />
  4. </div>
  5. </template>

是Unity部分进行显示(其中stytle的height:100% 不起作用,有知道的请留言,谢谢,所以我改为了height:100vh)。

Container.vue修改后代码如下:

  1. <script setup>
  2. import { ref, onMounted } from 'vue'
  3. const wechatGroupImg = 'https://tccc.qcloud.com/assets/wechatGroup.png';
  4. const arrowImg = 'https://tccc.qcloud.com/assets/arrow.png';
  5. const seat = ref('')
  6. const status = ref('')
  7. const number = ref('')
  8. const loading = ref(false)
  9. const isError = ref(false)
  10. const errorField = ref('')
  11. const statusMap = {
  12. offline: '已下线',
  13. disconnect: '网络断开,重连中',
  14. free: '空闲中',
  15. busy: '忙碌中',
  16. rest: '小休中',
  17. countdown: '话后倒计时',
  18. arrange: '话后整理中',
  19. notReady: '示忙中',
  20. }
  21. const errorFieldMap = {
  22. 'InvalidParameterValue.InstanceNotExist': 'sdkAppId',
  23. 'InvalidParameterValue.AccountNotExist': 'userId',
  24. 'AuthFailure.SignatureFailure': 'secretKey或secretId',
  25. 'AuthFailure.SecretIdNotFound': 'secretId',
  26. };
  27. const injectTCCC = ({ token, sdkAppId, userId, sdkUrl }) => {
  28. const scriptDom = document.createElement('script')
  29. scriptDom.setAttribute('crossorigin', 'anonymous')
  30. scriptDom.dataset.token = token
  31. scriptDom.dataset.sdkAppId = sdkAppId
  32. scriptDom.dataset.userid = userId
  33. scriptDom.src = sdkUrl
  34. document.body.appendChild(scriptDom)
  35. scriptDom.addEventListener('load', () => {
  36. // ready事件必须监听,否则容易发生tccc不存在的错误,所有呼入呼出的逻辑必须在ready事件触发后才可以调用
  37. window.tccc.on('ready', () => {
  38. // 以下为Demo逻辑,非业务必须。业务代码主要实现都在这个部分
  39. const statusVal = window.tccc.Agent.getStatus()
  40. status.value = statusVal;
  41. seat.value = userId;
  42. })
  43. // 以下为Demo逻辑,非接入必须
  44. setInterval(() => {
  45. const statusVal = window.tccc.Agent.getStatus()
  46. status.value = statusVal;
  47. }, 200)
  48. })
  49. }
  50. onMounted(() => {
  51. // 获取Token的方法必须在页面初始化时第一优先级调用
  52. fetch('/loginTCCC')
  53. .then((res) => res.json())
  54. .then((res) => {
  55. // 以下为Demo逻辑,需要替换为业务逻辑
  56. if (res.code) {
  57. if (res.type) {
  58. isError.value = true;
  59. errorField.value = errorFieldMap[res.code]
  60. } else {
  61. isError.value = true;
  62. if (errorFieldMap[res.code]) {
  63. errorField.value = errorFieldMap[res.code]
  64. } else {
  65. alert(res.errMsg);
  66. }
  67. return;
  68. }
  69. }
  70. // 调用成功后才可以开始执行TCCC的注入
  71. injectTCCC({
  72. token: res.token,
  73. userId: res.userId,
  74. sdkUrl: res.sdkUrl,
  75. sdkAppId: res.sdkAppId,
  76. })
  77. })
  78. .catch((error) => {
  79. console.error(`获取Token失败:${error.message}`)
  80. })
  81. })
  82. const handleCallout = async () => {
  83. if (loading.value) {
  84. return
  85. }
  86. loading.value = true
  87. // 调用呼出方法的核心代码
  88. try {
  89. await window.tccc.Call.startOutboundCall({ phoneNumber: number.value })
  90. } catch (error) {
  91. console.error(`呼出失败:${error.message}`)
  92. } finally {
  93. loading.value = false
  94. }
  95. }
  96. onMounted(()=>{
  97. window.addEventListener('message', unityWatch,true)
  98. })
  99. function unityWatch(e){
  100. console.log('unityWatch方法调用 e==' + e.data.guid + ' event=' + e.data.event)
  101. if(e.data.event=='tellphone'){
  102. handleCalloutByUnity(e.data.phone)
  103. vueSendToUnity()
  104. }
  105. }
  106. //Unity端调用vue里的打电话功能
  107. const handleCalloutByUnity = async (phone) => {
  108. if (loading.value) {
  109. return
  110. }
  111. loading.value = true
  112. // 调用呼出方法的核心代码
  113. try {
  114. await window.tccc.Call.startOutboundCall({ phoneNumber: phone })
  115. } catch (error) {
  116. console.error(`呼出失败:${error.message}`)
  117. } finally {
  118. loading.value = false
  119. }
  120. }
  121. const unityIframe = ref('unityIframe')
  122. function vueSendToUnity(){
  123. console.log(statusMap[status.value])
  124. unityIframe.value.contentWindow.sendMsgToUnity({userId:'****',状态:status.value|| '加载中...'})
  125. }
  126. </script>
  127. <template>
  128. <div >
  129. <iframe id="iframe" ref="unityIframe" src="/src/unity/index.html" style="width:100%;height:100vh" frameborder="0" scrolling="auto" />
  130. </div>
  131. </template>

2.7 测试运行

测试运行时得保证终端npm run dev在运行中

 在Unity 的界面上输入手机号点击拨打,电话打了出去,同时Unity端收到了vue发送过来的消息。

2.8 网页内全屏

这时候如果需要Unity在网页内全屏,且不显示滚动条,需要打开Unity的index.html进行再次修改:

 

 

 

 

 index.html的修改后如下:

  1. <!DOCTYPE html>
  2. <html lang="en-us">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6. <title>Unity WebGL Player | Web731</title>
  7. <link rel="shortcut icon" href="TemplateData/favicon.ico">
  8. <link rel="stylesheet" href="TemplateData/style.css">
  9. </head>
  10. <body>
  11. <div id="unity-container" style="width: 100%;height:100%">
  12. <canvas id="unity-canvas" width=auto height=auto></canvas>
  13. <div id="unity-loading-bar">
  14. <div id="unity-logo"></div>
  15. <div id="unity-progress-bar-empty">
  16. <div id="unity-progress-bar-full"></div>
  17. </div>
  18. </div>
  19. <div id="unity-warning"> </div>
  20. </div>
  21. <script>
  22. var container = document.querySelector("#unity-container");
  23. var canvas = document.querySelector("#unity-canvas");
  24. var loadingBar = document.querySelector("#unity-loading-bar");
  25. var progressBarFull = document.querySelector("#unity-progress-bar-full");
  26. //var fullscreenButton = document.querySelector("#unity-fullscreen-button");
  27. var warningBanner = document.querySelector("#unity-warning");
  28. // Shows a temporary message banner/ribbon for a few seconds, or
  29. // a permanent error message on top of the canvas if type=='error'.
  30. // If type=='warning', a yellow highlight color is used.
  31. // Modify or remove this function to customize the visually presented
  32. // way that non-critical warnings and error messages are presented to the
  33. // user.
  34. function unityShowBanner(msg, type) {
  35. function updateBannerVisibility() {
  36. warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
  37. }
  38. var div = document.createElement('div');
  39. div.innerHTML = msg;
  40. warningBanner.appendChild(div);
  41. if (type == 'error') div.style = 'background: red; padding: 10px;';
  42. else {
  43. if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
  44. setTimeout(function() {
  45. warningBanner.removeChild(div);
  46. updateBannerVisibility();
  47. }, 5000);
  48. }
  49. updateBannerVisibility();
  50. }
  51. var buildUrl = "Build";
  52. var loaderUrl = buildUrl + "/web0803.loader.js";
  53. var config = {
  54. dataUrl: buildUrl + "/web0803.data.unityweb",
  55. frameworkUrl: buildUrl + "/web0803.framework.js.unityweb",
  56. codeUrl: buildUrl + "/web0803.wasm.unityweb",
  57. streamingAssetsUrl: "StreamingAssets",
  58. companyName: "DefaultCompany",
  59. productName: "Web731",
  60. productVersion: "0.1",
  61. showBanner: unityShowBanner,
  62. };
  63. // By default Unity keeps WebGL canvas render target size matched with
  64. // the DOM size of the canvas element (scaled by window.devicePixelRatio)
  65. // Set this to false if you want to decouple this synchronization from
  66. // happening inside the engine, and you would instead like to size up
  67. // the canvas DOM size and WebGL render target sizes yourself.
  68. // config.matchWebGLToCanvasSize = false;
  69. if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
  70. var meta = document.createElement('meta');
  71. meta.name = 'viewport';
  72. meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
  73. document.getElementsByTagName('head')[0].appendChild(meta);
  74. container.className = "unity-mobile";
  75. canvas.style.width = window.innerWidth + 'px';
  76. canvas.style.height = window.innerHeight + 'px';
  77. unityShowBanner('暂不支持移动端...');
  78. } else {
  79. canvas.style.height= document.documentElement.clientHeight+"px";
  80. canvas.style.width = document.documentElement.clientWidth+"px";
  81. }
  82. loadingBar.style.display = "block";
  83. var script = document.createElement("script");
  84. script.src = loaderUrl;
  85. script.onload = () => {
  86. createUnityInstance(canvas, config, (progress) => {
  87. progressBarFull.style.width = 100 * progress + "%";
  88. }).then((unityInstance) => {
  89. loadingBar.style.display = "none";
  90. //fullscreenButton.onclick = () => {
  91. // unityInstance.SetFullscreen(1);
  92. //};
  93. unityInstanceV = unityInstance;
  94. }).catch((message) => {
  95. alert(message);
  96. });
  97. };
  98. document.body.appendChild(script);
  99. var unityInstanceV;
  100. function ReportReady() {
  101. window.parent.postMessage({guid:"",event:"ReportReady"}, "*");
  102. }
  103. function SendPhone(_type,_phone)
  104. {
  105. // alert(s);
  106. if (_type == "tellphone"){
  107. window.parent.postMessage({guid:"",event:_type,phone:_phone}, "*");
  108. }else {
  109. window.parent.postMessage({guid:_type,event:"guid"}, "*");
  110. }
  111. }
  112. function sendMsgToUnity(obj) {
  113. unityInstanceV.SendMessage('UIPanel','receiveMsgFromVue',JSON.stringify(obj))
  114. }
  115. </script>
  116. </body>
  117. </html>

打开Unity\TemplateData路径下的style.css增加:

  1. html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;}
  2. .webgl-content{width: 100%; height: 100%;}
  3. .unityContainer{width: 100%; height: 100%;}

style.css完整脚本如下:

  1. body { padding: 0; margin: 0 }
  2. #unity-container { position: absolute }
  3. #unity-container.unity-desktop { left: 50%; top: 50%; transform: translate(-50%, -50%) }
  4. #unity-container.unity-mobile { width: 100%; height: 100% }
  5. #unity-canvas { background: #231F20 }
  6. .unity-mobile #unity-canvas { width: 100%; height: 100% }
  7. #unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
  8. #unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center }
  9. #unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; background: url('progress-bar-empty-dark.png') no-repeat center }
  10. #unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center }
  11. #unity-footer { position: relative }
  12. .unity-mobile #unity-footer { display: none }
  13. #unity-webgl-logo { float:left; width: 204px; height: 38px; background: url('webgl-logo.png') no-repeat center }
  14. #unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px }
  15. #unity-fullscreen-button { float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center }
  16. #unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }
  17. html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;}
  18. .webgl-content{width: 100%; height: 100%;}
  19. .unityContainer{width: 100%; height: 100%;}

 但是vue的这个右侧还是有滚动条,还没找到隐藏的方法,有知道的同学请留言,谢谢。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/94952
推荐阅读
相关标签
  

闽ICP备14008679号