카카오톡 인앱 브라우저를 통해 접속한 유저가 카카오톡 본인인증 기능을 사용할 때 오류가 발생한다는 제보를 받았습니다.
직접 테스트했을 때 오류가 재현되진 않았지만, 인앱 브라우저에서 휴대폰 본인인증(PASS)을 진행하면 세션 데이터가 날아가는 버그를 겪고 있었기 때문에 인앱 브라우저를 외부 브라우저로 여는 방법을 찾기 시작했습니다.
그러다 아래 블로그를 발견했습니다.
이분 역시 인앱 브라우저를 벗어나길 원하셨고, 여러 해결 방법을 블로그에 기록하셨습니다.
저와 같은 전국 각지에서 고군분투하는 개발자들을 위해, 전체 소스코드도 제공하여 커스터마이징할 수 있도록 해주셨습니다.
해당 코드를 검토한 후, 코드 리팩토링을 진행했습니다.
execCommand()가 지원 중단되었기 때문에 Clipboard API로 대체하는 작업도 진행했습니다.
🔗 execCommand() 지원 중단
🔗 Clipboard API
class InApp {
#userAgent;
#targetUrl;
#browserPatterns;
constructor() {
this.#userAgent = navigator.userAgent.toLowerCase();
this.#targetUrl = location.href;
this.#browserPatterns = {
kakaotalk: /kakaotalk/i,
line: /line/i,
otherInApp: /inapp|naver|snapchat|wirtschaftswoche|thunderbird|instagram|everytimeapp|whatsApp|electron|wadiz|aliapp|zumapp|iphone(.*)whale|android(.*)whale|kakaostory|band|twitter|DaumApps|DaumDevice\/mobile|FB_IAB|FB4A|FBAN|FBIOS|FBSS|trill|SamsungBrowser\/[^1]/i,
ios: /iphone|ipad|ipod/i
};
this.#inAppDenyExecJs(this.#openOutLink.bind(this));
}
#inAppDenyExecJs = (callback) => {
document.readyState !== 'loading'
? callback()
: document.addEventListener('DOMContentLoaded', callback);
}
#openOutLink() {
const browserHandlers = {
kakaotalk: () => this.#openKakaoTalk(),
line: () => this.#openLine(),
otherInApp: () => this.#handleOtherInApp()
};
for (const [browser, handler] of Object.entries(browserHandlers)) {
if (this.#browserPatterns[browser].test(this.#userAgent)) {
return handler();
}
}
}
#openKakaoTalk() {
location.href = `kakaotalk://web/openExternal?url=${encodeURIComponent(this.#targetUrl)}`;
}
#openLine() {
const separator = this.#targetUrl.includes('?') ? '&' : '?';
location.href = `${this.#targetUrl}${separator}openExternalBrowser=1`;
}
#handleOtherInApp() {
this.#browserPatterns.ios.test(this.#userAgent)
? this.#handleIOS()
: this.#handleAndroid();
}
#handleAndroid() {
location.href = `intent://${this.#targetUrl.replace(/https?:\/\//i, '')}#Intent;scheme=http;package=com.android.chrome;end`;
}
#handleIOS() {
this.#setMobileViewport();
this.#setNotoSansFont();
this.#setIOSContent();
}
#setMobileViewport() {
const mobile = document.createElement('meta');
mobile.name = 'viewport';
mobile.content = 'width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, minimal-ui';
document.head.appendChild(mobile);
}
#setNotoSansFont() {
const fonts = document.createElement('link');
fonts.href = 'https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap';
document.head.appendChild(fonts);
}
#setIOSContent() {
const content = `
<style>
body {
width: 100%
height: 100%;
font-family: 'Noto Sans KR', sans-serif;
margin: 0;
padding: 0;
overflow: hidden;
}
article {
display: flex;
flex-direction: column;
align-items: center;
}
</style>
<h2 style='padding-top: 50px; text-align: center; font-family: "Noto Sans KR", sans-serif;'>
인앱 브라우저 호환성 문제로 인해<br>
Safari로 접속해야합니다.
</h2>
<article style='text-align: center; font-size: 17px; word-break: keep-all; color: #999;'>
아래 버튼을 눌러 Safari를 실행해주세요<br>
Safari가 열리면, 주소창을 길게 터치한 후<br>
'붙여놓기 및 이동'을 누르면<br>
정상적으로 이용할 수 있습니다.<br><br>
<button id="safariButton" style='min-width: 180px; margin-top: 10px; height: 54px; font-weight: 700; background-color: #31408E; color: #fff; border-radius: 4px; font-size: 17px; border: 0;'>
Safari로 열기
</button>
<img src="/img/in-app_safari.jpeg" alt="붙여넣기 및 이동" style='width: 70%; margin-top: 50px;'>
</article>
`;
document.body.innerHTML = content;
document.getElementById('safariButton').onclick = () => this.#inAppBrowserOut();
}
async #inAppBrowserOut() {
try {
const response = await this.#copyToClipboard(window.location.href);
if (response) {
alert('URL주소가 복사되었습니다.\n\nSafari가 열리면 주소창을 길게 터치한 뒤, "붙여놓기 및 이동"를 누르면 정상적으로 이용하실 수 있습니다.');
location.href = 'x-web-search://?';
}
} catch (error) {
console.error('Error:', error);
}
};
async #copyToClipboard(copyText) {
if (!document.hasFocus()) {
console.error('문서가 포커스되지 않았습니다. 클립보드에 쓸 수 없습니다.');
return false;
}
try {
// Clipboard API
await navigator.clipboard.writeText(copyText);
return true;
} catch (error) {
console.error('Clipboard API error:', error);
return false;
}
};
}
'IT > 웹 개발' 카테고리의 다른 글
간단하게 만드는 아코디언 메뉴 - HTML 전용 태그 활용 (0) | 2024.09.10 |
---|