📱 모바일 앱 연동 — 완전 분석
웹 페이지가 네이티브 앱(Android/iOS)과 어떻게 통신하는지, 앱 브릿지와 딥링크 시스템을 분석합니다.
🌉 callAppBridge() — 웹과 앱을 잇는 다리
이 함수는 웹 페이지(WebView) 안에서 네이티브 앱 기능을 호출할 때 사용됩니다. JavaScript에서 Android/iOS 네이티브 코드를 직접 호출하는 마법 같은 함수예요.
function callAppBridge(action, data) {
// action에 따라 분기 처리
switch (action) {
case 'camera':
// 명함 사진 촬영 → 네이티브 카메라 앱 실행
if (isAndroidApp()) {
window.Android.callCamera();
} else if (isIOSApp()) {
window.webkit.messageHandlers.callCamera.postMessage(data);
}
break;
case 'gallery':
// 갤러리에서 명함 이미지 선택
if (isAndroidApp()) {
window.Android.openGallery();
} else if (isIOSApp()) {
window.webkit.messageHandlers.openGallery.postMessage(data);
}
break;
case 'share':
// 카카오톡/인스타 등 외부 공유
if (isAndroidApp()) {
window.Android.shareContent(JSON.stringify(data));
} else if (isIOSApp()) {
window.webkit.messageHandlers.shareContent.postMessage(data);
}
break;
case 'phone_call':
// 전화 걸기
if (isAndroidApp()) {
window.Android.makePhoneCall(data.number);
} else if (isIOSApp()) {
window.webkit.messageHandlers.makePhoneCall.postMessage(data);
}
break;
case 'map':
// 지도 앱 열기
if (isAndroidApp()) {
window.Android.openMap(data.address);
} else if (isIOSApp()) {
window.webkit.messageHandlers.openMap.postMessage(data);
}
break;
}
}
🔍 앱 환경 감지 — 웹인가 앱인가?
// 1. UserAgent 기반 감지
function isAndroidApp() {
var ua = navigator.userAgent.toLowerCase();
return ua.indexOf('[앱식별자]') > -1;
}
function isIOSApp() {
var ua = navigator.userAgent.toLowerCase();
return ua.indexOf('[앱식별자-iOS]') > -1;
}
function isApp() {
return isAndroidApp() || isIOSApp();
}
// 2. URL 스킴 기반 감지
function isAppInstalled() {
// Android: intent:// 스킴 시도
// iOS: [앱스킴]:// 스킴 시도
// → 타이머로 실패 감지 (일정 시간 내 반응 없으면 미설치)
}
// 3. 감지 결과에 따른 분기
if (isApp()) {
// 앱 내부 WebView → callAppBridge() 사용
// UI 요소 중 일부 숨김 (앱 설치 버튼 등)
$('.app-only').show();
$('.web-only').hide();
} else {
// 일반 브라우저 → 웹 전용 UI 표시
$('.app-only').hide();
$('.web-only').show();
}
🔗 딥링크 시스템
웹에서 앱을 열거나, 앱이 설치되어 있지 않으면 Play Store로 보내는 시스템입니다.
// === goOnlyOneApp() 함수 분석 ===
function goOnlyOneApp() {
// 1. Android인지 확인
if (!isAndroidApp()) {
// 2. 일반 브라우저에서 앱 실행 시도
var now = new Date().getTime();
// 3. 커스텀 URL 스킴으로 앱 열기 시도
// [앱스킴]://open?url=... 형태
location.href = "[앱스킴]://open?url=" +
encodeURIComponent(window.location.href);
// 4. 2초 후에도 페이지에 남아있으면
// → 앱이 설치되지 않은 것!
setTimeout(function() {
if (new Date().getTime() - now < 2200) {
// 5. Play Store로 이동
location.href =
"[PlayStore앱URL]";
}
}, 2000);
}
}
// === goIamHome() 함수 ===
function goIamHome() {
// Android 앱 환경이면 AppScript로 /m 페이지 이동
if (isAndroidApp()) {
// WebView에서 JavaScript 인터페이스로 이동
window.AppScript.movePage('[앱내부경로]');
} else {
// 일반 웹 → 직접 /m 페이지로 이동
location.href = '[웹홈URL]';
}
}
⚠️ 딥링크의 마법 같은 트릭
2초 타이머가 핵심이에요! location.href로 앱 스킴을 호출하면:
1. 앱이 설치되어 있다면 → 앱이 열리고, 타이머는 앱으로 이동하면서 중단됨
2. 앱이 없으면 → 아무 일도 안 일어나고, 2초 후 Play Store로 이동!
이게 바로 "Fallback URL" 패턴이에요. 초등학생도 이해할 수 있죠?
📸 카메라 연동 — 명함 사진 촬영
// === app_camera_paper() 함수 ===
function app_camera_paper() {
if (isApp()) {
// 앱 환경 → 네이티브 카메라 호출
callAppBridge('camera', {
type: 'paper_card', // 어떤 용도의 촬영인지
quality: 0.8, // 이미지 품질 80%
maxWidth: 1200, // 최대 너비 1200px
callback: 'onCameraResult' // 결과 콜백 함수명
});
} else {
// 웹 환경 → 파일 업로드 input 표시
$('#paper_card_upload').click();
}
}
// === 네이티브 카메라 결과 콜백 ===
function onCameraResult(imageData) {
// imageData = base64 인코딩된 이미지 또는 파일 경로
$('#paper_card_img').attr('src', imageData);
$('#paper_card_url').val(imageData);
// OCR 처리를 위해 서버로 전송
$.ajax({
url: "[OCR서버URL]/[이미지처리]",
type: "POST",
data: { image: imageData },
success: function(ocrResult) {
// OCR 결과로 폼 자동 채우기
fillCardForm(ocrResult);
}
});
}
📞 전화 상태 & GPS 연동
// === recvPhoneStatus() — 전화 상태 수신 ===
function recvPhoneStatus(status) {
// status: "IDLE" | "RINGING" | "OFFHOOK"
// 앱에서 전화 상태가 바뀔 때마다 WebView로 알려줌
switch (status) {
case "RINGING":
// 전화 오는 중 → 자동 저장, 입력 중단 알림
autoSave();
showToast("전화가 와서 임시 저장했어요!");
break;
case "OFFHOOK":
// 통화 중 → 페이지 잠금
lockPage();
break;
case "IDLE":
// 통화 끝 → 잠금 해제
unlockPage();
break;
}
}
// === recvPhonePos() — GPS 위치 수신 ===
function recvPhonePos(lat, lng) {
// 현재 위치를 받아서 주소 검색에 활용
$('#current_lat').val(lat);
$('#current_lng').val(lng);
// 지도 API로 역지오코딩 (위도/경도 → 주소)
reverseGeocode(lat, lng, function(address) {
$('#paper_address').val(address);
});
}
🎓 초등학생도 따라하는 모바일 분석법
1
크롬 Device Mode 켜기
F12 → 좌측 상단 "Toggle device toolbar" (Ctrl+Shift+M)
F12 → 좌측 상단 "Toggle device toolbar" (Ctrl+Shift+M)
2
모바일 기기 선택
상단 드롭다운에서 "Galaxy S20" 또는 "iPhone 12" 선택
상단 드롭다운에서 "Galaxy S20" 또는 "iPhone 12" 선택
3
UserAgent 확인
Console에서
Console에서
navigator.userAgent 입력 → 모바일 UA 확인4
앱 환경 시뮬레이션
Console에서
Console에서
isApp = function(){ return true; } 로 강제 설정5
callAppBridge 추적
var orig = callAppBridge; callAppBridge = function(a,d){ console.log(a,d); orig(a,d); }💡 WebView 디버깅 꿀팁
실제 안드로이드 앱의 WebView를 디버깅하려면:
- 안드로이드 폰을 USB로 연결
- 폰에서 "개발자 옵션" → "USB 디버깅" 활성화
- PC 크롬에서
chrome://inspect입력 - 연결된 기기의 WebView 목록에서 "inspect" 클릭
- PC에서 폰의 WebView 콘솔/네트워크/요소 검사 가능!
📱 모바일 관련 주요 상수
| 항목 | 값 |
|---|---|
| Android 패키지명 | [앱패키지명] |
| 커스텀 URL 스킴 | [앱스킴]:// |
| Play Store 링크 | [PlayStore앱URL] |
| 웹 홈 URL | [웹홈URL] |
| Android WebView JS 인터페이스 | [JS인터페이스1], [JS인터페이스2] |
| iOS WebView 메시지 핸들러 | [iOS메시지핸들러] |