跳至主要內容

UBI LINK 广告平台DSP接入文档

大约 30 分钟

UBI LINK 广告平台DSP接入文档

修订历史

版本修订内容修订日期修订人
1.0发布2025-06-17房振春

1、背景及目的

UBI LINK 平台,依托自有SDK流量,旨在为各广告需求方(DSP)提供稳定而优质的交易服务。

为了协助各DSP顺利对接UBI LINK,本文档定义统一对接规范,作为各DSP平台与UBI LINK进行交互的标准规范。

image.png

2、DSP系统对接流程

1、DSP使用本文档进行对接,UBI LINK运营同学提供测试广告位以及价钱加密key

2、接口开发完成后,DSP提供联调地址,与UBI LINK进行联调

3、线上小量对数

3、竞价协议

1、UBI LINK 与DSP 之间的通信协议为HTTP协议,竞价请求使用HTTP POST方式发送,DSP服务需要开启长连接减少连接处理时间

2、竞价请求与响应采用Protobuf(Protocol Buffers)数据格式,HTTP标头需要设置:Content-Type:application/octet-stream,proto文件地址:https://gameley.coding.net/s/7110ded5-1f3f-4607-b5d0-7d9fbbb7b530open in new window

3、支持标准的gzip压缩机制,以减少传输数据的大小,若需要压缩,需要UBI LINK运营同学进行配置。广告请求数据gzip压缩会设置Http Header:”Content-Encoding: gzip”,响应数据需要gzip压缩并设置Http Header:”Content-Encoding: gzip

3、广告请求发出后,等待响应时间默认500ms

4、若DSP不参与竞价,需要设置HTTP状态码为204

4、竞价请求

BidRequest

字段名类型是否必传说明默认值
idstring请求唯一 idUUID.randomUUID().toString().replace("_", "")
impobject此次曝光的信息,目前仅支持一个
appobject媒体的 app 信息
deviceobject用户设备信息

Imp

字段名类型是否必传说明默认值
nativeobjectbanner、native 广告位用
videoobject视频广告位用,与 banner、native 互斥
bidFloorobject底价,单位分
extobject扩展字段

imp.ext

字段名类型是否必传说明默认值
platformint系统平台,1=IOS,2=Android,3=PC_Web,4=H5,5=PC_Client,6=OTT
stagidstringUBI LINK 平台的 DSP 广告位 id
tagstring用户标签码值,逗号分割参见用户标签码值
pddTagint是否安装拼多多,1=已安装拼多多,2=未安装,3=未知

imp.native

字段名类型是否必传说明默认值
wint广告位素材宽度
hint广告位素材高度

imp.video

字段名类型是否必传说明默认值
mindurationint视频的最小时长,单位为秒0
maxdurationint视频的最大时长,单位为秒最大值不超过60

app

字段名类型是否必传说明默认值
idintUBI LINK平台的预算源 appId
namestringapp名称
verstring应用版本号
bundlestringApp包名
storeurlstringApp Store 下载链接
publisherstring媒体信息
catstringAPP行业分类
appstoreversionstring手机应用商店版本号大陆厂商安卓设备AS(应用市场)
hmsversionstring华为HMS版本华为机型上的HMS core版本号

Publisher

字段名类型是否必传说明默认值
namestring媒体名称

Device

字段名类型是否必传说明默认值
uastringUser-Agent
geoobject设备经纬度信息
ipstring设备 ipv4 地址
devicetypeint设备类型4=phone,5=pad, 2=pc,3=OTT
osstring设备操作系统,例如:android、ios、windows
osvstring设备操作系统版本,例如10.2
dpistring屏幕像素密度
ppistring每英寸所拥有的像素数量
densitystring屏幕密度
orientationstring设备⽅向 0未知, 1纵向, 2横向0
hint设备分辨率,高,单位像素
wint设备分辨率,款,单位像素
carrierstring运营商参见:运营商字典表
connectiontypeint联网类型参见:联网类型字典表
ifastringidfa原值
ifaMd5stringidfa md5加密
idfvstringidfv原值
idfvMd5stringidfv md5加密
didstringimei原值
didmd5stringimei md5加密
oaidMd5stringoaid md5加密
dpidstringandroid id
dpidmd5stringandroid id,md5加密
macstringmac地址,去冒号
macmd5stringmac地址,md5加密
makestring设备生产商,如 Apple
modelstring设备型号 如 iphone
extobject扩展字段
bootmarkstring系统启动标识,取原值回传。 iOS:1623815045.970028;Android:ec7f4f33-411a-47bc-8067-744a4e7e0723
updatemarkstring系统更新标识,取原值回传。 iOS:1581141691.570419583;Android:1004697.70999999
boottimestring设备最近一次开机时间,iOS必传,秒级时间戳,小数点后保留6位,如:1595214620.383940
osupdatetimestring手机系统的更新时间(时间戳)
deviceNamestring设备名称
deviceNameMd5string设备名称Md5
memorystring物理内存大小;KB
hardDiskstring物理硬盘大小:KB
timezonestring系统当前时区
caidstring广协生成的caid
caidverstring广协生成的caid版本号
aaidstring阿里生成的aaid
startuptimestring开机时长
birthtimestring设备初始化时间
paidstring拼多多广告识别id

Geo

字段名类型是否必传说明默认值
latdouble地理位置纬度,例:31.232949
londouble地理位置经度,例:121.418011

device.ext

字段名类型是否必传说明默认值
imeistringimei 原值
androidstringandroidid 原值
macstring无线 mac,去冒号原值
oaidstringoaid 原值
brandstring设备品牌
mac3string有线 mac 地址,去冒号原值,ott 专用
mac4string蓝牙 mac 地址,去冒号原值,ott 专用
ipv6stringipv6 地址
verstringapp应用版本号
gidstringapp分发渠道号

请求示例:

{
    "id":"d3bb147293534f639b8044ad9b37c9cc",
    "imp":{
        "ext":{
            "tag":"1,2,3",
            "platform":2,
            "stagid":"10000079"
        }
    },
    "app":{
        "bundle":"",
        "cat":"0",
        "id":500039,
        "name":"API 托管模式_Android",
        "publisher":{
            "name":"API 托管模式"
        },
        "storeurl":""
    },
    "device":{
        "carrier":"46003",
        "connectiontype":2,
        "devicetype":4,
        "h":3,
        "w":4,
        "didmd5":"d41d8cd98f00b204e9800998ecf8427e",
        "dpidmd5":"d087848d7034fac159c6390a2fec0c91",
        "ext":{
            "androidid":"191e3789a779a501",
            "brand":"HONOR",
            "gid":"dev",
            "imei":"",
            "ipv6":"",
            "mac":"342EB6F1B2D8",
            "mac3":"",
            "mac4":"",
            "oaid":"",
            "ver":"1.0.0"
        },
        "geo":{
            "lat":0,
            "lon":0
        },
        "ifa":"",
        "ip":"127.0.0.1",
        "macmd5":"5bfc558756f0bb3664cba82b31101980",
        "make":"HUAWEI",
        "model":"HRY-AL00a",
        "os":"Android",
        "osv":"10",
        "ua":""
    }
}

5、竞价响应

注:ios 广告响应必须为https协议,android 建议使用https

BidResponse

字段名类型是否必传说明
flagboolean请求是否成功,true 为成功。
codeintcode 0 为编码
messagestring错误信息描述
dataarray object广告数据

Data

字段名类型是否必传说明
crequestidstring媒体生成的本次请求唯一 id
sposidstringUBI LINK平台的DSP广告位id
restypestring填充广告类型 5=网盟,其他为""
materialobject素材信息
sdkinfoobject arraysdk信息
monitorobject素材监测信息
extentedobject扩展字段
orderidstring订单号
backupadsobject array备播广告数组
adsequenceint贴片广告贴次
pricestring出价,单位分 RTB必填
spostypeint广告类型:
1=开屏,2=视频贴片,3=信息流, 4=banner,5=插屏,6=激励视频

Material

字段名类型是否必传说明
cridstring素材id
ldptypeint落地页类型
0=h5;1=下载APP, 2=deeplink,3=广点通下载类 默认值为0
ldpstring落地页url
deeplinkstringdeeplink url
universallinkstringiOS的universallink url
tempidstring广告样式模板id
videourlstring视频地址(视频信息流、贴片、激励视频、开屏)
durationint视频播放时长 开屏广告不填默认为5
imgurlstring array信息流图片地址或视频信息流封面图片地址
titlestring广告标题
descstring广告描述
admstring广告素材 url,开机、banner、插屏的图片 url
wstring主素材宽
hstring主素材高
iconurlstring图标url
apknamestring下载的app应用名称
packagenamestring下载的安装包名称(android)或唯— id 号(ios)
privacyUrlstring隐私地址
permissionUrlstring用户权限url
appPublisherstring开发者名称
versionNamestring版本号名称
apkSizestring应用宝大小
appIntrostring应用介绍

Monitor

字段名类型是否必传说明
paarray object曝光监测
caarray object点击监测
nurlarray object竞胜通知监测
ldpcaarray string落地页加载完成监测
advmlobject广告主监测链接
hcurlarray object汇川-点击反作弊监测链接
lurlarray object竞败通知监测

Advml

字段名类型是否必传说明
ledparray objectDeeplink字段不为空此字段必传,Deeplink唤醒成功监测信息
ledpfailtrsarray objectDeeplink字段不为空此字段必传,Deeplink唤醒失败监测信息
ledpreadytrsarray objectDeeplink字段不为空此字段必传,Deeplink唤醒开始监测信息
ledownstarttrsarray object下载开始监测地址
ledowncomptrsarray object下载完成监测地址
leinstallstarttrsarray object安装开始监测信息
leinstallcomptrsarray object安装完成监测地址
leinstallerrortrsarray object安装失败监测地址
leinstallactiontrsarray object安装激活监测地址
lereadyarray object视频素材加载成功监测信息
levideoloaderrorarray object视频素材加载错误监测信息
levideostartarray object视频开始播放监测信息
lefirstquartilearray object视频播放1/4监测信息
lemidpointarray object视频播放1/2监测信息
lethirdquartilearray object视频播放3/4监测信息
levideoendarray object视频播放完成监测信息
lemutearray object静音播放监测信息
leunmutearray object关闭静音监测信息
leskiparray object跳过监测信息
lereplayarray object重播监测信息
lepausearray object视频暂停监测信息

Ledp

字段名类型是否必传说明
urlstringDeeplink字段不为空此字段必传,Deeplink唤醒成功监测信息

ledpfailtrs

字段名类型是否必传说明
urlstringDeeplink字段不为空此字段必传,Deeplink唤醒失败监测信息

ledpreadytrs

字段名类型是否必传说明
urlstringDeeplink字段不为空此字段必传,Deeplink唤醒开始监测信息

ledownstarttrs

字段名
类型
是否必须
说明
urlstring下载开始监测地址

ledowncomptrs

字段名
类型
是否必须
说明
urlstring下载完成监测链接

leinstallstarttrs

字段名
类型
是否必须
说明
urlstring安装开始监测链接

leinstallcomptrs

字段名
类型
是否必须
说明
urlstring安装结束监测地址

leinstallerrortrs

字段名
类型
是否必须
说明
urlstring安装失败监测链接

leready

字段名
类型
是否必须
说明
urlstring视频素材加载成功监测地址

levideoloaderror

字段名
类型
是否必须
说明
urlstring视频素材加载失败监测地址

levideostart

字段名
类型
是否必须
说明
urlstring视频开始播放监测地址

lefirstquartile

字段名
类型
是否必须
说明
urlstring视频播放1/4监测地址

lemidpoint

字段名
类型
是否必须
说明
urlstring视频播放1/2监测地址

lethirdquartile

字段名
类型
是否必须
说明
urlstring视频播放3/4监测地址

levideoend

字段名
类型
是否必须
说明
urlstring视频播放完成监测地址

lemute

字段名
类型
是否必须
说明
urlstring静音播放监测地址

leunmute

字段名
类型
是否必须
说明
urlstring取消静音播放监测地址

leskip

字段名
类型
是否必须
说明
urlstring跳过监测地址

lereplay

字段名
类型
是否必须
说明
urlstring重新播放监测地址

lepause

字段名
类型
是否必须
说明
urlstring视频暂停监测地址

Pa

字段名
类型
是否必须
说明
sdkidstringsdkid 传""即可
urlstring曝光监测url
timeint曝光监测上报时间

ca

字段名
类型
是否必须
说明
sdkidstringsdkid 传""即可
urlstring点击监测url

nurl

字段名
类型
是否必须
说明
urlstring竞胜通知url

lurl

字段名
类型
是否必须
说明
urlstring竞败通知url

响应示例:

{
    "code": 2000,
    "flag": true,
    "message": "请求成功",
    "data": [{
        "requestid": "d3bb147293534f639b8044ad9b37c9cc",
        "restype": "4",
        "sdkinfo": [],
        "serialflag": 0,
        "sposid": "10000079",
        "spostype": 1,
        "adsequence": 1,
        "crequestid": "d3bb147293534f639b8044ad9b37c9cc",
        "extended": {},
        "loadtype": 0,
        "material": {
            "adm": "http://xxx.com/imgs/materials/2021/2/19/20210219180216_750m420.jpg",
            "apkname": "apkname",
            "deeplink": "http://www.deeplink.com",
            "desc": "878257",
            "duration": 5,
            "imgurl": ["imagurl"],
            "ldp": "http://www.baidu.com",
            "ldptype": 0,
            "packagename": "package",
            "tempid": "8",
            "videourl": "http://videourl0"
        },
        "monitor": {
            "advml": {
                "ledp": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "ledpfailtrs": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "ledownstarttrs": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "ledowncomptrs": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "leinstallstarttrs": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "leinstallcomptrs": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "leinstallerrortrs": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "leready": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "levideoloaderror": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.comi/event"
                }],
                "levideostart": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "lefirstquartile": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "lemidpoint": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "lethirdquartile": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "levideoend": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "lemute": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "leunmute": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "leskip": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }],
                "lereplay": [{
                    "url": "http://xxx.com/stat/ikanstat/monitor"
                }, {
                    "url": "https://xxx.com/event"
                }]
            },
            "ca": [{
                "url": "http://xxx.com/dj"
            }, {
                "url": "http://xxx.com/stat/ikanstat/click"
            }],
            "ldpca": ["http://xxx.com/stat/ikanstat/click?"],
            "pa": [{
                "time": 0,
                "url": "http://xxx.com/bg"
            }, {
                "time": 1,
                "url": "https://xxx.com/x/"
            }, {
                "time": 1,
                "url": "http://xxx.com"
            }, {
                "time": 1,
                "url": "http://xxx.com/stat/ikanstat/stat"
            }]
        }
    }]
}


6、宏替换处理

DSP平台下发广告响应时,需要将广告主相关宏替换替换为UBI LINK平台宏替换规范。

宏定义说明
__LEMON__TIMESTAMP__当前时间戳, 单位: 毫秒
__LEMON__PROGRESS__当前播放进度, 单位: 秒
__LEMON__C_DOWN_X__用户点击时手指按下时相对于屏幕的横坐标
__LEMON__C_DOWN_Y__用户点击时手指按下时相对于屏幕的纵坐标
__LEMON__C_UP_X__用户点击时手指离开手机屏幕时的横坐标
__LEMON__C_UP_Y__用户点击时手指离开手机屏幕时的纵坐标
__LEMON__C_UP_TIME__用户点击时手指离开手机屏幕时的时间戳, 单位: 毫秒
__LEMON__C_DOWN_OFFSET_X__用户点击时手指按下时相对于广告展示区域的横坐标
__LEMON__C_DOWN_OFFSET_Y__用户点击时手指按下时相对于广告展示区域的纵坐标
__LEMON__C_UP_OFFSET_X__用户点击时手指离开时相对于广告展示区域的横坐标
__LEMON__C_UP_OFFSET_Y__用户点击时手指离开时相对于广告展示区域的纵坐标
__LEMON__WIDTH__实际广告展示区域(广告位)宽
__LEMON__HEIGHT__实际广告展示区域(广告位)高
__LEMON__CLICK_ID__点击ID,用于二次访问广告业务时要做替换,例如:进入落地页,在做下载操作时需要替换Clickid,用于后续的转化上报
__LEMON__CLICKAREA__点击区域: 0-广告素材, 1-按钮
__LEMON__EVENT_TIME_START__开始事件触发的时间戳,单位毫秒
__LEMON__EVENT_TIME_SECOND__开始事件触发的时间戳,单位秒
__LEMON__EVENT_TIME_END__结束事件触发的时间戳,单位毫秒
__LEMON__VIDEO_DURATION__仅在视频广告应答出现, 点击视频时的播放时长,单位秒
__LEMON__DOWN_X_ABS__鼠标或手指触碰或点击屏幕时,触点相对于屏幕左上角的绝对 X 坐标
__LEMON__DOWN_Y_ABS__鼠标或手指触碰或点击屏幕时,触点相对于屏幕左上角的绝对 Y 坐标
__LEMON__UP_X_ABS__完成点击动作后,鼠标或手指离开手机屏幕时,触点相对于屏幕左上角的绝对 X 坐标
__LEMON__UP_Y_ABS__完成点击动作后,鼠标或手指离开手机屏幕时,触点相对于屏幕左上角的绝对 Y 坐标
__LEMON__GPS_LON__经度。
__LEMON__GPS_LAT__维度
__LEMON__CLICK_ID__类似广点通下载类广告必须替换的宏,参见需要二次访问的广告处理业务说明
__LEMON__TSS__发起或者执行上报事件动作时,手机客户端的当前时间戳,精确到秒(s)
__LEMON__VD__当视频上报事件发生时,此时视频已经播放完成的时间长度
__LEMON__VIDEO_TIME__视频总时长,单位:秒
__LEMON__IP__客户端IP
__LEMON__IDFA__设备idfa
__LEMON__IMEI__设备imei
__LEMON__IMEIMD5__设备imei的MD5值
__LEMON__IDFAMD5__设备idfa的MD5值
__LEMON__UA__数据上报终端设备User Agent
__LEMON__OAID__设备的oaid
__LEMON__MAC__用户终端的网卡接口的物理MAC地址(无冒号)
__LEMON__ANDROIDID__安卓客户端AndroidID
__LEMON__ANDROIDIDMD5__安卓客户端AndroidID md5
__LEMON__ALL_AAID__阿里阿里巴巴匿名设备标识,需集成阿里 SDK
__LEMON__CAID__中广协CAID
__LEMON__PRICE__竞得价,价格宏(需要进行加解密)
__LEMON__BUTTON_LUX__广告按钮区域坐标(坐标定义:以屏幕左上角坐标为原点)左上角横坐标
__LEMON__BUTTON_LUY__广告按钮区域坐标(坐标定义:以屏幕左上角坐标为原点)左上角纵坐标
__LEMON__BUTTON_RDX__广告按钮区域坐标(坐标定义:以屏幕左上角坐标为原点)右下角横坐标
__LEMON__BUTTON_RDY__广告按钮区域坐标(坐标定义:以屏幕左上角坐标为原点)右下角纵坐标
__LEMON__DISPLAY_LUX__广告展示区域坐标(坐标定义:以屏幕左上角坐标为原点)左上角横坐标
__LEMON__DISPLAY_LUY__广告展示区域坐标(坐标定义:以屏幕左上角坐标为原点)左上角纵坐标
__LEMON__DISPLAY_RDX__广告展示区域坐标(坐标定义:以屏幕左上角坐标为原点)右下角横坐标
__LEMON__DISPLAY_RDY__广告展示区域坐标(坐标定义:以屏幕左上角坐标为原点)右下角纵坐标
__LEMON__DP_WIDTH__广告位的宽度,Android 端单位为逻辑像素(dp)
__LEMON__DP_HEIGHT__广告位的高度,Android 端单位为逻辑像素(dp)
__LEMON__DP_DOWN_X__手指按下手机屏幕时的x 坐标(相对于素材左上顶点), Android 端单位为逻辑像素(dp)
__LEMON__DP_DOWN_Y__手指按下手机屏幕时的y 坐标(相对于素材左上顶点), Android 端单位为逻辑像素(dp)
__LEMON__DP_UP_X__手指离开手机屏幕时的x 坐标(相对于素材左上顶点),Android 端单位为逻辑像素(dp)
__LEMON__DP_UP_Y__手指离开手机屏幕时的y 坐标(相对于素材左上顶点),Android 端单位为逻辑像素(dp)
__LEMON__SLD__广告交互方式,0:常规触屏点击,1 :滑动点击,2:摇一摇,3:自定义手势,5:扭一扭,6:擦除。其中常规触屏点击、滑动点击、自定义手势、擦除需上报点击坐标;摇一摇、扭一扭可以不上报点击坐标,需将点击坐标宏替换为-999。
__LEMON__LOSE_REASON__竞败原因,枚举值。0:unknown(其他原因)1:非法参数(缺少参数或参数异常)2:禁止投放(黑名单)3:创意审核中4:价格低于其他参竞方

需要二次访问的广告处理业务说明

当ldptype =3时,说明本广告响应的落地页 (ldp)是一个广点通app下载,需要对ldp进行二次请求,以获取实际应用下载地址和clickid进行宏替换。

请求响应结构如下:

{
"ret": 0, // 返回码:0 成功; 1 失败
"data": { // APP下载和转化上报信息
"clickid": "xxxxxxxxx", // clickid 需要缓存下来,用于后续转化上报
"dstlink": "http://xxx/xxx.apk" // 当前广告对应的下载链接
}
}

参数说明:

clickid:用于后续的转化上报

dstlink:用于跳转到下载地址

需要上报开始下载到安装完成的监测。在上报前,

先要对上报 URL进行宏替换,需要替换的宏如下(如果存在的话):

参数类型说明
__LEMON__CLICK_ID__stringclick_id

7、字典表

状态码

错误码信息说明
50005广告位 ID 为空
50010无效的广告位参数有误(包含如下两种场景)
1、当广告位、应用、媒体任一开关为关闭;
2、广告位 id 不存在;
50040请求 ID 为空
50045app 和 site 参数有误媒体应用类型为 ADX&SSP 时,api 方式对接时,会校验 app 和 site 有且
仅有一个非空
50050平台参数错误系统平台:sdk 传参,与 SSP 查询结果做校验,若不匹配
(1=iOS、2=Android、3=PC_Client、4=H5,5=PC_Web、6=OTT)
返回错误码:平台参数有误

运营商

carrier值运营商
46000中国移动
46001中国联通
46003中国电信
46020中国铁通
0其他或未知

connectiontype联网类型
0未知
1有线网络
2wifi
3蜂窝网-未知
4蜂窝网-2G
5蜂窝网-3G
6蜂窝网-4G
7蜂窝网-5G

用户码值

码值名称包名
1淘宝-太好逛了吧com.taobao.taobao
2支付宝-便捷生活一点就好com.eg.android.AlipayGphone
3拼多多com.xunmeng.pinduoduo
4美团-美好生活小帮手com.sankuai.meituan
5抖音com.ss.android.ugc.aweme
6快手com.smile.gifmaker
7百度com.baidu.searchbox
8抖音极速版com.ss.android.ugc.aweme.lite
9快手极速版com.kuaishou.nebula
10京东-京东1111真便宜com.jingdong.app.mall
11得物com.shizhuang.duapp
12番茄免费小说com.dragon.read
13虎牙直播-热门游戏赛事直播com.duowan.kiwi
14腾讯视频-故乡别来无恙全网独播com.tencent.qqlive
15哔哩哔哩tv.danmaku.bili
16爱奇艺-无所畏惧全网独播com.qiyi.video
17YY-和附近的人聊天看直播com.duowan.mobile
18百度极速版com.baidu.searchbox.lite
19搜狐视频-2023舞蹈翻跳盛典com.sohu.sohuvideo
20百度大字版-字大不伤眼com.baidu.searchbox.tomas
21懂车帝com.ss.android.auto
22西瓜视频-疯狂元素城首播com.ss.android.article.video
23番茄畅听com.xs.fm
24噗叽com.kwai.thanos
25头条搜索极速版-原今日头条极速版com.ss.android.article.lite
26每日走路-计步赚钱多多com.yt.mrzl
27UC浏览器-好搜好看好好用com.UCMobile
28抖音火山版com.ss.android.ugc.live
29小红书-你的生活指南com.xingin.xhs
30有柿com.ss.android.article.search
31贝乐虎儿歌com.ubestkid.beilehu.android
32七猫免费小说com.kmxs.reader
33追书神器免费版com.ushaqi.zhuishushenqi.adfree
3458同城-招聘找工作租房家政买车com.wuba
35快看漫画-偷偷藏不住全网独家com.kuaikan.comic
36优酷视频-新闻女王 全网独播com.youku.phone
37知乎-有问题就会有答案com.zhihu.android
38饿了么-新人专享20元红包me.ele
39喜马拉雅-123狂欢节com.ximalaya.ting.android
40安居客-二手房新房租房com.anjuke.android.app
41Hello语音-游戏开黑语音交友com.yy.huanju
42儿歌点点-宝宝儿歌故事动画大全com.mampod.ergedd
43花椒直播-美女视频聊天交友com.huajiao
44TT语音-王者荣耀官方合作伙伴com.yiyou.ga
45贝壳找房-二手房新房租房装修com.lianjia.beike
46爱奇艺极速版-宁安如梦热播com.qiyi.video.lite
47搜狐新闻-24小时新闻热点实时更新com.sohu.newsclient
48幸福里-二手房新房大平台com.f100.android
49墨迹天气-实时预报com.moji.mjweather
50万能WiFi精灵-免费链接上网com.jiujing.wnwfjl
51满格WiFicom.zs.wf.full.lattice
52活宝工具箱android.yhctstl.hbgjx
53每刻充电-快速充电赚钱com.hzjl.mkcd
54全免小说-免费阅读com.martian.qmbook
55WiFi钥匙速联-免费上网连接大师com.hzsq.wifiyssl
56雷电清理大师-手机垃圾内存清理com.ntyy.clear.thunder
57今日头条com.ss.android.article.news
58神速清理-一键清理专家com.speedandroid.server.ctsion
59腾讯新闻com.tencent.news
60当准天气com.bee.rain
61WiFi钥匙天天连-免费上网com.youying.wfysttl
62手机天猫com.tmall.wireless
63闲鱼-闲置交易平台com.taobao.idlefish
64智能5G钥匙com.terminillo.hasty.clamp
65趣连WiFi-手机万能钥匙测速com.wx.wifi.qulian
66每日清理大师-清理助手com.ntyy.clear.everyday
67加速WiFi-手机上网安全管家com.ntyy.wifi.accelerate
68同程旅行com.tongcheng.android
69新氧医美-正品轻医美十亿补贴com.youxiang.soyoungapp
70脉脉com.taou.maimai
71追书神器com.ushaqi.zhuishushenqi
72大众点评-发现好去处com.dianping.v1
73芒果TV-以爱为营com.hunantv.imgo.activity
74最右-搞笑脑洞兴趣社区cn.xiaochuankeji.tieba
75伊对me.yidui
76新浪新闻com.sina.news
77唯品会-新人享豪礼com.achievo.vipshop
78微博-上微博看明星热点新闻资讯com.sina.weibo
79腾讯NOW直播-直播交友短视频平台com.tencent.now
80淘特com.taobao.litetao
81全民K歌-音乐视频平台com.tencent.karaoke
82链家-专业房产买卖租赁装修平台com.homelink.android
83酷狗音乐com.kugou.android
84高德地图-高德打车com.autonavi.minimap
85斗鱼-高清游戏娱乐直播air.tv.douyu.android
86阿里巴巴-1688批发采购进货市场com.alibaba.wireless
87多多走路赚-天天计步领红包com.shangyun.jbxns
88每日充电-边充边赚com.xy.mrcd
89电池修复大师-省电管家com.brs.battery.repair
90充电领宝-天天充电赚钱com.shk.cdlb
91美团外卖com.sankuai.meituan.takeoutnew
92(iOS)淘宝com.taobao.taobao4iphone
93(iOS)京东com.360buy.jdmobile
94(iOS)拼多多com.xunmeng.pinduoduo
95(iOS)美团com.meituan.imeituan
96(iOS)美团外卖com.meituan.itakeaway
97(iOS)支付宝com.alipay.iphoneclient
98(iOS)抖音com.ss.iphone.ugc.Aweme
99汽车之家com.cubic.autohome

8、价钱加解密

   竞价成功上报时需要进⾏价格宏替换,__LEMON__PRICE__即扣费价格宏替换,需要采⽤Google OpenRTB价格加解密⽅式经过base64encode 后,作为加密后成交价格串。加密所需的 e_key 和 i_key 通过 UBI LINK 商务获取。
import javax.crypto.spec.SecretKeySpec;


public class AdxEnDecrypter {
  //加密
   private static String enPrice(double price, String encryptionKey, String integrityKey) throws InvalidKeyException {
        DoubleClickCrypto.Keys keys = new DoubleClickCrypto.Keys(
                new SecretKeySpec(encryptionKey.getBytes(), "HmacSHA1"),
                new SecretKeySpec(integrityKey.getBytes(), "HmacSHA1"));
        DoubleClickCrypto.Price crypto = new DoubleClickCrypto.Price(keys);
        return crypto.encodePriceValue(price, null);
    }
//解密
     private static double dePrice(String encryptedPrice, String encryptionKey, String integrityKey) throws InvalidKeyException, SignatureException {
        DoubleClickCrypto.Keys keys = new DoubleClickCrypto.Keys(
                new SecretKeySpec(encryptionKey.getBytes(), "HmacSHA1"),
                new SecretKeySpec(integrityKey.getBytes(), "HmacSHA1"));
        DoubleClickCrypto.Price crypto = new DoubleClickCrypto.Price(keys);
        return crypto.decodePriceValue(encryptedPrice);
    }

}


//工具类
import com.google.common.base.MoreObjects;
import com.google.common.io.BaseEncoding;
import com.google.common.primitives.Ints;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import javax.inject.Inject;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.ThreadLocalRandom;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.lang.Math.min;

/**
 * Encryption and decryption support for the DoubleClick Ad Exchange RTB protocol.
 * <p>
 * Encrypted payloads are wrapped by "packages" in the general format:
 * <code>
 * initVector:16 || E(payload:?) || I(signature:4)
 * </code>
 * <br>where:
 * <ol>
 *   <li>{@code initVector = timestamp:8 || serverId:8} (AdX convention)</li>
 *   <li>{@code E(payload) = payload ^ hmac(encryptionKey, initVector)} per max-20-byte block</li>
 *   <li>{@code I(signature) = hmac(integrityKey, payloadKeys || initVector)[0..3]}</li>
 * </ol>
 * <p>
 * This class, and all nested classes / subclasses, are threadsafe.
 */
public class DoubleClickCrypto {
    private static final Logger logger = LoggerFactory.getLogger(DoubleClickCrypto.class);
    public static final String KEY_ALGORITHM = "HmacSHA1";

    /** Initialization vector offset in the crypto package. */
    public static final int INITV_BASE = 0;
    /** Initialization vector size. */
    public static final int INITV_SIZE = 16;
    /** Timestamp subfield offset in the initialization vector. */
    public static final int INITV_TIMESTAMP_OFFSET = 0;
    /** ServerId subfield offset in the initialization vector. */
    public static final int INITV_SERVERID_OFFSET = 8;
    /** Payload offset in the crypto package. */
    public static final int PAYLOAD_BASE = INITV_BASE + INITV_SIZE;
    /** Integrity signature size. */
    public static final int SIGNATURE_SIZE = 4;
    /** Overhead (non-Payload data) total size. */
    public static final int OVERHEAD_SIZE = INITV_SIZE + SIGNATURE_SIZE;

    private static final int COUNTER_PAGESIZE = 20;
    private static final int COUNTER_SECTIONS = 3*256 + 1;

    //    private static final int MICROS_PER_CURRENCY_UNIT = 1_000_000;
    private static final int MICROS_PER_CURRENCY_UNIT = 1;

    private final Keys keys;
    private final ThreadLocalRandom fastRandom = ThreadLocalRandom.current();

    /**
     * Initializes with the encryption keys.
     *
     * @param keys Keys for the buyer's Ad Exchange account
     */
    public DoubleClickCrypto(Keys keys) {
        this.keys = keys;
    }

    /**
     * Decodes data, from string to binary form.
     * The default implementation performs websafe-base64 decoding (RFC 3548).
     */
    protected  byte[] decode(String data) {
        return data == null ? null : BaseEncoding.base64Url().decode(data);
    }

    /**
     * Encodes data, from binary form to string.
     * The default implementation performs websafe-base64 encoding (RFC 3548).
     */
    protected String encode(byte[] data) {
        return data == null ? null : BaseEncoding.base64Url().encode(data);
    }

    /**
     * Decrypts data.
     *
     * @param cipherData {@code initVector || E(payload) || I(signature)}
     * @return {@code initVector || payload || I'(signature)}
     * Where I'(signature) == I(signature) for success, different for failure
     */
    public byte[] decrypt(byte[] cipherData) throws SignatureException {
        checkArgument(cipherData.length >= OVERHEAD_SIZE,
                "Invalid cipherData, %s bytes", cipherData.length);

        // workBytes := initVector || E(payload) || I(signature)
        byte[] workBytes = cipherData.clone();
        ByteBuffer workBuffer = ByteBuffer.wrap(workBytes);
        boolean success = false;

        try {
            // workBytes := initVector || payload || I(signature)
            xorPayloadToHmacPad(workBytes);
            // workBytes := initVector || payload || I'(signature)
            int confirmationSignature = hmacSignature(workBytes);
            int integritySignature = workBuffer.getInt(workBytes.length - SIGNATURE_SIZE);
            workBuffer.putInt(workBytes.length - SIGNATURE_SIZE, confirmationSignature);

            if (confirmationSignature != integritySignature) {
                throw new SignatureException("Signature mismatch: "
                        + Integer.toHexString(confirmationSignature)
                        + " vs " + Integer.toHexString(integritySignature));
            }

            if (logger.isDebugEnabled()) {
                logger.debug(dump("Decrypted", cipherData, workBytes));
            }

            success = true;
            return workBytes;
        } finally {
            if (!success && logger.isDebugEnabled()) {
                logger.debug(dump("Decrypted (failed)", cipherData, workBytes));
            }
        }
    }

    /**
     * Encrypts data.
     *
     * @param plainData {@code initVector || payload || zeros:4}
     * @return {@code initVector || E(payload) || I(signature)}
     */
    public byte[] encrypt(byte[] plainData) {
        checkArgument(plainData.length >= OVERHEAD_SIZE,
                "Invalid plainData, %s bytes", plainData.length);

        // workBytes := initVector || payload || zeros:4
        byte[] workBytes = plainData.clone();
        ByteBuffer workBuffer = ByteBuffer.wrap(workBytes);
        boolean success = false;

        try {
            // workBytes := initVector || payload || I(signature)
            int signature = hmacSignature(workBytes);
            workBuffer.putInt(workBytes.length - SIGNATURE_SIZE, signature);
            // workBytes := initVector || E(payload) || I(signature)
            xorPayloadToHmacPad(workBytes);

            if (logger.isDebugEnabled()) {
                logger.debug(dump("Encrypted", plainData, workBytes));
            }

            success = true;
            return workBytes;
        } finally {
            if (!success && logger.isDebugEnabled()) {
                logger.debug(dump("Encrypted (failed)", plainData, workBytes));
            }
        }
    }

    /**
     * Creates the initialization vector from component {@code (timestamp, serverId)} fields.
     * This is the format used by DoubleClick, and it's a good format generally,
     * even though the initialization vector can be any random data (a cryptographic nonce).
     * <p>
     * NOTE: Follow the advice from
     * https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-price#detecting_stale
     * by using a high-resolution timestamp; also if the {@code serverId} is not necessary, providing
     * a random value there helps further to prevent replay attacks. In all methods that have
     * a {@code initVector} parameter, passing null will cause {@code (current time, random)}
     * to be used (so if you really want all-zeros {@code initVector}, e.g. in unit tests to make
     * results reproducible, pass a zero-filled array).
     */
    public byte[] createInitVector(Date timestamp, long serverId) {
        byte[] initVector = new byte[INITV_SIZE];
        ByteBuffer byteBuffer = ByteBuffer.wrap(initVector);

        if (timestamp != null) {
            byteBuffer.putLong(INITV_TIMESTAMP_OFFSET, timestamp.getTime());
        }

        byteBuffer.putLong(INITV_SERVERID_OFFSET, serverId);
        return initVector;
    }

    /**
     * Returns the {@code timestamp} field from encrypted or decrypted data. Assumes that its
     * initialization vector has the structure {@code (timestamp, serverId)}.
     *
     * @param data Encrypted or decrypted data (the initialization vector is never encrypted)
     * @return Timestamp subfield of the initialization vector.
     */
    public Date getTimestamp(byte[] data) {
        return new Date(ByteBuffer.wrap(data).getLong(INITV_BASE + INITV_TIMESTAMP_OFFSET));
    }

    /**
     * Returns the {@code serverId} field from encrypted or decrypted data. Assumes that its
     * initialization vector has the structure {@code (timestamp, serverId)}.
     *
     * @param data Encrypted or decrypted data (the initialization vector is never encrypted)
     * @return Timestamp subfield of the initialization vector.
     */
    public long getServerId(byte[] data) {
        return ByteBuffer.wrap(data).getLong(INITV_BASE + INITV_SERVERID_OFFSET);
    }

    /**
     * Packages plaintext payload for encryption; returns {@code initVector || payload || zeros:4}.
     */
    protected byte[] initPlainData(int payloadSize, byte[] initVector) {
        byte[] plainData = new byte[OVERHEAD_SIZE + payloadSize];

        if (initVector == null) {
            ByteBuffer byteBuffer = ByteBuffer.wrap(plainData);
            byteBuffer.putLong(INITV_TIMESTAMP_OFFSET, System.nanoTime());
            byteBuffer.putLong(INITV_SERVERID_OFFSET, fastRandom.nextLong());
        } else {
            System.arraycopy(initVector, 0, plainData, INITV_BASE, min(INITV_SIZE, initVector.length));
        }

        return plainData;
    }

    /**
     * {@code payload = payload ^ hmac(encryptionKey, initVector || counterBytes)}
     * per max-20-byte blocks.
     */
    private void xorPayloadToHmacPad(byte[] workBytes) {
        int payloadSize = workBytes.length - OVERHEAD_SIZE;
        int sections = (payloadSize + COUNTER_PAGESIZE - 1) / COUNTER_PAGESIZE;
        checkArgument(sections <= COUNTER_SECTIONS, "Payload is %s bytes, exceeds limit of %s",
                payloadSize, COUNTER_PAGESIZE * COUNTER_SECTIONS);

        Mac encryptionHmac = createMac();

        byte[] pad = new byte[COUNTER_PAGESIZE + 3];
        int counterSize = 0;

        for (int section = 0; section < sections; ++section) {
            int sectionBase = section * COUNTER_PAGESIZE;
            int sectionSize = min(payloadSize - sectionBase, COUNTER_PAGESIZE);

            try {
                encryptionHmac.reset();
                encryptionHmac.init(keys.getEncryptionKey());
                encryptionHmac.update(workBytes, INITV_BASE, INITV_SIZE);
                if (counterSize != 0) {
                    encryptionHmac.update(pad, COUNTER_PAGESIZE, counterSize);
                }
                encryptionHmac.doFinal(pad, 0);
            } catch (ShortBufferException | InvalidKeyException e) {
                throw new IllegalStateException(e);
            }

            for (int i = 0; i < sectionSize; ++i) {
                workBytes[PAYLOAD_BASE + sectionBase + i] ^= pad[i];
            }

            Arrays.fill(pad, 0, COUNTER_PAGESIZE, (byte) 0);

            if (counterSize == 0 || ++pad[COUNTER_PAGESIZE + counterSize - 1] == 0) {
                ++counterSize;
            }
        }
    }

    private static Mac createMac() {
        try {
            return Mac.getInstance("HmacSHA1");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }
    }

    /**
     * {@code signature = hmac(integrityKey, payload || initVector)}
     */
    private int hmacSignature(byte[] workBytes) {
        try {
            Mac integrityHmac = createMac();
            integrityHmac.init(keys.getIntegrityKey());
            integrityHmac.update(workBytes, PAYLOAD_BASE, workBytes.length - OVERHEAD_SIZE);
            integrityHmac.update(workBytes, INITV_BASE, INITV_SIZE);
            return Ints.fromByteArray(integrityHmac.doFinal());
        } catch (InvalidKeyException e) {
            throw new IllegalStateException(e);
        }
    }

    private static String dump(String header, byte[] inData, byte[] workBytes) {
        ByteBuffer initvBuffer = ByteBuffer.wrap(workBytes, INITV_BASE, INITV_SIZE);
        Date timestamp = new Date(initvBuffer.getLong(INITV_BASE + INITV_TIMESTAMP_OFFSET));
        long serverId = initvBuffer.getLong(INITV_BASE + INITV_SERVERID_OFFSET);
        return new StringBuilder()
                .append(header)
                .append(": initVector={timestamp ")
                .append(DateFormat.getDateTimeInstance().format(timestamp))
                .append(", serverId ").append(serverId)
                .append("}, input =").append(BaseEncoding.base16().encode(inData))
                .append(", output =").append(BaseEncoding.base16().encode(workBytes))
                .toString();
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this).omitNullValues()
                .add("keys", keys)
                .toString();
    }

    /**
     * Holds the keys used to configure DoubleClick cryptography.
     */
    public static class Keys {
        private final SecretKey encryptionKey;
        private final SecretKey integrityKey;

        public Keys(SecretKey encryptionKey, SecretKey integrityKey) throws InvalidKeyException {
            this.encryptionKey = encryptionKey;
            this.integrityKey = integrityKey;

            // Forces early failure if any of the keys are not good.
            // This allows us to spare callers from InvalidKeyException in several methods.
            Mac hmac = DoubleClickCrypto.createMac();
            hmac.init(encryptionKey);
            hmac.reset();
            hmac.init(integrityKey);
            hmac.reset();
        }

        public SecretKey getEncryptionKey() {
            return encryptionKey;
        }

        public SecretKey getIntegrityKey() {
            return integrityKey;
        }

        @Override
        public int hashCode() {
            return encryptionKey.hashCode() ^ integrityKey.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            } else if (!(obj instanceof Keys)) {
                return false;
            }
            Keys other = (Keys) obj;
            return encryptionKey.equals(other.encryptionKey) && integrityKey.equals(other.integrityKey);
        }

        @Override public String toString() {
            return MoreObjects.toStringHelper(this).omitNullValues()
                    .add("encryptionKey", encryptionKey.getAlgorithm() + '/' + encryptionKey.getFormat())
                    .add("integrityKey", integrityKey.getAlgorithm() + '/' + integrityKey.getFormat())
                    .toString();
        }
    }

    /**
     * Encryption for winning price.
     * <p>
     * See <a href="https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-price">
     * Decrypting Price Confirmations</a>.
     */
    public static class Price extends DoubleClickCrypto {
        private static final int PAYLOAD_SIZE = 8;

        @Inject
        public Price(Keys keys) {
            super(keys);
        }

        /**
         * Encrypts the winning price.
         *
         * @param priceValue the price in micros (1/1.000.000th of the currency unit)
         * @param initVector up to 16 bytes of nonce data
         * @return encrypted price
         * @see #createInitVector(Date, long)
         */
        public byte[] encryptPriceMicros(long priceValue, byte[] initVector) {
            byte[] plainData = initPlainData(PAYLOAD_SIZE, initVector);
            ByteBuffer.wrap(plainData).putLong(PAYLOAD_BASE, priceValue);
            return encrypt(plainData);
        }

        /**
         * Decrypts the winning price.
         *
         * @param priceCipher encrypted price
         * @return the price value in micros (1/1.000.000th of the currency unit)
         */
        public long decryptPriceMicros(byte[] priceCipher) throws SignatureException {
            checkArgument(priceCipher.length == (OVERHEAD_SIZE + PAYLOAD_SIZE),
                    "Price is %s bytes, should be %s", priceCipher.length, (OVERHEAD_SIZE + PAYLOAD_SIZE));

            byte[] plainData = decrypt(priceCipher);
            return ByteBuffer.wrap(plainData).getLong(PAYLOAD_BASE);
        }

        /**
         * Encrypts and encodes the winning price.
         *
         * @param priceMicros the price in micros (1/1.000.000th of the currency unit)
         * @param initVector up to 16 bytes of nonce data, or {@code null} for default
         * generated data (see {@link #createInitVector(Date, long)}
         * @return encrypted price, encoded as websafe-base64
         */
        public String encodePriceMicros(long priceMicros, byte[] initVector) {
            return encode(encryptPriceMicros(priceMicros, initVector));
        }

        /**
         * Encrypts and encodes the winning price.
         *
         * @param priceValue the price
         * @param initVector up to 16 bytes of nonce data, or {@code null} for default
         * generated data (see {@link #createInitVector(Date, long)}
         * @return encrypted price, encoded as websafe-base64
         */
        public String encodePriceValue(double priceValue, byte[] initVector) {
            return encodePriceMicros((long) (priceValue * MICROS_PER_CURRENCY_UNIT), initVector);
        }

        /**
         * Decodes and decrypts the winning price.
         *
         * @param priceCipher encrypted price, encoded as websafe-base64
         * @return the price value in micros (1/1.000.000th of the currency unit)
         */
        public long decodePriceMicros(String priceCipher) throws SignatureException {
            return decryptPriceMicros(decode(checkNotNull(priceCipher)));
        }

        /**
         * Decodes and decrypts the winning price.
         *
         * @param priceCipher encrypted price, encoded as websafe-base64
         * @return the price value
         */
        public double decodePriceValue(String priceCipher) throws SignatureException {
            return decodePriceMicros(priceCipher) / ((double) MICROS_PER_CURRENCY_UNIT);
        }
    }

    /**
     * Encryption for Advertising ID.
     * <p> See
     * <a href="https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-advertising-id">
     * Decrypting Advertising ID</a>.
     */
    public static class AdId extends DoubleClickCrypto {
        private static final int PAYLOAD_SIZE = 16;

        @Inject
        public AdId(Keys keys) {
            super(keys);
        }

        /**
         * Encrypts the Advertising Id.
         *
         * @param adidPlain the AdId
         * @param initVector up to 16 bytes of nonce data, or {@code null} for default
         * generated data (see {@link #createInitVector(Date, long)}
         * @return encrypted AdId
         */
        public byte[] encryptAdId(byte[] adidPlain, byte[] initVector) {
            checkArgument(adidPlain.length == PAYLOAD_SIZE,
                    "AdId is %s bytes, should be %s", adidPlain.length, PAYLOAD_SIZE);

            byte[] plainData = initPlainData(PAYLOAD_SIZE, initVector);
            System.arraycopy(adidPlain, 0, plainData, PAYLOAD_BASE, PAYLOAD_SIZE);
            return encrypt(plainData);
        }

        /**
         * Decrypts the AdId.
         *
         * @param adidCipher encrypted AdId
         * @return the AdId
         */
        public byte[] decryptAdId(byte[] adidCipher) throws SignatureException {
            checkArgument(adidCipher.length == (OVERHEAD_SIZE + PAYLOAD_SIZE),
                    "AdId is %s bytes, should be %s", adidCipher.length, (OVERHEAD_SIZE + PAYLOAD_SIZE));

            byte[] plainData = decrypt(adidCipher);
            return Arrays.copyOfRange(plainData, PAYLOAD_BASE, plainData.length - SIGNATURE_SIZE);
        }
    }

    /**
     * Encryption for IDFA.
     * <p> See
     * <a href="https://support.google.com/adxbuyer/answer/3221407">
     * Targeting mobile app inventory with IDFA</a>.
     */
    public static class Idfa extends DoubleClickCrypto {
        @Inject
        public Idfa(Keys keys) {
            super(keys);
        }

        /**
         * Encrypts the IDFA.
         *
         * @param idfaPlain the IDFA
         * @param initVector up to 16 bytes of nonce data, or {@code null} for default
         * generated data (see {@link #createInitVector(Date, long)}
         * @return encrypted IDFA
         */
        public byte[] encryptIdfa(byte[] idfaPlain, byte[] initVector) {
            byte[] plainData = initPlainData(idfaPlain.length, initVector);
            System.arraycopy(idfaPlain, 0, plainData, PAYLOAD_BASE, idfaPlain.length);
            return encrypt(plainData);
        }

        /**
         * Decrypts the IDFA.
         *
         * @param idfaCipher encrypted IDFA
         * @return the IDFA
         */
        public byte[] decryptIdfa(byte[] idfaCipher) throws SignatureException {
            byte[] plainData = decrypt(idfaCipher);
            return Arrays.copyOfRange(plainData, PAYLOAD_BASE, plainData.length - SIGNATURE_SIZE);
        }

        /**
         * Encrypts and encodes the IDFA.
         *
         * @param idfaPlain the IDFA
         * @param initVector up to 16 bytes of nonce data, or {@code null} for default
         * generated data (see {@link #createInitVector(Date, long)}
         * @return encrypted IDFA, websafe-base64 encoded
         */
        public String encodeIdfa(byte[] idfaPlain, byte[] initVector) {
            return encode(encryptIdfa(idfaPlain, initVector));
        }

        /**
         * Decodes and decrypts the IDFA.
         *
         * @param idfaCipher encrypted IDFA, websafe-base64 encoded
         * @return the IDFA
         */
        public byte[] decodeIdfa(String idfaCipher) throws SignatureException {
            return decryptIdfa(decode(idfaCipher));
        }
    }

    /**
     * Encryption for {@code HyperlocalSet} geofence information.
     * <p> See
     * <a href="https://developers.google.com/ad-exchange/rtb/response-guide/decrypt-hyperlocal">
     * Decrypting Hyperlocal Targeting Signals</a>.
     */
    public static class Hyperlocal extends DoubleClickCrypto {
        @Inject
        public Hyperlocal(Keys keys) {
            super(keys);
        }

        /**
         * Encrypts the serialized {@code HyperlocalSet}.
         *
         * @param hyperlocalPlain the {@code HyperlocalSet}
         * @param initVector up to 16 bytes of nonce data, or {@code null} for default
         * generated data (see {@link #createInitVector(Date, long)}
         * @return encrypted {@code HyperlocalSet}
         */
        public byte[] encryptHyperlocal(byte[] hyperlocalPlain, byte[] initVector) {
            byte[] plainData = initPlainData(hyperlocalPlain.length, initVector);
            System.arraycopy(hyperlocalPlain, 0, plainData, PAYLOAD_BASE, hyperlocalPlain.length);
            return encrypt(plainData);
        }

        /**
         * Decrypts the serialized {@code HyperlocalSet}.
         *
         * @param hyperlocalCipher encrypted {@code HyperlocalSet}
         * @return the {@code HyperLocalSet}
         */
        public byte[] decryptHyperlocal(byte[] hyperlocalCipher) throws SignatureException {
            byte[] plainData = decrypt(hyperlocalCipher);
            return Arrays.copyOfRange(plainData, PAYLOAD_BASE, plainData.length - SIGNATURE_SIZE);
        }
    }
}




上次编辑于: