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
Các nhà mạng có thể tạo ứng dụng nhà mạng bằng EuiccManager để quản lý hồ sơ, như minh hoạ 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ụng LPA (LUI và phần phụ trợ LPA) cần 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 OEM
Ngoài logic gọi EuiccCardManager
và giao tiếp với eUICC, các ứng dụng LPA phải triển khai những nội dung sau:
- Ứng dụng 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 để có 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ý các khe cắm, bao gồm cả việc chuyển đổi giữa logic eSIM và pSIM. Đây là thông tin không bắt buộc nếu điện thoại chỉ có một chip eSIM.
- OTA eSIM
Mặc dù có thể có nhiều ứng dụng LPA trên điện thoại Android, 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 mỗi ứ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ể nhận thực thể EuiccManager
và gọi các phương thức trong EuiccManager
để nhận thông tin eUICC và quản lý các gói thuê bao (được gọi là hồ sơ trong tài liệu RSP của GSMA) dưới dạng các 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 cần thiết. Nhà mạng di động sẽ thêm các đặc quyền của nhà mạng 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 cho phù hợp.
Nền tảng Android không xử lý các quy tắc chính sách 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 của OEM bên thứ ba có thể xử lý các quy tắc chính sách bằng mã lỗi đặc biệt (mã lỗi được truyền từ LPA của OEM đến nền tảng, sau đó nền tảng truyền mã đến LUI của 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
.
Nhận 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 (công khai)
Kiểm tra xem gói thuê bao nhúng có được bật hay không. 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;
}
Nhận EID (công khai)
Lấy EID xác định phần cứng eUICC. Giá trị này có thể là giá trị rỗng nếu eUICC chưa sẵn sàng. Người 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.
}
Nhận EuiccInfo (công khai)
Lấy thông tin về eUICC. Thông tin 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 nội dung từ kênh đã đăng ký 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 RSP của GSMA). Bạn có thể tạo gói thuê bao bằng 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. Tải nội dung của một kênh mà bạn đăng ký là một thao tác không đồng bộ.
Người 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 mục tiêu. Để 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. Người 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 hiện đ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 có chuyển số điện thoại (công khai)
(Có từ Android 13) Chuyển sang (bật) gói thuê bao đã cho bằng chỉ mục cổng được chỉ định.
Người 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 hiện đ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 (công khai) không
public boolean isSimPortAvailable(int portIndex)
(Có từ Android 13) Trả về việc chỉ mục cổng truyền có sẵn hay không. Một cổng sẽ có sẵn nếu cổng đó không 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 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 bằng mã nhận dạng gói thuê bao. Nếu gói thuê bao hiện đang hoạt động, thì trước tiên, gói thuê bao đó sẽ bị vô hiệu hoá. Người 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ả các gói thuê bao (API hệ thống)
Xoá tất cả cá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 loại thuê bao thử nghiệm, hoạt động hay cả hai loại 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 cho một lỗi cụ thể.
...
mgr.startResolutionActivity(getActivity(), 0 /* requestCode */, resultIntent, callbackIntent);
Hằng số
Để xem danh sách hằng số public
trong EuiccManager
, hãy xem phần Hằng số.