运营商配置

Android 6.0 及更高版本包含一项功能,允许特许应用向平台提供运营商特定的配置。此功能基于 Android 5.1 (Lollipop MR1) 中引入的 UICC 运营商权限,允许将运营商配置从静态配置叠加层中移出,并使运营商和 OEM 能够通过定义的接口动态地向平台提供运营商配置。

经过正确签名的运营商应用可以预加载到系统映像中、自动安装或通过应用商店手动安装。平台会查询该应用,以提供以下设置的配置:

  • 漫游/非漫游网络
  • 可视语音邮件
  • 短信/彩信网络设置
  • VoLTE/IMS 配置

返回哪些值的决定完全取决于运营商应用,并且可以根据通过平台传递到应用的详细信息动态确定。

此方法的主要优势在于:

  • 动态配置 - 支持非 MCCMNC 派生配置等概念,例如移动虚拟网络运营商 (MVNO) 或客户选择加入额外服务。
  • 支持通过任何渠道销售的设备 - 例如,可以通过从应用商店下载应用来自动为开放市场手机配置正确的设置。
  • 安全性 - 提供此配置的权限仅授予由运营商签名的应用。
  • 定义的 API - 以前,此配置主要存储在框架内的内部 XML 叠加层中,而不是通过公共 API。Android 6.0 中的运营商配置 API 是公开且定义明确的。

工作原理

加载配置

此功能提供的运营商配置是一组键值对,用于更改平台中各种与电话相关的行为。

特定设备的这组值通过按顺序查询以下组件来确定

  1. 运营商应用(这是可选的,但它是推荐的附加配置位置,用于补充 Android 开源项目 (AOSP) 中已有的配置)
  2. 与系统映像捆绑在一起的平台配置应用
  3. 默认值,硬编码到框架中(等同于 Android 6.0 之前的行为)

平台配置应用

通用平台配置应用与系统映像捆绑在一起。此应用可以为常规运营商应用未提供的任何变量提供值。平台配置应用可以在以下位置找到(在 Android 6.0 中):packages/apps/CarrierConfig

此应用的目的是在未安装运营商应用时提供一些按网络配置,运营商/OEM 应仅对其自身映像进行最少的更改。相反,运营商应提供单独的运营商应用以进行运营商自定义,从而允许通过应用商店等渠道分发更新。

如何向运营商应用授予权限

有问题的运营商应用必须使用 SIM 卡上找到的相同证书进行签名,如 UICC 运营商权限 中所述。

传递给运营商应用的信息

运营商应用会收到以下值,使其能够动态决定要返回哪些值

  • MCC
  • MNC
  • SPN
  • IMSI
  • GID1
  • GID2
  • 运营商 ID

有关集成运营商 ID 的更多信息,请参阅 将运营商 ID 与 CarrierConfig 集成

何时加载运营商配置

键值对列表的构建发生在

  • SIM 卡加载时(启动或 SIM 卡热插拔)
  • 运营商应用手动触发重新加载时
  • 运营商应用更新时

有关更多详细信息,请参阅 android.service.carrier.CarrierService#onLoadConfig() 参考。

使用配置

构建配置后,其中包含的值将用于设置系统配置的各种值,包括

  • 内部框架电话设置
  • SDK 返回的配置值,例如,在 SmsManager 中
  • 应用设置,例如,拨号器中的 VVM 连接值

配置键

键列表在公共 SDK 中定义为 android.telephony.CarrierConfigManager 的一部分,并且在同一 API 级别内无法更改。有关键的摘要,请参见下表。

构建应用

创建应用

您的应用必须以 Android 6.0 API 级别 (23) 为目标。

声明一个类,该类覆盖 android.service.carrier.CarrierService

  1. 覆盖 onLoadConfig 以返回您希望根据传递的 service.carrier.CarrierIdentifier 对象提供的值。
  2. 添加逻辑以在运营商配置可能随时间变化的情况下(例如,当用户向其帐户添加额外服务时)调用 notifyConfigChangedForSubId

下面是一个示例

public class SampleCarrierConfigService extends CarrierService {

    private static final String TAG = "SampleCarrierConfigService";

    public SampleCarrierConfigService() {
        Log.d(TAG, "Service created");
    }

    @Override
    public PersistableBundle onLoadConfig(CarrierIdentifier id) {
        Log.d(TAG, "Config being fetched");
        PersistableBundle config = new PersistableBundle();
        config.putBoolean(
            CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL, true);
        config.putBoolean(
            CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, false);
        config.putInt(CarrierConfigManager.KEY_VOLTE_REPLACEMENT_RAT_INT, 6);
        // Check CarrierIdentifier and add more config if needed
        return config;
    }
}

有关更多详细信息,请参阅 android.service.carrier.CarrierService 参考。

在清单中命名类

下面是一个示例

<service android:name=".SampleCarrierConfigService"
android:label="@string/service_name"
android:permission="android.permission.BIND_CARRIER_SERVICES">
      <intent-filter>
      <action android:name="android.service.carrier.CarrierService"/></intent-filter>
</service>

使用 SIM 卡上的相同证书对应用进行签名

有关要求,请参阅 UICC 运营商权限

使用运营商应用添加 APN

要从运营商应用以编程方式添加 APN(例如,在 SIM 卡激活期间),请使用 ContentResolver API 将 APN 项添加到由 URI android.provider.Telephony.Carriers.CONTENT_URI 标识的内容提供程序。有关内容 URI 的表结构的更多信息,请参阅 Telephony.Carriers

有关更多信息,请参阅 APN 和 CarrierConfig

测试应用

构建配置应用后,您可以使用以下方法测试您的代码:

  • 包含有效证书签名的 SIM 卡
  • 运行 Android 6.0 及更高版本的设备,例如 Android 设备

设置运营商服务能力

在 Android 中,运营商服务能力描述了设备是否支持语音、消息和数据服务。运营商可以在设备级别和订阅级别(Android 15 或更高版本)指定设备运营商服务能力。

设备级别服务能力

设备级别服务能力在设备制造时配置(制造后无法更改)。运营商可以通过以下系统资源覆盖来指定设备级别能力:

应用可以通过以下 API 查询设备级别服务能力:

订阅级别服务能力

对于运行 Android 15 或更高版本的设备,运营商可以指定设备在订阅级别的服务能力。要指定订阅级别服务能力,请使用 CarrierConfigManager.KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY API。例如,要指定订阅仅限数据,请将值设置为 SubscriptionManager#SERVICE_CAPABILITY_DATA

应用(预加载的系统应用和第三方应用)可以通过 SubscriptionInfo.getServiceCapabilities() 方法查询指定订阅的运营商服务能力。这使应用开发者可以根据订阅的可用能力自定义应用的用户体验。例如,如果用户使用的是仅限数据的订阅,则应用开发者可以确保拨号器应用不允许拨打电话。

已弃用的服务能力 API

从 Android 15 开始,Android 同时提供设备级别和订阅级别服务能力。由于此更改,现有的设备级别能力 API 已重命名以提高可读性。下表列出了已弃用的 API 和 Android 15 中引入的重命名 API

已弃用(Android 14 或更低版本) 等效项(Android 15 或更高版本)
TelephonyManager.isVoiceCapable() TelephonyManager.isDeviceVoiceCapable()
TelephonyManager.isSmsCapable() TelephonyManager.isDeviceSmsCapable()