factual

Factual Developer Documenation

Welcome to the factual-devdocs developer hub. You'll find comprehensive guides and documentation to help you start working with factual-devdocs as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

Android

Getting Started

The steps below will guide you through installing the Engine SDK into your app via Android Studio and Java.

After completing the Getting Started guide please refer to the rest of our developer docs for examples of how to:


1. Ensure the SDK requirements are met

  • The Engine SDK is compatible with API level 21 or higher.
  • After compilation, the SDK should add approximately 1.5 MB to your app's download size.
  • The SDK requires ACCESS_FINE_LOCATION and INTERNET permissions.

2. Get an API key

Sign up for access to Engine here.


3. Add Repositories and Dependencies

Provided below are examples of how to install the SDK via Maven (3a) or to install manually (3b)


3a. Install via Maven

Add the Factual and Maven Central repository to your app/build.gradle:

repositories {
  mavenCentral()
  maven { url "https://factual.bintray.com/maven" }
}

Add the Engine dependencies to app/build.gradle:

Make sure to use the latest engine version by replacing [ENGINE_VERSION] in the code below with the latest version available in Bintray

dependencies {
  // Existing Dependencies
  ...

  // Third party libraries used by the Engine SDK:
  implementation 'com.android.volley:volley:1.1.0'
  implementation('com.google.android.gms:play-services-location:16.0.0', {
    exclude group: 'com.android.support', module: 'support-v4'
  })
  implementation 'org.apache.thrift:libthrift:0.9.3'
  implementation 'com.google.android.gms:play-services-analytics:16.0.4'

  implementation "android.arch.lifecycle:extensions:1.1.1"
  annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
 
  // The Engine Library:
  implementation 'com.factual:engine-sdk:[ENGINE_VERSION]'
}

You may need to exclude META-INF/DEPENDENCIES by adding a packagingOptions block under android in your app/build.gradle:

android {
  ...
  packagingOptions {
    exclude 'META-INF/DEPENDENCIES'
  }
}

3b. Install manually

Add Maven and the path to the AAR as repositories in your app/build.gradle:

repositories {
  // Volley and Thrift are found here
  mavenCentral()

  flatDir {
  // Path to the AAR, relative to your project's "app" dir.
  dirs "libs"
  }
}

dependencies {
  ...

Add the AAR and dependencies to app/build.gradle:

dependencies {
  // Existing Dependencies
  ...

  // Third party libraries used by the Engine SDK:
  implementation 'com.android.volley:volley:1.1.0'
  implementation('com.google.android.gms:play-services-location:16.0.0', {
    exclude group: 'com.android.support', module: 'support-v4'
  })
  implementation 'org.apache.thrift:libthrift:0.9.3'
  implementation 'com.google.android.gms:play-services-analytics:16.0.4'

  implementation "android.arch.lifecycle:extensions:1.1.1"
  annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
 
  // The Engine AAR:
  implementation(name: 'factual-engine-sdk-android', ext: 'aar')
}

You may need to exclude META-INF/DEPENDENCIES by adding a packagingOptions block under android in your app/build.gradle:

android {
  ...
  packagingOptions {
    exclude 'META-INF/DEPENDENCIES'
  }
}

4. Location Permissions and Service Registration

In AndroidManifest.xml under the application label, add the following service information:

...
    <service
        android:name="com.factual.engine.FactualJobIntentService"
        android:permission="android.permission.BIND_JOB_SERVICE"
        android:exported="false" />
  </application>
...

Also add your receiver that extends FactualClientReceiver. For example:

...
    <service
        android:name="com.factual.engine.FactualJobIntentService"
        android:permission="android.permission.BIND_JOB_SERVICE"
        android:exported="false" />
    <receiver android:name=".ConsoleLoggingFactualClientReceiver"/>
  </application>
...

Additionally, AndroidManifest.xml should include the following permissions:

 ...
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
  <uses-feature android:name="android.hardware.location.gps" />
  <uses-feature android:name="android.hardware.location.network" />
  
  <application
  ...
</manifest>

The SDK does NOT prompt for these permissions on its own. We've deliberately left that to you, so that you can lump in any other permissions you may require, as well as choose the method and timing of the prompt as you require.


5. Follow the sample implementation

The example Android code below will initialize and start Engine, in conjunction with the required permission checks. Once complete, the ConsoleLoggingFactualClientReceiver will print out basic information like when the SDK has started among other things.

A few things to note:

  • The SDK detects which location permissions your app has requested. It will not request any location authorizations on its own. This example contains boilerplate code for seeking the permissions.
  • The receiver allows your app to receive info from the SDK in the foreground and background.
package com.factual.androidwalkthrough;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;

import com.factual.engine.api.FactualException;
import com.factual.engine.FactualEngine;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    try {
      initializeEngine();
      /*
       *   We leave checking/obtaining location permissions to you, so that you can lump in
       *   any other permissions you may require, as well as choose the method and timing of the
       *   prompt.
       *
       *   Therefore, the following is for illustrative purposes:
       */
      if (isRequiredPermissionAvailable()) {
        startEngine();
      } else {
        requestLocationPermissions();
      }
    } catch (FactualException e) {
      Log.e("engine", e.getMessage());
    }
  }

  public void initializeEngine() throws FactualException {
    FactualEngine.initialize(this, "your api-key goes here"); // TODO: Put your API key here
    // ConsoleLoggingFactualClientReceiver extends FactualClientReceiver, the BroadcastReceiver version of FactualClientListener
    FactualEngine.setReceiver(ConsoleLoggingFactualClientReceiver.class);
  }

  private void startEngine() {
    try {
      FactualEngine.start();
    } catch (FactualException e) {
      Log.e("engine", e.getMessage());
    }
  }

  // example permissions boilerplate
  @Override
  public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    if (isRequiredPermissionAvailable()) {
      startEngine();
    } else {
      Log.e("engine", "Necessary permissions were never provided.");
    }
  }

  public boolean isRequiredPermissionAvailable(){
    return ContextCompat.checkSelfPermission(this,
        Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
        ContextCompat.checkSelfPermission(this,
            Manifest.permission.INTERNET) == PackageManager.PERMISSION_GRANTED;
  }

  public void requestLocationPermissions() {
    ActivityCompat.requestPermissions(
        this,
        new String[]{
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.INTERNET
        },
        0);
  }
}
package com.factual.androidwalkthrough;

import android.content.Context;
import android.util.Log;

import com.factual.engine.api.FactualConfigMetadata;
import com.factual.engine.api.FactualError;
import com.factual.engine.api.FactualInfo;
import com.factual.engine.FactualClientReceiver;

public class ConsoleLoggingFactualClientReceiver extends FactualClientReceiver {
  @Override
  public void onContext(Context context) {
    // If you need fields from the context
  }

  @Override
  public void onStarted() {
    Log.i("engine", "Engine has started.");
  }

  @Override
  public void onStopped() {
    Log.i("engine", "Engine has stopped.");
  }

  @Override
  public void onError(FactualError e) {
    Log.i("engine", e.getMessage());
  }

  @Override
  public void onInfo(FactualInfo i) {
    Log.i("engine", i.getInfo());
  }

  @Override
  public void onSyncWithGarageComplete() {
    Log.i("engine", "Garage synced.");
  }

  @Override
  public void onConfigLoad(FactualConfigMetadata data) {
    Log.i("engine", "Garage config loaded at: " + data.getVersion());
  }

  @Override
  public void onDiagnosticMessage(String diagnosticMessage) {
    // Delivers structured diagnostic data that is helpful for Factual when evaluating performance
    // and diagnosing issues.
  }
}

6. Insert your API Key

In MainActivity.java in the code example above, you'll need to provide your API key:

FactualEngine.initialize(this, "your API Key Goes Here");

Further Code Examples

Look through the rest of our developer docs for examples on how to:

Android


Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.