Flutterでのディープリンク対応
最近のMobileアプリ開発ではディープリンク対応を求められる事が増えている。Flutterの場合、どうやるのかについて記載する。基本的にはiOSとAndroidのやり方に準拠するので、まずはそれぞれについて記載してからFlutterの場合に移る。
SwiftUI (iOS)
1. Associated Domainsの設定
まず、Xcodeでプロジェクトの「Signing & Capabilities」タブに移動し、「+ Capability」ボタンをクリックして「Associated Domains」を追加する。以下の形式でドメインを追加する。
applinks:yourdomain.com
2. apple-app-site-associationファイルの作成
ドメインのルートに apple-app-site-association
ファイルを配置する。
{
"applinks": {
"apps": [],
"details": [
{
"appID": "<TeamID>.<bundleID>",
"paths": [ "/example/*" ]
}
]
}
}
3. SwiftUIでのディープリンクの処理
App
構造体でonOpenURL
を使用してリンクを処理する。
import SwiftUI
@main
struct DeepLinkApp: App {
@State private var deepLinkID: String?
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
if let id = url.pathComponents.last {
deepLinkID = id
}
}
.environmentObject(DeepLinkManager(deepLinkID: $deepLinkID))
}
}
}
class DeepLinkManager: ObservableObject {
@Binding var deepLinkID: String?
init(deepLinkID: Binding<String?>) {
_deepLinkID = deepLinkID
}
}
struct ContentView: View {
@EnvironmentObject var deepLinkManager: DeepLinkManager
var body: some View {
NavigationView {
VStack {
if let id = deepLinkManager.deepLinkID {
Text("Deep Link ID: \(id)")
} else {
Text("No Deep Link")
}
}
.navigationTitle("Deep Link Example")
}
}
}
Jetpack Compose (Android)
1. AndroidManifest.xmlの設定
AndroidManifest.xmlに<intent-filter>
を追加してディープリンクを設定する。
<activity android:name=".MainActivity">
<intent-filter android:autoVerify="true">
<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="www.example.com"
android:pathPrefix="/example" />
</intent-filter>
</activity>
2. Jetpack Composeでのディープリンクの処理
MainActivityで受信したインテントを処理する。
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.deeplink.ui.theme.DeepLinkTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var deepLinkID by remember { mutableStateOf<String?>(null) }
handleIntent(intent) { id ->
deepLinkID = id
}
DeepLinkTheme {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
if (deepLinkID != null) {
Text(text = "Deep Link ID: $deepLinkID")
} else {
Text(text = "No Deep Link")
}
}
}
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent) { id ->
deepLinkID = id
}
}
private fun handleIntent(intent: Intent, onDeepLinkReceived: (String?) -> Unit) {
val action = intent.action
val data: Uri? = intent.data
if (Intent.ACTION_VIEW == action && data != null) {
val id = data.lastPathSegment
onDeepLinkReceived(id)
} else {
onDeepLinkReceived(null)
}
}
}
Flutter
1. pubspec.yamlの設定
pubspec.yaml
に必要な依存関係を追加する。
dependencies:
flutter:
sdk: flutter
uni_links: ^0.5.1
url_launcher: ^6.0.9
2. プラットフォーム固有の設定
- Android:
- 前述のAndroidセクションに示したように、
AndroidManifest.xml
を更新する。
- 前述のAndroidセクションに示したように、
- iOS:
- iOSでのユニバーサルリンクの設定手順に従う。
3. Flutterでのリンク処理
Flutterコード内で、受信したリンクを処理する。
import 'package:flutter/material.dart';
import 'package:uni_links/uni_links.dart';
import 'package:url_launcher/url_launcher.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? _deepLink;
@override
void initState() {
super.initState();
initUniLinks();
}
Future<void> initUniLinks() async {
try {
final initialLink = await getInitialLink();
if (initialLink != null) {
setState(() {
_deepLink = initialLink;
});
}
linkStream.listen((String? link) {
setState(() {
_deepLink = link;
});
}, onError: (err) {
// エラーを処理する
});
} on PlatformException {
// 例外を処理する
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('ディープリンクの例'),
),
body: Center(
child: _deepLink != null
? Text('ディープリンクID: $_deepLink')
: Text('ディープリンクなし'),
),
),
);
}
}
これらのサンプルは、SwiftUIやJetpack Compose、Flutterを使用してディープリンクを処理する基本的な方法を示している。これにより、ユーザーが外部リンクからアプリ内の特定のコンテンツにシームレスに移動できるようになる。