본문 바로가기
C.W.K.
Lesson 02 of 07 · published

식별자는 순서대로 생겨나

~15 min · testflight, app-store-connect, bundle-id, provisioning, xcodegen

Level 0번들 열어본 사람
0 XP0/84 lessons0/17 achievements
0/100 XP to next level100 XP to go0% complete
"빈 목록에 새로 만들라는 링크까지 붙어 있으면 '없다'로 읽혀. 딱 틀린 쪽으로."

아카이브가 등록하고, 레코드는 고르기만 해

새 iOS 앱엔 팀 안의 App ID(애플이 아는 번들 식별자)와, 빌드가 올라갈 App Store Connect 레코드가 필요해. 직관적인 순서는 개발자 웹사이트에서 식별자부터 만들고, 레코드를 만들고, 마지막에 빌드하는 거야. 가족 앱은 반대 순서로 가. 자동 서명으로 xcodebuild archive -allowProvisioningUpdates를 돌리면 프로젝트에 필요한 걸 작업하는 김에 등록해주거든. 앱의 식별자, 공유 확장의 식별자, 둘이 같이 쓰는 App Group까지. 그래서 누군가 App Store Connect를 열 때쯤이면 식별자는 이미 있고, 새 앱 화면의 Bundle ID 칸은 그중에서 고르는 드롭다운이 돼.

팀은 Xcode 서명 창에서 고르지 않고 project.yml에 DEVELOPMENT_TEAM으로 적어둬. UI에서 고른 팀은 생성된 프로젝트에 들어가서 다음 xcodegen generate 때 사라지거든. 수출 규정 질문도 소스에 답을 적어둬(ITSAppUsesNonExemptEncryption). 그러면 누가 브라우저에서 답해주길 기다리느라 빌드가 멈추는 일이 없어.

오후 한나절, 앱 셋, 똑같은 헛발질

어느 오후, 가족 앱 세 개가 레코드를 만들 단계에 이르렀어. 세션들은 저마다 주인한테 자기 번들 id로 레코드를 만들어 달라고 했어. 주인이 새 앱 화면을 열어보니 Bundle ID 드롭다운이 비어 있었고, 그 아래 새 번들 ID를 등록하라는 링크가 있었어. 빈 목록에 등록하라는 링크까지 붙어 있으니 "없다"로 읽혔지. 링크를 따라가 보니 개발자 웹사이트는 이미 있다면서 별다른 설명 없이 거절했어. 그런 거절은 남의 앱과 이름이 겹친 것처럼 보여. 그래서 단어 하나를 더 붙인 두 번째 식별자를 지어내 레코드를 만들었어. 한 세션은 그 우회책에 맞추려고 앱의 진짜 번들 id까지 바꿔버렸고.

여기엔 사실 두 개가 겹쳐 있었어. 첫째, 드롭다운엔 새 등록이 몇 분 늦게 나타나. 둘째, 아카이브가 이미 식별자를 등록했으니 손으로 만드는 건 애초에 해야 할 단계가 아니었어. 드롭다운이 비어 있으면 새로 만들 게 아니라 기다렸다가 새로 고침하면 돼. 복구는 간단했어. 레코드의 Bundle ID는 첫 빌드가 올라가기 전까진 고칠 수 있거든. 그래서 한 앱은 레코드가 진짜 식별자를 가리키게 바꾸는 것만으로, 소스를 하나도 안 건드리고 고쳐졌어. 첫 업로드가 끝나면 굳어버려서, 그땐 레코드를 지우고 다시 만들어야 해.

그 항목이 네 건지 알아보는 법

Xcode가 등록한 식별자엔 Xcode가 정한 기본 설명이 붙어. XC라는 글자 뒤에, 점을 공백으로 바꾼 번들 id가 오는 형태야. 레코드의 Name은 레코드 이름일 뿐이고, 홈 화면 아이콘 밑에 뜨는 이름은 앱 소스의 CFBundleDisplayName이야. 둘은 달라도 돼. 확장은 본 앱 안에 실려 나가니까 따로 레코드가 필요 없어.

Code

아카이브를 돌린 뒤, 브라우저에서 할 단계 하나를 위해 세션이 넘겨주는 안내·text
App Store Connect > Apps > + > New App
  Platforms:    iOS
  Name:         Spark            (the record's name; the home-screen name is CFBundleDisplayName)
  Bundle ID:    CHOOSE com.example.spark.mobile from the dropdown. Do not create one.
                If the list is empty or missing it, wait and reload: the archive already
                registered it, and the dropdown lags behind registration.
  SKU:          spark-mobile
  User Access:  Full Access

The entry to look for reads "XC com example spark mobile - com.example.spark.mobile".
Anything described as XC plus the id with dots as spaces was registered by a build.
아카이브가 등록한 걸 내장 프로필에서 읽기·bash
# What did the archive register? Read the profile embedded in the archived app.
app=build/SparkMobile-42.xcarchive/Products/Applications/SparkMobile.app
profile=$(security cms -D -i "$app/embedded.mobileprovision")

print -r -- "$profile" | plutil -extract Name raw -o - -
#   iOS Team Provisioning Profile: com.example.spark.mobile
print -r -- "$profile" | plutil -extract Entitlements.application-identifier raw -o - -
#   EXAMPLE_TEAM.com.example.spark.mobile
print -r -- "$profile" | plutil -extract 'Entitlements.com\.apple\.security\.application-groups' json -o - -
#   ["group.com.example.spark"]

# The archive is development-signed (its profile lists devices). The export step re-signs
# it for App Store Connect, which is why no distribution profile is ever made by hand.

External links

Exercise

SparkMobile을 -allowProvisioningUpdates로 한 번 아카이브하고 결과물에 검사 명령을 돌려. 프로필 이름, 팀 접두사를 EXAMPLE_TEAM으로 바꾼 애플리케이션 식별자, App Group을 적어. 이어서 네 앱의 진짜 표시 이름, 번들 id, SKU를 채운 인계 안내를 쓰고, 드롭다운이 비었을 때의 대응까지 넣어서 레포의 배포 문서에 넣어둬.
Hint
plutil -extract는 키 안의 점을 백슬래시로 이스케이프해야 해서 App Group 키를 따옴표로 감쌌어. security cms -D가 아무것도 안 찍으면, 경로가 아카이브 폴더가 아니라 Products/Applications 안의 .app을 가리키는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.