반응형
Overview
해당 포스팅은 InAppWebView 5.8을 기준으로 작성되었습니다.
현재 버전 InAppwebView 6.0 마이그레이션은 아래을 포스팅을 참고하면 됩니다.
Flutter - InAppWebView 5.8.0 > 6.0.0 마이그레이션 가이드
개요인앱웹뷰가 6.0.0으로 버전업이 되었다. 이번에 마이그레이션을 하면서 느낀점은 편의성이 많이 좋아진 것 같은데 자세히는 안써봐서 잘 모르겠다. 우선은 내 프로젝트에 있는 코드들을 마
luvris2.tistory.com
inAppWebView를 이용하여 모바일 화면에 웹페이지를 표시하는 방법을 포스팅합니다.
포스팅에서 사용한 예제 프로젝트는 아래의 링크에서 확인 가능합니다.
프로젝트 설정
안드로이드
android/app/src/main/AndroidManifest.xml 에 권한을 추가한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 네트워크 작업을 수행하기 위한 권한 부여 -->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
iOS
ios/Runner/Info.plist 에 아래의 키를 추가한다.
<!-- 네트워크 작업을 수행하기 위한 권한 부여 -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
Flutter Main 함수
main() 함수 내의 WidgetsFlutterBinding.ensureInitialized() 메서드 호출
애플리케이션 실행 전에 반드시 명시적으로 써주어야 한다.
이는 인앱웹뷰와 플러터 엔진과의 상호작용을 위해 바인딩을 해주는 기능을 한다.
Future main() async {
// 위젯 바인딩 초기화 : 웹뷰와 플러터 엔진과의 상호작용을 위함
WidgetsFlutterBinding.ensureInitialized();
runApp(
const MaterialApp(home: MyApp()),
);
}
인앱웹뷰 초기 설정
컨트롤러 & 인앱웹뷰 초기 설정 정의
- 옵션은 사용자 정의이므로 아래의 코드를 모두 따를 필요는 없다.
// 인앱웹뷰 컨트롤러
InAppWebViewController? webViewController;
InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
// 플랫폼 상관없이 동작하는 옵션
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true, // URL 로딩 제어
mediaPlaybackRequiresUserGesture: false, // 미디어 자동 재생
javaScriptEnabled: true, // 자바스크립트 실행 여부
javaScriptCanOpenWindowsAutomatically: true, // 팝업 여부
),
// 안드로이드 옵션
android: AndroidInAppWebViewOptions(
useHybridComposition: true, // 하이브리드 사용을 위한 안드로이드 웹뷰 최적화
),
// iOS 옵션
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true, // 웹뷰 내 미디어 재생 허용
));
late PullToRefreshController pullToRefreshController; // 당겨서 새로고침 컨트롤러
당겨서 새로고침 컨트롤러 초기화
아래로 당길 경우 페이지가 새로고침되는 컨트롤러를 정의한다.
제스처로 새로고침을 필요로 할 경우 정의하며 필요 없으면 정의하지 않아도 된다.
@override
void initState() {
super.initState();
// 당겨서 새로고침 컨트롤러 설정
pullToRefreshController = PullToRefreshController(
options: PullToRefreshOptions(
color: Colors.blue, // 새로고침 아이콘 색상
),
// 플랫폼별 새로고침
onRefresh: () async {
if (Platform.isAndroid) {
webViewController?.reload();
} else if (Platform.isIOS) {
webViewController?.loadUrl(
urlRequest: URLRequest(url: await webViewController?.getUrl()));
}
},
);
}
인앱웹뷰 위젯 정의
InAppWebView(
// 시작 페이지
initialUrlRequest: URLRequest(
url: Uri.parse("https://luvris2.tistory.com/")),
// 초기 설정
initialOptions: options,
// 당겨서 새로고침 컨트롤러 정의
pullToRefreshController: pullToRefreshController,
// 인앱웹뷰 생성 시 컨트롤러 정의
onWebViewCreated: (controller) {
webViewController = controller;
},
// 페이지 로딩 시 수행 메서드 정의
onLoadStart: (controller, url) {
setState(() {
this.url = url.toString();
});
},
// 안드로이드 웹뷰에서 권한 처리 메서드 정의
androidOnPermissionRequest:
(controller, origin, resources) async {
return PermissionRequestResponse(
resources: resources,
action: PermissionRequestResponseAction.GRANT);
},
// URL 로딩 제어
shouldOverrideUrlLoading:
(controller, navigationAction) async {
var uri = navigationAction.request.url!;
// 아래의 키워드가 포함되면 페이지 로딩
if (![
"http",
"https",
"file",
"chrome",
"data",
"javascript",
"about"
].contains(uri.scheme)) {
if (await canLaunchUrl(Uri.parse(url))) {
// Launch the App
await launchUrl(
Uri.parse(url),
);
// and cancel the request
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
// 페이지 로딩이 정지 시 메서드 정의
onLoadStop: (controller, url) async {
// 당겨서 새로고침 중단
pullToRefreshController.endRefreshing();
setState(() {
this.url = url.toString();
});
},
// 페이지 로딩 중 오류 발생 시 메서드 정의
onLoadError: (controller, url, code, message) {
// 당겨서 새로고침 중단
pullToRefreshController.endRefreshing();
},
// 로딩 상태 변경 시 메서드 정의
onProgressChanged: (controller, progress) {
// 로딩이 완료되면 당겨서 새로고침 중단
if (progress == 100) {
pullToRefreshController.endRefreshing();
}
// 현재 페이지 로딩 상태 업데이트 (0~100%)
setState(() {
this.progress = progress / 100;
});
},
),
인앱웹뷰 위젯 / 컨트롤러 메서드 기능 설명
InAppWebView
- initialUrlRequest : 인앱웹뷰 호출 시 시작 페이지 설정
- initialOptions : 인앱웹뷰 호출 시 초기 설정
- pullToRefreshController : 당겨서 새로고침 컨트롤러 정의
- onWebViewCreated : 인앱웹뷰 생성 시 수행될 코드 정의
- onLoadStart : 페이지 로딩 시작 시 수행될 코드 정의
- onLoadStop : 페이지 로딩이 정지 시 수행될 코드 정의
- onLoadError : 페이지 로딩 중 오류 발생 시 수행될 코드 정의
- onProgressChanged : 페이지 로딩 상태 변경 시 메서드 정의
- androidOnPermissionRequest : 안드로이드 웹뷰에서 권한 관련 코드 정의
- shouldOverriderUrlLoading : URL 로딩 시 제어할 코드 정의
InAppWebViewController
- .reload() : 새로고침
- .loadUrl() : 특정 url 페이지 이동
- .getUrl() : 현재 url 주소 반환
- .goBack() : 이전 페이지로 이동
- .goForward() : 이전 페이지에서 다음 페이지로 이동
전체 소스 코드
안드로이드, iOS 초기 설정을 제외하곤 한 번에 확인할 수 있도록 메인 파일 하나에 코드를 모두 담았다.
더보기
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';
Future main() async {
// 위젯 바인딩 초기화 : 웹뷰와 플러터 엔진과의 상호작용을 위함
WidgetsFlutterBinding.ensureInitialized();
if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);
}
runApp(
const MaterialApp(home: MyApp()),
);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// 인앱웹뷰 컨트롤러
InAppWebViewController? webViewController;
InAppWebViewGroupOptions options = InAppWebViewGroupOptions(
// 플랫폼 상관없이 동작하는 옵션
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true, // URL 로딩 제어
mediaPlaybackRequiresUserGesture: false, // 미디어 자동 재생
javaScriptEnabled: true, // 자바스크립트 실행 여부
javaScriptCanOpenWindowsAutomatically: true, // 팝업 여부
),
// 안드로이드 옵션
android: AndroidInAppWebViewOptions(
useHybridComposition: true, // 하이브리드 사용을 위한 안드로이드 웹뷰 최적화
),
// iOS 옵션
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true, // 웹뷰 내 미디어 재생 허용
));
late PullToRefreshController pullToRefreshController; // 당겨서 새로고침 컨트롤러
String url = ""; // url 주소
double progress = 0; // 페이지 로딩 프로그레스 바
@override
void initState() {
super.initState();
// 당겨서 새로고침 컨트롤러 설정
pullToRefreshController = PullToRefreshController(
options: PullToRefreshOptions(
color: Colors.blue, // 새로고침 아이콘 색상
),
// 플랫폼별 새로고침
onRefresh: () async {
if (Platform.isAndroid) {
webViewController?.reload();
} else if (Platform.isIOS) {
webViewController?.loadUrl(
urlRequest: URLRequest(url: await webViewController?.getUrl()));
}
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: Stack(
children: [
InAppWebView(
// 시작 페이지
initialUrlRequest: URLRequest(
url: Uri.parse("https://luvris2.tistory.com/")),
// 초기 설정
initialOptions: options,
// 당겨서 새로고침 컨트롤러 정의
pullToRefreshController: pullToRefreshController,
// 인앱웹뷰 생성 시 컨트롤러 정의
onWebViewCreated: (controller) {
webViewController = controller;
},
// 페이지 로딩 시 수행 메서드 정의
onLoadStart: (controller, url) {
setState(() {
this.url = url.toString();
});
},
// 안드로이드 웹뷰에서 권한 처리 메서드 정의
androidOnPermissionRequest:
(controller, origin, resources) async {
return PermissionRequestResponse(
resources: resources,
action: PermissionRequestResponseAction.GRANT);
},
// URL 로딩 제어
shouldOverrideUrlLoading:
(controller, navigationAction) async {
var uri = navigationAction.request.url!;
// 아래의 키워드가 포함되면 페이지 로딩
if (![
"http",
"https",
"file",
"chrome",
"data",
"javascript",
"about"
].contains(uri.scheme)) {
if (await canLaunchUrl(Uri.parse(url))) {
// Launch the App
await launchUrl(
Uri.parse(url),
);
// and cancel the request
return NavigationActionPolicy.CANCEL;
}
}
return NavigationActionPolicy.ALLOW;
},
// 페이지 로딩이 정지 시 메서드 정의
onLoadStop: (controller, url) async {
// 당겨서 새로고침 중단
pullToRefreshController.endRefreshing();
setState(() {
this.url = url.toString();
});
},
// 페이지 로딩 중 오류 발생 시 메서드 정의
onLoadError: (controller, url, code, message) {
// 당겨서 새로고침 중단
pullToRefreshController.endRefreshing();
},
// 로딩 상태 변경 시 메서드 정의
onProgressChanged: (controller, progress) {
// 로딩이 완료되면 당겨서 새로고침 중단
if (progress == 100) {
pullToRefreshController.endRefreshing();
}
// 현재 페이지 로딩 상태 업데이트 (0~100%)
setState(() {
this.progress = progress / 100;
});
},
),
// 로딩 프로그레스 바 표현 여부
progress < 1.0
? LinearProgressIndicator(value: progress)
: Container(),
],
),
),
],
),
),
);
}
}
참고
반응형