iOS 유니버설 링크(Universal Links)를 설정하려면 /.well-known/apple-app-site-association 경로에서 JSON을 반환해야 한다. Rails에서 이걸 라우팅할 때 흔히 빠지는 함정 3가지를 정리한다.
에러
ActionController::RoutingError (No route matches [GET] "/.well-known/apple-app-site-association"):
ActionController::RoutingError (No route matches [GET] "/apple-app-site-association"):
배포 서버 로그에서 이 에러가 반복되고, iOS 앱에서 유니버설 링크가 동작하지 않는다.
함정 1: proc을 Rack 앱으로 사용
Rails routes에서 inline으로 파일을 반환하려고 proc을 쓰는 경우가 있다.
# 동작하지 않는 코드
get "/.well-known/apple-app-site-association", to: proc {
file = Rails.root.join("public/.well-known/apple-app-site-association")
[200, { "Content-Type" => "application/json" }, [File.read(file)]]
}
Rails 라우팅에서 to: 옵션에 Rack 앱을 직접 넣을 때는 env 인자를 받는 callable이어야 한다. proc { } 블록은 인자 없이 정의되어 있어서 Rack 인터페이스를 만족하지 못한다.
수정: lambda로 변경
aasa_handler = ->(env) {
file = Rails.root.join("public/.well-known/apple-app-site-association")
[200, { "Content-Type" => "application/json" }, [File.read(file)]]
}
get "/.well-known/apple-app-site-association", to: aasa_handler
-> (lambda)는 인자를 명시적으로 받으므로 Rack 앱으로 동작한다.
함정 2: 경로 alias 누락
Apple은 AASA 파일을 두 경로에서 모두 요청할 수 있다.
/.well-known/apple-app-site-association/apple-app-site-association
하나만 라우팅하면 나머지 경로로 요청이 들어올 때 404가 발생한다. 같은 핸들러를 두 경로에 모두 연결해야 한다.
aasa_handler = ->(env) {
file = Rails.root.join("public/.well-known/apple-app-site-association")
[200, { "Content-Type" => "application/json" }, [File.read(file)]]
}
get "/.well-known/apple-app-site-association", to: aasa_handler
get "/apple-app-site-association", to: aasa_handler # alias 추가
함정 3: 파일이 git에 추적되지 않음
로컬에서는 파일이 있고 라우팅도 맞아서 잘 되는데, 배포 서버에서는 계속 에러가 난다면 파일이 git에 포함되지 않은 경우다.
public/.well-known/ 디렉토리는 gitignore에 명시하지 않아도 Rails 기본 gitignore에 포함되지는 않지만, 직접 생성한 파일을 add하지 않으면 untracked 상태로 남는다.
# 확인
git status
# ?? server/public/.well-known/
# 추가
git add server/public/.well-known/apple-app-site-association
git commit -m "Add AASA file for Universal Links"
최종 코드
# config/routes.rb
aasa_handler = ->(env) {
file = Rails.root.join("public/.well-known/apple-app-site-association")
[200, { "Content-Type" => "application/json" }, [File.read(file)]]
}
get "/.well-known/apple-app-site-association", to: aasa_handler
get "/apple-app-site-association", to: aasa_handler
// public/.well-known/apple-app-site-association
{
"applinks": {
"details": [
{
"appIDs": ["TEAMID.com.example.app"],
"components": [
{ "/": "/trips/*" },
{ "/": "/invite/*" }
]
}
]
},
"webcredentials": {
"apps": ["TEAMID.com.example.app"]
}
}
체크리스트
배포 후에도 AASA가 안 된다면 아래를 순서대로 확인한다.
- lambda(
->)를 쓰고 있는가 (proc이 아닌지) - 두 경로 모두 라우팅되어 있는가
- AASA 파일이 git에 추가되어 있는가 (
git status로 확인) - 배포 후
curl https://yourdomain.com/.well-known/apple-app-site-association으로 JSON이 반환되는가

💬 댓글
비밀번호를 기억해두면 나중에 내 댓글을 삭제할 수 있어요.