유니버설 링크(Universal Links)#
앱에서 유니버설 링크를 지원하기 위해서는 apple-app-site-association(AASA)
파일을 작성해서 웹 서버에 올려두는 작업이 필요합니다.
iOS 12 이전#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
{
"applinks": {
"apps": [],
"details": [
{
"appID": "<TEAM_DEVELOPER_ID>.<BUNDLE_IDENTIFIER>",
"paths": ["*"]
},
{
"appID": "<TEAM_DEVELOPER_ID>.<BUNDLE_IDENTIFIER>",
"paths": ["/articles/*"]
},
{
"appID": "<TEAM_DEVELOPER_ID>.<ANOTHER_APP_BUNDLE_IDENTIFIER>",
"paths": ["/blog/*", "/articles/*"]
}
]
}
}
|
주의 사항#
- apps는 빈 배열이어야 합니다.
- 파일 이름은 json 확장자가 없는
apple-app-site-association
이어야 합니다.
- 파일 위치는
http://foobar.com/apple-app-site-association
입니다.
iOS 13 이후#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
{
"applinks": {
"details": [
{
"appIDs": [ "ABCDE12345.com.example.app", "ABCDE12345.com.example.app2" ],
"components": [
{
"#": "no_universal_links",
"exclude": true,
"comment": "Matches any URL whose fragment equals no_universal_links and instructs the system not to open it as a universal link"
},
{
"/": "/buy/*",
"comment": "Matches any URL whose path starts with /buy/"
},
{
"/": "/help/website/*",
"exclude": true,
"comment": "Matches any URL whose path starts with /help/website/ and instructs the system not to open it as a universal link"
}
{
"/": "/help/*",
"?": { "articleNumber": "????" },
"comment": "Matches any URL whose path starts with /help/ and which has a query item with name 'articleNumber' and a value of exactly 4 characters"
}
]
}
]
},
"webcredentials": {
"apps": [ "ABCDE12345.com.example.app" ]
}
}
|
주의 사항#
- 파일 이름은 json 확장자가 없는
apple-app-site-association
이어야 합니다.
- 파일 위치는
http://foobar.com/.well-known/apple-app-site-association
입니다.
apple-app-site-association
파일은 Signing을 해서 저장해야 합니다. 여기서는 OpenSSL을 기준으로 기술합니다.
1
|
openssl smime -sign -nodetach -in "./apple-app-site-association.json" -out "apple-app-site-association" -outform DER -inkey hostname.domain.key -signer hostname.domain.crt
|
만약 key
, crt
확장자 파일 대신 pem
확장자 파일만 있다면 OpenSSL
을 통해 생성 할 수 있습니다.
1
2
|
openssl rsa -in key.pem -text > hostname.domain.key
openssl x509 -inform PEM -in cert.pem -out hostname.domain.crt
|
웹서버에 올리는 파일은 텍스트 json 파일이 아닌 signing 한 json 확장자 없는 파일을 올려야 합니다.
웹서버 설정#
apple-app-site-association
파일에 대해 Content-type
을 변경해야 합니다. 여기서는 Nginx를 기준으로 기술합니다.
1
2
3
4
5
6
7
|
location ~ /.well-known/apple-app-site-association {
default_type application/json;
}
location ~ /apple-app-site-association {
default_type application/json;
}
|
주의 사항#
https
를 통해 파일에 접근하도록 해야 합니다.
https
인증서는 apple-app-site-association
파일을 signing 한 것과 같은 인증서를 써야 합니다.
- 유니버설 링크를 사용하는 사이트와
apple-app-site-association
파일은 서로 다른 도메인이어야 합니다.
App ID Configuration#
Associated Domains
Capabilities를 Enabled 해야 합니다.
- Xcode의 프로젝트 설정의
Signing & Capabilitites
탭의 Associated Domains
에 다음 항목들을 추가합니다.
1
2
3
4
|
applinks:foobar.com
applinks:ulink.foobar.com
applinks:www.foobar.com
webcredentials:ulink.foobar.com
|
위 예시는 도메인이 foobar.com
이며, Apple JSON Metadata File
파일을 ulink.foobar.com
에서 제공하는 경우입니다.
AppDelegate
구현#
iOS 9.1 이후#
1
2
3
4
5
6
7
8
|
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler {
NSURL *url = userActivity.webpageURL;
// ...
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
// ...
}
|
iOS 13 이후#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let urlToOpen = userActivity.webpageURL else {
return
}
// ...
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for urlContext in URLContexts {
let urlToOpen = urlContext.url
// ...
}
}
|
Apple JSON Metadata File
은 앱 설치 후 첫 실행 시 읽습니다. 그 이후로는 캐시를 활용하므로 개발 중 변경 시 Safari
의 캐시를 삭제하고 앱 또한 삭제 후 재설치 하는 과정이 필요합니다.