Trong Android 9, các API quản lý hồ sơ (công khai và @SystemApi) có sẵn thông qua lớp EuiccManager
. Các API giao tiếp eUICC (chỉ @SystemApi) có sẵn thông qua lớp EuiccCardManager
.
Giới thiệu về eUICC
Nhà mạng có thể tạo ứng dụng của nhà mạng bằng EuiccManager để quản lý hồ sơ, như trong Hình 1. Ứng dụng của nhà mạng không cần phải là ứng dụng hệ thống nhưng cần có các đặc quyền của nhà mạng do hồ sơ eUICC cấp. Ứng dụngLPA (LUI và phần phụ trợ LPA) phải là một ứng dụng hệ thống (tức là có trong hình ảnh hệ thống) để gọi @SystemApi.
Hình 1. Điện thoại Android có ứng dụng của nhà mạng và LPA của nhà sản xuất thiết bị gốc
Ngoài logic gọi EuiccCardManager
và giao tiếp với eUICC, ứng dụng LPA phải triển khai những nội dung sau:
- Máy khách SM-DP+ giao tiếp với máy chủ SM-DP+ để xác thực và tải hồ sơ xuống
- [Không bắt buộc] SM-DS để nhận thêm các hồ sơ tiềm năng có thể tải xuống
- Xử lý thông báo để gửi thông báo đến máy chủ nhằm cập nhật trạng thái hồ sơ
- [Không bắt buộc] Quản lý khe, bao gồm cả việc chuyển đổi giữa logic eSIM và pSIM. Bạn không bắt buộc phải làm việc này nếu điện thoại chỉ có một khối eSIM.
- eSIM OTA
Mặc dù điện thoại Android có thể có nhiều ứng dụng LPA, nhưng chỉ có thể chọn một LPA làm LPA hoạt động thực tế dựa trên mức độ ưu tiên được xác định trong tệp AndroidManifest.xml
của từng ứng dụng.
Sử dụng EuiccManager
Các API LPA là công khai thông qua EuiccManager
(trong gói android.telephony.euicc
). Ứng dụng của nhà mạng có thể lấy thực thể của EuiccManager
và gọi các phương thức trong EuiccManager
để lấy thông tin eUICC và quản lý gói thuê bao (được gọi là hồ sơ trong tài liệu GSMA RSP) dưới dạng thực thể SubscriptionInfo.
Để gọi các API công khai, bao gồm cả các thao tác tải xuống, chuyển đổi và xoá gói thuê bao, ứng dụng của nhà mạng phải có các đặc quyền bắt buộc. Các đặc quyền của nhà mạng di động được nhà mạng thêm vào siêu dữ liệu hồ sơ. API eUICC sẽ thực thi các quy tắc về đặc quyền của nhà mạng theo đó.
Nền tảng Android không xử lý các quy tắc chính sách về hồ sơ. Nếu một quy tắc chính sách được khai báo trong siêu dữ liệu hồ sơ, thì LPA có thể chọn cách xử lý quy trình tải xuống và cài đặt hồ sơ. Ví dụ: LPA OEM của bên thứ ba có thể xử lý các quy tắc chính sách bằng cách sử dụng mã lỗi đặc biệt (mã lỗi được chuyển từ LPA OEM đến nền tảng, sau đó nền tảng sẽ chuyển mã đó đến LUI OEM).
Để biết thông tin về nhiều API hồ sơ đã bật, hãy xem phần Nhiều hồ sơ đã bật.
API
Bạn có thể tìm thấy các API sau trong tài liệu tham khảo EuiccManager
và EuiccManager.java
.
Lấy thực thể (công khai)
Lấy thực thể của EuiccManager
thông qua Context#getSystemService
.
Để biết thông tin chi tiết, hãy xem getSystemService
.
EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
Đã bật tính năng kiểm tra (công khai)
Kiểm tra xem bạn đã bật gói thuê bao được nhúng hay chưa. Bạn nên kiểm tra điều này trước khi truy cập vào các API LPA. Để biết thông tin chi tiết, hãy xem isEnabled
.
boolean isEnabled = mgr.isEnabled();
if (!isEnabled) {
return;
}
Lấy EID (công khai)
Lấy EID (mã định danh dành cho eSIM) để xác định phần cứng eUICC. Giá trị này có thể là rỗng nếu eUICC chưa sẵn sàng. Phương thức gọi phải có đặc quyền của nhà mạng hoặc quyền READ_PRIVILEGED_PHONE_STATE
. Để biết thông tin chi tiết, hãy xem getEid
.
String eid = mgr.getEid();
if (eid == null) {
// Handle null case.
}
Lấy EuiccInfo (công khai)
Nhận thông tin về eUICC. Tệp này chứa phiên bản hệ điều hành. Để biết thông tin chi tiết, hãy xem getEuiccInfo
.
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
Tải gói thuê bao xuống (công khai)
Tải gói thuê bao đã cho xuống (được gọi là "hồ sơ" trong tài liệu GSMA RSP). Bạn có thể tạo gói thuê bao từ một mã kích hoạt. Ví dụ: bạn có thể phân tích cú pháp mã kích hoạt từ mã QR. Việc tải gói thuê bao xuống là một thao tác không đồng bộ.
Phương thức gọi phải có quyền WRITE_EMBEDDED_SUBSCRIPTIONS
hoặc có đặc quyền của nhà mạng đối với gói thuê bao đích. Để biết thông tin chi tiết, hãy xem downloadSubscription
.
// Register receiver.
String action = "download_subscription";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
resultIntent = intent;
}
};
context.registerReceiver(
receiver,
new IntentFilter(action),
"example.broadcast.permission" /* broadcastPermission*/, null /* handler */);
// Download subscription asynchronously.
DownloadableSubscription sub =
DownloadableSubscription.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.downloadSubscription(sub, true /* switchAfterDownload */, callbackIntent);
Chuyển đổi gói thuê bao (công khai)
Chuyển sang (bật) gói thuê bao đã cho. Phương thức gọi phải có WRITE_EMBEDDED_SUBSCRIPTIONS
hoặc có đặc quyền của nhà mạng đối với gói thuê bao đang bật và gói thuê bao mục tiêu. Để biết thông tin chi tiết, hãy xem switchToSubscription
.
// Register receiver.
String action = "switch_to_subscription";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0 /* defaultValue*/);
resultIntent = intent;
}
};
context.registerReceiver(receiver, new IntentFilter(action),
"example.broadcast.permission" /* broadcastPermission*/, null /* handler */);
// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);
Chuyển đổi gói thuê bao bằng cổng (công khai)
(Có trên Android 13) Chuyển sang (bật) gói thuê bao nhất định có chỉ mục cổng đã chỉ định.
Phương thức gọi phải có WRITE_EMBEDDED_SUBSCRIPTIONS
hoặc có đặc quyền của nhà mạng đối với gói thuê bao đang bật và gói thuê bao mục tiêu.
Để biết thông tin chi tiết, hãy xem switchToSubscription
.
// Register receiver.
String action = "switch_to_subscription";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0 /* defaultValue*/);
resultIntent = intent;
}
};
context.registerReceiver(receiver, new IntentFilter(action),
"example.broadcast.permission" /* broadcastPermission*/, null /* handler */);
// Switch to a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, 0 /*portIndex*/, callbackIntent);
Có cổng SIM không (công khai)
public boolean isSimPortAvailable(int portIndex)
(Có trong Android 13) Trả về liệu có chỉ mục cổng truyền hay không. Một cổng sẽ có sẵn nếu cổng đó chưa bật gói thuê bao hoặc ứng dụng gọi có đặc quyền của nhà mạng đối với gói thuê bao đã cài đặt trên cổng đã chọn. Để biết thông tin chi tiết, hãy xem isSimPortAvailable
.
Xoá gói thuê bao (công khai)
Xoá một gói thuê bao có mã nhận dạng gói thuê bao. Nếu gói thuê bao hiện đang hoạt động, trước tiên, gói thuê bao đó sẽ bị vô hiệu hoá. Phương thức gọi phải có WRITE_EMBEDDED_SUBSCRIPTIONS
hoặc đặc quyền của nhà mạng đối với gói thuê bao mục tiêu. Để biết thông tin chi tiết, hãy xem deleteSubscription
.
// Register receiver.
String action = "delete_subscription";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
resultIntent = intent;
}
};
context.registerReceiver(receiver, new IntentFilter(action),
"example.broadcast.permission" /* broadcastPermission*/,
null /* handler */);
// Delete a subscription asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.deleteSubscription(1 /* subscriptionId */, callbackIntent);
Xoá tất cả gói thuê bao (API hệ thống)
Xoá tất cả gói thuê bao trên một thiết bị. Kể từ Android 11, bạn nên cung cấp giá trị enum EuiccCardManager#ResetOption
để chỉ định xem có xoá tất cả các gói thuê bao kiểm thử, hoạt động hay cả hai loại gói thuê bao hay không. Phương thức gọi phải có quyền WRITE_EMBEDDED_SUBSCRIPTIONS
.
// Register receiver.
String action = "delete_subscription";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
resultIntent = intent;
}
};
context.registerReceiver(receiver, new IntentFilter(action),
"example.broadcast.permission" /* broadcastPermission*/,
null /* handler */);
// Erase all operational subscriptions asynchronously.
Intent intent = new Intent(action);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mgr.eraseSubscriptions(
EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES, callbackIntent);
Bắt đầu hoạt động phân giải (công khai)
Bắt đầu một hoạt động để giải quyết lỗi mà người dùng có thể giải quyết. Nếu một thao tác trả về EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
, bạn có thể gọi phương thức này để nhắc người dùng giải quyết vấn đề. Bạn chỉ có thể gọi phương thức này một lần đối với một lỗi cụ thể.
...
mgr.startResolutionActivity(getActivity(), 0 /* requestCode */, resultIntent, callbackIntent);
Hằng số
Để xem danh sách các hằng số public
trong EuiccManager
, hãy xem phần Hằng số.