Skip to main content

Shiply Android 远程配置 SDK 集成

一、接入SDK

1. 在项目根目录下的 build.gradle 中配置 Maven 仓库

allprojects {
repositories {
maven { url "https://maven.cnb.cool/tencent-tds/shiply-public/-/packages/" }
}
}

2. 在主 module 的 build.gradle 中添加运行时 SDK

dependencies {
implementation 'com.tencent.shiply:rdelivery:1.3.35-RC02'
}

3. 初始化 SDK,建议在 Application.onCreate 方法中初始化


String hostAppId = "testAppId"; // shiply 产品 appid
String hostAppKey = "testAppKey"; // shiply 产品 appkey
String hostPacketName = "com.tencent.shiply.demo"; // 宿主的 app 包名
String hostAppVersion = "1.0.0"; // 宿主的 app 版本
String userId = "123321"; // 用户id
boolean is64BitCpu = false; // 当前手机是否是64位cpu
boolean isDebugPackage = false; // 宿主是否是debug包

/**
* 本地配置开关更新策略
*
* 固定间隔拉取策略会计算APP在后台的时长。
* APP从后台切换到前台时,如果APP在后台的时长超过拉取时间间隔,直接触发拉取;
* 如果还没到时间间隔,按照剩余的时间间隔发起定时.
* 为了节省请求量,建议业务方只设置 START_UP 和 PERIODIC 两种策略,更新时间间隔建议大于1小时。
*/
int strategy = RDeliverySetting.UpdateStrategy.START_UP.getValue() // sdk 启动时拉取全量配置
| RDeliverySetting.UpdateStrategy.PERIODIC.getValue() // 按照固定时间间隔,周期拉取全量配置
| RDeliverySetting.UpdateStrategy.HOT_RELOAD.getValue() // app 切换后台超过30秒,再切回前台时拉取全量配置
| RDeliverySetting.UpdateStrategy.NETWORK_RECONNECT.getValue(); // 断网重连时拉取全量配置

int updateInterval = 60 * 60 * 3;
RDeliverySetting setting = new RDeliverySetting.Builder()
.setAppId(hostAppId)
.setAppKey(hostAppKey)
.setUserId(userId)
.setIsDebugPackage(isDebugPackage)
.setUpdateStrategy(strategy)
.setUpdateInterval(updateInterval)
.setBundleId(hostPacketName)
.setHostAppVersion(hostAppVersion)
.setDevModel(Build.MODEL)
.setDevManufacturer(Build.MANUFACTURER)
.setAndroidSystemVersion(String.valueOf(Build.VERSION.SDK_INT))
.setIs64BitCpu(is64BitCpu)
.setEnableDetailLog(true) // 是否要打印详细日志,为了方便排查问题,建议开启,当对配置保密性要求高时可以关闭
.build();
// 创建可以依赖注入的对象,如:网络请求、数据存储、任务调度、日志接出
DependencyInjector injector = new DependencyInjector(
new HttpsURLConnectionNetwork(this), // 网络接口的默认实现
new MmkvStorageFactory(), // 存储接口的默认实现
new HandlerTask(), // 任务调度接口的默认实现
new SystemLog() // 日志接口的默认实现,建议对接到业务方自己的日志接口,可以继承AbsLog类来快速实现
);

// 创建配置开关实例
RDelivery rDelivery = RDelivery.create(this, setting, injector, null);

二、 使用SDK

1. 通过 RDelivery 实例获取配置开关内容

String configSwitchName = "testName"; //配置开关名称

String defaultConfigValue = "";
String configValue = rDelivery.getStringByKey(configSwitchName, defaultConfigValue, true);//获取配置值

boolean defaultSwitchValue = false;
boolean switchValue = rDelivery.isOnByKey(configSwitchName, defaultSwitchValue, true);//获取开关值

RDeliveryData defaultConfigSwitchData = null;
RDeliveryData configSwitchData = rDelivery.getRDeliveryDataByKey(configSwitchName, defaultConfigSwitchData, true);//从内存缓存获取配置开关数据

RDeliveryData configSwitchData2=rDelivery.getRDeliveryDataByKeyFromDisc(configSwitchName);//直接从磁盘读取配置开关数据
Map<String, RDeliveryData> resultList=rDelivery.getAllRDeliveryData();
  • 通过 rDelivery.getStringByKey 获取配置值,当远端不存在这个配置开关 key 时,会返回 defaultConfigValue; readDiskWhenDataNotInited 参数为 true 时,如果本地内存数据未初始化好,会直接从磁盘读取数据;

  • 通过 rDelivery.isOnByKey 获取开关值,当远端不存在这个配置开关 key 或者前端页面这个配置开关 key 的开关值为「未设置」时,会返回 defaultSwitchValue; readDiskWhenDataNotInited 参数为 true 时,如果本地内存数据未初始化好,会直接从磁盘读取数据;

  • 通过 rDelivery.getRDeliveryDataByKey 从内存获取配置开关数据,RDeliveryData 中包含了同一个配置开关 key 的配置值和开关值,当远端不存在这个配置开关 key 时,会返回 defaultConfigSwitchData; readDiskWhenDataNotInited 参数为 true 时,如果本地内存数据未初始化好,会直接从磁盘读取数据;

  • 通过 rDelivery.getRDeliveryDataByKeyFromDisc 直接从磁盘读取配置开关数据;创建RDelivery实例时会异步将磁盘数据加载到内存,配置开关数量越多,这个异步加载耗时也会越大,这个过程中业务如果查询开关配置只会获取到默认值,为了解决这个问题,提供了这个直接从磁盘读取配置开关的接口;这个接口涉及到I/O,需要慎重使用,只推荐在APP启动时就需要读取配置开关的场景才使用;

  • 通过 rDelivery.getAllRDeliveryData 获取所有的配置开关数据;

2. 手动拉取 RDelivery 远程配置开关

FullReqResultListener fullReqResultListener = new FullReqResultListener() {
@Override
public void onSuccess() {}
@Override
public void onFail(@NotNull String reason) {}
};
rDelivery.requestFullRemoteData(fullReqResultListener);//请求全量配置

long sceneId = 123;
BatchReqResultListener batchReqResultListener = new BatchReqResultListener() {
@Override
public void onSuccess(@NotNull List<RDeliveryData> datas) {}
@Override
public void onFail(@NotNull String reason) {}
};
rDelivery.requestBatchRemoteDataByScene(sceneId, batchReqResultListener);//请求一组配置

String configSwitchKey = "testKey";
SingleReqResultListener singleReqResultListener = new SingleReqResultListener() {
@Override
public void onSuccess(@Nullable RDeliveryData data) {}
@Override
public void onFail(@NotNull String reason) {}
};
rDelivery.requestSingleRemoteDataByKey(configSwitchName, singleReqResultListener);//请求单个配置

List<String> keyList = new ArrayList<String>();
keyList.add("key1");
keyList.add("key2");
MultiKeysReqResultListener multiKeysReqResultListener = new MultiKeysReqResultListener() {
@Override
public void onSuccess(List<RDeliveryData> datas) {}
@Override
public void onFail(@NotNull String reason) {}
};
rDelivery.requestMultiRemoteData(keyList, multiKeysReqResultListener);

DataChangeListener dataChangeListener = new DataChangeListener() {
@Override
public void onDataChange(@NotNull String key,@Nullable RDeliveryData oldData, @Nullable RDeliveryData newData){}
};
rDelivery.addDataChangeListener(dataChangeListener);//监听数据变化

SingleDataChangeListener singleDataChangeListener=new SingleDataChangeListener(){
@Override
public void onDataChange(@Nullable RDeliveryData oldData,@Nullable RDeliveryData newData){}
};
rDelivery.addDataChangeListenerByKey("cfg",singleDataChangeListener);
rDelivery.setFullReqResultListener(new FullReqResultListener(){
@Override
public void onSuccess(){}
@Override
public void onFail(@NonNull String reason){}
});
  • 通过 rDelivery.requestFullRemoteData 请求全量配置;

  • 通过 rDelivery.requestBatchRemoteDataByScene 请求一组配置,sceneId 是前端页面中创建的场景的 id,绑定了这个场景的所有配置开关任务都会返回;

  • 通过 rDelivery.requestSingleRemoteDataByKey 请求单个配置, configSwitchName 是配置开关的名称;

  • 通过 rDelivery.requestMultiRemoteData 请求多个配置, keyList 是配置开关的名称列表;

  • 通过 rDelivery.addDataChangeListener 监听配置开关数据的变化,当数据有更新时会回调 dataChangeListener#onDataChange 接口;

  • 通过 rDelivery.addDataChangeListenerByKey 监听单个配置开关数据的变化,当"cfg" 配置数据有更新时会回调 singleDataChangeListener#onDataChange 接口;

  • 通过 rDelivery.setFullReqResultListener 监听 SDK 全量配置拉取请求的回包结果;

三、注意事项与常见问题

systemId 说明

Android RDelivery 通过 RDeliverySetting.Builder.setSystemId(String) 支持 systemId。默认值为 "10001"(Config 子系统)。当 RDelivery 实例需要与 ResHub 共享时,必须设置 setSystemId("10010")。更多 systemId 说明见 通用概念

注意事项

  1. 磁盘直读仅启动用getRDeliveryDataByKeyFromDisc 涉及 I/O,运行期用内存接口(getRDeliveryDataByKey)。
  2. readDiskWhenDataNotInited:true 时内存未初始化好会直读磁盘,仅启动场景需要。
  3. 定时策略后台计时PERIODIC/HOT_RELOAD 会计算 APP 在后台时长,后台超间隔切前台直接触发。
  4. 建议策略:只设 START_UP + PERIODIC,间隔大于 1 小时。
  5. 隐私信息注入devModel/devManufacturer/系统版本需业务提供。

RDeliverySetting.Builder 关键参数

参数类型必填说明
appId / appKeyString应用凭证
bundleIdString包名
userIdString用户 ID(默认 "")
qimeiString?设备 Qimei
logicEnvironmentString?逻辑环境 ID
updateStrategyInt?更新策略位运算
updateIntervalInt定时间隔秒,默认 14400(4h)
hostAppVersionString宿主版本
devModel / devManufacturerString型号/厂商(需注入)
isDebugPackageBooleandebug 包
enableDetailLogBoolean详细日志,默认 true
systemIdString?子系统 ID:默认 "10001",ResHub 共享用 "10010",TAB 模式 "10013"

UpdateStrategy 枚举

枚举说明
START_UP启动时更新
PERIODIC定时更新
HOT_RELOAD后台超 30 秒切前台触发
NETWORK_RECONNECT网络恢复触发

依赖注入

DependencyInjector(4 个必填注入项):

参数接口默认实现
netInterfaceIRNetworkHttpsURLConnectionNetwork
storageFactoryIRStorage.IRStorageFactoryMmkvStorageFactory
taskInterfaceIRTaskHandlerTask
logInterfaceIRLogSystemLog

监听器接口

interface DataChangeListener {
fun onDataChange(key: String, oldData: RDeliveryData?, newData: RDeliveryData?)
}
interface SingleDataChangeListener {
fun onDataChange(oldData: RDeliveryData?, newData: RDeliveryData?)
}
interface UserEventListener {
fun onQueryLocalData(key: String, data: RDeliveryData)
}
interface LocalDataInitListener {
fun onInitFinish()
}

移除监听

rDelivery.removeDataChangeListener(listener)       // 按对象引用移除
rDelivery.removeSingleDataChangeListener(key) // 按 key 移除(注意:入参是 key,不是 listener ref)
rDelivery.removeUserEventListener(listener) // 移除 UserEventListener
rDelivery.setFullReqResultListener(null) // setFullReqResultListener 无 remove 方法,传 null 清除

线程说明

RDelivery 没有任何 @MainThread/@WorkerThread 注解,也未暴露回调主线程配置。不能假设 listener 回调或请求回调运行在任何特定线程。

监听器注意事项

  • addSingleDataChangeListenerByKey 对应 removeSingleDataChangeListener(key)——命名不对称:add 用 ByKey(key, listener),remove 用 (key)
  • setFullReqResultListener(listener) 没有对应的 remove 方法——传 null 清除。
  • addDataChangeListener/removeDataChangeListener 支持多个监听器同时注册。

切换用户/环境

// 切换用户(SDK 会自动重新拉取配置)
rDelivery.switchUserId("newUserId", object : LocalDataInitListener {
override fun onInitFinish() { }
})

// 切换环境(""=正式, "1"=测试)
rDelivery.switchEnvironment("1", object : LocalDataInitListener {
override fun onInitFinish() { }
})

// 切换服务类型
rDelivery.switchServerType(BaseProto.ServerType.TEST, object : LocalDataInitListener {
override fun onInitFinish() { }
})

其他 API

rDelivery.clearAllCache()
rDelivery.deleteRdeliveryDataByKey("my_key")
val keys: Set<String> = rDelivery.getAllKeys()
rDelivery.setCustomParam("key", "value")
rDelivery.setCustomParam("key", null) // 清除
rDelivery.updateQimei("newQimei")
rDelivery.addUserToExperienceList(qrCodeContent, customIDType, customIDValue, listener)
rDelivery.reportBusinessEvent(eventName, cost, errCode, extInfo, reportImmediately)
val tags: String = rDelivery.getHitSubTaskTags()

常见问题

配置读取返回 null/默认值

  1. 确认 RDelivery.create() 初始化成功。
  2. 使用 requestFullRemoteData(listener) 主动拉取配置后再读取。
  3. 检查 RDeliverySetting.Builder.setLogicEnvironment(envId) 环境 ID 是否与平台一致(""=正式,"1"=测试)。

收不到配置变更事件

  1. 确保 addDataChangeListener 已注册,监听接口签名正确。
  2. 检查 key 名称与 Shiply 平台配置的 key 完全一致(含大小写)。

配置更新未生效

  1. 检查 updateStrategy 位掩码是否包含所需策略(如 START_UPPERIODIC)。
  2. 若使用 PERIODIC,检查 updateInterval 是否设置过小被 SDK 最小值兜底。
  3. 手动调用 requestFullRemoteData(listener) 主动拉取验证。

磁盘读取 vs 内存读取

  • 运行期使用 getRDeliveryDataByKey(key)(内存读取)。
  • 仅在启动阶段数据未初始化完时使用 getRDeliveryDataByKeyFromDisc(key)(磁盘读取,涉及 I/O)。

文档与实现差异

  • 版本号:官方文档写 1.3.38-RC02,config.gradle 实际为 1.3.38-RC05。以 config.gradle 为准。
  • 文档其余 API 与源码一致。
这篇文档对您有帮助吗?