# Chứng chỉ nhà phát triển iOS: provisioning profile và Expo

> Chứng chỉ chứng minh ai ký app của bạn, provisioning profile cho biết đó là app nào và chạy trên iPhone nào. Với Expo, EAS tạo và gia hạn cả hai giúp bạn.

Trang gốc: [Chứng chỉ nhà phát triển iOS: provisioning profile và Expo](https://devoria.fr/vi/blog/ios-developer-certificate-provisioning-profile-expo)
Tác giả: [Mehdi Azizi](https://devoria.fr/vi/mehdi-azizi)
Ngày đăng: 2026-11-04
Lần sửa nội dung gần nhất: 2026-11-04


Chứng chỉ nhà phát triển iOS chứng minh ai đã ký app của bạn. Provisioning profile (hồ sơ cấp phép) liên kết chứng chỉ đó với một app cụ thể và cho biết app được phép chạy ở đâu. **Với Expo, bạn gần như không bao giờ phải tự tay tạo chúng: EAS tạo, lưu trữ và gia hạn chúng khi bạn chạy build.**

Dù vậy, hiểu từng file làm gì vẫn có ích. Ngày một bản build không chịu cài hoặc một lần gửi bị kẹt, chính kiến thức này giúp bạn tiết kiệm cả một ngày. Bài này điểm qua bốn thành phần, thời hạn của chúng, các giới hạn của Apple và những lỗi thường gặp, kèm cách xử lý cho từng lỗi.

Tôi phát hành các app iOS của mình bằng Expo và EAS, trong đó có Solys và TradaZen. Toàn bộ quy trình có trong bài [phát hành app iOS không cần Mac](https://devoria.fr/vi/blog/phat-hanh-app-ios-khong-can-mac-expo-eas). Ở đây, ta mở nắp xem bên trong phần ký app.

## Vì sao Apple bắt buộc phải ký

Một app iOS phải được ký thì mới cài được lên iPhone hoặc gửi lên App Store Connect. Chữ ký đảm bảo app đến từ một nhà phát triển mà Apple biết, và không ai sửa đổi nó kể từ đó.

Với App Store, có một chi tiết khiến bạn yên tâm. Theo [ghi chú kỹ thuật TN3161 của Apple](https://developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates), App Store kiểm tra chứng chỉ phân phối của bạn còn hợp lệ lúc gửi, rồi ký lại app, nên app không còn phụ thuộc vào ngày hết hạn của chứng chỉ nữa. **Vì vậy chứng chỉ của bạn chỉ cần hợp lệ vào lúc gửi, không phải suốt vòng đời của app.**

## Bốn thành phần cần biết

[Tài liệu của Expo về thông tin xác thực](https://docs.expo.dev/app-signing/app-credentials/) liệt kê ba thành phần cho iOS: chứng chỉ phân phối, các profile và khóa thông báo đẩy. Tôi thêm App ID, vì không có nó thì không có profile nào cả.

### Chứng chỉ phân phối

Đây là chữ ký nhà phát triển của bạn. [Trang trợ giúp của Apple về chứng chỉ](https://developer.apple.com/help/account/certificates/certificates-overview) phân biệt hai loại:

- **Apple Development** dùng để chạy app trên thiết bị của bạn trong lúc phát triển. Nó thuộc về một cá nhân.
- **Apple Distribution** dùng để phân phối đến các thiết bị thử nghiệm được chỉ định hoặc gửi lên App Store Connect. Nó thuộc về nhóm, và chỉ chủ tài khoản hoặc admin mới tạo được.

Chứng chỉ phân phối không gắn với app nào cụ thể: cùng một chứng chỉ ký tất cả app của bạn. Nó đi kèm một khóa riêng tư (private key), và chính khóa này cho phép ký. Theo TN3161, một chứng chỉ Apple thường có hiệu lực một năm kể từ khi tạo.

### App ID

App ID định danh app của bạn trong một profile. Nó dùng bundle identifier của bạn, ví dụ `com.exemple.monapp` (ví dụ giả định). Theo [trang trợ giúp của Apple](https://developer.apple.com/help/account/identifiers/register-an-app-id), nó cũng chứa danh sách các capability được phép: thông báo đẩy, App Groups, Sign in with Apple…

Với Expo, đó là trường `ios.bundleIdentifier` trong cấu hình. **Hãy chọn nó một lần cho xong**: nó phải giống hệt nhau ở mọi nơi, trong cấu hình cũng như trong App Store Connect. App ID không hết hạn. Và theo [tài liệu Expo về capability iOS](https://docs.expo.dev/build-reference/ios-capabilities/), EAS đồng bộ capability của nó với cấu hình của bạn ở mỗi lần build.

### Provisioning profile

Profile là thứ kết nối mọi thứ. Nó chứa một App ID, một chứng chỉ và, tùy loại, một danh sách thiết bị được phép. Có ba loại liên quan đến bạn:

- **Development**: app thử nghiệm trên các thiết bị bạn đã đăng ký.
- **Ad hoc**: bản build cài được trên một danh sách thiết bị cụ thể, mỗi thiết bị được định danh bằng UDID. Đây là "internal distribution" (phân phối nội bộ) của EAS.
- **App Store**: dành cho App Store Connect và TestFlight. Nó không chứa danh sách thiết bị nào, theo giải thích của [ghi chú TN3125](https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles).

Mỗi profile có ngày hết hạn: thường không quá một năm theo Apple, 12 tháng theo Expo.

### Khóa thông báo đẩy (APNs)

Khóa APNs cho phép máy chủ của bạn, hoặc của Expo, gửi thông báo đến app. Đó là một file .p8 chỉ tải về được một lần: [Apple không lưu giữ nó](https://developer.apple.com/help/account/keys/create-a-private-key) trong tài khoản của bạn. Một khóa dùng chung cho tất cả app, và [nó không bao giờ hết hạn](https://developer.apple.com/support/expiration/).

## Bảng tóm tắt

| Thành phần                 | Dùng để                | Thời hạn          | Ai quản lý khi dùng Expo |
| -------------------------- | ---------------------- | ----------------- | ------------------------ |
| Chứng chỉ phân phối        | Ký các bản build       | Thường là một năm | EAS, sau khi đăng nhập   |
| App ID                     | Định danh app          | Không hết hạn     | Bạn, rồi đến EAS         |
| Profile App Store          | Gửi lên Apple          | Tối đa 12 tháng   | EAS                      |
| Profile ad hoc             | Cài lên iPhone của bạn | Tối đa 12 tháng   | EAS và thiết bị của bạn  |
| Khóa đẩy APNs              | Gửi thông báo          | Không hết hạn     | EAS hoặc bạn             |
| Profile tài khoản miễn phí | Thử nghiệm qua Xcode   | 7 ngày            | Xcode, không phải EAS    |

"Bạn, rồi đến EAS": bạn chọn bundle identifier, EAS lo phần capability. "EAS và thiết bị của bạn": bạn đăng ký từng iPhone thử nghiệm, EAS tạo profile. Dòng cuối liên quan đến tài khoản Apple miễn phí: theo [trang trợ giúp của Apple về tài khoản](https://developer.apple.com/help/account/basics/about-your-developer-account), profile của nó hết hạn 7 ngày sau khi tạo.

## Các giới hạn của Apple cần biết

- **Chứng chỉ phân phối**: rất ít cho mỗi tài khoản. Trang trợ giúp của Apple nói chỉ một cho mỗi loại phân phối và mỗi nhóm, bảng của Expo thì nói giới hạn là 2. Hãy nhớ quy tắc: **đừng tạo chứng chỉ mới cho mỗi lần build hay trên mỗi máy tính.**
- **Khóa APNs**: tối đa 2 cho mỗi tài khoản, theo Expo.
- **Profile**: không giới hạn, theo Expo.
- **Thiết bị**: tối đa 100 cho mỗi dòng sản phẩm và mỗi năm thành viên, theo [trang trợ giúp của Apple về thiết bị](https://developer.apple.com/help/account/devices/devices-overview). Vô hiệu hóa một thiết bị không giải phóng chỗ. Bộ đếm trở về 100 vào đầu năm thành viên tiếp theo, nếu bạn gỡ các thiết bị.

## EAS làm gì cho bạn

Theo [trang của Expo về thông tin xác thực được quản lý](https://docs.expo.dev/app-signing/managed-credentials/), lần build iOS đầu tiên sẽ đề nghị tạo những gì còn thiếu. Bạn đăng nhập tài khoản Apple Developer, EAS tạo chứng chỉ phân phối, profile và khóa đẩy, rồi lưu chúng trên máy chủ của mình. Các lần build sau dùng lại chúng.

Ba điểm hữu ích:

- **Mật khẩu Apple của bạn ở lại trên máy bạn.** [Trang bảo mật của Expo](https://docs.expo.dev/app-signing/security/) nói rõ mật khẩu không được gửi lên máy chủ của họ, và thông tin xác thực được lưu đều được mã hóa.
- **`eas credentials` cho bạn xem mọi thứ**: chứng chỉ, profile, khóa đẩy. Lệnh này cũng cho phép thay thế hoặc gỡ bỏ chúng.
- **Xóa trong EAS không xóa bên Apple.** Muốn giải phóng chỗ, bạn phải thu hồi (revoke) trong cổng Apple.

Bạn cũng có thể tự kiểm soát bằng thông tin xác thực cục bộ: một file `credentials.json` trỏ đến chứng chỉ (.p12) và profile (.mobileprovision) của bạn. Expo yêu cầu thêm các file này vào `.gitignore`. Đây là cùng quy tắc với [khóa API của app Expo](https://devoria.fr/vi/blog/khoa-api-bi-mat-app-expo): bí mật không bao giờ được đưa vào repo.

## Các lỗi thường gặp và cách xử lý

### Profile hết hạn

Một bản build ad hoc mang theo profile của nó: khi profile hết hạn, app không mở được nữa trên các iPhone thử nghiệm. Ngược lại, trên App Store, Expo xác nhận việc hết hạn không ảnh hưởng gì đến app đang chạy production. **Cách xử lý: chạy lại một bản build.** EAS tạo profile mới, hoặc bạn tự làm bằng `eas credentials`. Sau đó cài lại bản build mới lên thiết bị.

Đừng nhầm với TestFlight: một bản build TestFlight hết hạn sau 90 ngày, bất kể chứng chỉ của bạn. Chi tiết có trong bài [TestFlight để thử nghiệm app iPhone](https://devoria.fr/vi/blog/testflight-kiem-thu-app-iphone).

### Chứng chỉ hết hạn hoặc bị thu hồi

Apple nói rõ: nếu tư cách thành viên của bạn còn hiệu lực, các app đã có trên App Store không bị ảnh hưởng. Tuy nhiên, bạn không thể gửi bản build nào được ký bằng chứng chỉ đó nữa. Một bản build đã gửi nhưng chưa nộp duyệt có thể bị đánh dấu Invalid Binary nếu chứng chỉ của nó bị thu hồi. Và [các profile chứa chứng chỉ bị thu hồi sẽ trở nên không hợp lệ](https://developer.apple.com/help/account/certificates/revoke-a-certificate).

**Cách xử lý: tạo chứng chỉ mới từ `eas credentials` hoặc ở lần build tiếp theo**, rồi để EAS làm lại các profile. Và đừng bao giờ thu hồi theo phản xạ một chứng chỉ đang hoạt động tốt.

### Thiết bị không có trong profile ad hoc

Link cài đặt chạy được trên máy bạn, nhưng không chạy trên iPhone của người thử nghiệm. Nguyên nhân: [tài liệu Expo về phân phối nội bộ](https://docs.expo.dev/build/internal-distribution/) giải thích rằng chỉ những thiết bị có trong profile tại thời điểm build mới cài được app.

Cách xử lý:

1. Đăng ký thiết bị bằng `eas device:create`.
2. Chạy lại build ở chế độ tương tác, đã đăng nhập tài khoản Apple, để EAS cập nhật profile. Hoặc ký lại bản build hiện có bằng `eas build:resign`, không cần biên dịch lại toàn bộ.
3. Trong CI, chế độ không tương tác dùng lại profile mà không cập nhật danh sách. Hãy thêm tùy chọn `--refresh-ad-hoc-provisioning-profile`.

Với tài khoản mới hoặc vừa gia hạn, Apple có thể mất 24 đến 72 giờ để xử lý một thiết bị mới. Vì vậy bản build đầu tiên có thiết bị đó có thể thất bại: hãy đợi, rồi chạy lại.

### Đạt giới hạn chứng chỉ

Apple từ chối tạo chứng chỉ phân phối mới. Thường là do có những chứng chỉ cũ còn sót lại: tạo từ Xcode trên một máy Mac khác hoặc bởi một dịch vụ build khác. **Hãy dùng lại chứng chỉ hiện có nếu bạn có file .p12 của nó. Nếu không, hãy thu hồi chứng chỉ không còn dùng** trong cổng Apple. Việc thu hồi không ảnh hưởng đến các app đã lên kệ, nhưng làm vô hiệu các profile chứa nó.

### "Provisioning profile doesn't include signing certificate"

Thông báo này của Xcode có nghĩa là profile không chứa chứng chỉ có khóa riêng tư nằm trên máy bạn. Nguyên nhân điển hình: trộn lẫn chế độ ký tự động của Xcode với thông tin xác thực của EAS. **Hãy chọn một nguồn duy nhất**: build EAS với thông tin xác thực được quản lý, hoặc thông tin xác thực cục bộ, nhưng không dùng cả hai.

### Thông báo bị ngắt sau khi thu hồi khóa

Nếu bạn thu hồi khóa APNs, Expo cảnh báo rằng mọi app dùng khóa đó sẽ không nhận được thông báo nữa. Hãy tạo khóa mới và gửi lên bằng `eas credentials`. Token Expo Push của người dùng không thay đổi.

### Thêm capability, profile không hợp lệ

Bật một dịch vụ như thông báo đẩy hay App Groups [làm profile trở nên không hợp lệ](https://developer.apple.com/help/account/provisioning-profiles/edit-download-or-delete-profiles): bạn phải tạo lại nó. Với EAS, việc đồng bộ capability diễn ra ở mỗi lần build. Nếu profile vẫn bị từ chối, `eas credentials` cho phép tạo profile mới.

## Sau bước ký app

Một bản build đã ký chỉ là một bước. Trang thông tin, ảnh chụp màn hình, quyền riêng tư và việc gửi duyệt được gom lại trong [phát hành ứng dụng lên App Store](https://devoria.fr/vi/expertise/dang-ung-dung-len-app-store). Nếu bạn chưa là thành viên, hãy bắt đầu với [tài khoản nhà phát triển Apple](https://devoria.fr/vi/blog/tai-khoan-apple-developer-gia). Và để hiểu vì sao tôi khuyên người mới dùng Expo, hãy đọc [React Native và Expo cho app di động](https://devoria.fr/vi/expertise/ung-dung-di-dong-react-native-expo).

## Nếu bạn đang chuẩn bị phát hành lần đầu

Trước lần gửi đầu tiên, hãy làm [bài chẩn đoán miễn phí](https://devoria.fr/vi/diagnostic): nó cho bạn biết điều gì thực sự đang cản trở dự án và gửi bạn checklist chống bị Apple từ chối của tôi.

Để xây dựng app, tích hợp gói đăng ký và phát hành mà không phải vật lộn với phần ký app, [iOS & Android Kit](https://devoria.fr/vi/kits/ios) đi theo lộ trình bốn bước với Starter Code từ các app của tôi, theo tốc độ của bạn.

## Câu hỏi thường gặp

### Provisioning profile là gì?

Đó là file cho phép app của bạn chạy hoặc được gửi lên Apple. Nó liên kết một App ID, một chứng chỉ và, tùy loại, một danh sách thiết bị. Profile App Store không chứa thiết bị nào, profile ad hoc thì liệt kê một vài thiết bị.

### Chứng chỉ nhà phát triển iOS có miễn phí không?

Nó không có giá riêng: chứng chỉ phân phối đã bao gồm trong Apple Developer Program, giá 99 $ mỗi năm. Với tài khoản Apple miễn phí, Xcode cho phép bạn thử nghiệm trên tối đa 3 thiết bị, nhưng profile hết hạn sau 7 ngày và không thể phát hành.

### Chứng chỉ phân phối Apple có hiệu lực bao lâu?

Thường là một năm kể từ khi tạo, theo Apple. Provisioning profile cũng có hiệu lực tối đa 12 tháng. Còn khóa thông báo đẩy thì không bao giờ hết hạn.

### Điều gì xảy ra nếu chứng chỉ phân phối của tôi hết hạn?

Không có gì xảy ra với các app đã có trên App Store, miễn là tư cách thành viên của bạn còn hiệu lực. Bạn chỉ không thể gửi bản build mới được ký bằng chứng chỉ đó nữa. Với EAS, chứng chỉ mới được tạo ở lần build tiếp theo hoặc bằng `eas credentials`.

### Có cần máy Mac để tạo chứng chỉ iOS không?

Không, nếu bạn dùng EAS. Bạn đăng nhập tài khoản Apple từ dòng lệnh, và EAS tạo chứng chỉ cùng profile, trên Windows cũng như Linux. Không dùng EAS thì cách truyền thống là qua Xcode hoặc Keychain Access trên Mac.

### Một profile ad hoc chứa được bao nhiêu thiết bị?

Tài khoản của bạn có thể đăng ký tối đa 100 iPhone mỗi năm thành viên, và cũng ngần ấy cho mỗi dòng thiết bị khác. Thiết bị đã vô hiệu hóa vẫn được tính. Để thử nghiệm với nhiều người hơn, hãy dùng TestFlight.


## Dự án của bạn

[Review Kit](https://devoria.fr/vi/kits/app-review): Checklist duyệt App Store của mình, các lần Apple từ chối đã sửa, checklist Google Play và ba skill Claude Code. 1.399.000 ₫.

[iOS & Android Kit](https://devoria.fr/vi/kits/ios): Tạo app iPhone và Android với Claude Code: code khởi đầu từ các app của mình, lộ trình đến tận store và tất cả các kit. 2.799.000 ₫.

[Chẩn đoán: điều gì ngăn bạn có app iPhone](https://devoria.fr/vi/diagnostic): 7 câu hỏi, 60 giây: bạn biết điều gì thật sự cản bạn đăng app iPhone, lộ trình 4 bước và kit phù hợp với bạn.
