feat: Android 폰·태블릿 다운로드·앱 내 업데이트 완료
CI에서 APK 버전 자동 bump, 앱 복귀 시 업데이트 확인·시스템 다운로드, 프론트 Android 전용 UI 정리(iPad는 향후). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,50 +1,52 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { App } from '@capacitor/app';
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import { promptAppUpdateIfNeeded } from '../services/appUpdate';
|
||||
import { promptAppUpdate } from '../services/appUpdate';
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
/** Android 네이티브 — 시작 시 서버 APK 버전 확인 (무음 스킵, 이후 설정에서 수동 확인) */
|
||||
const isAndroidNative = () =>
|
||||
Capacitor.isNativePlatform() && Capacitor.getPlatform() === 'android';
|
||||
|
||||
/** Android — 시작·복귀 시 서버 APK 버전 확인 */
|
||||
export default function AppUpdateGate({ children }: Props) {
|
||||
const [ready, setReady] = useState(() =>
|
||||
!Capacitor.isNativePlatform() || Capacitor.getPlatform() !== 'android',
|
||||
);
|
||||
const [ready, setReady] = useState(() => !isAndroidNative());
|
||||
|
||||
useEffect(() => {
|
||||
if (ready) return;
|
||||
if (!isAndroidNative()) return;
|
||||
|
||||
let cancelled = false;
|
||||
void (async () => {
|
||||
|
||||
const runCheck = async () => {
|
||||
try {
|
||||
const { checkForAppUpdate, openApkDownload } = await import('../services/appUpdate');
|
||||
const check = await checkForAppUpdate();
|
||||
if (!cancelled && check.updateAvailable && check.remoteVersion) {
|
||||
const dismissed = sessionStorage.getItem(`gc_skip_update_${check.remoteVersion}`);
|
||||
if (!dismissed) {
|
||||
const ok = window.confirm(
|
||||
`GoldenChart v${check.remoteVersion} 업데이트가 있습니다.\n`
|
||||
+ `(현재 v${check.currentVersion})\n\n지금 APK를 다운로드하시겠습니까?`,
|
||||
);
|
||||
if (ok) {
|
||||
await openApkDownload(check.release);
|
||||
} else {
|
||||
sessionStorage.setItem(`gc_skip_update_${check.remoteVersion}`, '1');
|
||||
}
|
||||
}
|
||||
}
|
||||
await promptAppUpdate({ skipIfDismissed: true });
|
||||
} catch {
|
||||
/* 네트워크 오류 — 앱 진입 허용 */
|
||||
} finally {
|
||||
if (!cancelled) setReady(true);
|
||||
}
|
||||
};
|
||||
|
||||
void (async () => {
|
||||
await runCheck();
|
||||
if (!cancelled) setReady(true);
|
||||
})();
|
||||
return () => { cancelled = true; };
|
||||
}, [ready]);
|
||||
|
||||
const sub = App.addListener('appStateChange', ({ isActive }) => {
|
||||
if (isActive && !cancelled) {
|
||||
void runCheck();
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
void sub.then(h => h.remove());
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!ready) {
|
||||
return <div className="loading-center">업데이트 확인…</div>;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user