마켓(Play Store, App Store) 업데이트가 필요한 경우
- 플러그인을 업데이트하는 경우
- 예를 들어, vibration 패키지의 새 버전에서 내부 네이티브 코드가 변경되었다면, 새 버전의 앱을 빌드하여 Play Store/App Store에 다시 업로드해야 함.
- Android/iOS 네이티브 코드(AndroidManifest.xml, Info.plist, Kotlin/Swift) 변경 시
- 예를 들어, 새로운 푸시 알림 기능을 추가하려고 AndroidManifest.xml 또는 Info.plist 설정을 변경했다면 마켓 업데이트 필요.
마켓 업데이트 없이 적용 가능한 경우
- 단순한 UI 변경, 버그 수정, 서버에서 데이터 가져오는 방식 변경
- Shorebird(코드 푸시)를 이용하는 경우
Shorebird Code Push
Shorebird는 Flutter 앱을 업데이트할 때 전체 앱을 다시 빌드하지 않고 Dart 코드만 교체할 수 있는 기술.
- 네이티브(Android/iOS) 코드 변경 없이, Dart 코드만 업데이트 가능.
- UI 수정, 로직 변경, 버그 수정 가능.
- 하지만 네이티브 플러그인 업데이트나 Android/iOS SDK 변경은 불가능.
Shorebird로 가능한 것 ❌ 불가능한 것
업데이트 유형Shorebird 지원 여부
UI 변경 (Text, 버튼, 컬러 변경) | ✅ 가능 |
비즈니스 로직 변경 (예: API 주소 변경) | ✅ 가능 |
버그 수정 (예: 크래시 해결) | ✅ 가능 |
새로운 화면 추가 (Dart 코드로만 구현된 경우) | ✅ 가능 |
플러그인 업데이트 (예: firebase_messaging 버전 업) | ❌ 불가능 |
Android/iOS 네이티브 코드 수정 (예: MainActivity, AppDelegate 변경) | ❌ 불가능 |
AndroidManifest.xml 또는 Info.plist 변경 | ❌ 불가능 |
미리 모든 네이티브 플러그인을 추가
- 마켓 업데이트 없이 Shorebird 또는 서버에서 기능 활성화(Feature Flag) 방식으로 새로운 기능을 활성화할 수 있음.
- 앱을 배포할 때, 이후 필요한 기능을 추가하는 데 마켓 승인 시간을 절약할 수 있음.
- 예를 들어
dependencies:
vibration: latest_version
url_launcher: latest_version
geolocator: latest_version
camera: latest_version
firebase_messaging: latest_version
flutter_local_notifications: latest_version
위와 같이 모든 네이티브 기능을 미리 추가해 두면, 나중에 Shorebird를 통해 코드 수정만으로 해당 기능을 활성화할 수 있음
미리 네이티브 플러그인 추가의 몇 가지 문제점
1. 앱 용량이 불필요하게 커짐
- 사용하지 않는 네이티브 플러그인까지 포함되므로 앱 크기가 증가할 수 있음.
- 네이티브 라이브러리는 Flutter build 과정에서 포함되므로 불필요한 기능까지 앱에 탑재됨.
2. iOS의 App Store Review에서 거절될 가능성 있음
- Apple App Store 정책상 사용하지 않는 권한(예: 카메라, 위치 정보)이 있는 경우, 심사에서 거절될 수 있음.
- 예를 들어, camera 플러그인을 추가했지만 카메라 기능을 사용하지 않으면 "권한 요청 불필요" 등의 이유로 거절될 가능성이 있음.
- iOS에서는 Info.plist에 권한을 정의해야 하는데, 이를 미리 추가하면 심사에서 문제될 가능성이 높음.
<key>NSCameraUsageDescription</key>
<string>이 앱은 카메라를 사용합니다.</string>
3. Android Play Store에서도 불필요한 권한이 감지될 수 있음
- AndroidManifest.xml에 불필요한 권한이 남아있으면, Google Play에서 정책 위반으로 앱이 등록되지 않을 가능성이 있음
- 예를 들어, geolocator 패키지를 추가하면 Android는 위치 권한을 자동으로 포함시키는데, 실제 사용하지 않으면 Google Play 심사에서 거부될 수 있음
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
그러면 어떻게???
방법 1: 필요한 플러그인만 최소한으로 추가
- 처음부터 모든 네이티브 기능을 추가하지 말고, 필요할 때 추가하는 게 최선.
방법 2: 앱 권한을 동적으로 요청
- Android에서는 AndroidManifest.xml에서 권한을 미리 추가하되, Permission Handler 플러그인을 활용해 동적으로 요청하면 Google Play 심사에서 문제될 가능성을 줄일 수 있음
import 'package:permission_handler/permission_handler.dart';
void requestCameraPermission() async {
var status = await Permission.camera.request();
if (status.isGranted) {
print("카메라 권한 허용됨");
} else if (status.isDenied) {
print("카메라 권한 거부됨");
} else if (status.isPermanentlyDenied) {
print("카메라 권한이 영구적으로 거부됨. 설정에서 변경해야 함.");
openAppSettings(); // 앱 설정 화면 열기
}
}
앱을 실행할 때 권한을 동적으로 요청하면 심사에서 "불필요한 권한 추가" 문제를 방지할 수 있음
여러개 권한 요청
void requestMultiplePermissions() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.camera,
Permission.microphone,
Permission.location
].request();
print("카메라 권한: ${statuses[Permission.camera]}");
print("마이크 권한: ${statuses[Permission.microphone]}");
print("위치 권한: ${statuses[Permission.location]}");
}
방법 3: Feature Flag(기능 플래그) 활용
- Firebase Remote Config 또는 자체 API를 활용해 특정 기능을 서버에서 활성화/비활성화하는 방법.
- 예를 들어, 앱에는 camera 플러그인이 포함되어 있지만, 앱 UI에서 버튼을 숨겨놓고 Firebase Remote Config를 통해 카메라 기능을 나중에 활성화할 수 있음.
import 'package:firebase_remote_config/firebase_remote_config.dart';
void checkFeatureFlag() async {
final remoteConfig = FirebaseRemoteConfig.instance;
await remoteConfig.fetchAndActivate();
bool isCameraEnabled = remoteConfig.getBool("enable_camera");
if (isCameraEnabled) {
print("카메라 기능 활성화됨");
} else {
print("카메라 기능 비활성화됨");
}
}
방법 4: 네이티브 기능을 MethodChannel로 직접 호출
- 모든 네이티브 기능을 플러그인으로 추가하지 않고, Flutter → 네이티브(Android/iOS)로 직접 요청하는 방식(MethodChannel 사용).
- 플러그인이 아니라 네이티브 코드에서 기능을 처리하므로, 필요할 때만 기능을 활성화할 수 있음.
예: Flutter에서 Android 네이티브 진동 기능 호출
import 'package:flutter/services.dart';
const platform = MethodChannel('com.example.vibrate');
void triggerVibration() async {
try {
await platform.invokeMethod('vibrate');
} on PlatformException catch (e) {
print("에러 발생: ${e.message}");
}
}
Android 네이티브 코드(Java)
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.example.vibrate";
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("vibrate")) {
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null && vibrator.hasVibrator()) {
vibrator.vibrate(500);
result.success("Vibration started");
} else {
result.error("UNAVAILABLE", "Vibrator not available", null);
}
} else {
result.notImplemented();
}
}
);
}
}
이렇게 하면 Shorebird로 Flutter 코드만 변경하면서도, 네이티브 기능을 필요할 때만 활성화할 수 있음.
위의 방법 2의 동적으로 권한 요청 (안드로이드 AndroidManifest.xml 만 가능)
서버에서 권한 활성화 여부를 설정 (Feature Flag)
- Firebase Remote Config 또는 자체 API를 사용하여 앱에서 특정 권한을 요청할지 여부를 서버에서 결정.
- 이렇게 하면 앱 코드 자체는 변경하지 않고, 서버에서 설정만 변경하여 기능 활성화 가능.
예제: Firebase Remote Config를 활용하여 카메라 권한 활성화 여부를 서버에서 제어
import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:permission_handler/permission_handler.dart';
void checkFeatureFlag() async {
final remoteConfig = FirebaseRemoteConfig.instance;
await remoteConfig.fetchAndActivate();
bool isCameraEnabled = remoteConfig.getBool("enable_camera");
if (isCameraEnabled) {
print("카메라 기능 활성화됨. 권한 요청 시작.");
requestCameraPermission();
} else {
print("카메라 기능 비활성화됨. 권한 요청 안 함.");
}
}
서버에서 enable_camera 값을 false로 설정하면, 앱은 카메라 권한을 요청하지 않음
Android에서 AndroidManifest.xml을 동적으로 설정하는 방법
AndroidManifest.xml을 직접 변경할 수는 없지만, Flutter 앱 빌드 시 권한을 동적으로 추가하는 방법이 있음.
- Android Gradle에서 AndroidManifest.xml을 서버에서 가져오기
- Flutter에서 앱을 빌드할 때 manifestPlaceholders로 동적으로 추가
예: Android Gradle에서 권한을 동적으로 추가
android {
defaultConfig {
manifestPlaceholders = [
ENABLE_CAMERA: "true"
]
}
}
예: AndroidManifest.xml에서 동적으로 적용
<uses-permission android:name="android.permission.CAMERA" android:required="${ENABLE_CAMERA}"/>
'Flutter' 카테고리의 다른 글
Flutter 이벤트 사용법 (0) | 2025.02.02 |
---|---|
Flutter 기본 정리 (0) | 2025.02.02 |