월별 글 목록: 2016년 9월월

애플 푸쉬서비스(APNs) 토큰 방식 인증 추가

애플 플랫폼에서 개발하다 보면 유독 인증서를 많이 이용하는것을 볼수 있습니다. 보안 때문이라고는 하지만 구글 같은곳에서도 인증에 키를 사용하는데 애플은 인증서를 사용하는 경우가 대부분이죠. 이로 인해 대부분의 애플 개발 시작하기는 인증서 파일 만들기, 인증서 파일 등록하기,  여러대의 컴퓨터에서 인증서 사용하기 등 의 문서가 많습니다.

그런데 애플이 애플 푸쉬서비스(Apple Push Notification Service)에 토큰 기반 인증을 지원한다고 하네요!!

애플 뉴스 : Token Authentication Now Available for Push Notifications

그동안 애플 푸쉬서비스를 사용하려면 인증서를 애플 개발자 사이트에서 다운로드 받아서 openssl로 한번 파일 변환하고 이를 푸쉬 전송하는 서버에서 푸쉬 보낼때 전송했어야 했는데요. 

이제는 인증서 대신 토큰으로만 전송할 수 있게 되었습니다. 또한 인증서는 1년의 유효기간을 가지고 있어서 1년에 한번씩 갱신하는것을 까먹을경우 푸쉬가 전송되지 않는 문제도 있었는데 토큰은 유효기간이 없습니다 !!

푸쉬 인증서 타입에 토큰이 추가됨

토큰이라서 문자열이지만 파일로 받는다

만료기간이 없다


토큰을 생성해보니 p8 확장자를 가진 파일을 다운로드 하게 하는데요. 파일을 열어보면 문자열을 확인할 수 있습니다. FCM(aka GCM)처럼 단순 키 문자열은 아니라 뭔가 낚인것도 같지만… 그전에 인증서 발급할때 openssl 로 했던거 생각하면 이게 어딘가요 ㅜㅜ

푸쉬 서버를 직접 운영하고 있다면 이 새로운 기능을 위해 별도 구현을 해야되구요. 저처럼 외부 푸시 서비스를 이용하는경우에는 해당서비스에서 지원하기를 기다리면 되겠습니다 ~ (카카오 푸쉬 사용하고 있는데 해주시면 감사히 잘쓰겠습니다 ㅎㅎ)

참고로 APNs 서버 API 문서(APNs Provider API)를 보면 인증에 HTTP/2 + JWT(JSON Web Token)를 사용한다고 되있습니다. 이게 JSON으로 인증하는 표준기술이라던데 저도 어떻게 동작하는지는 모르겠는데 애플도 사용한다고 하니 괜찮은가보다라는 생각이 드네요. 

앞으로 개발자 인증서나 앱별로 별도로 만들어야 되는 프로파일도 없애주면 좋겠네요. 애플은 개발자들 불편한거 오래 방치하다가 풀어준단 말이죠… 그러면 저를 포함한 개발자들의 와우 효과는 더 커지구요 ㅎㅎ 

게시글의 아마존, iTunes 링크들을 통해 구매를 하시면 제휴(Affiliate) 프로그램에 의해 저에게 일정 금액이 적립될 수 있습니다. ^_____^

애플서버에서 권한허용 문제로 빌드 실패하는 경우

Xcode 8로 업데이트후 애플 서버에 빌드를 제출하면 잠시후 아래와 같은 메시지로 실패했다고 메일이 오는 경우가 있다. 애플 빌드서버에서 실패하는거라 실제로는 Xcode 8 이 아니라 iOS 10을 지원하는 경우 발생한다고 보는게 맞겠다.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCameraUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSAppleMusicUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSContactsUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSCalendarsUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSBluetoothPeripheralUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data.

This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSMotionUsageDescription key with a string value explaining to the user how the app uses this data.

이는 카메라나 달력등 개인정보 관련된 권한을 사용할때만 Info.plist에 설정하면 되는 코드인데 사용하지 않는데도 애플 빌드서버에서 이런 오류를 발생하는 경우가 있다.

확인해보니 애플서버에서는 빌드할때 개인정보 관련코드가 외부 라이브러리에 있더라도 이걸 체크해서 무조건 위와 같이 오류를 발생한다.

나는 PermissionScope 라는 라이브러리를 사용하는데 이거는 앱 사용자에게 현재 권한을 보여주고 쉽게 권한을 요청하기에 좋은데 라이브러리 특성상 모든 개인정보 권한 코드를 가지고 있다. 라이브러리 사용할때 특정 개인정보는 사용하지 않으면 사용자가 볼일이 없는데도 라이브러리에 코드가 있다는 이유로 애플 빌드서버에서는 이런 오류를 발생시킨다.

이 문제를 고치려면 이와 같은 라이브러리를 사용하지 않거나 위에 언급된 키들에 대해 모두 문자열을 추가하면된다. 그런데 라이브러리에서 내부적으로 사용하지 않는 코드가 들어있을수도 있는데 이걸 다 어떻게 체크하나 ㅜㅜ 애드몹 같은 경우도 달력이나 몇개의 개인정보에 접근하는 코드가 있는데 이건 개발자가 적용할때 안쓴다고 하면 안쓰는건데…. 그래서 그냥 속편하게 모든 키를 다 추가하면 된다. 어차피 사용자가 안볼 문구이니까

게시글의 아마존, iTunes 링크들을 통해 구매를 하시면 제휴(Affiliate) 프로그램에 의해 저에게 일정 금액이 적립될 수 있습니다. ^_____^

Xcode 8 에서 쓸모없는 로그 출력안하게 하기

Xcode 8을 설치하고 시뮬레이터에서 앱을 실행하면 이전과 달리 엄청난 로그들을 만나게 됩니다. 대략 아래와 같은 로그들이죠…

2016-09-20 18:43:53.720846 daangna[49804:209191] [] nw_endpoint_flow_attach_protocols [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] Attached flow protocol
2016-09-20 18:43:53.720996 daangna[49804:209191] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] received child report:[6.1 31.13.68.12:443 in_progress socket-flow (satisfied)]
2016-09-20 18:43:53.721119 daangna[49804:209191] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] reported event flow:start_connect
2016-09-20 18:43:53.725114 daangna[49804:209191] [] nw_socket_handle_socket_event Event mask: 0x800
2016-09-20 18:43:53.725334 daangna[49804:209191] [] nw_socket_handle_socket_event Socket received CONNECTED event
2016-09-20 18:43:53.725523 daangna[49804:209191] [] nw_socket_setup_notsent_lowat Set TCP_NOTSENT_LOWAT(16384)
2016-09-20 18:43:53.725712 daangna[49804:209191] [] nw_endpoint_flow_protocol_connected [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] Output protocol connected
2016-09-20 18:43:53.726224 daangna[49804:209191] [] nw_endpoint_flow_connected_path_change [6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:43:53.726454 daangna[49804:209191] [] nw_endpoint_flow_connected_path_change [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Connected path is satisfied
2016-09-20 18:43:53.726645 daangna[49804:209191] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] received child report:[6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:43:53.726839 daangna[49804:209191] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 ready socket-flow (satisfied)] reported event flow:finish_connect
2016-09-20 18:43:53.727092 daangna[49804:209191] [] nw_connection_endpoint_report [6 graph.facebook.com:443 ready resolver (satisfied)] reported event flow:finish_connect
2016-09-20 18:43:53.727326 daangna[49804:209191] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 ready resolver (satisfied)] received child report:[6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:43:53.727563 daangna[49804:209191] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 ready socket-flow (satisfied)] reported event flow:changed_viability
2016-09-20 18:43:53.727758 daangna[49804:209191] [] nw_connection_endpoint_report [6 graph.facebook.com:443 ready resolver (satisfied)] reported event flow:changed_viability
2016-09-20 18:43:53.728074 daangna[49804:209175] [] __tcp_connection_start_block_invoke 6 sending event TCP_CONNECTION_EVENT_CONNECTED in response to state ready and error (null)
2016-09-20 18:43:53.728255 daangna[49804:209175] [] tcp_connection_event_notify 6 event: TCP_CONNECTION_EVENT_CONNECTED, reason: nw_connection event, should deliver: true
2016-09-20 18:43:53.728673 daangna[49804:209175] [] nw_endpoint_start_tls_while_connected [6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:43:53.728852 daangna[49804:209175] [] nw_endpoint_start_tls_while_connected [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Using CoreTLS
2016-09-20 18:43:53.729044 daangna[49804:209175] [] nw_endpoint_start_tls_while_connected [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Set custom TLS client queue
2016-09-20 18:43:53.729243 daangna[49804:209175] [] nw_endpoint_start_tls_while_connected [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Set custom TLS prepare handler
2016-09-20 18:43:53.729432 daangna[49804:209175] [] nw_endpoint_start_tls_while_connected [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Set custom TLS message handler
2016-09-20 18:43:53.729621 daangna[49804:209175] [] nw_endpoint_start_tls_while_connected [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Attached TLS protocol to connected flow
2016-09-20 18:43:53.729784 daangna[49804:209175] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 ready resolver (satisfied)] received child report:[6.1 31.13.68.12:443 in_progress socket-flow (satisfied)]
2016-09-20 18:43:53.730001 daangna[49804:209175] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] reported event flow:start_secondary_connect
2016-09-20 18:43:53.730186 daangna[49804:209175] [] nw_connection_endpoint_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] reported event flow:start_secondary_connect
2016-09-20 18:43:53.730400 daangna[49804:209175] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] received child report:[6.1 31.13.68.12:443 in_progress socket-flow (satisfied)]
2016-09-20 18:43:53.730580 daangna[49804:209175] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] reported event flow:start_connect
2016-09-20 18:43:53.730777 daangna[49804:209175] [] nw_connection_endpoint_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] reported event flow:start_connect
2016-09-20 18:43:53.730938 daangna[49804:209175] [] nw_endpoint_flow_protocol_connected [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] Transport protocol connected
2016-09-20 18:43:53.731079 daangna[49804:209175] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] received child report:[6.1 31.13.68.12:443 in_progress socket-flow (satisfied)]
2016-09-20 18:43:53.731277 daangna[49804:209175] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] reported event flow:finish_transport
2016-09-20 18:43:53.731424 daangna[49804:209175] [] nw_connection_endpoint_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] reported event flow:finish_transport
2016-09-20 18:43:53.746985 daangna[49804:209191] [] nw_endpoint_flow_protocol_connected [6.1 31.13.68.12:443 in_progress socket-flow (satisfied)] Output protocol connected
2016-09-20 18:43:53.747630 daangna[49804:209191] [] nw_endpoint_flow_connected_path_change [6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:43:53.747850 daangna[49804:209191] [] nw_endpoint_flow_connected_path_change [6.1 31.13.68.12:443 ready socket-flow (satisfied)] Connected path is satisfied
2016-09-20 18:43:53.748068 daangna[49804:209191] [] nw_endpoint_resolver_receive_report [6 graph.facebook.com:443 in_progress resolver (satisfied)] received child report:[6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:43:53.748310 daangna[49804:209191] [] nw_connection_endpoint_report [6.1 31.13.68.12:443 ready socket-flow (satisfied)] reported event flow:finish_connect
2016-09-20 18:43:53.748607 daangna[49804:209191] [] nw_connection_endpoint_report [6 graph.facebook.com:443 ready resolver (satisfied)] reported event flow:finish_connect
2016-09-20 18:43:53.748830 daangna[49804:209175] [] __tcp_connection_start_block_invoke 6 sending event TCP_CONNECTION_EVENT_TLS_HANDSHAKE_COMPLETE in response to state ready and error (null)
2016-09-20 18:43:53.749050 daangna[49804:209175] [] tcp_connection_event_notify 6 event: TCP_CONNECTION_EVENT_TLS_HANDSHAKE_COMPLETE, reason: nw_connection event, should deliver: true
2016-09-20 18:43:53.749295 daangna[49804:209175] [] tcp_connection_get_statistics DNS: 3ms/4ms since start, TCP: 10ms/17ms since start, TLS: 18ms/34ms since start
2016-09-20 18:44:07.686676 daangna[49804:209118] subsystem: com.apple.UIKit, category: Touch, enable_level: 0, persist_level: 0, default_ttl: 1, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0
2016-09-20 18:44:07.687387 daangna[49804:209118] subsystem: com.apple.UIKit, category: Gesture, enable_level: 0, persist_level: 0, default_ttl: 1, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0
2016-09-20 18:44:07.688917 daangna[49804:209118] subsystem: com.apple.UIKit, category: GestureExclusion, enable_level: 0, persist_level: 0, default_ttl: 1, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0
2016-09-20 18:44:58.968517 daangna[49804:209882] [] nw_socket_handle_socket_event Event mask: 0x2
2016-09-20 18:44:58.968960 daangna[49804:209883] [] tcp_connection_cancel 6
2016-09-20 18:44:58.969395 daangna[49804:209882] [] nw_socket_handle_socket_event Socket received READ_CLOSE event
2016-09-20 18:44:58.969753 daangna[49804:209882] [] nw_endpoint_handler_cancel [6 graph.facebook.com:443 ready resolver (satisfied)]
2016-09-20 18:44:58.970003 daangna[49804:209882] [] nw_endpoint_handler_cancel [6.1 31.13.68.12:443 ready socket-flow (satisfied)]
2016-09-20 18:44:58.970305 daangna[49804:209882] [] nw_endpoint_flow_protocol_disconnected [6.1 31.13.68.12:443 cancelled socket-flow (null)] Output protocol disconnected
2016-09-20 18:44:58.970517 daangna[49804:209882] [] nw_resolver_cancel_on_queue 0x618000103210
2016-09-20 18:44:58.970791 daangna[49804:209882] [] -[NWConcrete_tcp_connection dealloc] 6

이 로그들을 없애려면 “Edit Scheme” 에서 “Run” > “Arguments” > “Environment Variables” 에 다음과 같은 값을 추가해야합니다.

Name 에는 OS_ACTIVITY_MODE 를 추가하고 Value 에는 disable 을 입력후 왼쪽 체크박스를 체크한 상태로 둡니다.

Xcode 8 log fix

Xcode 8 log fix

이 현상은 애플이 의도적으로 넣은건지 아닌지 모르겠지만 꽤나 귀찮습니다.

참고자료

게시글의 아마존, iTunes 링크들을 통해 구매를 하시면 제휴(Affiliate) 프로그램에 의해 저에게 일정 금액이 적립될 수 있습니다. ^_____^