运营商配置

Android 6.0 及更高版本为特权应用推出了一项功能,可以为相应平台提供运营商专属配置。此功能是以 Android 5.1 (Lollipop MR1) 中推出的 UICC 运营商权限为基础,使运营商配置得以弃用静态配置叠加层,并使运营商和原始设备制造商 (OEM) 能够通过指定接口向相应平台动态提供运营商配置。

经过正确签名的运营商应用可以预先加载到系统映像中,也可以自动安装,或者通过应用商店手动安装。平台会询问应用并提供以下配置信息以便于设置应用:

  • 漫游/非漫游网络
  • 可视语音信箱
  • 短信/彩信网络设置
  • VoLTE/即时通讯配置

返回值的选择完全取决于运营商应用,并且可以根据通过平台传递给应用的详细信息做出动态抉择。

这种方法的主要优点包括:

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

工作原理

加载配置

此功能提供的运营商配置是一组可以改变平台中各种电话相关行为的键值对。

适用于特定设备的那组值是通过依序查询以下组件来确定:

  1. 运营商应用(虽然这不是必需的,但对于 Android 开源项目 (AOSP) 之外的其他配置来说,建议进行征询)
  2. 与系统映像捆绑在一起的平台配置应用
  3. 硬编码到框架中(相当于 Android 6.0 之前的行为)的默认值

平台配置应用

通用的平台配置应用会与系统映像捆绑在一起。此应用能够提供常规运营商应用不会提供的变量的值。平台配置应用可在 packages/apps/CarrierConfig(Android 6.0 中)找到。

此应用的目的是在未安装运营商应用的情况下提供一些基于运营商网络的配置,运营商/OEM 应在他们自己的映像中仅对配置进行很小的改动。不过,运营商应该提供单独的运营商应用以实现运营商定制,从而使更新可以通过诸如应用商店之类的渠道分发给用户。

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

根据 UICC 运营商授权中的记录,相关的运营商应用必须使用在 SIM 卡上发现的同一证书进行签名。

向运营商应用传递的信息

对运营商应用提供以下值,以使运营商应用能够对要返回的值做出动态抉择:

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

如需详细了解如何集成运营商 ID,请参阅将运营商 ID 与 CarrierConfig 集成

在加载运营商配置时发生

在以下情况下,将构建键值对列表:

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

如需了解详情,请参阅 android.service.carrier.CarrierService#onLoadConfig() 参考文档。

使用配置

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

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

配置密钥

密钥列表在 android.telephony.CarrierConfigManager 内的公共 SDK 中进行定义,且不能在相同的 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.ConfigService"/></intent-filter>
    </service>
    

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

如需了解签名要求,请参阅 UICC 运营商权限

测试应用

构建配置应用后,您可以使用以下工具来测试代码:

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