플러터 웹뷰 Navigation Decision 에러 해결하지
오늘은 Flutter 앱에서 발생한 에러를 해결하는 데 시간을 보냈다. 에러 메시지는 다음과 같았다:
The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr<navigationdecision>', is a potentially non-nullable type. Try adding either a return or a throw statement at the end.
이 에러는 onNavigationRequest 함수에서 NavigationDecision을 반환하지 않는 경로가 존재한다는 것을 나타냈다. 이 메서드는 비동기적으로 실행되기 때문에 특정 조건에서 NavigationDecision을 반드시 반환해야 한다. 만약 아무런 값을 반환하지 않으면 기본적으로 null이 반환되는데, 이는 FutureOr<NavigationDecision>과 맞지 않아 오류가 발생하게 된다.
문제 원인
문제를 해결하기 위해 코드의 흐름을 면밀히 분석해봤다. 각 조건문이 어떻게 작동하는지, 그리고 반환 값이 없는 경우가 있는지를 점검했다. 기본적으로 모든 경로에서 적절한 NavigationDecision을 반환해야 한다는 사실을 깨달았다.
수정된 코드
아래는 수정한 onNavigationRequest 함수의 코드이다:
onNavigationRequest: (NavigationRequest request) async {
// 생략 ...
if (isAllowedInAppLink(finalUrl)) {
return NavigationDecision.navigate;
} else if (uri.scheme == 'http' || uri.scheme == 'https') {
debugPrint('Opening in external browser: ${request.url}');
if (await canLaunchUrl(uri)) {
await launchUrl(
uri,
mode: LaunchMode.externalApplication,
);
return NavigationDecision.prevent; // Prevent navigation in the WebView
} else {
// This path will never reach a return statement, throw an exception instead
throw 'Could not launch $request.url';
}
}
// If none of the conditions are met, you need to return a default NavigationDecision
return NavigationDecision.prevent; // Prevent navigation for any other URL
}
if문 경로마다 적절한 return 값을 추가하였다.
주요 수정 사항
내가 수정한 코드 일부분의 내용은 다음과 같다.
- if (isAllowedInAppLink(finalUrl)) 블록과 else if (uri.scheme == 'http' || uri.scheme == 'https') 블록에서 각각의 조건을 처리한 후, 기본적으로 return NavigationDecision.prevent;를 추가했다. 이제 모든 경우에 대해 적절한 NavigationDecision을 반환하도록 보장된다.
- throw 문은 예외를 던지기 때문에 일반적으로 메서드의 종료를 나타낸다. 이 경우 메서드가 정상적으로 종료되지 않지만, 예외 처리가 필요할 때 사용할 수 있다. 에러를 적절히 처리할 수 있는 방법을 고민해야겠다.