웹뷰 앱 브리지 샘플

이 앱이 웹페이지에 제공하는 자바스크립트 핸들러 6개를 실제로 눌러 볼 수 있는 페이지다. 각 블록에 실제 호출 코드를 그대로 실었으니 그대로 복사해 쓰면 된다. 정확한 규격은 docs/bridge-api.md 를 본다.

0. 지금 어디서 실행 중인가

window.flutter_inappwebview 는 이 앱이 주입하는 전역 객체다. 일반 브라우저에는 없으므로, 핸들러를 부르기 전에 이걸로 앱 안인지 먼저 확인하는 것이 안전하다.

if (window.flutter_inappwebview) {
  // 앱 안이다. 핸들러를 부를 수 있다.
}

1. socialNetworkSignIn(providerCode)

소셜 계정 로그인을 시작한다. 인자는 'Kakao'·'Google'· 'Naver'·'Apple'(대소문자 무관). 그 밖의 값은 전부 미지원 갈래로 빠진다.

반환값으로 성공을 판단하지 마라. 로그인에 실패했을 때도 resulttrue 로 온다. nextUrl 이 문자열 "null"(네 글자)이면 이동할 주소가 없다는 뜻인데, 여기에는 사용자 취소, 세션 쿠키 없음, 그리고 로그인은 성공했는데 서버가 nextUrl 을 안 준 경우가 전부 섞여 있다. 완전히 성공하면 앱이 알아서 페이지를 옮기므로, 웹에서 따로 이동시킬 필요가 없다.

응답의 mode'native' 면 SDK 경로, 'web' 이면 웹 로그인 화면이 열린 것이다. 웹 경로는 이 시점에 로그인이 끝나지 않았다 — 팝업 안에서 리다이렉트가 끝나고 콜백 페이지가 window.close() 를 부를 때 완료된다. 어느 제공자가 어느 경로인지는 config.yamlWEB_LOGIN_URLS 가 정한다.

window.flutter_inappwebview.callHandler('socialNetworkSignIn', 'Kakao')
  .then(function (res) {
    // res.result 는 실패했을 때도 true 다. 성공 판단에 쓰지 마라.
    console.log(res);
  })
  .catch(function (err) {
    // 앱 내부 오류 등 예기치 못한 경우에만 온다.
    console.log(err);
  });
아직 호출하지 않음

2. socialNetworkSignOut()

현재 로그인된 소셜 계정에서 로그아웃한다. 인자는 없다. 한 번도 로그인하지 않았다면 원인과 무관하게 { result: false, msg: 'Unsupported provider!' } 가 온다.

window.flutter_inappwebview.callHandler('socialNetworkSignOut')
  .then(function (res) { console.log(res); });
아직 호출하지 않음

3. windowOpen(url) — 그리고 window.open() 이 안 되는 이유

새 웹뷰 화면(팝업)을 연다. 인자는 호스트를 포함한 절대 URL 이어야 한다. 허용된 URL이면 팝업을 열고 true, 거부되면 아무것도 하지 않고 false 를 돌려준다.

표준 window.open() 은 이 앱에서 동작하지 않는다. 후킹되어 있지 않아 눌러도 아무 일도 일어나지 않는다. 아래 두 버튼을 차례로 눌러 직접 확인해 보라 — 팝업을 열려면 반드시 핸들러를 직접 불러야 한다.
// 이렇게 해야 열린다
window.flutter_inappwebview.callHandler('windowOpen', 'https://www.sample.com/promo/event.php');

// 이건 이 앱 안에서 아무 일도 일어나지 않는다
window.open('https://www.sample.com/promo/event.php');
아직 호출하지 않음

4. windowClose(src)

현재 화면을 닫는다. 인자로 자바스크립트 코드 문자열을 넘기면 닫히는 화면이 아니라 이 화면을 연 쪽(opener)에서 그 코드가 실행된다. 팝업이 자기를 닫으면서 부모 화면을 갱신시킬 때 쓴다. opener 가 없으면 화면만 닫힌다.

window.close() 는 이 앱이 자동으로 후킹하므로 그냥 써도 된다. 위 3번에서 팝업을 먼저 연 뒤 그 팝업에서 눌러야 효과가 보인다.

// 팝업을 닫으면서 부모 화면을 새로고침시킨다
window.flutter_inappwebview.callHandler('windowClose', 'location.reload();');

// 표준 API 도 후킹되어 있어 그대로 쓸 수 있다
window.close();
아직 호출하지 않음

5. historyBack() / historyGo(level)

history.back()history.go(n) 은 앱이 자동으로 후킹하므로 보통은 핸들러를 직접 부를 필요가 없다. 표준 API를 그냥 쓰면 된다. historyGo 의 인자는 음수일 때만 동작한다 — 0 이나 양수(앞으로가기)는 아무 일도 일어나지 않는다. 둘 다 반환값이 없다.

history.back();      // 후킹되어 historyBack 핸들러로 간다
history.go(-1);      // 후킹되어 historyGo 핸들러로 간다

// 직접 부를 수도 있다
window.flutter_inappwebview.callHandler('historyBack');
window.flutter_inappwebview.callHandler('historyGo', -1);
아직 호출하지 않음

6. 후킹이 실제로 걸렸는지 확인

앱은 문서 로드 시작 시점에 스크립트를 주입해 아래 세 가지 브라우저 API를 자기 핸들러로 바꿔치기한다. 각 함수의 소스에 callHandler 가 들어 있는지로 확인할 수 있다.

history.back.toString().indexOf('callHandler') >= 0
아직 호출하지 않음