내가 맡은 세 개의 플랫폼 중에 한 개는 웹뷰, 한 개는 하이브리드 앱, 마지막은 네이티브앱 다양한 앱의 형태를 가지고 있다. 이 중 웹뷰나 하이브리드앱을 개발할 때는 웹과 앱간의 통신이 필수불가결하다. 웹과 네이티브 앱 간의 상호작용을 위한 인터페이스를 설계하는 것부터 작동원리를 알아본다. 아래의 예시들은 웹앱일 경우의 예시들이다.
1. JavaScript 를 실행시키는 함수 : evaluateJavaScript
로드된 웹 페이지의 JavaScript 코드를 실행시키고 싶을 경우이다. 예를 들어 모바일을 이용하는 유저가 다이나믹링크를 클릭시 앱을 실행시킴과 동시에 특정 페이지로 이동해야 하는 상황이다. 다이나믹링크가 앱까지는 실행시켜주겠지만 웹뷰안에서 특정 페이지를 이동하는 것은 웹의 영역이다. 이 때 앱에서는 다이나믹링크에서 path 값을 받고, 이를 웹에 전달하여 라우트 이동을 하는 설계를 해야한다. 먼저 Chrome WebView 에서 제공하는 메소드부터 보자.
evaluateJavascript(String script, ValueCallback<String> resultCallback)
: Asynchronously evaluates JavaScript in the context of the currently displayed page.
⚡️ webViewer.evaluateJavascript() 함수는 안드로이드의 WebView에서 JavaScript 코드를 실행시키기 위한 함수이다.
이 함수를 사용하면 WebView에서 현재 보여지는 HTML 문서 안에서 JavaScript 코드를 실행시키거나, JavaScript 코드에서 WebView 안에 있는 DOM 요소를 조작할 수 있는 등 원하는 동작을 실행시킬 수 있다.
다음은 evaluateJavaScript() 함수를 사용하여 WebView 안에서 alert 창을 띄우는 예시이다.
webViewer.evaluateJavascript("alert('Hello, World!');", null)
위의 코드는 WebView 안에서 "Hello,Wolrd!" 라는 메시지를 포함한 alert창을 띄우는 JavaScript 코드를 실행시키는 예시이다. evaluateJavascript() 함수의 첫 번째 인자로는 실행시킬 JavaScript 코드를 문자열로 전달한다. 두 번째 인자로는 실행 결과를 받을 ValueCallback 객체를 전달한다. 만약 실행 결과를 받을 필요가 없다면 null 값을 전달한다.
webView.evaluateJavascript(
JavascriptEvent<JavascriptEvent.MoveToPage>().dispatch(
"moveToPage", JavascriptEvent.MoveToPage(path)
)
) {}
다음 코드는 특정 페이지로 이동하는 값을 구현한 코드이다. evaluateJavascript() 메서드를 사용하여 JavaScript를 실행하고, 이 때 호출할 JavaScript 함수를 JavaScriptEvent라는 클래스를 사용하여 구현했다. 여기서 JavaScriptEvent 안 dispatch 함수는 자바스크립트 코드를 실행시킬 값을 함수로 구현한 것이다. 아래에서 어떻게 Javascript가 실행할 이벤트를 Native 쪽에서 생성해서 전달하는지까지 알아보자.
class JavascriptEvent<T> {
fun dispatch(name: String, detail: T): String {
return "window.dispatchEvent(new CustomEvent(\"${name}\", {detail: ${Gson().toJson(detail)}}));"
}
}
1-1. Custom Event 생성
웹 클라이언트쪽에서는 이벤트를 달아 상황에 맞게 이벤트가 실행되게 등록시켜놓아야 하기 때문에 new CustomEvent 인 커스텀 이벤트를 이용한다.
const customEvent = new CustomEvent(type, options)
새로운 이벤트를 생성하려면 위와 같이 new CustomEvent() 생성자를 사용하여 새로운 Event 객체를 생성한다. 여기서 type 은 이벤트의 이름을 나타내는 문자열이다. options 에는 이벤트가 상위 요소로 전파되어야 하는 지 여부, 이벤트를 취소할 수 있는지 여부 등을 설정할 수 있지만 우리는 'detail' 옵션을 사용하여 이벤트 객체에 포함할 세부 정보를 나타내는 값을 설정했다.
1-2. Custom Event 전달
domElement.dispatchEvent(event)
CustomEvent() 생성자로 커스텀 이벤트 객체를 생성한 다음 커스텀 이벤트를 사용하려면 이벤트 객체를 전달하는 과정이 필요하다. 이 과정이 필요한 이유는 커스텀 이벤트 객체를 생성했다고 해당 이벤트를 바로 사용할 수 없기 때문이다. HTML 요소에서 커스텀 이벤트를 사용하려면 dispatchEvent() 메서드를 사용한다. 매개변수 event 에는 CustomEvent 객체를 설정한다.
이벤트 객체를 생성한 다음에는 dispatchEvent(event) 를 호출해 요소에 있는 이벤트를 '실행' 시켜줘야한다. 이렇게 이벤트를 실행시켜줘야 핸들러가 일반 브라우저 이벤트처럼 이벤트에 반응할 수 있다. Web 쪽에서 이를 addEventListener 를 통해 이벤트를 등록시켜놓았기 때문에 Native 쪽에서 원하는 시점에 실행까지 시켜주는 것이다. 버튼을 실제로 클릭하지 않았지만, 이벤트 핸들러가 동작하는 것을 확인할 수 있다.
우리는 실행시킬 이벤트 이름으로 "moveToPage" 로 정의하였고, detail 부분에는 웹에서 이동시킬 path 값을 전달한다. 이 코드가 하는 일은 JavaScript에서 moveToPage() 함수를 호출하여 path 인자로 지정한 페이지로 이동하는 것이다. 객체로 들어오는 MoveToPage 클래스를 Json 으로 변환하여 문자열 형태로 만든다.
2. Android에서 JavaScript로의 상호작용을 활성화 : addJavaScriptInterface
addJavascriptInterface(Object object, String name)
Injects the supplied Java object into this WebView.
⚡️ addJavaScriptInterface를 통해 Java Object를 WebView에 전달할 수 있다.
웹뷰 Javascript에서 Android 네이티브 코드를 호출하기 위해 사용하는 Android에서 제공하는 인터페이스를 추가하는 코드이다.
네이티브쪽에서 채널톡 SDK 를 사용하기로 했고, 채널톡 boot 을 위해서는 user의 정보들이 필요했다. user의 정보들은 웹에서 가지고 있는 데이터이고 네이티브단에서는 이 데이터를 웹으로부터 받아 채널톡 boot 할 때의 정보를 셋팅해주어야 했다. 먼저 앱 실행 시점에 addJavaScriptInterface 를 웹뷰에 등록하여 웹에 등록한 이벤트를 실행시키고 이를 payload 로 받아 앱에서 실행할 코드를 작성해주는 플로우로 접근해야한다.
class ChannelTalkInit(
private val webViewer: WebView
) {
@JavascriptInterface
fun execute(payload: String) {
//채널톡 셋팅
}
}
webView.addJavascriptInterface(ChannelTalkInit(webView),"setChannelTalk")
ChannelTalkInit 클래스는 WebView와 상호작용하는 함수들을 가지고 있는 클래스이다. @JavascriptInterface 어노테이션을 작성하게 되면, 클래스 안 execute 함수는 웹뷰안 JavaScript 코드에서 호출할 수 있는 함수가 된다. 또한 웹뷰로부터 무언가를 받아야할 데이터가 있다면 파라미터를 추가해줄 수도 있고, 함수가 실행함과 동시에 payload 받아 네이티브 코드에서 원하는 결과를 처리해줄 수 있다.
@JavascriptInterface를 사용하여 안드로이드에서 웹 뷰의 JavaScript와 통신할 때, 기본적으로 문자열 형태로 데이터를 주고받는다. 따라서 @JavascriptInterface를 사용하는 메서드의 매개변수는 문자열 타입으로 선언되어야 한다.
만약 자바스크립트 코드가 잘 실행되는지 보려면, 이 execute 함수안에서 로그를 찍어 확인하면 된다. payload 인자는 JavaScript 에서 전달된 JSON 문자열이며, 해당 JSON 데이터를 파싱하여 네이티브쪽에서 만든 객체로 원하는 정보를 가공, 변경하여 채널톡 유저 정보를 넣어주면 된다.
이 클래스를 이제 웹뷰에 추가해주자. addJavaScriptInterface는 안드로이드 WebView에서 자바스크립트와 상호작용하기 위한 인터페이스를 추가하는 역할을 한다. addJavascriptInterface에 ChannelTalkInit 객체를 생성하여 첫번째 인자로 추가하고 setChannelTalk 이름으로 WebView 에 등록할 이벤트 이름을 두번째 인자로 추가하여 Javascript Inteface를 추가한다. 웹뷰 Javascript 코드에서는 setChannelTalk.execute(payload) 의 형태로 execute 함수를 호출할 수 있게 된다.
'🐸 Android' 카테고리의 다른 글
[Android] Fastlane으로 앱스토어 자동 배포하기 (0) | 2023.07.04 |
---|---|
[Android] 앱 삭제 후 데이터가 남아있는 문제 (0) | 2023.07.04 |
멀티 셀렉이 가능한 커스텀 갤러리 만들기 (2) | 2023.07.04 |
[Android] Task and Back Stack (0) | 2023.07.04 |
블로그 이전 (1) | 2023.02.12 |