记一次electron+腾讯云trtc+im的使用

371 阅读5分钟

       最近业务要做一个桌面应用,用于公司内部的直播培训,基础架构采用electron+vue然后接腾讯云的实时音视频和im的sdk来实现。

首先vue创建项目,进入项目后执行vue add electron-builder来添加electron和配置启动打包命令,执行完后会生成background.js,里面是配置的桌面窗口。

async function createWindow() {  
    win = new BrowserWindow({    
        width: 770,    
        height: 450,    
        webPreferences: {      
            nodeIntegration: true,      
            contextIsolation: false,      
            preload: path.join(__dirname, "./preload.js"),      
            webSecurity: false,    
       },    
        // frame: false /* 去掉顶部导航 去掉关闭按钮 最大化最小化按钮 */,  
    })  
    if (process.env.WEBPACK_DEV_SERVER_URL) {    
        win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)    
        if (!process.env.IS_TEST) win.webContents.openDevTools()  
    } else {    
        // win.loadURL("app://./index.html")    
        win.loadFile("app://./index.html")  
    }  
    // win.setMenu(null)  // 设置窗口是否可以由用户手动最大化。双击全屏  
    win.setMaximizable(false)  
    win.loadFile("./dist/index.html")
}

上面是配置窗口的基本信息,包括窗口大小,配置项之类的。

接下来就是引入官方的插件tim-js-sdk``trtc-electron-sdk``trtc-js-sdk三个插件,分别是实现im和trtc的插件。

首先说实时音视频,在需要使用音视频的地方初始化:

let videoContainer = document.querySelector("#video-container");

首先获取展示视频流的元素,

let trtcCloud = new TRTCCloud();

然后实例化一个 trtc-electron-sdk,在这里有一个非常主要的参数,是在腾讯音视频官网申请的签名,这里我就放张图展示,SDKAPPIDSECRETKEY

接下来配置基本的事件订阅,例如进入房间,离开房间等

trtcCloud.on("onError", (errcode, errmsg) => {      
    console.info("trtc_demo: onError :" + errcode + " msg" + errmsg);    
});    
trtcCloud.on("onStatistics", (statis) => {
    // logger.log("onStatistics", statis);    
});    
trtcCloud.on("onEnterRoom", 
    this.onEnterRoom.bind(this)
);    
trtcCloud.on("onExitRoom", this.onExitRoom.bind(this));    
trtcCloud.on("onUserVideoAvailable", this.onUserVideoAvailable.bind(this));    
trtcCloud.on("onRemoteUserEnterRoom", // this.onRemoteUserEnterRoom.bind(this)      
    (uid) => {        
        console.log("有用户进入直播间uid:", uid); 
    }
);    
trtcCloud.on("onNetworkQuality", (
    localQuality, remoteQulity) => {      
    // console.log("localQuality.quality", localQuality.quality); 
});    
trtcCloud.on("onRemoteUserLeaveRoom",this.onRemoteUserLeaveRoom.bind(this));    
trtcCloud.on("onUserSubStreamAvailable",this.onUserSubStreamAvailable.bind(this));

接下来就是配置编码参数,TRTCVideoEncParam 的详细说明,请参考:trtc-1252463788.file.myqcloud.com/electron_sd…

然后就是进入房间的参数,TRTCParams 详细说明,请查看文档:trtc-1252463788.file.myqcloud.com/electron_sd…

let param = new TRTCParams();

房间参数根据官方文档必填项进行配置就可以了。

相关文档可到官网观看 cloud.tencent.com/document/pr…

接下来就是im聊天的功能:

tim = TIM.create({      
    SDKAppID: genTestUserSig("").SDKAppID,    
});    
let onIMReady = function (event) {      
    console.log("TIMready");    
};
// 监听初始化成功事件tim.on(TIM.EVENT.SDK_READY, onIMReady);

其中SDKAppID和音视频一样,是在im官网申请的

初始化成功之后,需要进行登录和创建群组才能进行聊天,说白了就类似微信登录和创建群聊

//登录    
tim.login({        
    userID: "",        
    userSig: "",      
}).then((imResponse) => {        
    console.log(imResponse.data); // 登录成功        
    if (imResponse.data.repeatLogin === true) {          
        // 标识账号已登录,本次登录操作为重复登录         
        console.log(imResponse.data.errorInfo);        
    }     
});

//创建群组
tim.createGroup({        
    type: TIM.TYPES.GRP_MEETING,        
    name: planName,        
    groupID: roomId.toString(),      
}).then(function(imResponse){
    // 创建成功    
    console.log("创建群组成功imResponse.data.groupimResponse.data.group",      
        imResponse.data.group    
    ); // 创建的群的资料})
.catch(function (imError) {
    console.warn("创建群组失败createGroup error:", imError);
})

创建成功开始监听im的消息,其中that.onReceiveMessage就可以去处理各种接收到的消息。

tim.on(TIM.EVENT.MESSAGE_RECEIVED, that.onReceiveMessage);

发送消息首先需要加入群组,需要在一个群组内,就像音视频需要在同一个房间之内一样。

let promise = tim.joinGroup({        
    groupID: group,        
    type: TIM.TYPES.GRP_MEETING,      
});      
promise.then(function (imResponse) {          
    switch (imResponse.data.status) {            
        case TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL:              
            console.log("等待同意");              
            break; // 等待管理员同意            
        case TIM.TYPES.JOIN_STATUS_SUCCESS: // 加群成功              
            console.log("加入的群组", imResponse.data.group); 
            // 加入的群组资料              
            break;            
        case TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP: // 已经在群中              
            console.log("已经在群中");              
            break;            
        default:break;          
}}).catch(function (imError) {          
    console.warn("joinGroup error:", imError); 
    // 申请加群失败的相关信息        
});

加群成功,设置角色之后就可以调用发送消息方法tim.sendMessage(message)了,但是要注意message的数据结构。

let message = tim.createTextMessage({        
    to: this.groupId,        
    conversationType: TIM.TYPES.CONV_GROUP,        
    payload: {          
        text: JSON.stringify(msg_staff),        
    },      
});

接收消息除了基本消息之后,有一种自定义消息,可以自定义消息状态,比如直播间的请离和禁言这种基本操作,就可以使用自定义消息,然后根据消息的状态进行对应的操作。

let atObj = {        
    at: at * 1, 
    //1开播 2关播 3暂停 4取消暂停 5禁言 6解除禁言 7踢出 8添加管理员 9删除管理员 
    10关闭摄像头 11开启摄像头  12全员禁言  13取消全员禁言 14用户进入直播间  
    15用户离开直播间 16停止共享 17开启共享  18解除请离   20上传文件成功        
    id: uid,        
    name: name,      
};      
let messData = {        
    action: "301", //301为自定义消息        
    command: "1",        
    message: JSON.stringify(atObj),      
};      
let that = this;      
let message = tim.createCustomMessage({        
    to: this.groupId,        
    conversationType: TIM.TYPES.CONV_GROUP,        
    payload: {         
        data: JSON.stringify(messData), // 用于标识该消息          
        description: "",          
        extension: "",        
    },      
});

上面可以看到我们有20钟自定义消息类型,可以进行不同的操作。

上面大约就是trtc和im的基本使用,还有一些别的操作没有加进来,如果各位想使用其他的一些复杂功能请到官网查看。

接下来说一下我打包遇到的一些重大的问题。

首先是electron不支持import的方法(注:可能我没有使用插件,只是当时打包报错),然后所有的import引入方法都改成require方式引入。

所以需要进行配置,首先可以创建一个preload.js文件

global.electron = require("electron")
window.ipcRenderer = require("electron").ipcRenderer
window.remote = require("electron").remote
sessionStorage.setItem("ipcRenderer", JSON.stringify(window.ipcRenderer))
window.nodeRequire = require
delete window.require
delete window.exports
delete window.module

document.addEventListener("DOMNodeInserted", function (event) {
// 页面内容加载之前需要引入的一些代码
if (document.head && !document.getElementById("module")) {
    var script = document.createElement("script")
    script.setAttribute("id", "module")
    script.innerHTML ="if (typeof module === 'object') {
        window.module = module; module = undefined;
    }"document.head.appendChild(script)}
})
document.addEventListener("DOMContentLoaded", function (event) {
// 页面内容加载之后需要引入的一些操作
    var script = document.createElement("script")
    script.innerHTML = `if (window.module) module = window.module;`
    document.body.appendChild(script)
})

还记得我在最开始background.js的截图吗,里面在创建窗口的时候引入了这个js,可以解决import报错的问题。

然后就是打包会说找不到trtc和node,或者trtc初始化失败,当时报错截图找不到了。。。。。。。。

这个问题困扰了我们好几天的时间,最后发现是判断引入的问题,一定要注意一下。

vue.config.js的文件里

module.exports = {  
    publicPath: "./",  
    configureWebpack: {    
    devtool: "source-map",    
    module: {      
        rules: [{          
            test: /\.node$/,          
            loader: "native-ext-loader",          
            options: {            
                emit: true,            
                rewritePath:              
                param.TRTC_ENV === "production"? 
                    param.TARGET_PLATFORM === "win32"? 
                    "./resources/"                  
                    : "../Resources"                
                    : "./node_modules/trtc-electron-sdk/build/Release",          
            },        
        }],   
    },    
    plugins: [new StringReplaceWebpackPlugin()],  },  
    pluginOptions: {    
        electronBuilder: {      
            nodeIntegration: true,    
        },  
    }
}

其中module下面的option里面,rewritePath判断了当前环境和电脑的操作系统引入了不同文件夹下面的trtc-electron-sdk,一定要根据电脑环境来进行修改这里面的配置。

这次第一次参与桌面应用和直播音视频流的开发,让我受益很多。

好了,这就是我这次使用的经验,其余遇到的问题还有很多,但是都是小问题,这里就不一一列举,如果有还有问题的,可以在评论区一起探讨。