버전 표시 오류 수정

This commit is contained in:
hansoo
2025-03-23 22:42:23 +09:00
parent f5e3b39c73
commit 9375d06aa2
4 changed files with 242 additions and 160 deletions

View File

@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react';
import { getAppVersionInfo, isAndroidPlatform, isIOSPlatform } from '@/utils/platform';
import { Label } from '@/components/ui/label';
import { Capacitor } from '@capacitor/core';
// 버전 정보 인터페이스 정의
interface VersionInfo {
@@ -12,7 +13,7 @@ interface VersionInfo {
timestamp?: number;
error?: boolean;
errorMessage?: string;
defaultValues?: boolean;
defaultValuesUsed?: boolean;
}
interface AppVersionInfoProps {
@@ -26,11 +27,14 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
showDevInfo = true,
editable = false
}) => {
// localStorage에서 이전에 저장된 버전 정보 가져오기
const getSavedVersionInfo = useCallback((): VersionInfo | null => {
// 저장된 버전 정보 가져오기 (localStorage)
const savedInfo = useMemo(() => {
try {
const saved = localStorage.getItem('app_version_info');
return saved ? JSON.parse(saved) : null;
if (typeof localStorage !== 'undefined') {
const saved = localStorage.getItem('app_version_info');
return saved ? JSON.parse(saved) : null;
}
return null;
} catch (e) {
console.error('저장된 버전 정보 파싱 오류:', e);
return null;
@@ -39,53 +43,40 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
// 기본 버전 정보를 useMemo로 생성하여 불필요한 재계산 방지
const defaultInfo = useMemo<VersionInfo>(() => {
// 웹 환경에서는 더 높은 버전 정보를 기본값으로 사용
const webDefaultInfo: VersionInfo = {
versionName: '1.1.1.2', // 웹 환경에서 사용할 버전 이름
buildNumber: 6, // 웹 환경에서 사용할 빌드 번호
versionCode: 6, // 웹 환경에서 사용할 버전 코드
platform: 'web',
defaultValues: false // 기본값이 아닌 것으로 설정하여 우선순위 높이기
const platform = Capacitor.getPlatform();
const isWeb = platform === 'web';
if (savedInfo) {
return savedInfo;
}
const defaultVersionInfo: VersionInfo = {
versionName: isWeb ? '1.1.1.2' : '1.0.0',
buildNumber: isWeb ? 6 : 1,
versionCode: isWeb ? 6 : 1,
platform: platform,
defaultValuesUsed: true
};
// localStorage에 저장된 정보 가져오기
const savedInfo = getSavedVersionInfo();
console.log('불러온 저장 정보:', savedInfo);
console.log('사용할 기본 정보:', defaultVersionInfo);
// 웹 환경에서는 웹 기본값, 안드로이드/iOS에서는 기존 기본값 사용
const baseDefault = (!isAndroidPlatform() && !isIOSPlatform())
? webDefaultInfo
: {
versionName: '1.0.0',
buildNumber: 1,
versionCode: 1,
platform: 'default',
defaultValues: true
};
// 저장된 정보가 있으면 우선 사용, 없으면 기본값 사용
const result = savedInfo || baseDefault;
console.log('사용할 기본 정보:', result);
// localStorage에 초기 정보 저장 (웹에서만)
if (!savedInfo && !isAndroidPlatform() && !isIOSPlatform()) {
if (isWeb && typeof localStorage !== 'undefined') {
try {
console.log('웹 기본 정보를 localStorage에 초기 저장');
localStorage.setItem('app_version_info', JSON.stringify(result));
localStorage.setItem('app_version_info', JSON.stringify(defaultVersionInfo));
console.log('localStorage에 초기 버전 정보 저장됨');
} catch (e) {
console.error('초기 정보 저장 실패:', e);
console.error('localStorage에 초기 버전 정보 저장 실패:', e);
}
}
return result;
}, [getSavedVersionInfo]);
return defaultVersionInfo;
}, [savedInfo]);
const [versionInfo, setVersionInfo] = useState<VersionInfo>(defaultInfo);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [retries, setRetries] = useState(0);
// 버전 정보 가져오기
const fetchVersionInfo = useCallback(async () => {
setLoading(true);
setError(false);
@@ -94,82 +85,56 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
console.log('현재 플랫폼은',
isAndroidPlatform() ? 'Android' : isIOSPlatform() ? 'iOS' : '웹');
// 재시도를 하는 경우 짧은 지연 추가
if (retries > 0) {
await new Promise(resolve => setTimeout(resolve, 300));
}
// localStorage에서 저장된 값을 먼저 확인
const savedInfo = getSavedVersionInfo();
// 웹 환경에서는 저장된 값이 있으면 바로 사용
if (!isAndroidPlatform() && !isIOSPlatform() && savedInfo && !savedInfo.defaultValues) {
console.log('웹 환경에서 저장된 버전 정보 사용:', savedInfo);
setVersionInfo(savedInfo);
setLoading(false);
return;
}
// 네이티브 환경이거나 저장된 값이 없는 경우에만 플러그인 호출
const info = await getAppVersionInfo();
console.log('받은 앱 버전 정보:', info);
// 데이터 검증 - 유효한 버전 정보인지 확인
if (!info || typeof info !== 'object') {
throw new Error('유효하지 않은 응답 형식');
}
// 타입 안전성을 위한 변환 함수
const parseVersionInfo = (data: any): VersionInfo => {
// 빌드 번호 변환
const parseVersionInfo = (data: Record<string, unknown>): VersionInfo => {
let buildNumber: number = defaultInfo.buildNumber;
if (typeof data.buildNumber === 'number') {
buildNumber = data.buildNumber;
} else if (typeof data.buildNumber === 'string' && data.buildNumber.trim() !== '') {
} else if (typeof data.buildNumber === 'string') {
const parsed = parseInt(data.buildNumber, 10);
if (!isNaN(parsed)) buildNumber = parsed;
}
// 버전 코드 변환
let versionCode: number | undefined = defaultInfo.versionCode;
if (typeof data.versionCode === 'number') {
versionCode = data.versionCode;
} else if (typeof data.versionCode === 'string' && data.versionCode.trim() !== '') {
const parsed = parseInt(data.versionCode, 10);
} else if (typeof data.versionCode === 'string') {
const parsed = parseInt(data.versionCode as string, 10);
if (!isNaN(parsed)) versionCode = parsed;
}
// 응답 객체 구성
return {
versionName: typeof data.versionName === 'string' && data.versionName.trim() !== ''
? data.versionName
? data.versionName as string
: defaultInfo.versionName,
buildNumber,
versionCode,
platform: typeof data.platform === 'string' ? data.platform : defaultInfo.platform,
platform: data.platform as string || defaultInfo.platform,
pluginResponse: typeof data.pluginResponse === 'string'
? data.pluginResponse
: JSON.stringify(data),
timestamp: typeof data.timestamp === 'number' ? data.timestamp : Date.now(),
defaultValues: false
defaultValuesUsed: false
};
};
// 타입 변환 및 정제
const newVersionInfo = parseVersionInfo(info);
// 웹 환경에서는 defaultValues가 true인 경우(기본값) localStorage 값 우선 적용
if (!isAndroidPlatform() && !isIOSPlatform() && newVersionInfo.defaultValues && savedInfo) {
console.log('웹 환경의 기본값 대신 저장된 값 사용');
setVersionInfo(savedInfo);
setLoading(false);
return;
}
// LocalStorage에 버전 정보 저장
try {
localStorage.setItem('app_version_info', JSON.stringify(newVersionInfo));
console.log('버전 정보가 localStorage에 저장됨:', newVersionInfo);
if (typeof localStorage !== 'undefined') {
localStorage.setItem('app_version_info', JSON.stringify(newVersionInfo));
console.log('버전 정보가 localStorage에 저장됨:', newVersionInfo);
}
} catch (e) {
console.warn('버전 정보 저장 실패:', e);
}
@@ -181,63 +146,94 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
console.error('버전 정보 가져오기 실패:', error);
setError(true);
setLoading(false);
// 오류 발생 시 기존 저장된 값 유지 (초기화 방지)
console.log('오류 발생으로 기본값 사용');
}
}, [retries, defaultInfo]);
// 재시도 처리
const handleRetry = useCallback(() => {
setRetries(prev => prev + 1);
fetchVersionInfo();
}, [fetchVersionInfo]);
// 초기화 완료 후 한번 더 시도하도록 설정
const initialLoadAttemptedRef = useRef(false);
// 컴포넌트 마운트 시 즉시 실행 (IIFE)
useEffect(() => {
// 초기화 직후 localStorage 확인
console.log('컴포넌트 마운트 시 localStorage 확인:', localStorage.getItem('app_version_info'));
let isMounted = true;
let isMounted = true;
(async () => {
// 즉시 버전 정보 가져오기 시도
await fetchVersionInfo();
// 컴포넌트가 언마운트되었는지 확인
if (!isMounted) return;
// 1000ms 후에 한번 더 시도 (네이티브 플러그인이 완전히 로드되지 않았을 경우 대비)
setTimeout(() => {
const loadVersionInfo = async () => {
console.log('앱 버전 정보 로딩 시작');
try {
if (savedInfo && isMounted) {
console.log('저장된 정보로 먼저 표시:', savedInfo);
setVersionInfo(savedInfo);
}
const newVersionInfo = await getAppVersionInfo();
if (!isMounted) return;
if (error || loading) {
fetchVersionInfo();
initialLoadAttemptedRef.current = true;
console.log('불러온 버전 정보:', newVersionInfo);
if (!isAndroidPlatform() && !isIOSPlatform() &&
'defaultValuesUsed' in newVersionInfo &&
newVersionInfo.defaultValuesUsed === true &&
savedInfo) {
console.log('웹 환경의 기본값 대신 저장된 값 사용');
setVersionInfo(savedInfo);
setLoading(false);
return;
}
}, 1000);
})();
// 개발 모드에서는 버전 정보 변경을 쉽게 확인하기 위해 주기적 갱신
let interval: number | undefined;
if (process.env.NODE_ENV === 'development') {
interval = window.setInterval(() => {
try {
if (typeof localStorage !== 'undefined') {
localStorage.setItem('app_version_info', JSON.stringify(newVersionInfo));
console.log('버전 정보가 localStorage에 저장됨:', newVersionInfo);
}
} catch (e) {
console.warn('버전 정보 저장 실패:', e);
}
if (isMounted) {
fetchVersionInfo();
setVersionInfo(newVersionInfo);
setLoading(false);
console.log('앱 버전 정보 표시 준비 완료');
}
} catch (error) {
console.error('버전 정보 가져오기 실패:', error);
if (isMounted) {
const fallbackInfo = savedInfo || defaultInfo;
console.log('오류 발생으로 대체 정보 사용:', fallbackInfo);
setVersionInfo(fallbackInfo);
setLoading(false);
}
}, 30000); // 30초마다 새로 가져오기
}
return () => {
isMounted = false;
if (interval) {
clearInterval(interval);
}
};
}, [fetchVersionInfo, error, loading]);
loadVersionInfo();
return () => {
isMounted = false;
};
}, [savedInfo, defaultInfo]);
const renderDevInfo = () => {
if (versionInfo && showDevInfo) {
return (
<div className="mt-2 text-xs text-muted-foreground">
<div>
<span className="font-semibold"> :</span> {versionInfo.platform || 'unknown'}
</div>
{versionInfo.defaultValuesUsed && (
<div className="text-yellow-600 dark:text-yellow-400">
: 실제
</div>
)}
</div>
);
}
return null;
};
return (
<div className={className}>
@@ -276,6 +272,7 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
{editable && (
<p className="text-gray-400 font-semibold text-sm mt-2">ZELLYY CLOUD</p>
)}
{renderDevInfo()}
</div>
)}
</div>