---
# System prepended metadata

title: A/B 2.0
tags: [tech]

---

---
tags: tech
---
# A/B 2.0

AB系统2.0版本（支持基于设备、电话号码、UserID的AB策略）
AB系统
AB如何生效
前端APP访问API：/abtest/abgroup，获取AB信息；
如果访问API得到的body内容中包含json信息，
解析json信息，这些就是AB Group key，客户端通过判断是否存在这个AB Group key 来确定是否命中AB策略，从而进行相应AB策略的展示
则需要在后续的所有request中增加一个特定的Header。Header的Name为：“X-Testing-Group”，该Header的Value为json中"abHeader"的Value。合并后的Header为：X-Testing-Group: “name=ab1,onlyapp=false,apis=uri1?para1,uri2?para2;name=ab2,onlyapp=false,apis=uri1?para1,uri2?para2”
如果访问API得到的Body为空，则不用做任何处理
请求部分
请求时机
用户登录状态下，进入首页前只请求基于userID的AB策略
用户未登录的状态下，启动时请求基于设备的AB策略，到达输入电话号码页面后，点击继续按钮后，请求基于电话号码的AB策略，到达首页逻辑处理后，请求基于userID的AB策略
请求网址
https://abtest.tantanapp.com/abtest/abgroup
请求字段
{  
   "names":[  
      "QA20180123:2",
      "clean-cache"
   ],
   "properties":{  
      "QA20180123:2":{  
         "restart":true
      },
      "clean-cache":{  
         "restart":false
      }
   },
   "abHeader":"name=QA20180123-2,apis=%5E%2Fv1%2Fmoments%24,%5E%2Fusers%2F%25w%2B%2Fmoments%24"
}
其中：

names字段表示进入的AB组信息
abHeader当前用户的AB信息，会添加到所有请求的Header中，用于解决问题1
propertiesproperties 字段标示 A/B 的详细信息，目前只增加了一个属性：
restart 标示前端是否需要重启来应用新的 A/B
本地没有已存储的 A/B 信息，只要获取的信息中有属性 restart 为 true 的 A/B，弹框显示上线/下线文案并重启App，然后应用最新的 A/B 逻辑
获取的信息中有新增或者移除属性 restart 为 true 的 A/B， 弹框显示上线/下线文案并重启App，然后应用最新的 A/B 逻辑
没有属性 restart 为 true 的A/B 的更改，直接应用最新的 A/B 逻辑
AB生效时机
基于设备的AB策略，立即生效
基于电话号码的AB策略，立即生效
AB友好上下线之后，生效时机由AB后台控制。默认都是下次启动生效，如果需要立即生效，需要设置"restart = true",进行弹窗提示，点击确认后，新的AB信息立即生效
实现
实现文件
P1ABTesting :

旧AB系统存在时：主要职能是有2部分，一是：旧AB系统处理AB分组逻辑 二是：对工程提供AB组信息的判断逻辑
旧AB系统废弃后：对工程提供AB组信息的判断逻辑
P1ABTestGroupObject : 基类。新AB系统的AB分组及存储逻辑、AB实时上下线逻辑New UI 判断展示逻辑

P1UserIdBasedABTestGroupObject : 基于UseId的AB实现类，其中包含ew UI 判断展示逻辑

P1DeviceBasedABTestGroupObject : 基于Device的AB实现类

P1PhoneNumberBasedABTestGroupObject : 基于电话号码的AB实现类

P1UserStateHandler : 辅助存储类，主要作用是本地化存储AB信息。

实现逻辑
AB加载及失效时机
/**
Case 1:
 登录->登录
 P1AppDelegate -> didFinishLaunchingWithOptions -> setupAndShowHomeViewAnimated
 
 [P1ABTestGroupObject loadCurrentUserABTestGroupFromLocal]
 
 加载数据到内存
 ---------------------------------------------------
Case 2:
 登录-> 登录 -> AB 变化 UI重启 分为2个阶段：
 第一阶段：正常启动
  P1AppDelegate -> didFinishLaunchingWithOptions -> setupAndShowHomeViewAnimated
 
 [P1ABTestGroupObject loadCurrentUserABTestGroupFromLocal]
 
 加载数据到内存
 第二阶段：AB变换弹窗提示：
 getNotification(NOTIFICATION_APP_RESTART_ABGROUP_CHANGED) -> rebuildUIWithABValueChanged -> rebuildAndShowHomeViewAnimated
 
  [P1ABTestGroupObject resetABTestValue]
 [P1ABTestGroupObject loadCurrentUserABTestGroupFromLocal]
 
---------------------------------------------------
Case 3:
 登录->退出登录
 P1AppDelegate -> switchToLandingPageAnimated:(BOOL)animated isAppFirstOpen:(BOOL)isAppFirstOpen withCompletion:(void(^)())completion

 [P1ABTesting resetUserIdBasedAndPhoneNumberBasedABTest]
 清空内存记录
 
---------------------------------------------------
Case 4:
 退出登录->登录
 P1AppDelegate -> landingPageControllerDidLogin -> setupAndShowHomeViewAnimated 
 
 [P1ABTestGroupObject loadCurrentUserABTestGroupFromLocal]
 
 
AB友好上下下逻辑
 iOS：AB生效时机
 iOS客户端启动|---获取本地存储的AB信息---->展示UI--------------------------|---------------------------------|End
            |-->请求AB后台获取AB信息->存储到本地-->判断是否需要重启APP--|是---更新本地AB信息--->弹框提示，UI重启---|End
                                                                |否--->更新本地AB信息 --------------------|End
流程图
这里一直上传不了，我直接发给李明了。

备注
Note 1：由于现在方案：基于Device-Based、Phone Number-Based的AB是使用最新网络值，而User-Based使用的是上次本地值，导致前后的AB-Header不一致。因此在登录后尽量避免使用Device-Based、Phone Number-Based的AB信息，该问题暂时不考了。
Note 2: 由于基于设备的AB请求只会在未登录状态启动时，请求一次，因此从登录到退出登录，现在暂时未请求基于设备的AB请求。如果需要支持从登录到退出登录也请求基于设备的AB请求，可以做如下修改
if([[Authenticator sharedAuthenticator] isLoggedIn]) {
        //VIP National Version, disable all Scenario Match.
        if ([UserObject currentUser].profile.scenarios.count) {
            [[SettingsFactory asyncUsecase] setScenarios:@[] withCompletionBlock:nil];
        }
        [self switchToHomeViewAnimated:NO];
    } else {
        //未登录状态下，请求基于Device的ABTest Group信息
        [P1ABTesting refreshDeviceBasedABTest];
        
        [self switchToLandingPageAnimated:NO isAppFirstOpen:isAppFirstOpen withCompletion:nil];
    }
    
把该逻辑`[P1ABTesting refreshDeviceBasedABTest];`添加到下面的函数中

- (void)switchToLandingPageAnimated:(BOOL)animated isAppFirstOpen:(BOOL)isAppFirstOpen withCompletion:(void(^)())completion {

但是此时修改会存在一次APP生命周期内，请求二次的基于设备AB请求。

这2个Note 于乐也知道，后续如果有需求涉及在补充。

Select a repo