From my Android app, I'd like to publish its install back to facebook to allow for conversion tracking for their new mobile app install ads, but I'd like to do it without using their api.
So instead of doing
com.facebook.Settings.publishInstall(context, appId);
I'd like to just send a HTTP request with the required parameters to some URL.
EDIT:
I logged the two requests that get sent to facebook to publish the app install and they look like this:
Request:
GET /[app id]?format=json&sdk=android&fields=supports_attribution HTTP/1.1
User-Agent: FBAndroidSDK.3.0.0.b
Content-Type: multipart/form-data; boundary=3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Host: graph.facebook.com
Connection: Keep-Alive
Accept-Encoding: gzip
Response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Type: text/javascript; charset=UTF-8
ETag: "24ea6554744eece05b90dd2e65af63277cdcaf53"
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: no-cache
X-FB-Rev: 658994
X-FB-Debug: P2GE3fDVAnRJh62rBS5WXD4ce1hTy8Pwvjq5rT/I+TI=
Date: Tue, 30 Oct 2012 11:37:09 GMT
Connection: keep-alive
Content-Length: 52
{"supports_attribution":true,"id":"[app id]"}
Request:
POST /[app id]/activities?format=json&sdk=android&migration_bundle=fbsdk%3A20120913 HTTP/1.1
User-Agent: FBAndroidSDK.3.0.0.b
Content-Type: multipart/form-data; boundary=3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Host: graph.facebook.com
Connection: Keep-Alive
Transfer-Encoding: chunked
Accept-Encoding: gzip
261
--3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Content-Disposition: form-data; name="format"
json
--3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Content-Disposition: form-data; name="sdk"
android
--3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Content-Disposition: form-data; name="migration_bundle"
fbsdk:20120913
--3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Content-Disposition: form-data; name="attribution"
ab175007-2725-464f-a111-b8b1a92bf1dd
--3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
Content-Disposition: form-data; name="event"
MOBILE_APP_INSTALL
--3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f
0
Response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Type: text/javascript; charset=UTF-8
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: no-cache
X-FB-Rev: 658994
X-FB-Debug: +0GWQ4cu+tFeAg3QEuwYGx+HAt7t37itzxEYBaTZF8U=
Date: Tue, 30 Oct 2012 11:38:33 GMT
Connection: keep-alive
Content-Length: 4
true
I've included a trimmed down version of the facebook api in my app that cannot do anything else, but just send those two requests. I'll try it out and report back on how it works.
Optimally, I'd like to send the requests from a server and not from the phone at all.
You can do this with simple call
FacebookHelper.appInstall(this.getApplicationContext(), "<com.your.package>",
"<your facebook app id>");
and library below.
Remember that you can track application only if facebook app is installed - then you have attributionId. If you would like to send this request on server you have to send attributionId to your server.
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import java.io.IOException;
import java.nio.charset.Charset;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public class FacebookHelper {
private static final Uri ATTRIBUTION_ID_CONTENT_URI =
Uri.parse("content://com.facebook.katana.provider.AttributionIdProvider");
private static final String ATTRIBUTION_ID_COLUMN_NAME = "aid";
private static final String USER_AGENT = "FBAndroidSDK/3.5.0";
private final DefaultHttpClient mHttpClient;
private final String mApplicationPackage;
private final String mApplicationId;
private FacebookHelper(String applicationPackage, String applicationId) {
checkNotNull(applicationPackage);
checkNotNull(applicationId);
mApplicationPackage = applicationPackage;
mApplicationId = applicationId;
mHttpClient = new DefaultHttpClient();
}
private static String getAttributionId(ContentResolver cr) {
checkNotNull(cr);
final String [] projection = {ATTRIBUTION_ID_COLUMN_NAME};
final Cursor cursor = cr.query(ATTRIBUTION_ID_CONTENT_URI, projection,
null, null, null);
if (cursor == null) {
return null;
}
try {
if (!cursor.moveToFirst()) {
return null;
}
final int attributionColumnIndex = cursor.getColumnIndex(ATTRIBUTION_ID_COLUMN_NAME);
if (attributionColumnIndex < 0) {
return null;
}
return cursor.getString(attributionColumnIndex);
} finally {
cursor.close();
}
}
public static void appInstall(Context applicationContext, String applicationPackage,
String applicationId) throws IOException {
checkNotNull(applicationContext);
checkNotNull(applicationPackage);
checkNotNull(applicationId);
final ContentResolver cr = applicationContext.getContentResolver();
final String attributionId = getAttributionId(cr);
if (attributionId == null) {
// we can not send anything if facebook app is not installed
return;
}
final FacebookHelper facebookHelper = new FacebookHelper(applicationPackage, applicationId);
facebookHelper.appInstall(attributionId);
}
private void appInstall(String attribution) throws IOException {
checkNotNull(attribution);
String url = String.format("https://graph.facebook.com/%s/activities", mApplicationId);
MultipartEntity entity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
Charset charset = Charset.forName(HTTP.UTF_8);
entity.addPart("sdk", new StringBody("android", charset));
entity.addPart("format", new StringBody("json", charset));
entity.addPart("event", new StringBody("MOBILE_APP_INSTALL", charset));
entity.addPart("attribution", new StringBody(attribution, charset));
entity.addPart("auto_publish", new StringBody("false", charset));
entity.addPart("application_tracking_enabled", new StringBody("true", charset));
entity.addPart("migration_bundle", new StringBody("fbsdk:20130708", charset));
entity.addPart("application_package_name", new StringBody(mApplicationPackage, charset));
HttpEntityEnclosingRequestBase request = new HttpPost(url);
setupDefaultHeaders(request);
request.setEntity(entity);
HttpResponse response = getHttpClient().execute(request);
validateResponseCode(response, HttpStatus.SC_OK);
}
private void validateResponseCode(HttpResponse response,
int expectedStatusCode) throws IOException {
checkNotNull(response);
checkArgument(expectedStatusCode != HttpStatus.SC_UNPROCESSABLE_ENTITY);
checkArgument(expectedStatusCode != HttpStatus.SC_NOT_FOUND);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != expectedStatusCode) {
throw new IOException("Wrong response code: "+
"expected <" +expectedStatusCode +"> was <" +statusCode+">");
}
}
private HttpClient getHttpClient() {
return mHttpClient;
}
private void setupDefaultHeaders(HttpRequestBase request) {
checkNotNull(request);
request.setHeader("Accept", "application/json");
request.setHeader("User-Agent", USER_AGENT);
}
}
this library use guava checkArgument and checkNotNull if you do not use guava you can just skip those lines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With