Build number App Store Connect: version và số build
Bởi Mehdi Azizi
Đăng ngày , 8 phút
Version là số khách hàng nhìn thấy, build number định danh từng lần gửi. Cặp này phải là duy nhất: với Expo, EAS tự tăng số build cho bạn.
Build number của App Store Connect chính là số build: khóa CFBundleVersion, dùng để định danh từng lần gửi. Version, tức CFBundleShortVersionString, là con số khách hàng của bạn nhìn thấy trên App Store. Apple yêu cầu cặp version và số build phải là duy nhất: mỗi số build chỉ dùng được một lần cho cùng một version.
Với Expo, bạn tự đặt version, còn EAS có thể tăng số build ở mỗi lần build production. Bài này giải thích hai con số, các quy tắc của Apple, lỗi ITMS-90062 và ITMS-90189, và những gì cần kiểm tra khi build của bạn không xuất hiện.
Mình phát hành các app iOS bằng Expo và EAS, trong đó có Solys, TradaZen và Nolera. Các thiết lập bên dưới lấy từ chính file eas.json của chúng.
Version và số build: khác nhau thế nào?
Hai khóa trong Info.plist định danh app của bạn. Tài liệu của Apple về CFBundleShortVersionString mô tả nó là version người dùng nhìn thấy: ba số nguyên cách nhau bằng dấu chấm, ví dụ 10.14.1. Tài liệu về CFBundleVersion nói về version của build: từ một đến ba số nguyên, chỉ gồm chữ số và dấu chấm.
| Thành phần | Khóa iOS | Ai nhìn thấy | Trường Expo |
|---|---|---|---|
| Version | CFBundleShortVersionString | Khách hàng của bạn | version |
| Số build | CFBundleVersion | Bạn và Apple | ios.buildNumber |
Ví dụ giả định: với version 1.4.0, bạn gửi các build 12, 13 và 14 trong lúc test, rồi chọn một build để gửi duyệt. Trang trợ giúp App Store Connect tóm gọn: version gắn build với trang app của nó, còn số build định danh build đó ở mọi nơi trong hệ thống.
Quy tắc tăng số của Apple
- Cặp số phải là duy nhất. Theo tài liệu Xcode Cloud, App Store Connect yêu cầu tổ hợp version và số build không trùng lặp. Vì vậy app iPhone có thể bắt đầu lại từ 1 cho version mới. App Mac thì không: số của nó luôn phải tăng.
- Version đã được duyệt là đóng lại. Khi Apple đã duyệt version 1.4.0, bạn không thể thêm build vào nó nữa. Version tiếp theo phải mang số cao hơn.
- Mỗi số được so sánh như số nguyên. 1.10 đứng sau 1.9, vì 10 lớn hơn 9. Một version 1.9 gửi sau khi 1.20 đã được duyệt sẽ bị từ chối.
Lời khuyên của mình: giữ số build là số nguyên luôn tăng, đừng đặt lại về 1. Trên iPhone thì được phép bắt đầu lại từ 1, nhưng một số duy nhất suốt vòng đời app giúp bạn không nhầm hai build trong TestFlight. Đó là điều mình thấy trên các app dùng chế độ remote: bộ đếm cứ chạy tiếp từ version này sang version khác.
Quản lý version và build với Expo và EAS
Trang của Expo về version, cập nhật ngày 25 tháng 9 năm 2026, tách rõ vai trò. Version (version trong app.json) do bạn quản lý: bạn đổi nó khi chuẩn bị một bản phát hành mới. Số build (ios.buildNumber) có thể giao cho EAS. Expo còn nêu việc quên tăng số này là nguyên nhân phổ biến khiến lần gửi bị từ chối.
Mọi thứ được thiết lập trong eas.json:
{
"cli": {
"appVersionSource": "remote"
},
"build": {
"production": {
"autoIncrement": true
}
}
}
"remote": server của EAS lưu số build. Đây là cách được khuyến nghị từ EAS CLI 12. Bộ đếm bắt đầu từ giá trị trong cấu hình của bạn, hoặc từ 1, sau đóios.buildNumberbị bỏ qua."local": cấu hình của bạn là chuẩn. VớiautoIncrement, EAS sửaios.buildNumbertrong file, và bạn phải commit thay đổi đó sau mỗi lần build.autoIncrement: tài liệu tham chiếu eas.json chấp nhậntruehoặc"buildNumber"cho số build, và"version"để tăng chữ số cuối của version. Ở chế độ remote, Expo nói rõ"version"không được hỗ trợ.
Với mình, TradaZen và Nolera dùng remote. Solys vẫn để local: số build nằm trong app.json và mỗi lần build production lại tăng nó trong file. Cả hai đều chạy được, nhưng chế độ remote loại bỏ rủi ro quên commit.
Hai lệnh hoàn thiện hệ thống này. eas build:version:set khởi tạo bộ đếm remote: nhập số build cuối cùng bạn đã gửi cho Apple. eas build:version:sync chép giá trị remote về project của bạn, hữu ích nếu một ngày bạn build bằng Xcode. Với EAS Update, chế độ remote không chạy với chính sách nativeVersion: Expo khuyên dùng appVersion.
ITMS-90062: version đã được duyệt
Thông báo trông như sau (số giả định):
ERROR ITMS-90062: This bundle is invalid. The value for key
CFBundleShortVersionString [1.4.0] in the Info.plist file must
contain a higher version than that of the previously approved
version [1.4.0].
Apple đã duyệt version 1.4.0: bạn không thể thêm build vào đó nữa. Hãy tăng version trong app.json, ví dụ lên 1.4.1, rồi build lại. Chỉ đổi số build là không đủ.
Nếu lỗi vẫn quay lại dù version đã cập nhật, hãy tìm trường ios.version. Theo tài liệu tham chiếu cấu hình Expo, nó được ưu tiên hơn version trên iOS. Cách xử lý tương tự cho lỗi họ hàng ITMS-90186, "Invalid Pre-Release Train", báo rằng version đó đã đóng với build mới.
ITMS-90189: Redundant Binary Upload
Lần này, số build là thứ gây kẹt:
ERROR ITMS-90189: Redundant Binary Upload. You've already uploaded
a build with build number '12' for version number '1.4.0'.
Cặp 1.4.0 (12) đã tồn tại bên Apple. Với Expo, có bốn nguyên nhân hay gặp:
- Profile đang dùng không có
autoIncrement. Nếu bạn tạo một profile riêng cho TestFlight, như của Nolera, hãy thêm lại tùy chọn này. - Bộ đếm remote bị tụt lại. Bạn chuyển sang
remotesau vài lần gửi thủ công: chạyeas build:version:setvới số cuối cùng Apple đã biết. - Quên commit ở chế độ local. Lần build sau lại bắt đầu từ số cũ.
- Bạn gửi lại cùng một binary. Với
eas submit, hãy chọn build mới, không phải build cũ.
Cách sửa luôn giống nhau: một build mới với số cao hơn.
"No builds available": build của bạn không xuất hiện
Build đã được gửi đi, nhưng trang app không hiện nó. Kiểm tra theo thứ tự sau.
- Nó vẫn đang được xử lý. Apple xử lý từng build trước khi hiển thị và gửi email cho bạn khi xong. Expo cho biết thường mất 10 đến 15 phút. Theo Apple, nếu xử lý quá 24 giờ, bạn cần mở ticket Feedback Assistant.
- Nó đang chờ bạn khai báo mã hóa. Đó là trạng thái Missing Compliance, chi tiết ở dưới.
- Version không khớp. Một build 1.4.1 không nằm dưới trang app đã chuẩn bị cho 1.5.0 trong App Store Connect. Hãy cho hai bên khớp nhau.
- Có một version vừa phát hành trong lúc đó. Theo trang trợ giúp về chọn build, danh sách khi đó chỉ hiện các build gửi sau lần phát hành ấy.
- Người test mới là người không thấy. Trong app TestFlight, "no builds available" thường có nghĩa build không nằm trong nhóm nào, đang chờ duyệt beta hoặc đã hết hạn. Chi tiết có trong TestFlight để test app iPhone của bạn.
Các trạng thái cần biết
Những trạng thái thường giải thích việc build không xuất hiện, theo danh sách của Apple. Processing và Failed không có trong đó: đây là trạng thái gửi được mô tả ở trang theo dõi build.
| Trạng thái | Ý nghĩa | Cách xử lý |
|---|---|---|
| Processing | Apple đang xử lý build | Chờ email |
| Failed | Lỗi khi xử lý | Đọc lỗi, gửi lại |
| Missing Compliance | Chưa khai báo mã hóa | Trả lời hoặc Info.plist |
| Invalid Binary | Bản gửi không hợp lệ | Sửa, build mới |
| Expired | Quá 90 ngày | Build mới |
| Ready to Submit | Sẵn sàng để test hoặc duyệt | Thêm vào một nhóm |
Khai báo mã hóa một lần cho xong
Nếu thiếu khóa ITSAppUsesNonExemptEncryption, Apple sẽ hỏi bạn các câu hỏi tuân thủ ở mỗi version mới. Với Expo, trường này là ios.config.usesNonExemptEncryption:
{
"expo": {
"ios": {
"config": {
"usesNonExemptEncryption": false
}
}
}
}
false nghĩa là: không có mã hóa, hoặc chỉ có mã hóa được miễn trừ. Apple nói rõ rằng mã hóa tích hợp sẵn trong hệ thống, như kết nối HTTPS, thường được miễn trừ, và câu trả lời cũng bao gồm các thư viện của bạn. Cả ba app của mình đều khai báo false. Chỉ đặt false nếu điều đó đúng với app của bạn: khai báo này ràng buộc trách nhiệm của bạn.
Có đổi được số của build đã gửi không?
Không. Số này được ghi vào binary đã ký: muốn sửa, bạn cần một build mới.
Thứ bạn đổi được là build gắn với version. Apple chỉ cho phép một build mỗi version, nhưng bạn có thể thay nó bao nhiêu lần tùy thích cho đến khi gửi duyệt:
- Mở version trong App Store Connect, phần Build.
- Di chuột lên build hiện tại và bấm nút xóa, dấu trừ.
- Bấm nút thêm, dấu cộng, chọn đúng build, rồi lưu.
Gỡ build khỏi version không xóa nó khỏi tài khoản của bạn. Nếu version đã đang được duyệt, hãy rút bản gửi trước: quá trình duyệt sẽ bắt đầu lại từ đầu.
Trước lần gửi tiếp theo
Số build chỉ là một trong các bước kiểm tra khi gửi. Image build có thể gây ra ITMS-90725, còn việc ký có những cái bẫy riêng, chi tiết trong chứng chỉ developer iOS và provisioning profile. Toàn bộ chuỗi, từ build đến TestFlight, có trong phát hành app iOS không cần Mac, và thời gian duyệt có trong thời gian duyệt App Store. Mọi bước được tập hợp ở trang phát hành ứng dụng lên App Store.
Nếu bạn đang chuẩn bị bản phát hành đầu tiên, làm bài chẩn đoán miễn phí: nó cho bạn biết điều gì đang chặn project của bạn và gửi bạn checklist chống bị Apple từ chối của mình. Để xây app, tích hợp gói thuê bao và phát hành, iOS & Android Kit đi theo lộ trình bốn bước với Starter Code từ các app của mình, theo nhịp của bạn.
Câu hỏi thường gặp
Version và build number trên App Store Connect khác nhau thế nào?
Version là số công khai của bản phát hành, như 1.4.0. Build number định danh một binary cụ thể gửi cho Apple cho version đó. Bạn có thể gửi nhiều build cho cùng một version, mỗi build một số riêng.
Có cần đổi số build mỗi lần gửi không?
Có, với cùng một version. Apple từ chối lần gửi thứ hai có cùng cặp version và số build, đó là lỗi ITMS-90189. Với EAS, autoIncrement lo việc này ở mỗi lần build production.
Số build có phải bắt đầu lại từ 1 ở mỗi version không?
Không bắt buộc. Trên iPhone, Apple chấp nhận số thấp hơn cho version mới, vì chỉ cặp số cần là duy nhất. Một bộ đếm luôn tăng vẫn dễ theo dõi hơn.
Làm sao đổi build number trong App Store Connect?
Bạn không thể sửa số của build đã gửi. Nhưng bạn có thể thay build gắn với version, từ phần Build của trang app, miễn là nó chưa được gửi duyệt. Muốn có số mới, hãy build lại.
Tại sao build của tôi không xuất hiện trong App Store Connect?
Thường là nó vẫn đang được xử lý hoặc đang chờ bạn khai báo mã hóa. Hãy kiểm tra cả việc version của nó khớp với version trên trang app. Nếu xử lý quá 24 giờ, Apple yêu cầu mở ticket.

