deep-linking
Android App LinksやiOS Universal Linksといったモバイルアプリのディープリンク技術を使い、アプリ内の特定画面へ直接誘導したり、インストール遅延後の連携を実現したりするSkill。
📜 元の英語説明(参考)
Deep linking patterns for mobile - Android App Links, iOS Universal Links, intent filters, URI handling, deferred deep links, and navigation integration.
🇯🇵 日本人クリエイター向け解説
Android App LinksやiOS Universal Linksといったモバイルアプリのディープリンク技術を使い、アプリ内の特定画面へ直接誘導したり、インストール遅延後の連携を実現したりするSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o deep-linking.zip https://jpskill.com/download/16409.zip && unzip -o deep-linking.zip && rm deep-linking.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/16409.zip -OutFile "$d\deep-linking.zip"; Expand-Archive "$d\deep-linking.zip" -DestinationPath $d -Force; ri "$d\deep-linking.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
deep-linking.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
deep-linkingフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
モバイル向けのディープリンクパターン
URIスキームの設計
実装前に一貫性のある URI スキームを設計します。
myapp:// # アプリのルート
myapp://home # ホーム画面
myapp://product/{id} # 製品詳細
myapp://profile/{userId} # ユーザープロフィール
myapp://settings/notifications # ネストされた設定
myapp://search?q={query} # クエリパラメータ
パスは RESTful で小文字、かつ予測可能に保ちます。パスセグメントは階層構造に、クエリパラメータはフィルタに使用します。
Android
AndroidManifest.xml の Intent Filter
<activity
android:name=".MainActivity"
android:exported="true">
<!-- Custom URI scheme -->
<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="myapp"
android:host="product"
android:pathPrefix="/" />
</intent-filter>
<!-- App Links (HTTPS verified) -->
<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.myapp.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>
assetlinks.json を使用した App Links
https://www.myapp.com/.well-known/assetlinks.json にホストします。
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.myapp.android",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
]
}
}]
証明書のフィンガープリントを取得します。
keytool -list -v -keystore my-release-key.keystore -alias my-key-alias
Activity でのディープリンクの処理
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleDeepLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLink(intent)
}
private fun handleDeepLink(intent: Intent) {
val uri = intent.data ?: return
val path = uri.path ?: return
val segments = path.split("/").filter { it.isNotEmpty() }
when {
segments.firstOrNull() == "product" -> {
val productId = segments.getOrNull(1)
navigateToProduct(productId)
}
segments.firstOrNull() == "profile" -> {
val userId = segments.getOrNull(1)
navigateToProfile(userId)
}
}
}
}
Compose Navigation Deep Link の統合
NavHost(navController, startDestination = "home") {
composable(
route = "product/{productId}",
arguments = listOf(navArgument("productId") { type = NavType.StringType }),
deepLinks = listOf(
navDeepLink { uriPattern = "myapp://product/{productId}" },
navDeepLink { uriPattern = "https://www.myapp.com/product/{productId}" }
)
) { backStackEntry ->
val productId = backStackEntry.arguments?.getString("productId")
ProductScreen(productId = productId)
}
}
Deferred Deep Links (インストールアトリビューション)
アプリのインストール後も有効な遅延ディープリンクには、Firebase Dynamic Links または AppsFlyer を使用します。
Firebase.dynamicLinks
.getDynamicLink(intent)
.addOnSuccessListener { pendingDynamicLinkData ->
val deepLink: Uri? = pendingDynamicLinkData?.link
deepLink?.let { handleDeepLink(it) }
}
iOS
apple-app-site-association を使用した Universal Links
https://www.myapp.com/.well-known/apple-app-site-association にホストします。
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.com.myapp.ios",
"paths": ["/product/*", "/profile/*", "/settings/*"]
}
]
}
}
Xcode で Associated Domains を有効にします: applinks:www.myapp.com
Info.plist の URL Schemes
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
<key>CFBundleURLName</key>
<string>com.myapp.ios</string>
</dict>
</array>
AppDelegate / SceneDelegate での処理
// SceneDelegate (iOS 13+)
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
DeepLinkRouter.shared.handle(url: url)
}
// Universal Links
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let url = userActivity.webpageURL else { return }
DeepLinkRouter.shared.handle(url: url)
}
SwiftUI .onOpenURL
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
DeepLinkRouter.shared.handle(url: url)
}
}
}
}
ディープリンクのルーティングアーキテクチャ
// iOS Router
final class DeepLinkRouter: ObservableObject {
static let shared = DeepLinkRouter()
@Published var destination: Destination?
enum Destination: Equatable {
case product(id: String)
case profile(userId: String)
case settings
}
func handle(url: URL) {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return }
let pathSegments = components.path.split(separator: "/").map(String.init)
switch pathSegments.first {
case "product":
destination = .product(id: pathSegmen 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Deep Linking Patterns for Mobile
URI Scheme Design
Design a consistent URI scheme before implementation:
myapp:// # App root
myapp://home # Home screen
myapp://product/{id} # Product detail
myapp://profile/{userId} # User profile
myapp://settings/notifications # Nested settings
myapp://search?q={query} # Query parameters
Keep paths RESTful, lowercase, and predictable. Use path segments for hierarchy and query params for filters.
Android
Intent Filter in AndroidManifest.xml
<activity
android:name=".MainActivity"
android:exported="true">
<!-- Custom URI scheme -->
<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="myapp"
android:host="product"
android:pathPrefix="/" />
</intent-filter>
<!-- App Links (HTTPS verified) -->
<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.myapp.com"
android:pathPrefix="/product" />
</intent-filter>
</activity>
App Links with assetlinks.json
Host at https://www.myapp.com/.well-known/assetlinks.json:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.myapp.android",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
]
}
}]
Get your certificate fingerprint:
keytool -list -v -keystore my-release-key.keystore -alias my-key-alias
Handling Deep Links in Activity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleDeepLink(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLink(intent)
}
private fun handleDeepLink(intent: Intent) {
val uri = intent.data ?: return
val path = uri.path ?: return
val segments = path.split("/").filter { it.isNotEmpty() }
when {
segments.firstOrNull() == "product" -> {
val productId = segments.getOrNull(1)
navigateToProduct(productId)
}
segments.firstOrNull() == "profile" -> {
val userId = segments.getOrNull(1)
navigateToProfile(userId)
}
}
}
}
Compose Navigation Deep Link Integration
NavHost(navController, startDestination = "home") {
composable(
route = "product/{productId}",
arguments = listOf(navArgument("productId") { type = NavType.StringType }),
deepLinks = listOf(
navDeepLink { uriPattern = "myapp://product/{productId}" },
navDeepLink { uriPattern = "https://www.myapp.com/product/{productId}" }
)
) { backStackEntry ->
val productId = backStackEntry.arguments?.getString("productId")
ProductScreen(productId = productId)
}
}
Deferred Deep Links (Install Attribution)
Use Firebase Dynamic Links or AppsFlyer for deferred deep links that survive app install:
Firebase.dynamicLinks
.getDynamicLink(intent)
.addOnSuccessListener { pendingDynamicLinkData ->
val deepLink: Uri? = pendingDynamicLinkData?.link
deepLink?.let { handleDeepLink(it) }
}
iOS
Universal Links with apple-app-site-association
Host at https://www.myapp.com/.well-known/apple-app-site-association:
{
"applinks": {
"apps": [],
"details": [
{
"appID": "TEAMID.com.myapp.ios",
"paths": ["/product/*", "/profile/*", "/settings/*"]
}
]
}
}
Enable Associated Domains in Xcode: applinks:www.myapp.com
URL Schemes in Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
<key>CFBundleURLName</key>
<string>com.myapp.ios</string>
</dict>
</array>
Handling in AppDelegate / SceneDelegate
// SceneDelegate (iOS 13+)
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else { return }
DeepLinkRouter.shared.handle(url: url)
}
// Universal Links
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let url = userActivity.webpageURL else { return }
DeepLinkRouter.shared.handle(url: url)
}
SwiftUI .onOpenURL
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
DeepLinkRouter.shared.handle(url: url)
}
}
}
}
Deep Link Routing Architecture
// iOS Router
final class DeepLinkRouter: ObservableObject {
static let shared = DeepLinkRouter()
@Published var destination: Destination?
enum Destination: Equatable {
case product(id: String)
case profile(userId: String)
case settings
}
func handle(url: URL) {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { return }
let pathSegments = components.path.split(separator: "/").map(String.init)
switch pathSegments.first {
case "product":
destination = .product(id: pathSegments[safe: 1] ?? "")
case "profile":
destination = .profile(userId: pathSegments[safe: 1] ?? "")
default:
break
}
}
}
Testing Deep Links
# Android - test custom scheme
adb shell am start -a android.intent.action.VIEW -d "myapp://product/123"
# Android - test App Links
adb shell am start -a android.intent.action.VIEW -d "https://www.myapp.com/product/123"
# iOS Simulator - test URL scheme
xcrun simctl openurl booted "myapp://product/123"
# iOS Simulator - test Universal Link
xcrun simctl openurl booted "https://www.myapp.com/product/123"
Analytics Tracking for Deep Links
Track deep link opens with source attribution:
fun trackDeepLinkOpen(uri: Uri, source: String) {
analytics.logEvent("deep_link_opened") {
param("uri", uri.toString())
param("source", source) // "notification", "email", "social", "qr_code"
param("path", uri.path ?: "")
param("has_referrer", (uri.getQueryParameter("ref") != null).toString())
}
}