feat(flutter): [새 버전 받기]를 포털 받기 화면으로 바꾸고 release 는 우리 키 · 운영 주소로만 만든다

스토어에 올리지 않으니 업데이트 화면의 Play 스토어 열기를 포털 /app 을 바깥 브라우저로 여는 것으로 바꾸고,
설정 › 앱 정보에도 같은 줄을 더했다. release 빌드는 우리 서명 키(key.properties) · google-services.json ·
운영 포털의 https API 주소가 갖춰지지 않으면 까닭을 알리고 멈춘다 — debug 키로 조용히 서명되거나
개발 주소가 든 판이 직원에게 나가지 않게(알리는 글에 주소 값은 싣지 않는다).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-08 23:29:05 +09:00
parent 433ef12cc3
commit e9acb7809c
17 changed files with 755 additions and 173 deletions
+2 -12
View File
@@ -44,23 +44,14 @@ String _clean(String? value) {
: kept;
}
/// 이 기기의 앱 판 · 패키지 이름(업데이트 화면의 Play 스토어 주소) · User-Agent · 안드로이드 판(API — 새 메일 알림의 권한을 가른다) — main 에서 한 번.
/// 이 기기의 앱 판 · User-Agent · 안드로이드 판(API — 새 메일 알림의 권한을 가른다) — main 에서 한 번.
/// 기기 정보를 읽지 못하면 아는 것만 싣는다.
Future<
({
String? appVersion,
String? packageName,
String userAgent,
int? androidSdkInt,
})
>
Future<({String? appVersion, String userAgent, int? androidSdkInt})>
loadAppDeviceInfo() async {
String? appVersion;
String? packageName;
try {
final PackageInfo info = await PackageInfo.fromPlatform();
appVersion = info.version;
packageName = info.packageName.isEmpty ? null : info.packageName;
} on PlatformException {
appVersion = null;
}
@@ -69,7 +60,6 @@ loadAppDeviceInfo() async {
);
return (
appVersion: appVersion,
packageName: packageName,
userAgent: device.userAgent,
androidSdkInt: device.androidSdkInt,
);
@@ -0,0 +1,73 @@
import 'package:arasystem_app/core/api/dio_provider.dart';
import 'package:arasystem_app/core/app_download/app_download_link.dart';
import 'package:arasystem_app/core/app_download/app_download_texts.dart';
import 'package:arasystem_app/shared/widgets/keep_all_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
/// 다른 앱으로 주소를 넘기는 함수 — 기본은 url_launcher 의 [launchUrl]. 시험은 가짜를 넣는다
typedef AppDownloadLaunch = Future<bool> Function(Uri url, LaunchMode mode);
Future<bool> _launchExternal(Uri url, LaunchMode mode) =>
launchUrl(url, mode: mode);
/// [새 버전 받기] — 포털의 휴대폰 앱 받기 화면(`app_download_link.dart`)을 바깥 브라우저로 연다.
/// 업데이트 화면과 설정 › 앱 정보가 이 런처 하나를 함께 쓴다(같은 주소 · 같은 실패 알림).
///
/// - 바깥 앱(`LaunchMode.externalApplication` — 휴대폰의 기본 브라우저)으로 연다. 받기 화면은 로그인한 직원만 받으므로
/// 브라우저의 웹메일 로그인을 쓴다(앱의 토큰은 넘기지 않는다).
/// - `canLaunchUrl` 은 쓰지 않는다(debug 판 안드로이드가 묻는 주소를 로그에 남긴다 — 인증 앱 열기와 같은 규칙).
/// 못 열면 플러그인 예외를 버리고 거짓 — 화면이 [failureMessage] 를 알린다
class AppDownloadLauncher {
AppDownloadLauncher({
required String apiBaseUrl,
AppDownloadLaunch launch = _launchExternal,
}) : pageUrl = appDownloadPageUrlOf(apiBaseUrl),
_launch = launch;
/// 받기 화면 주소 — 앱의 API 주소로 만들지 못했으면 null(열지 않고 알린다)
final Uri? pageUrl;
final AppDownloadLaunch _launch;
/// 열었으면 참
Future<bool> open() async {
final Uri? url = pageUrl;
if (url == null) return false;
try {
return await _launch(url, LaunchMode.externalApplication);
} on Object {
// PlatformException(받을 앱 없음 · 화면 없음) 등 — 화면은 주소를 알려 직접 들어가게 한다
return false;
}
}
/// 열지 못했을 때의 알림 글 — 직원이 브라우저에 직접 넣을 주소(스킴 없이)를 담는다
String get failureMessage {
final Uri? url = pageUrl;
return url == null
? AppDownloadTexts.openFailedNoAddress
: AppDownloadTexts.openFailed(appDownloadPageAddressOf(url));
}
}
/// 받기 화면 런처 — 앱의 API 주소(`apiConfigProvider`)로 주소를 만든다. 시험은 가짜로 덮어쓴다
final Provider<AppDownloadLauncher> appDownloadLauncherProvider =
Provider<AppDownloadLauncher>(
(Ref ref) =>
AppDownloadLauncher(apiBaseUrl: ref.watch(apiConfigProvider).baseUrl),
);
/// [새 버전 받기]를 누른 뒤 — 받기 화면을 열고, 열지 못하면 주소를 담아 알린다(두 화면이 같은 알림을 쓴다).
/// [messenger] 는 누른 화면에서 기다리기 전에 잡아 둔다(브라우저가 뜨는 동안 화면이 바뀔 수 있다)
Future<void> openAppDownloadPage(
WidgetRef ref,
ScaffoldMessengerState messenger,
) async {
final AppDownloadLauncher launcher = ref.read(appDownloadLauncherProvider);
if (await launcher.open()) return;
messenger
..hideCurrentSnackBar()
..showSnackBar(SnackBar(content: KeepAllText(launcher.failureMessage)));
}
@@ -0,0 +1,30 @@
/// 포털의 휴대폰 앱 받기 화면 주소 — 앱을 스토어에 올리지 않고 사내에서 직접 나눠 주는 곳(2026-11-08).
/// 앱의 업데이트 화면 · 설정 › 앱 정보의 [새 버전 받기]가 이 주소를 바깥 브라우저로 연다(앱 보드 `App1Push` ⑩ · ④).
///
/// 같은 주소 배포라 앱의 API 주소(`.env` 의 `API_URL` — `ApiConfig.baseUrl`)는 늘 포털 출처의 `/api` 다.
/// 그래서 받는 곳 주소를 서버에서 받지 않고(앱 설정 계약은 싣지 않는다) API 주소의 출처에 받기 화면 경로를 붙여 만든다.
library;
/// 받기 화면 경로 — 짝: 웹 `frontend/src/shared/constants/mobile-app.ts` 의 `MOBILE_APP_PATH`(한쪽을 바꾸면 둘 다)
const String kAppDownloadPagePath = '/app';
/// API 주소에서 받기 화면 주소를 만든다 — `https://portal.arasystem.it.kr/api` → `https://portal.arasystem.it.kr/app`.
///
/// 출처(스킴 · 호스트 · 포트)만 남긴다: API 경로(`/api`) · 쿼리 · 조각 · 사용자 정보는 버리고, 스킴의 기본 포트는 적지 않는다.
/// http · https 주소가 아니거나 호스트가 없으면 null — 화면은 주소 없이 알린다
Uri? appDownloadPageUrlOf(String apiBaseUrl) {
final Uri? api = Uri.tryParse(apiBaseUrl.trim());
if (api == null) return null;
if (api.scheme != 'http' && api.scheme != 'https') return null;
if (api.host.isEmpty) return null;
return Uri(
scheme: api.scheme,
host: api.host,
port: api.hasPort ? api.port : null,
path: kAppDownloadPagePath,
);
}
/// 알림에 보이는 주소 — 스킴 없이(`portal.arasystem.it.kr/app` · `10.0.2.2:5173/app`).
/// 직원이 휴대폰 브라우저의 주소 칸에 그대로 넣는다
String appDownloadPageAddressOf(Uri url) => '${url.authority}${url.path}';
@@ -0,0 +1,16 @@
/// 휴대폰 앱 받기 화면을 여는 [새 버전 받기]의 글 — 업데이트 화면(`features/app_update`)과 설정 › 앱 정보(`features/settings`)가 함께 쓴다.
///
/// 앱 보드 `App1Push` ⑩ · ④ 앱 정보 절(2026-11-08 확정 — 캔버스 v68)의 글 그대로다(디자인 README 「화면 문구 — 사용자에게 말하듯」).
abstract final class AppDownloadTexts {
/// 업데이트 화면의 단추 · 설정 › 앱 정보의 줄
static const String getNewVersion = '새 버전 받기';
/// 브라우저를 열지 못했을 때(알림) — [address] 는 받기 화면 주소를 스킴 없이(`portal.arasystem.it.kr/app`).
/// 직원이 휴대폰 브라우저에 직접 넣는다
static String openFailed(String address) =>
'브라우저를 열지 못했습니다. 휴대폰의 브라우저에서 $address에 들어가 새 버전을 받아 주세요.';
/// 받기 화면 주소를 만들지 못했을 때(앱의 API 주소가 http · https 주소가 아니다 — 보드에 없는 경우.
/// 그런 판은 서버에도 닿지 못해 업데이트 화면 · 설정 탭에 오지 않는다)
static const String openFailedNoAddress = '브라우저를 열지 못했습니다. 관리자에게 문의해 주세요.';
}
@@ -1,7 +1,7 @@
/// 앱 전체에서 쓰는 이름 · 식별 값.
///
/// 식별자(Android applicationId · iOS bundle id `kr.it.arasystem.app`)는 플랫폼 설정 파일에 있다 —
/// 스토어에 올린 뒤에는 바꿀 수 없다.
/// 직원 휴대폰에 설치한 뒤에는 바꿀 수 없다(식별자가 다르면 다른 앱이라 새 판이 그 위에 설치되지 않는다).
library;
/// 홈 화면 · 작업 전환 화면에 보이는 앱 이름
@@ -5,9 +5,3 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
final Provider<String?> appVersionProvider = Provider<String?>(
(Ref ref) => null,
);
/// 앱 식별자(패키지 이름 — Android applicationId `kr.it.arasystem.app`). main 이 기기 정보를 읽어 덮어쓴다.
/// 업데이트 화면의 [Play 스토어 열기]가 쓴다 — 읽지 못했으면 null(단추를 누르면 열지 못했다고 알린다)
final Provider<String?> appPackageNameProvider = Provider<String?>(
(Ref ref) => null,
);
@@ -1,52 +0,0 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:url_launcher/url_launcher.dart';
/// 다른 앱으로 주소를 넘기는 함수 — 기본은 url_launcher 의 [launchUrl]. 시험은 가짜를 넣는다
typedef StoreLaunch = Future<bool> Function(Uri url, LaunchMode mode);
Future<bool> _launchExternal(Uri url, LaunchMode mode) =>
launchUrl(url, mode: mode);
/// Play 스토어의 이 앱 쪽 주소(앱이 없을 때 여는 웹 주소)
const String kPlayStoreWebDetails =
'https://play.google.com/store/apps/details';
/// [Play 스토어 열기] — 이 앱의 Play 스토어 쪽을 연다(업데이트 화면).
///
/// 먼저 Play 스토어 앱(`market://details?id=…` — 브라우저가 아닌 앱만), 열리지 않으면 웹 주소를 바깥 앱(브라우저)으로.
/// 패키지 이름은 앱 정보에서 읽은 값이다(하드코딩하지 않는다). `canLaunchUrl` 은 쓰지 않는다(debug 판이 주소를 로그에 남긴다 —
/// 인증 앱 열기와 같은 규칙). 못 열면 플러그인 예외를 버리고 거짓 — 화면이 알린다
class AppStoreLauncher {
const AppStoreLauncher({StoreLaunch launch = _launchExternal})
: _launch = launch;
final StoreLaunch _launch;
/// 열었으면 참
Future<bool> open(String packageName) async {
final Uri market = Uri(
scheme: 'market',
host: 'details',
queryParameters: <String, String>{'id': packageName},
);
if (await _tryLaunch(market, LaunchMode.externalNonBrowserApplication)) {
return true;
}
final Uri web = Uri.parse(
kPlayStoreWebDetails,
).replace(queryParameters: <String, String>{'id': packageName});
return _tryLaunch(web, LaunchMode.externalApplication);
}
Future<bool> _tryLaunch(Uri url, LaunchMode mode) async {
try {
return await _launch(url, mode);
} on Object {
return false;
}
}
}
/// [Play 스토어 열기] — 시험은 가짜로 덮어쓴다
final Provider<AppStoreLauncher> appStoreLauncherProvider =
Provider<AppStoreLauncher>((Ref ref) => const AppStoreLauncher());
@@ -1,22 +1,18 @@
/// 업데이트 화면의 글 — 앱 보드 `App1Push` ⑩(2026-11-07 확정)의 글 그대로다. 제목은 `core/constants/screen_titles.dart` 의 `ScreenTitles.update`.
/// 업데이트 화면의 글 — 앱 보드 `App1Push` ⑩(2026-11-08 사내 직접 배포로 고쳐 확정 — 캔버스 v68)의 글 그대로다.
/// 제목은 `core/constants/screen_titles.dart` 의 `ScreenTitles.update`, [새 버전 받기]와 브라우저를 열지 못했을 때의 알림은
/// 설정 › 앱 정보와 함께 쓰므로 `core/app_download/app_download_texts.dart` 에 있다.
///
/// 화면 글은 디자인 README 「화면 문구 — 사용자에게 말하듯」 말투를 따른다.
abstract final class AppUpdateTexts {
static const String message =
'지금 쓰는 버전으로는 로그인하거나 메일을 볼 수 없습니다. Play 스토어에서 ARA SYSTEM을 업데이트한 뒤 다시 열어 주세요.';
static const String openStore = 'Play 스토어 열기';
'지금 쓰는 버전으로는 로그인하거나 메일을 볼 수 없습니다. 새 버전을 받아 설치한 뒤 다시 열어 주세요.';
/// 지금 쓰는 판 — "지금 쓰는 버전 1.0.0"
static String currentVersion(String version) => '지금 쓰는 버전 $version';
/// 문의 줄 — 연락처(`GET /api/support-contact`)가 있으면 물음 다음 줄에 연락처
static const String supportQuestion = 'Play 스토어에 업데이트가 보이지 않나요?';
static const String supportQuestion = '새 버전을 받거나 설치하기 어려우신가요?';
/// 연락처를 정하지 않았거나 받지 못했을 때(보드에 없는 경우 — 로그인 화면의 문의 줄과 같은 꼴)
static const String supportFallback =
'Play 스토어에 업데이트가 보이지 않나요? 관리자에게 문의해 주세요.';
/// Play 스토어를 열지 못했을 때(알림)
static const String openStoreFailed =
'Play 스토어를 열지 못했습니다. Play 스토어 앱을 직접 열어 ARA SYSTEM을 찾아 업데이트해 주세요.';
static const String supportFallback = '새 버전을 받거나 설치하기 어려우신가요? 관리자에게 문의해 주세요.';
}
@@ -1,11 +1,12 @@
import 'dart:async';
import 'package:arasystem_app/core/app_download/app_download_launcher.dart';
import 'package:arasystem_app/core/app_download/app_download_texts.dart';
import 'package:arasystem_app/core/constants/app_info_provider.dart';
import 'package:arasystem_app/core/constants/screen_titles.dart';
import 'package:arasystem_app/core/theme/app_spacing.dart';
import 'package:arasystem_app/core/theme/app_theme.dart';
import 'package:arasystem_app/core/theme/app_typography.dart';
import 'package:arasystem_app/features/app_update/data/app_store_launcher.dart';
import 'package:arasystem_app/features/app_update/presentation/app_update_texts.dart';
import 'package:arasystem_app/features/auth/presentation/providers/login_providers.dart';
import 'package:arasystem_app/features/auth/presentation/widgets/login_frame.dart';
@@ -17,9 +18,10 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
/// 업데이트 화면 — 앱 보드 `App1Push` ⑩. 이 앱의 판이 서버의 최소 판보다 낮으면 라우터가 어느 화면에서든 이리로 옮긴다
/// (로그인 전 화면도 — 옛 앱이 로그인 API 를 잘못 부르지 않게. `core/router/session_redirect.dart`).
///
/// - 로그인 첫 단계처럼 큰 브랜드 띠(로고만) 아래에 제목 · 글 · [Play 스토어 열기] · 지금 쓰는 판 · 문의 줄.
/// - [Play 스토어 열기]: Play 스토어 앱 → 안 되면 웹 주소. 열지 못하면 알린다.
/// - 뒤로 가기는 앱을 닫는다(이 화면으로는 `go` 로만 오니 쌓인 화면이 없다). 업데이트하면 Play 가 앱을 끝내고,
/// - 로그인 첫 단계처럼 큰 브랜드 띠(로고만) 아래에 제목 · 글 · [새 버전 받기] · 지금 쓰는 판 · 문의 줄.
/// - [새 버전 받기]: 포털의 휴대폰 앱 받기 화면(`<포털 출처>/app`)을 바깥 브라우저로 연다 — 앱은 스토어에 올리지 않고
/// 사내에서 직접 나눠 준다(2026-11-08). 열지 못하면 그 주소를 담아 알린다(설정 › 앱 정보와 같은 런처 · 알림 — `core/app_download/`).
/// - 뒤로 가기는 앱을 닫는다(이 화면으로는 `go` 로만 오니 쌓인 화면이 없다). 새 판을 설치하면 안드로이드가 이 앱을 끝내고,
/// 서버가 최소 판을 내리면 다음 확인에서 세션이 고른 화면으로 돌아간다.
class AppUpdatePage extends ConsumerStatefulWidget {
const AppUpdatePage({super.key});
@@ -35,18 +37,8 @@ class _AppUpdatePageState extends ConsumerState<AppUpdatePage> {
unawaited(ref.read(supportContactProvider.notifier).ensureLoaded());
}
Future<void> _openStore() async {
final ScaffoldMessengerState messenger = ScaffoldMessenger.of(context);
final String? packageName = ref.read(appPackageNameProvider);
final bool opened =
packageName != null &&
await ref.read(appStoreLauncherProvider).open(packageName);
if (opened) return;
messenger
..hideCurrentSnackBar()
..showSnackBar(
const SnackBar(content: KeepAllText(AppUpdateTexts.openStoreFailed)),
);
void _openDownloadPage() {
unawaited(openAppDownloadPage(ref, ScaffoldMessenger.of(context)));
}
@override
@@ -79,12 +71,12 @@ class _AppUpdatePageState extends ConsumerState<AppUpdatePage> {
],
),
FilledButton(
onPressed: () => unawaited(_openStore()),
onPressed: _openDownloadPage,
child: const Row(
mainAxisSize: MainAxisSize.min,
spacing: AppSpacing.s8,
children: <Widget>[
Text(AppUpdateTexts.openStore),
Text(AppDownloadTexts.getNewVersion),
Icon(Icons.open_in_new, size: AppSize.iconSmall),
],
),
@@ -1,5 +1,7 @@
import 'dart:async';
import 'package:arasystem_app/core/app_download/app_download_launcher.dart';
import 'package:arasystem_app/core/app_download/app_download_texts.dart';
import 'package:arasystem_app/core/constants/app_info_provider.dart';
import 'package:arasystem_app/core/modules/module_routes.dart';
import 'package:arasystem_app/core/theme/app_spacing.dart';
@@ -18,11 +20,12 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
/// 설정 탭 — 앱 보드 `App1Shell`(설정 탭 · 로그아웃 확인 창)과 `App1Push` ④(새 메일 알림 줄).
/// 설정 탭 — 앱 보드 `App1Shell`(설정 탭 · 로그아웃 확인 창)과 `App1Push` ④(새 메일 알림 줄 · 앱 정보 절).
/// 글자는 테마 크기로 맞췄다(보드 15.5 → 16 · 14 → 15 · 13 → 13 — 앱 디자인 README 의 크기 정리와 같다).
///
/// 한 화면에 절을 모두 둔다: 내 정보(이름 · 주소) · 알림(새 메일 알림) · 다른 모듈이 내놓은 절 · 앱 정보(앱 버전 · 오픈소스 라이선스) ·
/// 문의(`GET /api/support-contact` — 로그인 화면과 같은 저장소, 화면을 열 때 받아 둔다) · [로그아웃].
/// 한 화면에 절을 모두 둔다: 내 정보(이름 · 주소) · 알림(새 메일 알림) · 다른 모듈이 내놓은 절 ·
/// 앱 정보(앱 버전 · [새 버전 받기] · 오픈소스 라이선스) · 문의(`GET /api/support-contact` — 로그인 화면과 같은 저장소, 화면을 열 때 받아 둔다) · [로그아웃].
/// [새 버전 받기]는 업데이트 화면의 단추처럼 포털의 휴대폰 앱 받기 화면을 바깥 브라우저로 연다(같은 런처 · 같은 실패 알림 — `core/app_download/`).
/// [로그아웃]은 확인 창부터 연다(처음 초점은 [취소] — 로그아웃하면 이 휴대폰의 새 메일 알림도 멈춘다고 알린다).
/// 비밀번호 · 2단계 인증 같은 계정 설정은 웹에서 한다.
class SettingsPage extends ConsumerStatefulWidget {
@@ -65,6 +68,10 @@ class _SettingsPageState extends ConsumerState<SettingsPage> {
await ref.read(sessionProvider.notifier).signOut();
}
void _openDownloadPage() {
unawaited(openAppDownloadPage(ref, ScaffoldMessenger.of(context)));
}
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
@@ -118,6 +125,11 @@ class _SettingsPageState extends ConsumerState<SettingsPage> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_VersionRow(version: version),
_LinkRow(
label: AppDownloadTexts.getNewVersion,
opensOutside: true,
onTap: _openDownloadPage,
),
_LinkRow(
label: SettingsTexts.licenses,
onTap: () =>
@@ -321,13 +333,21 @@ class _VersionRow extends StatelessWidget {
}
}
/// 누르면 다른 화면으로 가는 한 줄 — 이름 · 오른쪽 화살표
/// 누르는 한 줄 — 이름 · 오른쪽 끝 아이콘. 앱 안의 다른 화면으로 가면 화살표, 바깥(브라우저)으로 열면 바깥으로 여는 아이콘
/// (보드: 화살표 20 · 바깥 아이콘 18 을 20 칸 가운데에 — 두 아이콘의 가운데가 맞는다)
class _LinkRow extends StatelessWidget {
const _LinkRow({required this.label, required this.onTap});
const _LinkRow({
required this.label,
required this.onTap,
this.opensOutside = false,
});
final String label;
final VoidCallback? onTap;
/// 바깥 앱(브라우저)으로 연다 — 끝 아이콘이 바깥으로 여는 아이콘
final bool opensOutside;
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
@@ -352,10 +372,15 @@ class _LinkRow extends StatelessWidget {
children: <Widget>[
Expanded(child: Text(label, style: theme.textTheme.bodyLarge)),
ExcludeSemantics(
child: Icon(
Icons.chevron_right,
size: AppSize.iconMedium,
color: extra.textMuted,
child: SizedBox.square(
dimension: AppSize.iconMedium,
child: Icon(
opensOutside ? Icons.open_in_new : Icons.chevron_right,
size: opensOutside
? AppSize.iconSmall
: AppSize.iconMedium,
color: extra.textMuted,
),
),
),
],
@@ -1,5 +1,6 @@
/// 설정 모듈의 화면 글 — 앱 보드 `App1Shell`(설정 탭 · 로그아웃 확인 창)의 글 그대로다.
/// 새 메일 알림 줄의 글은 받은편지함 권하기 줄과 함께 쓰므로 `core/push/push_texts.dart` 에 있다(보드 `App1Push`).
/// 앱 정보의 [새 버전 받기] 줄과 그 실패 알림은 업데이트 화면과 함께 쓰므로 `core/app_download/app_download_texts.dart` 에 있다(보드 `App1Push` ④).
///
/// 화면 글은 디자인 README 「화면 문구 — 사용자에게 말하듯」 말투를 따른다.
abstract final class SettingsTexts {
+2 -8
View File
@@ -41,13 +41,8 @@ Future<void> main() async {
firstRun: PrefsFirstRunMarker(),
);
await tokenStore.prepare();
final ({
String? appVersion,
String? packageName,
String userAgent,
int? androidSdkInt,
})
device = await loadAppDeviceInfo();
final ({String? appVersion, String userAgent, int? androidSdkInt}) device =
await loadAppDeviceInfo();
// 새 메일 알림(FCM) — Firebase 를 띄우고 플러그인의 소식 줄(FID · 받은 알림 · 누른 알림)을 지금 듣는다.
// 띄우지 못하면(google-services.json 없이 빌드 · 5초 넘음) 알림 없이 돈다 — 설정 줄은 "이 휴대폰에서는 받을 수 없음"
@@ -70,7 +65,6 @@ Future<void> main() async {
tokenStoreProvider.overrideWithValue(tokenStore),
userAgentProvider.overrideWithValue(device.userAgent),
appVersionProvider.overrideWithValue(device.appVersion),
appPackageNameProvider.overrideWithValue(device.packageName),
downloadedFileStoreProvider.overrideWithValue(downloadedFiles),
pickedFileStoreProvider.overrideWithValue(pickedFiles),
pushMessagingProvider.overrideWithValue(pushMessaging),