diff --git a/public/posts/storyboardHelper/thumbnail.png b/public/posts/storyboardHelper/thumbnail.png new file mode 100644 index 0000000..fc83385 Binary files /dev/null and b/public/posts/storyboardHelper/thumbnail.png differ diff --git a/src/posts/project/spam_killer/thumbnail.png b/src/posts/project/spam_killer/thumbnail.png deleted file mode 100644 index 14113c9..0000000 Binary files a/src/posts/project/spam_killer/thumbnail.png and /dev/null differ diff --git a/src/posts/project/spam_killer_1/content.mdx b/src/posts/project/spam_killer_1/content.mdx new file mode 100644 index 0000000..68ff208 --- /dev/null +++ b/src/posts/project/spam_killer_1/content.mdx @@ -0,0 +1,138 @@ +--- +title: "[draft]스팸 문자/전화좀 그만해라 (1)" +date: 2024-11-22 +desc: 지긋지긋한 스팸들... +thumbnail: /posts/spam_killer/thumbnail.jpg +--- + +![스팸 문자/전화좀 그만해라](/posts/spam_killer/thumbnail.jpg) + +## 개인적인 잡담 + +요즘들어 갑지기 070 전화가 하루 한번 이상 오기 시작했다. + +이전 회사에서 이런 스팸관련 전화/문자에 대해 구현한 경험이 떠올라 +간단하게 개인용 앱을 만들어 보고, 관련 과정을 공유하려고 한다. + +추가적으로, 이전회사에서 알게 된 내용이 있는데, + +> SKT 통신사의 경우, T전화를 개발하는 부서가 전화의 수발신을 담당하는 회사(SKT)내에 존재한다. +한 회사이기 때문에, 개인정보 걱정없이 특정번호 수신을 미리 차단 가능하다. + +> KT의 경우 이런 전화번호관련 개발회사(ex. 후후)가 자회사로 분리되어있다. +때문에, 전화수발신에 대해 관여하기 위해서는 복잡한 개인정보동의가 필요하다. (거의 불가능) + +운나쁘게도, 난 KT를 사용하고 있다. ㅠㅠ + +--- + +## 목표 + +### 1. 스팸전화 (`070` 시작번호) 차단 + +`010`으로 오는 전화는 어떤 전화인지 모르기때문에 차단하지 않기로 했다. + +iOS의 경우, 전화와 관련되어 Callkit이라는 프레임워크를 제공하고 있다. + +민감한 정보와 관련되다보니, 아주 제한적인 기능만을 제공하고 있는데, 이 기능 중 전화번호 저장/차단과 관련된 callkit extension을 사용해보려고 한다. + +이전 개발시점(2019년)까지는 extension 하나당 최대 약20만개의 전화번호까지만 등록/차단이 가능했으나, +현재는 테스트해보니, 200만개까지 가능하다. (이런건 제발 공식문서에 기록좀 해붰으면 좋겠다.) + +우리가 차단해야하는 번호는 070-xxxx-xxxx 형식으로, 경우의 수는 1억개의 패턴이 나온다. +이전에 20만개 차단일 경우에는 500개의 exntension을 설치&활성화해야함으로 불가능했으나, +현재는 200만개로, 50개면 추가해볼만 할것으로 판단된다. + +callkit extension에는 여러가지 주의점이 존재하는데, +1. extension임으로, 메모리는 7mb정도만 사용이 가능함 (한계 메모리가 넘어가면, 강제종료됨) +2. 전화번호 등록시, sort가 되어있지 않으면 에러 발생 +3. 한번에 2000개씩 저장(설정 불가능)되며, 2번과 같은 특징때문에 멀티쓰레드 처리가 불가능함 + +이러한 특징때문에, 1억개의 전화번호를 등록하려면 상당한 시간이 소모될 것으로 판단된다. +따라서, 스팸 등록시 현재 진행상황을 보여주는 화면도 필요할 것으로 판단된다. + +또한, 설정 - 전화 - 전화번호차단에서 옵션을 on할때 바로 전화를 등록하면 +50개의 extension을 한개씩 켜다가 답답해 죽을 수 있으니, 여기서 설정시에는 전화번호 등록을 안해야한다. + +이전 경험상, 이런 extension을 한번에 여러개 키는 경우에, 시스템 에러가 발생(활성화 오류)하며 이런 에러를 수정하기 위해서는 +문제가 되는 extension애서 이미 저장된 번호를 다 삭제한 뒤, 완료를 기다렸다 다시 저장해아한다. + +그냥 편하게, +1. 하나에서 실패가 발생하면 모든 전화번호를 다시 저장한다. +2. enxtension에서 전화번호 저장 시작은 앱에서만 실행하며, 동시에 실행되는 extension 개수를 최대한 보수적으로 설정한다. + +이렇게 하는게 나을 것 같다. + + + +### 2. 스팸문자 차단 + +iOS에서는 스팸문자로 등록되면, 실시간 알람에 안뜨고, 문자 뱃지 카운트만 증가해주는 로직이 존재한다. +또한 스팸은 거래/광고/정크 타입으로 등록이 가능하며, 문자수신시 최초 1번만 등록이 가능하다. + +무슨말이냐면, 최초로 수신되는 문자였을때만 문자내용이 extensino으로 전달되며, +이후에는 동일번호로는 extension 문자로 체크할 수 없다는 것이다. + +또한 3~4초내에 스팸인지 아닌지 답을 주지 않으면, 비스팸으로 처리되는 로직도 있다. + +문자수신 시점에만 실행되며, 프레임워크가 제공하는 형식의 API가 강제되며 +개인정보를 판별할 수 있는 정보는 보낼 수가 없다. (sender/content만 서버로 전달 가능) + +따라서 특정 사용자를 인식한다던가.. (예를 들어 회원인지 아닌지), 누구한테 보낸 문자인지 (receiver)를 알 수 없다. + + +스팸으로 등록된 문자는 문자 - 정크항목으로 들어가게 되며, 알람도 노출되지 않는다. + +문제는, 해당 전화번호로 오는 문자를 다시 받고 싶은 경우인데... +이럴때 exntenion에서는 해결 할 수 있는 방법이 없다. + +이미 수신된 문자가 있어서, 위의 조건(최초수신시에만 전달)이 되지 않으며, +전체 문자를 삭제하면, 최초 수신시에만 전달조건에는 일치하나, extension 로직상 다시 스팸으로 처리될 가능성이 높다. + +뭐랄까... 해결책은 좀 생뚱맞을 수 있는데, +해당 문자에 대한 reply를 3번이상 하면 시스템에서 자동 해제 된다. + +이런 제약과 문제점(?) 때문에, 후후앱 개발시 CS팀이 꾀나 고생했덜걸로 기억한다. + + + +### 3. UI 및 구현 + +기존처럼 rxswift + storybaord를 사용할까 했는데, +이왕이면 공부할 겸, swiftUI + combine을 사용해보려고 한다. + +이전회사에서 swiftUI로 일부화면을 구현해봤으나, +swiftUI + hostingViewController는 넘 비효츌적인 경우가 많아서, 일부분만 사용해봤었다. + +이번에는 full swfitUI + combine에 ribs 구조를 사용해보려고 한다. + +또한 50개의 extension을 생성/셋팅해아함으로, +수동으로 만드는 것보다 tuist를 사용, 자동으로 구축해보려고 한다. + +UI는 토이프로젝트임을 감안해, 어디선가 많이 보던 UI를 최대한 비슷하게 구현해볼까 한다. + +### 4. 서버구축 + +스팸문자의 경우, 앱 내에서 판별도 가능하지만, API를 통해 질의도 가능하다. +때마침 집에 Nas를 통한 웹서버를 구동중임으로, OpenAI API를 통한 스팸여부 판단로직을 구현해보려고 한다. + + + +### 5. 테스트 + +자.. 문제의 테스트 항목까지 넘어왔다. +후후를 개발하면서도 느꼈지만, 시스템 항목 중 민감정보, 특히 전화번호/문자 관련해서는 Unit/UI 테스트가 불가능하다. + +자동화 테스트라는게, 특정 기능(함수)를 호출하고 원하는 결과값이 나타나는지를 확인하는건데, + +위의 두가지 extension은 +1. 특정 기능에 대한 수동 호출 불가능 (스팸문자) +2. 기능에 대한 검증 불가능 (스팸문자) +3. 특정 기능 수행 및 검증을 위한 mocking 불가능 (전화차단) + +따라서, extension에 대한 검증은 실제 테스트로 대채하며, 그 외에 항목은 최대한 테스트를 진행할 예정이다. + +## 정리 + +이리저리 아이디어를 정리하다보니, 처음 생각보다 커진것 같다. +에상 목표는 1주일로 잡고, 최대한 빨리 정리해 올려보도록 노력하겠다. \ No newline at end of file diff --git a/src/posts/project/spam_killer_2/content.mdx b/src/posts/project/spam_killer_2/content.mdx new file mode 100644 index 0000000..602eb9f --- /dev/null +++ b/src/posts/project/spam_killer_2/content.mdx @@ -0,0 +1,139 @@ +--- +title: "[draft]스팸 문자/전화좀 그만해라 (1)" +date: 2024-11-22 +desc: 지긋지긋한 스팸들... +thumbnail: /posts/spam_killer/thumbnail.jpg +--- + +![스팸 문자/전화좀 그만해라](/posts/spam_killer/thumbnail.jpg) + +## 개인적인 잡담 + +회사를 그만두고나서, 그동안 부족했던 부분에 대해서 여러가지 공부를 하려고 준비중이다. +그런데, 갑지기 070 전화가 하루 한번 이상 오기 시작했다. + +이전에 [후후앤컴퍼니](/about)에서 이런 스팸관련 전화/문자에 대해, +여러가지 기능을 구현해본 경험이 있기 문에, 간단하게 개인용 앱을 만들어 보고, 관련 과정을 공유하려고 한다. + +추가적으로, 이전회사에서 알게 된 내용이 있는데, + +> SKT 통신사의 경우, T전화를 개발하는 부서가 전화의 수발신을 담당하는 회사(SKT)내에 존재한다. +한 회사이기 때문에, 개인정보 걱정없이 특정번호 수신을 미리 차단 가능하다. + +> KT의 경우 이런 전화번호관련 개발회사(ex. 후후)가 자회사로 분리되어있다. +때문에, 전화수발신에 대해 관여하기 위해서는 복잡한 개인정보동의가 필요하다. (거의 불가능) + +운나쁘게도, 난 KT를 사용하고 있다. ㅠㅠ + +--- + +## 목표 + +### 1. 스팸전화 (070 시작번호) 차단 + +010으로 오는 전화는 어떤 전화인지 모르기때문에 차단하지 않기로 했다. + +iOS의 경우, 전화와 관련되어 Callkit이라는 프레임워크를 제공하고 있다. + +민감한 정보와 관련되다보니, 아주 제한적인 기능만을 제공하고 있는데, 이 기능 중 전화번호 저장/차단과 관련된 callkit extension을 사용해보려고 한다. + +이전 개발시점(2019년)까지는 extension 하나당 최대 약20만개의 전화번호까지만 등록/차단이 가능했으나, +현재는 테스트해보니, 200만개까지 가능하다. (이런건 제발 공식문서에 기록좀 해붰으면 좋겠다.) + +우리가 차단해야하는 번호는 070-xxxx-xxxx 형식으로, 경우의 수는 1억개의 패턴이 나온다. +이전에 20만개 차단일 경우에는 500개의 exntension을 설치&활성화해야함으로 불가능했으나, +현재는 200만개로, 50개면 추가해볼만 할것으로 판단된다. + +callkit extension에는 여러가지 주의점이 존재하는데, +1. extension임으로, 메모리는 7mb정도만 사용이 가능함 (한계 메모리가 넘어가면, 강제종료됨) +2. 전화번호 등록시, sort가 되어있지 않으면 에러 발생 +3. 한번에 2000개씩 저장(설정 불가능)되며, 2번과 같은 특징때문에 멀티쓰레드 처리가 불가능함 + +이러한 특징때문에, 1억개의 전화번호를 등록하려면 상당한 시간이 소모될 것으로 판단된다. +따라서, 스팸 등록시 현재 진행상황을 보여주는 화면도 필요할 것으로 판단된다. + +또한, 설정 - 전화 - 전화번호차단에서 옵션을 on할때 바로 전화를 등록하면 +50개의 extension을 한개씩 켜다가 답답해 죽을 수 있으니, 여기서 설정시에는 전화번호 등록을 안해야한다. + +이전 경험상, 이런 extension을 한번에 여러개 키는 경우에, 시스템 에러가 발생(활성화 오류)하며 이런 에러를 수정하기 위해서는 +문제가 되는 extension애서 이미 저장된 번호를 다 삭제한 뒤, 완료를 기다렸다 다시 저장해아한다. + +그냥 편하게, +1. 하나에서 실패가 발생하면 모든 전화번호를 다시 저장한다. +2. enxtension에서 전화번호 저장 시작은 앱에서만 실행하며, 동시에 실행되는 extension 개수를 최대한 보수적으로 설정한다. + +이렇게 하는게 나을 것 같다. + + + +### 2. 스팸문자 차단 + +iOS에서는 스팸문자로 등록되면, 실시간 알람에 안뜨고, 문자 뱃지 카운트만 증가해주는 로직이 존재한다. +또한 스팸은 거래/광고/정크 타입으로 등록이 가능하며, 문자수신시 최초 1번만 등록이 가능하다. + +무슨말이냐면, 최초로 수신되는 문자였을때만 문자내용이 extensino으로 전달되며, +이후에는 동일번호로는 extension 문자로 체크할 수 없다는 것이다. + +또한 3~4초내에 스팸인지 아닌지 답을 주지 않으면, 비스팸으로 처리되는 로직도 있다. + +문자수신 시점에만 실행되며, 프레임워크가 제공하는 형식의 API가 강제되며 +개인정보를 판별할 수 있는 정보는 보낼 수가 없다. (sender/content만 서버로 전달 가능) + +따라서 특정 사용자를 인식한다던가.. (예를 들어 회원인지 아닌지), 누구한테 보낸 문자인지 (receiver)를 알 수 없다. + + +스팸으로 등록된 문자는 문자 - 정크항목으로 들어가게 되며, 알람도 노출되지 않는다. + +문제는, 해당 전화번호로 오는 문자를 다시 받고 싶은 경우인데... +이럴때 exntenion에서는 해결 할 수 있는 방법이 없다. + +이미 수신된 문자가 있어서, 위의 조건(최초수신시에만 전달)이 되지 않으며, +전체 문자를 삭제하면, 최초 수신시에만 전달조건에는 일치하나, extension 로직상 다시 스팸으로 처리될 가능성이 높다. + +뭐랄까... 해결책은 좀 생뚱맞을 수 있는데, +해당 문자에 대한 reply를 3번이상 하면 시스템에서 자동 해제 된다. + +이런 제약과 문제점(?) 때문에, 후후앱 개발시 CS팀이 꾀나 고생했덜걸로 기억한다. + + + +### 3. UI 및 구현 + +기존처럼 rxswift + storybaord를 사용할까 했는데, +이왕이면 공부할 겸, swiftUI + combine을 사용해보려고 한다. + +이전회사에서 swiftUI로 일부화면을 구현해봤으나, +swiftUI + hostingViewController는 넘 비효츌적인 경우가 많아서, 일부분만 사용해봤었다. + +이번에는 full swfitUI + combine에 ribs 구조를 사용해보려고 한다. + +또한 50개의 extension을 생성/셋팅해아함으로, +수동으로 만드는 것보다 tuist를 사용, 자동으로 구축해보려고 한다. + +UI는 토이프로젝트임을 감안해, 어디선가 많이 보던 UI를 최대한 비슷하게 구현해볼까 한다. + +### 4. 서버구축 + +스팸문자의 경우, 앱 내에서 판별도 가능하지만, API를 통해 질의도 가능하다. +때마침 집에 Nas를 통한 웹서버를 구동중임으로, OpenAI API를 통한 스팸여부 판단로직을 구현해보려고 한다. + + + +### 5. 테스트 + +자.. 문제의 테스트 항목까지 넘어왔다. +후후를 개발하면서도 느꼈지만, 시스템 항목 중 민감정보, 특히 전화번호/문자 관련해서는 Unit/UI 테스트가 불가능하다. + +자동화 테스트라는게, 특정 기능(함수)를 호출하고 원하는 결과값이 나타나는지를 확인하는건데, + +위의 두가지 extension은 +1. 특정 기능에 대한 수동 호출 불가능 (스팸문자) +2. 기능에 대한 검증 불가능 (스팸문자) +3. 특정 기능 수행 및 검증을 위한 mocking 불가능 (전화차단) + +따라서, extension에 대한 검증은 실제 테스트로 대채하며, 그 외에 항목은 최대한 테스트를 진행할 예정이다. + +## 정리 + +이리저리 아이디어를 정리하다보니, 처음 생각보다 커진것 같다. +에상 목표는 1주일로 잡고, 최대한 빨리 정리해 올려보도록 노력하겠다. \ No newline at end of file diff --git a/src/posts/project/storyboardHelper/content.mdx b/src/posts/project/storyboardHelper/content.mdx new file mode 100644 index 0000000..0f3a56d --- /dev/null +++ b/src/posts/project/storyboardHelper/content.mdx @@ -0,0 +1,147 @@ +--- +title: "Storyboard Helper" +date: 2024-11-25 16:30 +desc: 이젠 슬슬 보내줘야지.. +thumbnail: /posts/storyboardHelper/thumbnail.png +--- + +![이제 슬슬 보내줘야하나](/posts/storyboardHelper/thumbnail.png) + +## 들어가며 + +아주 예전에, 스토리보드가 막 생기기 시작했을때부터 만들어서 사용하던 [프로젝트](https://github.com/manaes/StoryboardUtil)가 있었다. +대충 만들어서 쓰다가, 팀 내부에 공유할 일이 있어서 아주 약간의 Document + SPM으로 배포했다. +원래부터 공유용이 아니다보니, 여러가지 기능이 잡다하게 섞여어 이번 기회에 좀 정리하려고 한다. + +--- + +## Storyboard + +아직은 xib가 대세일때, 여러개의 뷰를 한꺼번에 보여주며, 동작 정의도 가능한 `UIStoryboard`는 획기적이라 생각했다. + +하지만, 사용하다보니 다음의 문제점들이 발생했는데... + +1. 무거움 +많은 뷰가 스토리보드 파일에 들어가있는 경우, 스토리보드 클릭하면 엄청난 렉이 발생. 열리기전까지 crash가 발생하지 않기를 빌어야했다. + +2. 복잡성 +autolayout을 정의할때, 자동조건으로 생성하거나, 중복되는 조건을 넣는 경우가 발생하는데, 이 경우 해당뷰를 찾아서 최적화하기가 너무 힘들었다. + +3. 소스파일 변경 +단순히 뷰만 보더라도, 개발자들의 pc 셋팅에 따라 스토리보드 파일 내용이 변경되는 경우가 많았다. +스토리보드내 1개 뷰만 수정했는데, 다른 뷰도 같이 수정되고, 이 파일을 다른 사람이 열먼 또 수정되는... +악순환이 반복되는 문제가 발생한다. + +기타 여러가지 문제점들이 있지만, 대체제로 나온 `swiftUI`로 전환이 쉽지 않아서 +기존 프로젝트가 존재하는 경우 스토리보드를 사용하는 경우가 대부분이었다. + +`swiftUI`를 추가하기 어려웠던 이유를 생각나는대로 적어보면, + +1. 호환성 : 일부 충돌하는 framework를 사용중이거나, 시뮬레이터 호환성이 없는 경우 동작시 에러 발생 + +2. 복잡성 : SwiftUI는 어렵지 않으나, 기존 프로젝트에서 사용하려면 `HostingViewController`를 사용해야함. +이때, 기존 구조 유지기 어려워서 관련 로직을 다 수정하거나, 이 부분만을 위한 중복로직을 추가해야하는 문제 발생 + +3. Alert/Sheet : 1개의 뷰에 하나의 Alert/Sheet. 이전에 전환하려고 했던 프로젝트에서는 많은 수의 알럿이 존재했는데, +이 알럿을 하나의 뷰에서 보여주기 위해서는, 알럿을 보여주기 위해 구조적으로 많은 부분을 수정했음 + +4. 기타 : 시간... (비겁한 변명이십니다!!) + +--- + +## 그래서? + +결론적으로, 위에서 이야기한 `UIStoryboard` 문제를 해결하기 위해 여러가지 방법을 사용했는데 + +1. 파일 쪼개기 +각 기능별/카테고리별 스토리보드 파일을 여러개 만들어서 사용하면, 스토리보드내 뷰가 줄어들어 대부분의 문제점이 해결된다. + +2. 자동 autolayout 사용하지 않기 +의외(?)로 warnning/error 발생시, 자동생성 버튼을 누르는 개발자들이 존재했다!! 중복제거 및 죄적화를 위해서는 절대 사용해서는 안된다고 생각한다. + +2. cell 스토리보드 사용 금지 +cell의 경우, 특성상 반복되는 경우가 많은데 스토리보드 - 뷰에 넣는 경우 당연히 문제가 발생한다. (디자인 수정시, 일일히 찾아서 수정한다던가...) +이때, `snapkit`을 사용해, 코드로 뷰를 구현하거나, `xib`로 뷰를 만들어서 불러오면 렉도 줄고 재사용도 편해진다. + +--- + +## StoryboardHelper? + +### 문제 + +1번의 경우, 스토리보드를 쪼개다보니 뷰 클래스 관리가 점점 햇갈리기 시작했다. + +```swift +let storyboard = UIStoryboard(name: "Main", bundle: .main) +let vc = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController +``` + +이런 코드의 경우, 단일 스토리보드에 단일 클래스라 큰 문제가 되지 않는다. + +하지만, 스토리보드 파일이 10개, 20개, 30개... 늘어난다면? + +> 특정 뷰를 instance 하려고 하는데, 어느 스토리보드에 생성했는지 햇갈리는 경우가 발생한다. + +두번째로, + +```swift +let storyboard = UIStoryboard(name: "Intro", bundle: .main) +let vc = storyboard.instantiateViewController(withIdentifier: "IntroViewController") as! IntroViewController +``` + +Instance된 VC 객체를 불러오기 위해, 상당히 많은 코드를 작성해야한다. + +### 수정 + +이걸 해결하기 위한 간단한 프로젝트가 [StoryboardHelper](https://github.com/manaes/StoryboardHelper)이다. + +1. SPM으로 프로젝트 추가 +```swift +// swift-tools-version:4.0 +import PackageDescription + +let package = Package( + name: "YOUR_PROJECT_NAME", + dependencies: [ + .package(url: "https://github.com/manaes/StoryboardHelper.git", from: "1.0.0"), + ] +) +``` + +2. 스토리보드에 뷰 생성시, 클래스명과 동일하게 storyboard id를 입력해줌 + + + + +3. 다음 코드를 사용해 VC 객체를 얻을 수 있음 + +```swift +try await Storyboard().controller(TestViewController.self) +``` + +끝!! + +--- + +### 개선점 + +1. 스토리보드에 `storyboard id`를 입력하지 않았다면, 현재는 실행시에 에러가 발생하게 되어있다. +추후에는 [buildPlugin](https://developer.apple.com/videos/play/wwdc2022/110401/)을 사용해, prebuild 상태에서 에러를 체크하는 로직을 추가하려한다. + +2. swift package에서 Unit Test 진행시, + +```swift +swiftSettings: [ + .define("UNIT_TESTING") +] +``` +설정이 정상적으로 되지 않았다. + +```swift +ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil +``` +로 체크, 테스트 파일 경로를 지정해줬으나, 추후에는 `swiftSettings`값으로 변경해야함다. + +3. 미묘(?)하게 code coverage가 `98%`다. 몇줄 되지 않은 코드이니, `100%`를 노려봐야겠다. \ No newline at end of file