시작하며
UIWebView
시절부터 내가 허용한 도메인. 즉, 화이트 리스트 관리를 위해서는 웹이 로딩(loading)되는 시점 혹은 이동(redirection)되는 시점에 허용한 도메인인지 체크를 해왔다. 이 방식은 일반적이긴 하지만 코드가 길어지고 관리하기가 힘든 문제가 있었다.
WKWebView
가 강제되기 시작한 시점에서도 메소드명만 바뀌었지 동일한 문제가 있었는데 iOS11
부터는 이를 쉽게 적용하고 관리할 수 있게 되었다고 한다.
이는 WKContentRuleListStore
를 통하여 Rule List를 정의하면 되는데 이에 대해서 알아보겠다.
ContentRuleList 란?
iOS11 부터 WKContentRuleListStore
클래스가 추가되었다. JSON 형태의 규칙을 여기에 저장하고 이를 userContentController
에 add
함으로 쉽게 적용할 수 있다. 결국 규칙을 정의하는 것이 중요하다고 할 수 있다.
이를 위해서는 규칙(Rule List)이 필요하다. 이 리스트는 지정된 형식이 있는데 상세한 내용은 아래 애플 문서에서 볼 수 있다. 하지만 친절하진 않다.. 늘 그렇듯이..
Creating a Content Blocker 문서
Creating a Content Blocker 문서로 이동
중요한 것만 간단히 설명하자면, 이 규칙은 아래와 같은 JSON 형태이다.
![](https://i0.wp.com/y8k.me/wp-content/uploads/2020/05/Screen-Shot-2020-05-27-at-1.07.36-PM.png?resize=1200%2C793&ssl=1)
trigger
는 지정할 도메인 규칙이다.
regex값을 가질 수 있는 url-filter
는 필수값이며, regex도 아래 리스트처럼 일부만 사용이 가능한 것 같다. 조금 더 복잡한 regex를 적용해보았는데 허용하지 않는다는 오류가 나타났었다.
![url-filter 에 적용할 수 있는 regular expression](https://i0.wp.com/y8k.me/wp-content/uploads/2020/05/Screen-Shot-2020-05-27-at-11.54.28-AM.png?resize=1200%2C873&ssl=1)
url-filter
와 함께 아래 첨부한 패턴에 따라 규칙을 더 상세하게 정의할 수 있다.
![추가할 수 있는 trigger fileds](https://i0.wp.com/y8k.me/wp-content/uploads/2020/05/Screen-Shot-2020-05-27-at-1.13.55-PM.png?resize=1200%2C1602&ssl=1)
action
은 trigger
로 지정된 도메인에 대한 규칙이다. 이 규칙은 아래와 같이 차단, 쿠키만 차단, CSS 무시, 이전 규칙 무시, HTTPS로 호출이 있다.
![Action Type](https://i0.wp.com/y8k.me/wp-content/uploads/2020/05/Screen-Shot-2020-05-27-at-1.19.14-PM.png?resize=1200%2C927&ssl=1)
WKWebView
에 규칙 지정하기
지정한 규칙을 웹뷰에 지정하기 위해서는 아래 코드처럼 지정한 규칙을 가져와 WKContentRuleListStore
를 통해 컴파일을 하고 최종적으로 웹뷰에 지정하면 쉽게 적용할 수 있다.
let jsonString = "..."
WKContentRuleListStore.default()?.compileContentRuleList(
forIdentifier: "ContentRuleList",
encodedContentRuleList: jsonString,
completionHandler: { ruleList, error in
guard let ruleList = ruleList else {
// Error
return
}
webView.configuration.userContentController.add(ruleList)
})
WKWebView
에서 허용할 도메인 지정하기
위에서 설명한 규칙을 이용하여 원하는 도메인만 허용을 하기 위해서는
regex를 허용한다는 url-filter
값을 이용해보면 되지 않을까란 막연한 생각에 오랜만에 규칙을 만들고 적용을 했더니 허용하지 않는 regex라며 오류가 발생했다… 이 시도에서 위 리스트에서 지정된 regex만 적용이 되는 걸로 이해했다..
어떻게 해결할까 고민을 하다가 ignore-previous-rules
라는 것에 눈이 갔고 이 규칙이 앞서 규칙을 무시한다면 기본적으로 다 막아버리고 내가 허용할 도메인에 이 규칙을 적용하면 되지 않을까? 해서 아래와 같은 규칙을 이용하여 테스트를 진행했다.
[
{
"trigger": {
"url-filter": ".*"
},
"action": {
"type": "block"
}
},
{
"trigger": {
"url-filter": "file://.*"
},
"action": {
"type": "ignore-previous-rules"
}
},
{
"trigger": {
"url-filter": ".*.y8k.me"
},
"action": {
"type": "ignore-previous-rules"
}
}
]
테스트 결과 허용하기로 한 도메인에서는 웹 호출이 잘 되었다. 일단 목적은 쉽게 해결을 하였다.
에러 처리하기
허용하지 않는 도메인의 페이지 열기를 시도할 경우 아래 메소드를 통해 오류를 확인할 수 있다.
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { }
error
속성 중 도메인 값은 WebKitErrorDomain
이며 코드는 104
이다. 그리고 열려고 시도한 URL은 NSErrorFailingURLStringKey
값으로 알 수 있다.
즉, 허용하지 않은 도메인을 열고자 시도했을 경우 친절하게(?)는 이 값을 이용하여 앱 내에서는 로딩을 허용하지 않았지만 다른 방법으로 (i.e. 사파리로 전달) UX의 흐름을 망치지 않을 수 있다는 것이다.
허용할 도메인 지정 후 오류없이 로딩이 안되는 문제
웹 페이지 중 <iframe>
을 이용하여 화면을 구성한 경우가 있는데 이 때는 어떠한 오류도 없이 로딩이 되지 않았다. 이 때는 위에서 언급한 규칙(Rule list)에 <iframe>
을 통해 로딩할 도메인도 명시를 해야한다.
끝으로
이 글로 알아본 규칙은 사파리에서 광고 차단 매커니즘을 웹뷰로 옮겨온 것이라고 한다. 이 정보를 확장하면 광고 차단 앱도 만들어 볼 수 있지 않을까?