Adxmi android offers order callback protocol en

来自有米广告开发者WIKI
跳转至: 导航搜索

Adxmi Android OfferWall Server Callback Protocol

Statement

  • This document is used for Android platform. For iOS platform, please refer to here:iOS Rewarded Offerwall Server Callback Interface
  • The uniform encoding of interface: UTF-8
  • Be suited to developers who use their own server to manage currency points.
  • Once Adxmi gets the feedback data from advertisers, we will report back to developers' server immediately.
  • It will need developers to offer an interface to receive data. The method for interface to receive data: GET.
  • All parameters will process [urlencode](http://php.net/manual/en/function.urlencode.php)
  • After setting callback url in [Developer Control Panel](https://www.adxmi.com/apps#/settings), Adxmi will allocate an individual secret key `$dev_server_secret` for signature using.


Procedure

  1. Developers will set up the currency points feedback address in Adxmi's developer background control panel, eg: https://www.adxmi.com/apps#/setting
  2. Once Adxmi's server receives an effective data record, it will feedback to developers' server (with GET method) with the feedback url address which is offered by developers. Relevant parameters will be will plus to the url address as below.


Parameters

Full Name Brief Name Type Statement
Order ID order string Order ID: This value is unique. If developer receives the same order ID, that means the order is already existed.
App ID app string The Application ID
Ad Name ad string The advertisement name. If the ad type is app, then the ad name is the application's name
Adid adid int Advertisement ID
User ID user string User ID: Developers can set up their own user ID. For example, if developers' apps have the login function, then user ID can be used to replace the CID identification which is offered by Adxmi. (Adxmi will generate an identification number for each device) Otherwise, Adxmi will use CID as user ID. <br/Notes: The parameters and processed by urlencode. Please use urldecode to acquire the original parameters.
Device ID device string Device ID:imei for android
Notes: The parameters and processed by urlencode. Please use urldecode to acquire the original parameters.
Channel chn int Channel ID
Revenue revenue float The revenue that developer can earn.
Points points int The currency points that users can earn.
If this value is 0, that means user won't get the currency points due to some reasons. For example, users already exceed the limited activation number.
OrderCreateTime time int The time that Adxmi create this order.
StoreId storeid string Id from application store
PackageName pkg string package name of campaign app
AdType ad_type string Value is video or offer wall.
Sign sign string Parameters signature, the signature algorithm as below.
This value is used for verify the integrity of the above parameters, to prevent the third party to tamper with them.


Signature Algorithm

Use all parameters except sign in 【Parameters】 list as key to compute MD5 value. Assume that the parameters participate in computing signature are k1,k2,k3, then the signature calculation method is below:

Formatting the non-binary type request parameters to key=value format. For example: k1=v1,k2=v2,k3=v3 Sort the key-value in ascending order and connect them together. For example: k1=v1k2=v2k3=v3 Append $dev_server_secret after the conneted key-value string. MD5 of the above string is the signature value. Notice

Don't include the sign(signature) parameters when calculating the signature. The parameters in signature procedure have not been processed by urlencode. In order to ensure the signature won't be abnormal when changing the callback parameters, please make sure using the signature function we offer as the verification method. If developer's callback url contains parameters, these parameters will also join in the signature. Encryption function implemention method as below.

Example

php:

<?php
$url = 'http://api.demo.net/postback?order=YM140927--uPMAL-c7&app=9076333dcfc7f490&ad=AdName&adid=4188&user=1067748&chn=0&points=979&revenue=1.96&time=1411751092&device=0AD80C3C-D320-AC2B-5FD3-994E2FA7A153&storeid=555610791';
$dev_server_secret = '21bd64dc2eaf91f7';
$url .= '&sign=' . getUrlSignature($url, $dev_server_secret);
var_dump($url);
 
function getUrlSignature($url, $secret){
  $params = array();
  $url_parse = parse_url($url);
  if (isset($url_parse['query'])){
    $query_arr = explode('&', $url_parse['query']);
    if (!empty($query_arr)){
        foreach($query_arr as $p){
            if (strpos($p, '=') !== false){
                list($k, $v) = explode('=', $p);
                $params[$k] = urldecode($v);
            }
        }
    }
  }
  return getSignature($params, $secret);
}
 
 function getSignature($params, $secret){
   $str = '';
   ksort($params);
   foreach ($params as $k => $v) {
     $str .= "{$k}={$v}";
   }
   $str .= $secret;
   return md5($str);
 }

java:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.TreeMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.security.MessageDigest; 
import java.security.GeneralSecurityException; 
 
public class AdxmiSign {
    /**
     * Signature Generation Algorithm
     *
     * @param HashMap<String,String> params 	Request paramenters set, all parameters need to convert to string type before this
     * @param String                 dev_server_secret 	The secret key from Adxmi Developer Control Panel Setting
     * @return String
     * @throws IOException
     */
    public static String getSignature(HashMap<String, String> params, String dev_server_secret) throws IOException {
        // Sort the parameters in ascending order
        Map<String, String> sortedParams = new TreeMap<String, String>(params);
 
        Set<Map.Entry<String, String>> entrys = sortedParams.entrySet();
        // Traverse the set after sorting, connect all the parameters as "key=value" format
        StringBuilder basestring = new StringBuilder();
        for (Map.Entry<String, String> param : entrys) {
            basestring.append(param.getKey()).append("=").append(param.getValue());
        }
        basestring.append(dev_server_secret);
        //System.out.println(basestring.toString());
        // Calculate signature using MD5
        byte[] bytes = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            bytes = md5.digest(basestring.toString().getBytes("UTF-8"));
        } catch (GeneralSecurityException ex) {
            throw new IOException(ex);
        }
        // Convert the MD5 output binary result to lowercase hexadecimal result.
        StringBuilder sign = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex);
        }
        return sign.toString();
    }
 
    /**
     * Calculate signature with a completed unsigned URL, append the signature at the end of this URL.
     * 
     * @param String url 	The completed unsigned URL
     * @param String dev_server_secret  	Secret key for calculating signature
     * @return String
     * @throws IOException, MalformedURLException
     */
    public static String getUrlSignature(String url, String dev_server_secret) throws IOException, MalformedURLException {
        try {
            URL urlObj = new URL(url);
            String query = urlObj.getQuery();
            String[] params = query.split("&");
            Map<String, String> map = new HashMap<String, String>();
            for (String each : params) {
                String name = each.split("=")[0];
                String value;
                try {
                    value = URLDecoder.decode(each.split("=")[1], "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    value = "";
                }
                map.put(name, value);
            }
            String signature = getSignature((HashMap<String, String>) map, dev_server_secret);
            return url + "&sign=" + signature;
        } catch (MalformedURLException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        }
    }
 
    /**
     * Check the completed URL with signature parameter. Check the signature is correct or not.
     * 
     * @param String url 	The completed URL with signature parameter
     * @param String dev_server_secret 	Secret key for calculating signature
     * @return boolean
     */
    public static boolean checkUrlSignature(String signedUrl, String dev_server_secret) {
        String urlSign = "";
        try {
            URL urlObj = new URL(signedUrl);
            String query = urlObj.getQuery();
            String[] params = query.split("&");
            Map<String, String> map = new HashMap<String, String>();
            for (String each : params) {
                String name = each.split("=")[0];
                String value;
                try {
                    value = URLDecoder.decode(each.split("=")[1], "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    value = "";
                }
                if ("sign".equals(name)) {
                    urlSign = value;
                } else {
                    map.put(name, value);
                }
            }
            if ("".equals(urlSign)) {
                return false;
            } else {
                String signature = getSignature((HashMap<String, String>) map, dev_server_secret);
                return urlSign.equals(signature);
            }
        } catch (MalformedURLException e) {
            return false;
        } catch (IOException e) {
            return false;
        }
    }
}

object-c:

//
//  AppDelegate.m
//  sign
//
//  Created by Enzo Yang on 11/7/14.
//  Copyright (c) 2014 Adxmi. All rights reserved.
//
 
#import "AppDelegate.h"
#import <CommonCrypto/CommonHMAC.h>
 
 
@interface URLSigner : NSObject
 
// Get URL signature accoring to parameters searching
- (NSString *)generateSignWithDict:(NSDictionary *)params serverSecret:(NSString *)serverSecret;
 
@end
 
@implementation URLSigner
 
- (NSString *)generateSignWithDict:(NSDictionary *)params serverSecret:(NSString *)serverSecret {
    NSArray *keys = [params allKeys];
 
    // Sort keys using alphabet order
    NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2 options:NSLiteralSearch];
    }];
 
    // Connect the stings with format k1=v1k2=v2 using ascending order
    NSMutableString *str = [[NSMutableString alloc]init];
    for (NSString *key in sortedKeys) {
        [str appendString:[NSString stringWithFormat:@"%@=%@", key, [params objectForKey:key]]];
    }
 
    // append secret key string
    [str appendString:serverSecret];
 
    // get signature using MD5
    return [self md5HexDigest:str];
}
 
- (NSString*)md5HexDigest:(NSString*)input {
    const char* str = [input UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, (uint32_t)(strlen(str)), result);
 
    // 32 bits lowercase MD5
    NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [ret appendFormat:@"%02x",result[i]];
    }
 
    return ret;
}
 
 
@end

Notes:

  1. $dev_server_secret: The secret key from developers' server, offered by Adxmi. Enter this page "http://www.adxmi.com/apps#/setting" after logging, find the rewarded ads callback method setting-server callback setting, and set up the server address. After successfully setting, a secret key will be assigned to your app.
    , you can inquire the key in the developers back end control panel.
  2. $order: The parameter order in interface, like the others parameters.
  3. $user、$ad、$device:It is the original parameters which are involved in signature. It will use urlencode when transferring. So you should use original parameters when verifying sig.


Verification of signature parameters

Statements:In the early stage of integrating advertisement SDK, developers might find it fail to pass the verification, then this verification interface will be needed to verify. 
Of course, you can also contact our customer service directly. Normal verification logic will be implemented by developers themselves.

Supposed that developers receive the feedback request from Adxmi is:

http://api.developer.com/adxmi.php?order=YM130402cygr_UTb42&app=30996ced018a2a5e&ad=KC%E7%BD%91%E7%BB%9C%E7%94%B5%E8%AF%9D&user=1141058&device=50ead626ae6e&chn=0&points=7&time=1364890524&sig=15b3dfe0&adid=100&pkg=abc

Just replace the prefix http://api.kaifazhe.com/adxmi.php with http://aos.wall.youmi.net/v2/check_fb_sig and do some tests:

http://aos.wall.youmi.net/v2/check_fb_sig?order=YM130402cygr_UTb42&app=30996ced018a2a5e&ad=KC%E7%BD%91%E7%BB%9C%E7%94%B5%E8%AF%9D&user=1141058&device=50ead626ae6e&chn=0&points=7&time=1364890524&sig=15b3dfe0&adid=100&pkg=abc


Return Value

  1. Adxmi will proceed the next operation according to the returning http status code from developers' server. The normal http status code should be 200 or 403.
  2. If the http status code is 200, that means developers already received and processed the message normally.
  3. If the http status code is 403, that means developers refuse this request, which also means middle-tier server will not repeatedly make request to developers' server.
  4. If timeout, or the http status code isn't one of 2xx, 301, 302, 303, 307, 400 and 403, the middle-tier server will make request to developers' server again in the next cycle.
  5. There will be delays in the next cycle request to developers' server, the delay time will respectively be: 5s, 10s, 60s, 300s, 600s, 3600s(since last request). Which means, in the worst case, Adxmi will send seven requests. If all of the seven requests fail, the link will be discarded.
  6. Because of network issues or other reasons, developers' server will receive multiple records with the same order ID. In this case, developers' server need to abandon the duplicate records, and output with http status code 403.