博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
腾讯广告广点通API接入文档(Android)
阅读量:6501 次
发布时间:2019-06-24

本文共 9305 字,大约阅读时间需要 31 分钟。

如果能够看懂文档的也没有必要再往下面看了。本篇文章就到此结束。

下面记录的是本人在上面锁踩过的坑,因为我发现Mac电脑上面的联系客服不是我想要的。

本来只是内部使用的文档,后来想想还是公开出来,希望能够帮助到人。

进入正式的接入流程吧!!!

这两步建议可以直接看文档,坑不在这一块。但是创建应用的时候有几个点可以注意下

  • 应用介绍:这个不只是简单的介绍一下应用,还需要表明创建应用以后需要用到哪些接口,并且是干嘛使用的

    应用介绍说明(自己的应用介绍说明),主要使用到的接口有:1、https://developers.e.qq.com/oauth/authorize 通过这个接口获取到 authorization_code ;2、调用接口 https://api.e.qq.com/oauth/token 获取到 access_tokenrefresh_token ; 3、最后在调用 https://api.e.qq.com/v1.0/campaigns/add 发送请求

  • 回调地址:这个可以是你们公司的域名之类的,可以是不正确的,没有很大的关系。
  • 创建应用以后会向邮箱里面给你发送一些数据,我整个过程中没有使用这个数据,直接使用的是正式流程中的数据。主要还是看自己吧!

应用创建成功以后并且审核通过的话,就可以进行接下来的步骤了。

授权认证就是用浏览器去调用一个接口

https://developers.e.qq.com/oauth/authorize?client_id=123456&redirect_uri=https://www.example.com&state=&scope=

其中:

  • client_id:开发者创建的应用唯一标识id,必填,可通过 [应用程序管理页面] 查看;
  • redirect_uri:回调地址,由开发者自行提供和定义(地址主域需与开发者创建应用程序时登记的回调主域一致),用于跳转并接收回调信息,必填;
  • state:开发者自定义参数,可用于验证请求有效性或者传递其他自定义信息,回调的时候会原样带回,可选;
  • scope:授权的能力范围,可选,不传时表示授权范围为当前应用程序所拥有的所有能力;

OAuth 2.0 授权页面如下图所示:

同意授权以后,页面将会跳转到以下链接:

https://www.test.com/?authorization_code=1066a051ea8fbaf011b892c202ae1c93&state=

https://www.test.com 表示你所填写的回调地址。

authorization_code=1066a051ea8fbaf011b892c202ae1c93 这个参数将会在接下来的步骤中有这很大的作用。

点击进入你的腾讯社交平台->应用程序管理->应用test,进入应用test详情页面,会在页面的最底下绑定帐号管理栏里面多出刚刚授权的账号,

我这边有两个是因为我授权了两个账号。注意到图片上面有个广点通账号,这个将会对你有用的。

腾讯文档关于获取这个还是说的很清楚的,具体可以查看文档。直接贴一个我这边请求的图:

这个接口的请求方式是GET

上报用户行为数据之前需要广点通人员在DMP后台新建App用户行为数据源,这一步骤将会取得 用户属性数据源 id ,接口会要用到的。

请求地址:

https://api.e.qq.com/v1.0/user_properties/add?access_token=<ACCESS_TOKEN>&timestamp=<TIMESTAMP>&nonce=<NONCE>'

对参数进行讲解一下

  • access_token:就是上一个接口获取到的数据
  • timestamp : 时间戳 (秒级别)
  • nonce : 32位随机码

请求方式:POST

请求参数:

名称 类型 描述
account_id(必填) integer 推广帐号 id,有操作权限的帐号id,包括代理商和广告主帐号 id
user_action_set_id(必填) integer 用户行为源 id,通过 [user_action_sets 接口] 创建用户行为源时分配的唯一 id
actions(必填) struct[] 返回数组列表,不能大于 50KB 数组最小长度 1,最大长度 50
action_time(必填) integer 行为发生时,客户端的时间点。 UNIX时间,单位为秒,如果不填将使用服务端时间填写 最小值 0,最大值 2147483647
user_id(必填) struct 用户标识
hash_imei(必填) string IMEI 设备号保持小写,进行 md5 编码 字段长度最小 32 字节,长度最大 32 字节
action_type(必填) enum 标准行为类型,当值为 'CUSTOM' 时表示自定义行为类型,[枚举详情] 枚举列表:{ CUSTOM, REGISTER, VIEW_CONTENT, CONSULT, ADD_TO_CART, PURCHASE, ACTIVATE_APP, SEARCH, ADD_TO_WISHLIST, INITIATE_CHECKOUT, COMPLETE_ORDER, START_APP, RATE, PAGE_VIEW, RESERVATION, SHARE, APPLY, CLAIM_OFFER, NAVIGATE, PRODUCT_RECOMMEND, VISIT_STORE, TRY_OUT, DELIVER, SIGN_IN }

上面只是对参数进行讲解

还是给个json示例吧

{	"account_id": "
", "user_action_set_id": "
", "actions": [ { "action_time": 1535097324, "user_id": { "hash_imei": "f9efca36a3c30e1cf28170d86ecbf5e9" }, "action_type": "REGISTER", } ]}复制代码

account_id 怎么获取呢?两种方式:

一种就是我们在获取 access_token 的时候,返回结果数据里面还有一个 account_id 的字段,没错,就是那个了。

第二种就是我们在应用详情下面的绑定账号管理里面的广点通账号ID

user_action_set_id 就是用户属性数据源 id ,让对面对接人员提供。

action_time :时间戳(秒级别的)

hash_imei :imei的MD5加密字符串

action_type :本次上报的类型

如果接口返回的是

{    "code": 0,    "message": ""}复制代码

那就恭喜你,流程已经走通了。

现在是不是要开始上代码了呢,别急,还有一些要注意的东西。

比如说,上面获取到的 access_token 是会过期的,需要使用到 refresh_token 去刷新有效期的。具体怎么刷新?看腾讯文档。现在的问题在哪里呢?比如说,今天对接测试通过了,打包上线并且审核通过了,过两天下载的用户就会出现 access_token 过期的问题,怎么处理呢?有同学肯定会说,那我们在用户调用上报数据接口的时候去刷新一下不就行了。其实也可以的,但是我觉得这个刷新也太频繁了吧。所以我特意询问过腾讯的技术支持,他们建议把刷新 access_token 的机制放到我们的服务器端去做,也就是让服务器端帮我们一天刷新一下这个 token ,刷新 access_token 并不会改变 access_token 的值,只会改变 access_token 的有效期。那我们在客户端所要做的事情就很简单了,那就是上报数据就行了。

代码该上还是要上的(注意:以下代码由kotlin编写):

实体类

class OCPABean(        /**         * 广点通帐号ID,(可以自己查找,也可以由对方提供)         */        var accountID: String?,        /**         * 用户行为源 id,这个由对方提供(广点通)         */        var userActionSetId: String?,        /**         * 通过code获取到的token         */        var token: String?,        /**         *         */        var channelIdList: List
?)复制代码

下面这个类主要是用来初始化我们的一些必要的数据

object OCPAStorage {    /**     * 用于存储app包名所对应的渠道号     */    var ocpaConfig = mutableMapOf
() init { initTest() } private fun initTest() { var list = listOf("getui1") var ocpaBean = OCPABean("83005", "177844", "5a42ed16464f8cda38c7e4ea000", list) ocpaConfig["com.baidu.test"] = ocpaBean }}复制代码

工具类,提供一些方法,注:currentRegisterNeedReport 这个方法可以根据自己的需求进行实现

object OCPAUtil {    var ocpaBean: OCPABean? = null    /**     * 当前的包名和渠道是否需要上报     */    fun currentRegisterNeedReport(context: Context): Boolean {        var packageName = context.packageName        var ocpaConfigMap = OCPAStorage.ocpaConfig        var keys = ocpaConfigMap.keys        if (packageName in keys) {            var ocpaBean = ocpaConfigMap[packageName]            var channelIdList = ocpaBean?.channelIdList            var channelName = ChannelUtil.getChannelName(context)            if (channelIdList?.contains(channelName) == true) {                this@OCPAUtil.ocpaBean = ocpaBean                return true            }        }        return false    }    /**     * 获取当前秒级的时间戳     */    fun getTimeStamp(): String {        var timeStamp = System.currentTimeMillis() / 1000        return timeStamp.toString()    }    /**     * 生成32位编码     * @return string     */    fun getUUID(): String {        return UUID.randomUUID().toString().trim().replace("-", "")    }    }复制代码

下面这个类是主要做网络请求,上报接口的,采用的Okhttp3网络框架

object OCPAHttpClient {    const val SP_CONSTANT = "OCPA_SP_CONSTANT"    fun register(context: Context) {        var spConstant = FRSharedPreferences.getStringNotClear(SP_CONSTANT, "")//        var spConstant = ""        if (TextUtils.isEmpty(spConstant) && OCPAUtil.currentRegisterNeedReport(context)) {            httpRegister()        }    }    private fun httpRegister() {        var ocpaBean = OCPAUtil.ocpaBean        ocpaBean?.let {            val okHttpClient = OkHttpClient.Builder()                    .connectTimeout(30, TimeUnit.SECONDS)                    .writeTimeout(30, TimeUnit.SECONDS)                    .readTimeout(30, TimeUnit.SECONDS)                    .build()            //获取当前的秒级时间戳            var timeStamp = OCPAUtil.getTimeStamp()            //构造一个url            var baseUrl = "https://api.e.qq.com/v1.0/user_actions/add?access_token=${ocpaBean.token}&timestamp=$timeStamp&nonce=${OCPAUtil.getUUID()}"            var dataJsonObject = JSONObject()            //构造参数            try {                dataJsonObject.put("account_id", ocpaBean.accountID)                dataJsonObject.put("user_action_set_id", ocpaBean.userActionSetId)                var actionJA = JSONArray()                var actionJO = JSONObject()                actionJO.put("action_time", timeStamp)                actionJO.put("action_type", "REGISTER")                var userIdJO = JSONObject()                var imei = FRDeviceUtil.getPhoneInfo()                imei?.let {                    userIdJO.put("hash_imei", FREncryptUtil.string2MD5(imei))                }                actionJO.put("user_id", userIdJO)                actionJA.put(actionJO)                dataJsonObject.put("actions", actionJA)            } catch (e: JSONException) {                e.printStackTrace()            }            var requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), dataJsonObject.toString())            var request = Request.Builder()                    .url(baseUrl)                    .post(requestBody)                    .build()            okHttpClient.newCall(request).enqueue(object : Callback {                override fun onFailure(call: Call?, e: IOException?) {                    FRLog.e("log", "OCPA注册失败")                }                override fun onResponse(call: Call?, response: Response?) {                    FRSharedPreferences.setStringNotClear(SP_CONSTANT, SP_CONSTANT)                    FRLog.e("log", response?.body()?.string())                }            })        }    }}复制代码

MD5加密类:

public class FREncryptUtil {    /**     * 利用MD5进行加密     *     * @param inStr 待加密的字符串     * @return 加密后的字符串     * @throws NoSuchAlgorithmException     没有这种产生消息摘要的算法     * @throws UnsupportedEncodingException     */    public static String string2MD5(String inStr) {        if (TextUtils.isEmpty(inStr))            return "";        MessageDigest md5 = null;        try {            md5 = MessageDigest.getInstance("MD5");        } catch (Exception e) {            System.out.println(e.toString());            e.printStackTrace();            return "";        }        char[] charArray = inStr.toCharArray();        byte[] byteArray = new byte[charArray.length];        for (int i = 0; i < charArray.length; i++)            byteArray[i] = (byte) charArray[i];        byte[] md5Bytes = md5.digest(byteArray);        StringBuffer hexValue = new StringBuffer();        for (int i = 0; i < md5Bytes.length; i++) {            int val = ((int) md5Bytes[i]) & 0xff;            if (val < 16)                hexValue.append("0");            hexValue.append(Integer.toHexString(val));        }        return hexValue.toString();    }}复制代码

获取Imei的方法:这个方法可能和使用的时候有点不一样,具体的修改自己看着改一下吧。

/** * 获取手机的IMEI * * @return */public static String getPhoneInfo(Context context) {    TelephonyManager tm = null;    try {        tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);        return tm.getDeviceId();    } catch (Exception e) {        return "";    }}复制代码

好了,到此结束吧。不要忘记叫后台帮忙刷新 token 啊!!!

转载于:https://juejin.im/post/5b7fda3cf265da437d6e02ef

你可能感兴趣的文章
文件操作示例脚本 tcl
查看>>
大家好,新年快乐。
查看>>
prototype
查看>>
Android学习路线
查看>>
Linux下的redis的持久化,主从同步及哨兵
查看>>
在相同的主机上创建一个duplicate数据库
查看>>
Date15
查看>>
从Date类型转为中文字符串
查看>>
el-popover可以设高度_农村建房资金充裕,不妨建个地下室,车库、酒窖、卡拉OK都可以...
查看>>
基于multisim的fm调制解调_苹果开始自研蜂窝网调制解调器 最快2024年能用上?
查看>>
mupdf不支持x64_Window权限维持(七):安全支持提供者
查看>>
cf修改游戏客户端是什么意思_瓦罗兰特很有可能取代cf成为国内最火的fps游戏...
查看>>
proto文件支持继承吗_JavaScript继承(一)——原型链
查看>>
labview如何弹出提示窗口_LabVIEW开发者必读的问答汇总,搞定疑难杂症全靠它了!...
查看>>
提取series中的数值_Python中None和numpy.nan的区别
查看>>
hikariconfig mysql_HikariConfig配置解析
查看>>
mysql批量数据多次查询数据库_mysql数据库批量操作
查看>>
jquery 乱码 传参_jquery获取URL中参数解决中文乱码问题的两种方法
查看>>
JDBC_MySQL_jdbc连接mysql_MySQL
查看>>
新手学习python零基础_新手零基础学习Python第一步,搭建开发环境!
查看>>