## 릴리즈 빌드 준비 - android/app/build.gradle.kts: 디버그 키로 서명하던 release 빌드 타입을 android/key.properties 기반 정식 릴리즈 키스토어(upload-keystore.jks) 서명으로 변경 - applicationId를 com.example.school_attendance → com.backsanhighschool.app 로 변경 (com.example.* 패키지는 구글 플레이 업로드 자체가 거부되기 때문) ## Firebase 재등록 - 새 패키지명(com.backsanhighschool.app)으로 Firebase Android 앱을 새로 등록 - google-services.json, lib/firebase_options.dart, firebase.json을 새 앱 ID 기준으로 재생성 ## HTTPS 전환 - lib/config.dart: baseUrl을 http:// → https:// 로 변경 (서버에 이미 발급되어 있었지만 프록시에 연결이 안 되어 있던 Let's Encrypt 인증서를 nginx-proxy-manager에 연결하고 HTTP→HTTPS 강제 리다이렉트 설정) - AndroidManifest.xml: 더 이상 필요 없는 usesCleartextTraffic="true" 제거 ## NFC 태그 쓰기 기능 (신규) - lib/screens/nfc_tag_writer_screen.dart 추가: 관리자가 빈 NFC 스티커에 "POCKET_번호" 텍스트를 쓰고, 태그 하드웨어 UID를 서버(/api/pockets/register)에 등록해서 태그 복제(내용만 베낀 위조 태그)를 방지 - lib/nfc_poccket_checkin_screen.dart: 체크인 시 태그 UID를 함께 서버로 전송해서 등록된 진짜 주머니 번호로 검증하도록 변경 - lib/screens/student_dashboard.dart: 개발자 메뉴에 "NFC 태그 쓰기" 카드 추가, 기존 "가상 NFC 태깅" 카드는 "NFC 태그"로 이름 변경 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
69 lines
2.6 KiB
Dart
69 lines
2.6 KiB
Dart
// 🌐 앱 전역 공통 설정 및 유틸 함수 모음
|
|
// (서버 주소, FCM 관련 상수/함수, 기기 UUID 조회 등 여러 화면에서 공유하는 것들)
|
|
import 'dart:io';
|
|
import 'package:device_info_plus/device_info_plus.dart';
|
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
|
|
|
// 🌐 기존에 사용하시던 실제 백엔드 서버 도메인 주소로 통일합니다.
|
|
const String baseUrl = 'https://backsanhi.mcv.kr';
|
|
|
|
// 🔑 웹에서 FCM 토큰을 받으려면 필요한 VAPID 키
|
|
// (Firebase Console > 프로젝트 설정 > Cloud Messaging > 웹 구성 > 웹 푸시 인증서에서 발급)
|
|
const String webVapidKey =
|
|
'BG4LnirukBdW3cXVWxhvY9pcjevBKDhpsaq1SLZdBs2cOEiwLAFyuuZLkMqpEGp9uOuHdPOe_y3FdwdZaz3qdfk';
|
|
|
|
// 권한 요청 및 FCM 토큰을 가져와서 콘솔에 출력하는 함수
|
|
Future<void> printFCMToken() async {
|
|
try {
|
|
FirebaseMessaging messaging = FirebaseMessaging.instance;
|
|
|
|
// 1. 🚨 안드로이드/iOS 알림 권한 요청 (이 코드가 핵심이야!)
|
|
print("🚨 [FCM] 알림 권한 요청 중...");
|
|
NotificationSettings settings = await messaging.requestPermission(
|
|
alert: true,
|
|
badge: true,
|
|
sound: true,
|
|
);
|
|
|
|
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
|
|
print("🚨 [FCM] 알림 권한 허용됨! 🎉");
|
|
} else if (settings.authorizationStatus == AuthorizationStatus.denied) {
|
|
print("🚨 [FCM] 알림 권한 거부됨... 😢 (설정에서 직접 켜야 합니다)");
|
|
}
|
|
|
|
// 2. 토큰 불러오기 (웹은 VAPID 키가 필요함)
|
|
print("🚨 [FCM] 토큰을 불러오는 중...");
|
|
String? token = kIsWeb
|
|
? await messaging.getToken(vapidKey: webVapidKey)
|
|
: await messaging.getToken();
|
|
|
|
if (token != null) {
|
|
print("🚨 [FCM 토큰 발급 성공] 👉 $token");
|
|
} else {
|
|
print("🚨 [FCM 토큰] 토큰이 null입니다.");
|
|
}
|
|
} catch (e) {
|
|
print("🚨 [FCM 토큰 에러] 👉 $e");
|
|
}
|
|
}
|
|
|
|
// 📱 폰의 고유 식별 번호(UUID)를 가져오는 공통 함수
|
|
Future<String> getDeviceUuid() async {
|
|
final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
|
|
String uuid = "UNKNOWN_DEVICE";
|
|
|
|
try {
|
|
if (Platform.isAndroid) {
|
|
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
|
|
uuid = androidInfo.id; // 안드로이드 폰의 고유 하드웨어 ID 추출
|
|
} else if (Platform.isIOS) {
|
|
IosDeviceInfo iosInfo = await deviceInfo.iosInfo;
|
|
uuid = iosInfo.identifierForVendor ?? "UNKNOWN_IOS"; // iOS 고유 ID
|
|
}
|
|
} catch (e) {
|
|
print("기기 ID 추출 failed: $e");
|
|
}
|
|
return uuid;
|
|
}
|