본문 바로가기
알아두면 손해 없는 정보 저장소

C 모듈을 사용하는 iOS 앱 개발 1

by anothel 2022. 3. 18.

골수 앱등이 개발자, 10년 만에 드디어 MacOS 첫 발을 떼다

 

바쁜 현대인을 위한 요약: Swift로 C 기반의 모듈을 호출하는 iOS App 제작을 일주일 만에 성공했다.

 

오랫동안 사용해온 가계부 iOS 애플리케이션이 있다. 2017년 초부터 지금까지 나의 모든 자산 관련 이력이 남아 있다. 특징으로는 거의 모든 것을 수동으로 작업해야 해서 엄청난 수고로움이 있지만, 그만큼 자유도가 높은 편이다. 그래서 요즘 많이들 사용하는 뱅크 샐러드나 기타 자산 관리 애플리케이션과 견주어도 밀리지 않을 그런 애플리케이션이다.

 

그런데 더 이상의 업데이트를 하지 않는다. 물론 가계부라는 게 추가되는 서비스가 없어도 사용하는데 아무런 지장이 없긴 하지만, 개인적으로 아이폰의 인터페이스가 아주 작은 화면(SE)에서 가장 큰 화면(12 Pro Max)으로 변경되다 보니 오류가 조금씩 있더라. 그래서 내가 한번 만들어 봐야지 했는데 시작도 하지 않고 포기했다. 왜냐하면 어려워서? 귀찮아서?

 

이 애플리케이션 만들어주신 분 상드립니다. 댓글 달아주세요.

 

그러던 중 드디어 모바일을 손대 볼 일이 강제적(반강제적 아님 그냥 강제적)으로 생겨버렸다. 회사에서는 다양한 OS에서 암호화 모듈을 빌드하고 테스트해야 하는데 그중에 iOS가 있었다. 드디어 PC를 벗어나 모바일에 손대 볼 수 있는 기회가 생긴 것이다. 그리고 나는 지옥을 봤다. 일주일은 이것만 붙잡고 있었던 것 같다. 아, 개발 아니고 환경설정만.

 

(이미 많은 수의 OS에서 수행한) 빌드와 테스트를 iOS에서 수행

테스트 수행을 위해서는 C 기반의 암호모듈(.dylib)을 링킹 하고 런타임 호출하는 테스트 프로그램을 만들어야 한다(사실 PC에서 하면 진짜 아무것도 아닌데, 나는 모바일이 처음이고, 세상 사람들 핸드폰 다 들고 다닌다.). MacOS 기반의 PC에서 Xcode를 실행하고, 기본 앱을 만들고 해당 모듈을 로드해서 함수를 호출하면 끝. 그런데 이 과정이 너무 험난했다.

 

특별히 힘들거나 험난했던 순간:  MacOS를 사용하는 모든 순간

ssh 접속 후 codesign 진행

.dylib 파일을 빌드하기 위해서 필요한 스크립트는 이미 있는 상태였다. 단, 지금 이 파일이 제대로 된 파일인지 빌드가 잘되는 것은 맞는지는 잘 모르는 일이었다. 그냥 잘 된다고 가정하고 빌드를 해본다. 역시나 잘 안됐다. 그 에러 중 시작은 codesign을 하려고 하는데 적절한 아이템(아이템이라고 하면 뭔지 아냐고;)을 키체인에서 찾지 못했다는 것이다.

error: The specified item could not be found in the keychain.

 

이 문제는 키체인 접근이라는 유틸리티에 해당하는 인증서가 없어서 발생하는 것이다. 그래서 나만의 키체인을 만들고 비밀번호 설정 후 unlock 시켜 놓으면 된다. 이러면 최소한 ssh로 MacOS에 붙어서 codesign을 진행시키는데 문제가 없다. codesign을 해야 하는 이유는 .dylib을 만들어서 나중에 앱에 넣을 때 sign이 되어 있는 모듈이어야만 하기 때문이다.

 

MacOS(M1)과 iOS는 같은 arm64 프로세서 (CPU) 아키텍처인데 왜 안되는겨?: 당연한 건 없다.

Killed: 9

프로그램을 iOS 옵션으로 빌드 후 Mac에서 실행하면 프로그램이 죽는다. iOS도 MacOS도 같은 cpu(이름)을 사용하기 때문에 당연히 돼야 한다고 생각했다. 그런데 당연히 안될 리가 없다고 생각한 게 문제였다. 정확하게는 모르겠지만 비록 서로 cpu(이름)가 같다고 하더라도 iOS빌드 옵션으로 빌드한 프로그램은 MacOS에서 사용할 수 없다. 당연한 건 없었다.

 

현재 모듈의 Path를 좀 가져와봐야겠는데?

#include <stdio.h>
#include <dlfcn.h>

void test(void) {
    Dl_info info;
    if (dladdr(test, &info)) {
        printf("Loaded from path = %s\n", info.dli_fname);
    }
}

무결성 검증을 위해 전자서명 값을 파일 뒤에 붙였는데, 이때 파일을 읽기 위해서 GetModuleFileName, 리눅스에서는 현재 path를 환경변수를 넘겨줬고, AIX에서는 access, unlink, link를 사용해서 현재 로드된 모듈의 위치를 가져올 수 있었다. 그런데 iOS에서는? dladdr라는 새로운 방식으로 현재 로드된 모듈의 path를 간신히 가져올 수 있었다. 

 

중간 마무리

글 쓰는 실력도 많이 부족하고, 개발을 잘하는 것도 아닌 내가 이렇게나마 남겨놓으려고 시도하는 이유는 마우스 스크롤이 반대였던 기억을 잊기 전에, 테스트 장비 흰 화면에 숫자 0 하나가 찍히는 그 감격적인 순간 느꼈던 성취감을 잊기 전에 기록으로 남기고 싶었기 때문이다. 이걸 계기로 앞으로 하는 것들에 있어서 더 빠른 해결을 볼 수 있길 바랄 뿐이다.

 

728x90

 

번외: 딱 한 줄로 알아보는 iOS 버전

 

한 줄로 짤 코드를 누가 열 줄로 만들어놨어요? 에러 찾기 힘들게. (잠시 뒤) 코드가 길어서 프로그램만 무거워졌잖습니까? 이러니까 서비스가 버벅대지.

 

두줄도 필요 없고, 구구단 코드를 짤 필요도 없다. 딱 한 줄이면 된다.

Text(String(UIDevice.current.systemVersion)).padding()

 

Reference

벤토이

- http://www.ventoy.com/

ssh로 붙어서 작업할 때, 커맨드에서 키체인 unlock: 매번 수행해야 함

- https://stackoverflow.com/questions/24023639/xcode-command-usr-bin-codesign-failed-with-exit-code-1-errsecinternalcomponen%EF%BB%BF

ssh로 붙어서 작업할 때, 매번 unlock을 할 필요가 없게끔 하고 싶은데

- https://stackoverflow.com/questions/39868578/security-codesign-in-sierra-keychain-ignores-access-control-settings-and-ui-p%EF%BB%BF

swift에서 OS 버전이 알고 싶어

- https://stackoverflow.com/questions/24503001/check-os-version-in-swift

현재 모듈의 path를 알고 싶어

- https://stackoverflow.com/questions/7583163/how-do-i-retrieve-the-path-to-my-dylib-at-runtime

 

728x90