Flutter에서 Deep Linking은 애플리케이션 내의 특정 화면이나 콘텐츠로 직접 이동할 수 있게 해주는 기능입니다. 이는 사용자가 애플리케이션을 열 때 특정 URL 또는 경로를 통해 특정 페이지나 상태로 직접 이동할 수 있도록 합니다. Deep Linking은 웹, 모바일 앱(앱 링크), 그리고 앱 내부의 링크로 구현할 수 있습니다. Flutter에서는 이러한 기능을 통해 애플리케이션의 탐색을 더 매끄럽고 직관적으로 만들 수 있습니다.
1. Deep Linking 기본 개념
- Deep Linking: 애플리케이션의 특정 부분으로 사용자를 직접 안내할 수 있는 기능입니다. 예를 들어, 사용자가 이메일이나 푸시 알림에서 클릭하면 특정 상품 페이지로 바로 이동할 수 있습니다.
- Universal Links / App Links: 모바일 앱에서 사용할 수 있는 고급 형태의 Deep Linking으로, 사용자가 링크를 클릭했을 때 앱이 설치되어 있으면 앱을 열고, 그렇지 않으면 웹 페이지를 열도록 설정할 수 있습니다.
2. Flutter에서 Deep Linking 구현
Flutter에서 Deep Linking을 구현하는 방법에는 여러 가지가 있으며, 주요 방법은 다음과 같습니다:
- 앱 내 Deep Linking (Flutter)
- 앱 링크와 웹 링크 (iOS와 Android)
- 기타 유용한 라이브러리와 패키지
2.1. 앱 내 Deep Linking (Flutter)
Flutter에서는 Navigator
를 사용하여 앱 내에서 Deep Linking을 구현할 수 있습니다. 이를 위해 URL 기반 라우팅을 지원하는 패키지를 사용할 수 있습니다. 기본적으로 Flutter의 Navigator 2.0
을 사용하여 URL 기반 내비게이션을 설정할 수 있습니다.
Navigator 2.0을 사용한 Deep Linking
Navigator 2.0
을 사용하면 URL 기반 내비게이션을 구현할 수 있습니다. 이 접근 방식은 선언적 내비게이션을 지원하며, 웹과 데스크톱 애플리케이션에서 특히 유용합니다.
예제 코드:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _routerDelegate = MyRouterDelegate();
final _routeInformationParser = MyRouteInformationParser();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routerDelegate: _routerDelegate,
routeInformationParser: _routeInformationParser,
);
}
}
class MyRouterDelegate extends RouterDelegate<RouteSettings>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<RouteSettings> {
final GlobalKey<NavigatorState> navigatorKey;
List<Page> _pages = [MaterialPage(child: HomePage())];
MyRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();
@override
RouteSettings get currentConfiguration => _pages.last.arguments as RouteSettings;
@override
Future<void> setNewRoutePath(RouteSettings configuration) async {
if (configuration.name == '/') {
_pages = [MaterialPage(child: HomePage())];
} else if (configuration.name == '/details') {
_pages.add(MaterialPage(child: DetailsPage()));
}
notifyListeners();
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: List.of(_pages),
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
_pages.removeLast();
notifyListeners();
return true;
},
);
}
}
class MyRouteInformationParser extends RouteInformationParser<RouteSettings> {
@override
Future<RouteSettings> parseRouteInformation(RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.location!);
if (uri.pathSegments.isEmpty) {
return RouteSettings(name: '/');
} else if (uri.pathSegments.length == 1 && uri.pathSegments[0] == 'details') {
return RouteSettings(name: '/details');
} else {
return RouteSettings(name: '/');
}
}
@override
RouteInformation? restoreRouteInformation(RouteSettings configuration) {
if (configuration.name == '/') {
return RouteInformation(location: '/');
} else if (configuration.name == '/details') {
return RouteInformation(location: '/details');
}
return null;
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pushNamed('/details');
},
child: Text('Go to Details Page'),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Details Page'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Back to Home Page'),
),
),
);
}
}
2.2. 앱 링크와 웹 링크 설정
앱 링크와 웹 링크는 iOS와 Android에서 설정할 수 있습니다. 이를 통해 사용자가 웹 링크를 클릭하면 앱이 설치되어 있을 때 앱을 열도록 할 수 있습니다.
Android에서 App Links 설정
AndroidManifest.xml
에 인텐트 필터 추가
<activity
android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="example.com" />
</intent-filter>
</activity>
assetlinks.json
파일 생성https://example.com/.well-known/assetlinks.json
에 다음과 같은 JSON 파일을 배포합니다.
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": ["YOUR_CERT_FINGERPRINT"]
}
}
]
iOS에서 Universal Links 설정
Info.plist
파일 수정
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
<key>AssociatedDomains</key>
<array>
<string>applinks:example.com</string>
</array>
apple-app-site-association
파일 생성https://example.com/apple-app-site-association
에 다음과 같은 JSON 파일을 배포합니다.
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAM_ID.com.example.app",
"paths": ["*"]
}
]
}
}
2.3. 패키지와 라이브러리
uni_links
패키지: Flutter 애플리케이션에서 Deep Linking을 지원합니다.
설치 : pubspec.yaml
에 추가합니다
dependencies:
uni_links: ^0.5.1
사용
import 'package:uni_links/uni_links.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_initLinks();
}
Future<void> _initLinks() async {
try {
final initialLink = await getInitialLink();
if (initialLink != null) {
print('Initial link: $initialLink');
// Handle the link
}
linkStream.listen((String? link) {
print('Link: $link');
// Handle the link
});
} catch (e) {
print('Failed to get initial link');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Deep Linking')),
body: Center(child: Text('Home Page')),
),
);
}
}
요약
- Deep Linking은 애플리케이션 내의 특정 화면으로 직접 이동할 수 있게 해줍니다.
- Flutter 내비게이션을 사용하여 URL 기반 라우팅을 구현할 수 있습니다.
- 앱 링크와 웹 링크는 iOS와 Android에서 설정할 수 있습니다.
uni_links
패키지를 사용하여 Flutter 애플