하이브리드 앱을 만들고 싶다면 반드시 알아야 할 Window API.

서혁준·2022년 8월 14일
1
post-thumbnail

📌 계기

electron.js를 이용해서 데스크탑 앱을 만들 때나, 웹뷰를 이용한 하이브리드 앱을 구축하려면 웹뷰와 네이티브 앱이 통신하는 방법이 필요하다. 이 때 가장 일반적으로 사용하는 방법이 브라우저에서 제공하는 Window 인터페이스를 사용하는 방식인데, 그래서 Window 인터페이스에 대해서 한번 정리해보기로 했다.

예시

예를 들어 안드로이드 기반 하이브리드 어플리케이션을 만들었다고 생각해 보자.
일반적으로 안드로이드에서는 '뒤로가기 버튼' 을 클릭 했을때 앱의 페이지 상에서 뒤로가기가 된
다. 그리고 앱의 최상단 화면에서 뒤로가기를 누르면 앱이 꺼진다.

이러한 기능을 웹뷰를 이용해서 구현하려면 어떻게 해야할까?
이를 구현하기 위한 방법이 Window 인터페이스에 사용자 정의 함수를 등록하는 것과, Window.postmessage 를 이용하는 것이다.

📌 window 객체에 사용자 정의함수 등록하기 ( in TS )

위의 상황에서 뒤로가기를 잘 구현하려면 우선 웹상에서 사용자가 뒤로가기 버튼을 눌렀다는 것을 알아야 한다. 이를 위해서 우리는 windowhandleAndroidBackButtonPress()라는 함수를 달아 줄 것이다.

이를 구현하는 방법은 사실 간단하다.
일반 객체에 함수를 달듯이, 이렇게 달아주면 된다.

window.handleAndroidBackButtonPress() = (
	function() {
		...
	}
) 

그러면 모바일 앱에서 웹뷰 객체에 대해 handleAndroidBackButtonPress() 를 호출 할 수 있다.

Typescript를 사용할 경우 window object does not have property handleAndroidBackButtonPress... 에러가 뜰텐데, 이를 해결하기 위한 방법들 중 2가지를 소개한다.

1. Custom Interface를 만들어서 사용하기

원하는 함수들이 등록되어 있는 새로운 인터페이스를 작성한 뒤, window 인터페이스에 대해서 이 커스텀 인터페이스를 쓸 것이다! 하고 선언하는 방식이다.

export interface HybridWindow extends Window {
    handleAndroidBackButtonPress: () => void;
}

declare let window : HybridWindow;

window.handleAndroidBackButtonPress = () => {
	history.back();
  	...
}

2. type assertion 사용하기

두번째는 typescript 의 type assertion 기능을 이용하는 방식이다.

(window as any).handleAndoridBackButtonPress = () =(
	function(){...}
)

📌 Window.postMessage()

다음 방식은 Window에서 스크립트 간 통신을 위해 지원하는 postMessage() 를 이용하는 것이다.

postMessage() 는 window 객체 간의 cross-origin communication을 가능하게 해주는 메서드로써, 원래 서로 다른 페이지 상의 스크립트들은 same-origin policy에 해당하는 스크립트들끼리만 소통이 가능하지만, postMessage()를 이용하면 이 제한을 비켜갈 수 있다.

하지만 제한을 비켜감으로서 보안에 취약해질 수 있으므로, MDN 글을 읽어보면 알겠지만 항상 origin과 source를 명시하고, 체크해야한다!!!

사용 예시

targetWindow.postMessage(message, targetOrigin, [transfer] )

targetWindow.postMessage("app_quit");
  • targetWindow 메시지를 전달받을 window.
  • message 해당 윈도우에 전달할 메시지 내용. 이 메시지는 structured clone algorithm 에 의해 serialize되므로 어떤 데이터 타입을 넣든 상관이 없다! (JSON 형식으로 보낼수도 있다.)
  • targetOrigin event를 dispatch할 targetWindow의 origin이 어디인지 명시한다. 와일드카드 *를 사용가능하지만 보안상 항상 명시해주는 것을 MDN에서 권장하고 있다! ( ex. 비밀번호 전송에 쓰일 경우 인터셉트 당할수있음 )
  • transfer (선택) 메시지랑 같이 보낼 object 배열.

PostMessage로 전송된 event를 받아오기

window.addEventListener("message", (event) => {
	if(event.origin !== "http://example.org:8080")
		return;
}, false);

이 이벤트를 구성하는 요소들은 다음과 같다.

  • event.data 다른 window에서 받아온 object
  • event.origin 이 메시지를 보낸 (postmessage를 호출한) window의 origin.
  • event.source 이 메시지를 보낸 window 객체에 대한 reference. 이걸 통해서 양방향 통신을 할수 있다.

항상 메시지를 수신할 때 sender의 identity를 체크할 것 ( origin 체크하기 )

window.onMessage 를 이용해서 받아올 수도 있다.

여기에서 말하는 origin의 경우 서로 다른 웹사이트 간 통신할 때 중요한 부분이다. (ex. 특정 사이트 내부에 iframe으로 들어간 사이트)

만약 하이브리드 앱 등에서 사용한다면.. 그래도 조심해야 할 것 같긴 하다. 관련해서 어떤 postMessage를 지원하는지는 알 수 없지만 웹 특성상 아무나 하이브리드 앱을 통해서 악의적인 postMessage 통신이 가능하기 때문에!

📌 참고


Window.postMessage() - Web APIs | MDN

How to add new property to window object in typescript? | Cloudhadoop

profile
방구석에 앉아 미래를 상상하는 나

0개의 댓글