fix: 웹앱 새로고침 후 버전 정보 유지 및 BuildInfoPlugin 오류 수정

This commit is contained in:
hansoo
2025-03-23 22:17:42 +09:00
parent 200f08860f
commit f5e3b39c73
3 changed files with 163 additions and 34 deletions

View File

@@ -22,10 +22,10 @@ android {
applicationId "com.lovable.zellyfinance" applicationId "com.lovable.zellyfinance"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode versionCode versionCode = versionCode
versionName versionName versionName = versionName
// 빌드 번호 추가 - BuildConfig 필드로 정의 // 빌드 번호 추가 - BuildConfig 필드로 정의
buildConfigField "int", "BUILD_NUMBER", buildNumber.toString() buildConfigField("int", "BUILD_NUMBER", String.valueOf(buildNumber))
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions { aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.

View File

@@ -66,10 +66,21 @@ public class BuildInfoPlugin extends Plugin {
} catch (Exception e) { } catch (Exception e) {
// 오류 로깅 강화 // 오류 로깅 강화
Log.e(TAG, "빌드 정보 가져오기 오류", e); Log.e(TAG, "빌드 정보 가져오기 오류", e);
JSObject errorObj = new JSObject();
errorObj.put("message", e.getMessage()); // 오류 발생 시에도 기본 정보 반환하여 앱 중단 방지
errorObj.put("stack", Log.getStackTraceString(e)); JSObject fallbackResult = new JSObject();
call.reject("빌드 정보 가져오기 실패", errorObj); fallbackResult.put("versionName", "1.1.1.2"); // 버전명 기본값
fallbackResult.put("versionCode", 6); // 버전 코드 기본값
fallbackResult.put("buildNumber", 6); // 빌드 번호 기본값
fallbackResult.put("packageName", getContext().getPackageName());
fallbackResult.put("androidVersion", Build.VERSION.RELEASE);
fallbackResult.put("androidSDK", Build.VERSION.SDK_INT);
fallbackResult.put("platform", "android-fallback");
fallbackResult.put("error", e.getMessage());
fallbackResult.put("timestamp", System.currentTimeMillis());
Log.d(TAG, "오류 발생으로 기본값 반환: " + fallbackResult.toString());
call.resolve(fallbackResult); // reject 대신 기본값으로 resolve
} }
} }
} }

View File

@@ -1,8 +1,20 @@
import React, { useCallback, useEffect, useState, useRef, useMemo } from 'react';
import React, { useCallback, useEffect, useState, useRef } from 'react';
import { getAppVersionInfo, isAndroidPlatform, isIOSPlatform } from '@/utils/platform'; import { getAppVersionInfo, isAndroidPlatform, isIOSPlatform } from '@/utils/platform';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
// 버전 정보 인터페이스 정의
interface VersionInfo {
versionName: string;
buildNumber: number;
versionCode?: number;
platform?: string;
pluginResponse?: string;
timestamp?: number;
error?: boolean;
errorMessage?: string;
defaultValues?: boolean;
}
interface AppVersionInfoProps { interface AppVersionInfoProps {
className?: string; className?: string;
showDevInfo?: boolean; showDevInfo?: boolean;
@@ -14,16 +26,61 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
showDevInfo = true, showDevInfo = true,
editable = false editable = false
}) => { }) => {
const [versionInfo, setVersionInfo] = useState<{ // localStorage에서 이전에 저장된 버전 정보 가져오기
versionName: string; const getSavedVersionInfo = useCallback((): VersionInfo | null => {
buildNumber: number; try {
versionCode?: number; const saved = localStorage.getItem('app_version_info');
platform?: string; return saved ? JSON.parse(saved) : null;
pluginResponse?: string; } catch (e) {
}>({ console.error('저장된 버전 정보 파싱 오류:', e);
versionName: '1.0.1', return null;
buildNumber: 3 }
}); }, []);
// 기본 버전 정보를 useMemo로 생성하여 불필요한 재계산 방지
const defaultInfo = useMemo<VersionInfo>(() => {
// 웹 환경에서는 더 높은 버전 정보를 기본값으로 사용
const webDefaultInfo: VersionInfo = {
versionName: '1.1.1.2', // 웹 환경에서 사용할 버전 이름
buildNumber: 6, // 웹 환경에서 사용할 빌드 번호
versionCode: 6, // 웹 환경에서 사용할 버전 코드
platform: 'web',
defaultValues: false // 기본값이 아닌 것으로 설정하여 우선순위 높이기
};
// localStorage에 저장된 정보 가져오기
const savedInfo = getSavedVersionInfo();
console.log('불러온 저장 정보:', savedInfo);
// 웹 환경에서는 웹 기본값, 안드로이드/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()) {
try {
console.log('웹 기본 정보를 localStorage에 초기 저장');
localStorage.setItem('app_version_info', JSON.stringify(result));
} catch (e) {
console.error('초기 정보 저장 실패:', e);
}
}
return result;
}, [getSavedVersionInfo]);
const [versionInfo, setVersionInfo] = useState<VersionInfo>(defaultInfo);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(false); const [error, setError] = useState(false);
const [retries, setRetries] = useState(0); const [retries, setRetries] = useState(0);
@@ -35,12 +92,25 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
try { try {
console.log('앱 버전 정보 요청 시작... (retries:', retries, ')'); console.log('앱 버전 정보 요청 시작... (retries:', retries, ')');
console.log('현재 플랫폼은', console.log('현재 플랫폼은',
isAndroidPlatform() ? 'Android' : isIOSPlatform() ? 'iOS' : '알 수 없음'); isAndroidPlatform() ? 'Android' : isIOSPlatform() ? 'iOS' : '');
// 재시도를 하는 경우 은 지연 추가 // 재시도를 하는 경우 은 지연 추가
if (retries > 0) { if (retries > 0) {
await new Promise(resolve => setTimeout(resolve, 300)); 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(); const info = await getAppVersionInfo();
console.log('받은 앱 버전 정보:', info); console.log('받은 앱 버전 정보:', info);
@@ -49,28 +119,73 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
throw new Error('유효하지 않은 응답 형식'); throw new Error('유효하지 않은 응답 형식');
} }
// 유효한 빌드 번호인지 확인하고 숫자로 변환 // 타입 안전성을 위한 변환 함수
let buildNumber = info.buildNumber; const parseVersionInfo = (data: any): VersionInfo => {
if (typeof buildNumber === 'string') { // 빌드 번호 변환
buildNumber = parseInt(buildNumber, 10); let buildNumber: number = defaultInfo.buildNumber;
if (typeof data.buildNumber === 'number') {
buildNumber = data.buildNumber;
} else if (typeof data.buildNumber === 'string' && data.buildNumber.trim() !== '') {
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);
if (!isNaN(parsed)) versionCode = parsed;
}
// 응답 객체 구성
return {
versionName: typeof data.versionName === 'string' && data.versionName.trim() !== ''
? data.versionName
: defaultInfo.versionName,
buildNumber,
versionCode,
platform: typeof data.platform === 'string' ? data.platform : defaultInfo.platform,
pluginResponse: typeof data.pluginResponse === 'string'
? data.pluginResponse
: JSON.stringify(data),
timestamp: typeof data.timestamp === 'number' ? data.timestamp : Date.now(),
defaultValues: false
};
};
// 타입 변환 및 정제
const newVersionInfo = parseVersionInfo(info);
// 웹 환경에서는 defaultValues가 true인 경우(기본값) localStorage 값 우선 적용
if (!isAndroidPlatform() && !isIOSPlatform() && newVersionInfo.defaultValues && savedInfo) {
console.log('웹 환경의 기본값 대신 저장된 값 사용');
setVersionInfo(savedInfo);
setLoading(false);
return;
} }
setVersionInfo({ // LocalStorage에 버전 정보 저장
versionName: info.versionName || '1.0.1', try {
buildNumber: isNaN(buildNumber) ? 3 : buildNumber, localStorage.setItem('app_version_info', JSON.stringify(newVersionInfo));
versionCode: info.versionCode, console.log('버전 정보가 localStorage에 저장됨:', newVersionInfo);
platform: info.platform, } catch (e) {
pluginResponse: info.pluginResponse console.warn('버전 정보 저장 실패:', e);
}); }
setVersionInfo(newVersionInfo);
setLoading(false); setLoading(false);
console.log('앱 버전 정보 표시 준비 완료'); console.log('앱 버전 정보 표시 준비 완료');
} catch (error) { } catch (error) {
console.error('버전 정보 가져오기 실패:', error); console.error('버전 정보 가져오기 실패:', error);
setError(true); setError(true);
setLoading(false); setLoading(false);
// 오류 발생 시 기존 저장된 값 유지 (초기화 방지)
console.log('오류 발생으로 기본값 사용');
} }
}, [retries]); }, [retries, defaultInfo]);
// 재시도 처리 // 재시도 처리
const handleRetry = useCallback(() => { const handleRetry = useCallback(() => {
@@ -83,6 +198,9 @@ const AppVersionInfo: React.FC<AppVersionInfoProps> = ({
// 컴포넌트 마운트 시 즉시 실행 (IIFE) // 컴포넌트 마운트 시 즉시 실행 (IIFE)
useEffect(() => { useEffect(() => {
// 초기화 직후 localStorage 확인
console.log('컴포넌트 마운트 시 localStorage 확인:', localStorage.getItem('app_version_info'));
let isMounted = true; let isMounted = true;
(async () => { (async () => {