Flutter 앱과 안드로이드 네이티브 코드(Kotlin) 간의 통신을 위한 플러그인(Platform Channel) 구현 코드
📌 주요 역할
- Flutter에서 보낸 메소드 호출(Method Call) 을 안드로이드 네이티브에서 처리
- 할 일 목록(To-Do List)을 저장하고 불러오는 기능 제공
- SharedPreferences를 이용해 데이터를 저장 및 관리
📂 코드 상세 설명
1. 기본 클래스 및 변수 선언
class MainActivity : FlutterActivity() {
private val CHANNEL_NAME = "com.example.to_do_list/task_channel"
private val TAG = "MainActivity"
- MainActivity는 FlutterActivity를 상속받아 Flutter와 연결
- CHANNEL_NAME: Flutter와 통신할 때 사용하는 채널 이름 (Flutter에서 이 이름으로 메소드 호출)
- TAG: Log.d(TAG, "...") 같은 방식으로 로그를 출력할 때 사용
2. Flutter와 통신하는 코드 (configureFlutterEngine 메서드)
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NAME)
.setMethodCallHandler { call, result ->
- configureFlutterEngine: Flutter와 네이티브(Android) 코드를 연결하는 역할
- **MethodChannel**을 생성해서 CHANNEL_NAME으로 Flutter와 연결
- setMethodCallHandler: Flutter에서 특정 메소드를 호출하면, 여기서 받아서 처리
3. Flutter에서 보낸 메소드 처리
(1) updateTasks → 특정 날짜의 할 일 목록 저장
"updateTasks" -> {
val date = call.argument<String>("date")
val tasks = call.argument<List<*>>("tasks")
if (date != null && tasks != null) {
val jsonArray = JSONArray(tasks)
val sharedPref: SharedPreferences =
getSharedPreferences("Tasks", Context.MODE_PRIVATE)
sharedPref.edit().putString(date, jsonArray.toString()).apply()
Log.d(TAG, "tasks update: $date, tasks: $tasks")
} else {
result.error("INVALID_ARGUMENT", " null", null)
}
}
📌 동작 방식
- date (날짜)와 tasks (할 일 목록)를 Flutter에서 전달받음.
- tasks를 JSON 배열(JSONArray)로 변환하여 저장.
- SharedPreferences를 사용해 "Tasks"라는 저장소에 데이터를 저장.
- 저장이 끝나면 Log.d()로 로그 출력.
💡 SharedPreferences란?
- 간단한 데이터를 앱 내부 저장소(로컬 저장소) 에 저장하는 방식.
- Map 구조인 Key - Value 형태로 저장.
- 앱이 종료되더라도 데이터가 유지됨.
- 앱이 삭제되기 전까지 내부에 보관됨
- Mode 종류
MODE_PRIVATE | 생성한 애플리케이션에서만 사용 가능 , 외부 APP에서는 접근 불가 (Default) |
MODE_WORLD_READABLE | 외부 App에서 사용 가능, 읽기만 가능 |
MODE_WORLD_WRITEABLE | 외부 App에서 사용 가능, 읽기/쓰기 가능 |
(2) getTasks → 특정 날짜의 할 일 목록 불러오기
"getTasks" -> {
val date = call.argument<String>("date")
if (date != null) {
val sharedPref: SharedPreferences =
getSharedPreferences("Tasks", Context.MODE_PRIVATE)
val tasksString = sharedPref.getString(date, null)
if (tasksString != null) {
val jsonArray = JSONArray(tasksString)
val tasksList = mutableListOf<Map<String, Any>>()
for (i in 0 until jsonArray.length()) {
val jsonObj = jsonArray.getJSONObject(i)
val task = jsonObj.getString("task")
val isDone = jsonObj.getBoolean("isDone")
tasksList.add(mapOf("task" to task, "isDone" to isDone))
}
Log.d(TAG, "date: $date, tasks: $tasksList")
result.success(tasksList)
} else {
result.success(emptyList<Map<String, Any>>())
}
} else {
result.error("INVALID_ARGUMENT", "null", null)
}
}
📌 동작 방식
- date를 Flutter에서 전달받음.
- SharedPreferences에서 date에 해당하는 저장된 JSON 데이터를 가져옴.
- JSON 데이터를 리스트(Map 형태) 로 변환하여 Flutter로 반환.
- Log.d(TAG, "...")로 데이터를 출력.
(3) getAllTasks → 모든 날짜의 할 일 목록 불러오기
"getAllTasks" -> {
val sharedPref: SharedPreferences =
getSharedPreferences("Tasks", Context.MODE_PRIVATE)
val allEntries = sharedPref.all
val allTasks = mutableMapOf<String, Any>()
for ((key, value) in allEntries) {
if (key.length == 8 && value is String) {
try {
val jsonArray = JSONArray(value)
val tasksList = mutableListOf<Map<String, Any>>()
for (i in 0 until jsonArray.length()) {
val jsonObj = jsonArray.getJSONObject(i)
val task = jsonObj.getString("task")
val isDone = jsonObj.getBoolean("isDone")
tasksList.add(mapOf("task" to task, "isDone" to isDone))
}
allTasks[key] = tasksList
} catch (e: Exception) {
Log.e(TAG, "Key Error: $key", e)
}
}
}
Log.d(TAG, "all tasks: $allTasks")
result.success(allTasks)
}
📌 동작 방식
- SharedPreferences에 저장된 모든 데이터를 가져옴.
- allEntries에서 날짜 형식(YYYYMMDD)인 키만 필터링.
- 각 날짜별로 JSON 데이터를 변환하여 Flutter로 반환.
- Log.d(TAG, "...")로 전체 할 일 목록을 출력.
📝 정리
메소드 설명
updateTasks | 특정 날짜의 할 일을 저장 |
getTasks | 특정 날짜의 할 일 목록 불러오기 |
getAllTasks | 모든 날짜의 할 일 목록 불러오기 |
🔥 주요 기술
- MethodChannel: Flutter와 안드로이드 간의 통신
- SharedPreferences: 간단한 데이터를 앱 내부 저장소에 저장
- JSON 처리: JSONArray, JSONObject를 활용하여 데이터 변환
🚀 Flutter에서 사용 예시
💡 Flutter에서 위 메소드를 호출하는 방법 (task_notifier.dart)
const platform = MethodChannel('com.example.to_do_list/task_channel');
// 1. 할 일 목록 저장
Future<void> _saveTasksForDate(
DateTime date,
List<Map<String, dynamic>> tasks,
) async {
final dateKey = _formatDate(date);
await platform.invokeMethod('updateTasks', {
'date': dateKey,
'tasks': tasks,
});
}
// 2. 특정 날짜의 할 일 불러오기
Future<void> loadTasks() async {
final dateKey = _formatDate(state.selectedDate);
final result = await platform.invokeMethod('getTasks', {'date': dateKey});
if (result is List) {
final tasksForDate =
result.map((e) => Map<String, dynamic>.from(e)).toList();
state = TaskModel(
selectedDate: state.selectedDate,
tasks: {...state.tasks, state.selectedDate: tasksForDate},
);
}
}
// 3. 모든 할 일 불러오기
Future<void> loadAllTasks() async {
final result = await platform.invokeMethod('getAllTasks');
if (result is Map) {
final Map<DateTime, List<Map<String, dynamic>>> tasksMap = {};
result.forEach((key, value) {
//이때 result에서 key가 String으로 반환되기 때문에 년,월,일을 따로 저장하여 다시
//DateTime으로 변경해줘야한다.
final year = int.parse(key.substring(0, 4));
final month = int.parse(key.substring(4, 6));
final day = int.parse(key.substring(6, 8));
final date = DateTime(year, month, day);
if (value is List) {
tasksMap[date] =
value.map((e) => Map<String, dynamic>.from(e)).toList();
}
});
state = TaskModel(selectedDate: state.selectedDate, tasks: tasksMap);
}
}
'개발 > Android' 카테고리의 다른 글
[Flutter] Riverpod 상태관리 - ConsumerStatefulWidget 가이드 (0) | 2025.04.02 |
---|---|
[Flutter] Riverpod 상태관리 - watch vs read 차이 (0) | 2025.04.02 |
[Flutter] Riverpod 상태관리 - ConsumerWidget 가이드 (0) | 2025.04.02 |
[Flutter] MethodChannel이란 ? (1) | 2025.03.10 |
[Flutter] Riverpod 상태관리 라이브러리 (0) | 2025.02.20 |