Jetpack Compose 네비게이션 딥링크 에러

김흰돌·2023년 9월 26일
0

Compose를 사용하여 앱을 제작하던 도중 경험한 Navigation 에러를 공유하고자 한다.

먼저 에러가 발생하는 상황을 보자

수정하기 버튼을 눌렀을 때 앱이 종료되는 현상이 발생하고 다음과 같은 에러를 출력한다.

java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/update/{"content":"테스트","date":"2023년 9월 26일","id":1,"imageUri":"content://media/external/images/media/1000000102","like":false,"title":"테스트"} } cannot be found in the navigation graph ComposeNavGraph(0x0) startDestination={Destination(0x78d845ec) route=home}

이 에러 메시지는 안드로이드의 네비게이션이 목적지를 찾지 못했다는 것을 나타낸다.
NavDeppLinkRequest를 통해
android-app://androidx.navigation/update/{"content":"테스트","date":"2023년 9월 26일","id":1,"imageUri":"content://media/external/images/media/1000000102","like":false,"title":"테스트"}
이라는 URI로 네비게이션 하려고 시도했지만 일치하는 URI를 네비게이션 그래프에서 찾을 수 없었기 때문이다.

그리고 에러가 발생한 코드를 살펴보자

composable(
route = "detail/{id}", arguments = listOf(navArgument("id") {
    type = NavType.IntType
})
) { backStackEntry ->
    val id = backStackEntry.arguments?.getInt("id")
    id?.let {
        DetailScreen(
            id,
            viewModel,
            callNavController = {
                navController.popBackStack()
            },
            onClicked = { itemJsonString ->
                navController.navigate(
                    "update/${itemJsonString}"
                )
            }
        )
    }
}

composable(route = "update/{itemJsonString}") { backStackEntry ->
    val itemJsonString = backStackEntry.arguments?.getString("itemJsonString")
    itemJsonString?.let {
        UpdateScreen(
            itemJsonString,
            callNavController = {
                navController.popBackStack()
            },
            onClicked = { itemEntity ->
                viewModel.updateItem(itemEntity)
                navController.popBackStack()
            }
        )
    }
}

이 코드를 작성한 목적은 DetailScreen에서 수정하기 버튼을 눌렀을 경우 기존의 값을 UpdateScreen으로 넘겨주고, UpdateScreen에선 받아온 값을 화면에 띄우고 사용자가 원하는 부분만 수정하여 다시 SQLite에 반영하는 걸 목표로 작성됐다.

원인을 찾아보니 작성자는 itemEntity를 네비게이션을 통해 다른 컴포저블로 넘기기 위해서 itemEntity를 json으로 변환하여 String 타입으로 값을 넘겼는데
첨부한 GIF와 같이 DetailScreen에 사진이 있을 경우 사진의 URI가 문제를 발생시킨 거였다.

이 문제를 해결하기 위해서 문자열을 인코딩 해줘야 한다.

따라서 위의 코드는 아래와 같이 수정할 수 있다.

composable(
route = "detail/{id}", arguments = listOf(navArgument("id") {
    type = NavType.IntType
})
) { backStackEntry ->
    val id = backStackEntry.arguments?.getInt("id")
    id?.let {
        DetailScreen(
            id,
            viewModel,
            callNavController = {
                navController.popBackStack()
            },
            onClicked = { itemJsonString ->
                navController.navigate(
                    "update/${
                        URLEncoder.encode(
                            itemJsonString,
                            StandardCharsets.UTF_8.toString()
                        )
                    }"
                )
            }
        )
    }
}

composable(route = "update/{itemJsonString}") { backStackEntry ->
    val itemJsonString = backStackEntry.arguments?.getString("itemJsonString")
    itemJsonString?.let {
        UpdateScreen(
            URLDecoder.decode(itemJsonString, StandardCharsets.UTF_8.toString()),
            callNavController = {
                navController.popBackStack()
            },
            onClicked = { itemEntity ->
                viewModel.updateItem(itemEntity)
                navController.popBackStack()
            }
        )
    }
}

네비게이션에 itemJsonString을 태워보낼 때 인코딩을 URLEncoder.encode 함수를 이용해 문자열을 인코딩 해주고

받아온 itemJsonString을 URLDecoder.decode 함수를 이용해 디코딩을 수행하여 다시 원래의 문자열로 만들어 준 뒤 UpdateScreen에 넘겨주는 방법을 사용했다.

0개의 댓글