지난 주말에 electron을 이용해 채팅 app을 만들려고 했지만 응답을 받지 못해서 문제가 있었다.

renderer process에서 socket이 자꾸 응답이 없길래 electron 문제인줄 알았는데 cors문제였다.

electron 디버깅을 해보니 소켓이 응답을 못받고 403만 받고 있더라…ㅡㅡ

서버에서 electron app으로 들어오는 값을 받기위해 origin을 변경했다.

이후 앱을 구동해보니 채팅 기록을 제대로 받아온다!

이제 채팅이 왔을때 알림이 오는 기능을 추가해보자.

//child window... real child not...
child = new BrowserWindow({width: 210, height: 60, frame: false, type:"notification"});
child.setIgnoreMouseEvents(true);
child.setAlwaysOnTop(true);
child.setPosition(electron.screen.getPrimaryDisplay().bounds.width-210, electron.screen.getPrimaryDisplay().bounds.height-60);
child.loadURL(url.format({
pathname: path.join(__dirname, 'childView/getMsg.html'),
protocol: 'file:',
slashes: true
}));
child.isResizable(false);
child.hide();
//child.webContents.openDevTools();

child window라고 생성은 했지만 실제로 mainwindow의 child는 아니다..(네이밍을 잘못했네 ㅡㅡ)

parent값을 넣어 mainwindow의 child로 만들 경우 메시지 알림이 올경우 mainwindow도 같이 활성화 된다.

child만 활성화하여 메시지 알림을 하는게 목표이기 때문에 독자적인 윈도우로 만든다.

type에도 notification 값이 들어가는데 윈도우가 활성화 되었을때 foucs를 뺏기지 않기 위함이다.

메시지 알림이 올때마다 foucs를 뺏겨서 하던 작업이 멈춰버리면 얼마나 빡치겠는가?

위치는 setPosition을 이용해서 우측 하단에 알림 메시지가 오도록 셋팅한다.

//chattingView.js -> renderer process
if(cursor.state.appStartTime<data.chat.date)
    ipcRenderer.send('msgReceive', data);

//main process
ipcMain.on('msgReceive', (event, data) => {
  if(mainWindow.isFocused()==false){
    child.reload();
    child.webContents.once('did-finish-load', () => {
      child.webContents.send("requestMsg",data);
      child.show();
    });
    //child.webContents.send("requestMsg",data);
  }
});

다음은 renderer process에서 알림 메시지가 올때마다 main process로 전송하도록한다.

receive 이벤트 안에 작성하면된다.

그런데 나의 경우 서버로부터 받는 메시지 이벤트를 receive 하나로 통일해서 기존 채팅기록이랑 실시간 채팅 메시지를 같은 곳을 받아오다보니 알림 메시지를 구별할 수 없다.

이벤트를 세분화 하면 되지만 다시 서버에 접속해서 코드를 변경하기 귀찮아서 app 구동시 시간보다 큰 값만 실시간 채팅으로 구분해서 main process로 보내도록 했다.

main process에서 msgReceive 채널로 값을 수신하면 mainwindow의 포커즈 여부를 검사하여 포커즈가 없을때만 메시지 알림을 보여준다.

webContents를 이용하여 main process에서 renderer process로 값을 전송하고 한 번만 전송할것이기에 once로 did-finish-load(페이지가 다 로딩 되었을때 이벤트 발생) 이벤트를 통해 메시지를 전송한다.

//getMsg.js -> renderer process
const { ipcRenderer } = require('electron');

ipcRenderer.on("requestMsg", function (event, data) {
    document.getElementById("msgBox").innerHTML = "<div class='ip'>"+data.chat.ip+"</div><div class='msg'>"+data.chat.msg+"</div>";
});

setTimeout(() => {
    ipcRenderer.send('hideChild');
}, 3000);

//main process
ipcMain.on('hideChild', (event, data) => {
  child.hide();
});

renderer process에서는 requestMsg 채널로 받은 메시지를 보여주고 3초 후에 main process에 hideChild 채널로 전송한다.(호출 용도이기 때문에 전송할 값은 없다.)

main process에서는 hideChild 채널이 호출되면 child window를 숨긴다.

계속 메시지 알림이 와도 msgReceive 채널에서 child가 reload된 뒤에 이벤트가 발생하기 때문에 타이머도 초기화된다.

그렇기에 계속 메시지가 와도 최종 메시지로부터 3초후에 child window가 사라진다.

이제 휴대폰으로 채팅서버에 접속해서 메시지를 보내보도록 하자.

우측 하단에 보면 채팅앱에 포커즈가 없을 경우 알림 메시지를 성공적으로 받는것을 볼 수 있다.

전체 코드는 이곳에서 확인할 수 있다.