[Android] - @JavascriptInterface에 대해서
@JavascriptInterface란 무엇인가?
간단하게 정리하자면, WebView에서 JavaScript와 Java를 연결하는 다리(Bridge) 라고 생각하면 쉽다.
이 때 안드로이드환경에서 개발을 하다 보면, WebView 안에서
HTML, CSS, JavaScript로 구성된 웹 페이지를 띄워야하는 상황에서 단순히 웹을 보여주는 것만으로는 부족할 때가 있는데예를 들어 웹 화면에서 버튼을 누르면, 앱의 특정 기능(예: 카메라 실행, 로그인 토큰 전달 등)을 실행해야하는 상황이 그렇다.
이때 필요한 게 바로 @JavascriptInterface
@JavascriptInterface는
WebView에서 실행되는 자바스크립트 코드가 Java 메서드를 호출할 수 있도록 허용하는 어노테이션이다.
WebView는 원래 앱 내부에서 HTML 페이지를 렌더링하는 View이다.
여기에 JavaScript가 포함되어 있다면, 앱 안의 Java 코드와 소통할 수 있어야 한다.
이 때, 그 역할을 담당하는 구조는 아래와 같다.
JavaScript ⇄ WebView ⇄ Java
이때 JavaScript → Java 방향의 호출을 허용하려면,
Java 메서드 위에 반드시 @JavascriptInterface를 붙여야 한다.
# 예제 코드
1. Java Code
public class WebAppInterface {
@android.webkit.JavascriptInterface
public boolean isDevMode() {
return CommonStr.DEV_MODE;
}
}
2. WebView설정
WebView webView = findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebAppInterface(), "Android");
3. JavaScript 코드
let isDev = Android.isDevMode();
alert("현재 개발모드 여부: " + isDev);
# @JavascriptInterface의 등장 배경
안드로이드 4.2(API 17) 이전에는
JavascriptInterface()로 연결된 객체의 모든 public 메서드가 자바스크립트에서 호출 가능했었다.
즉, 악성 웹페이지가 앱 내부 함수를 마음대로 호출할 수 있는 보안 취약점이 존재했다. 😨
그래서 4.2 버전부터는 **명시적으로 허용된 메서드(@JavascriptInterface 붙은 메서드)**만 호출할 수 있도록 정책이 바뀌었다.
⚠️ 안드로이드 4.2 이전의 동작 방식 (보안 취약 버전)
1. java
public class InsecureInterface {
public void showToast(String msg) {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
public void deleteAllFiles() {
File dir = new File("/sdcard/");
for (File file : dir.listFiles()) {
file.delete();
}
}
public String getDeviceInfo() {
return Build.MODEL + " / " + Build.VERSION.SDK_INT;
}
}
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new InsecureInterface(), "Android");
2. Javascript
<html>
<body>
<script>
// 모든 public 메서드에 접근 가능했던 시절 😨
Android.showToast("안드로이드에서 호출됨!");
// 심지어 이런 것도 가능했음!
Android.deleteAllFiles();
// 기기 정보 수집도 가능
alert(Android.getDeviceInfo());
</script>
</body>
</html>