›Discovery SDK

    Overview

    • SDK Information

    Location Optimised SDK

    • LO - iOS SDK
    • LO - Android SDK
    • LO - React Native

    Discovery SDK

    • LOD - iOS SDK
    • LOD - Android SDK

    LOD - Android SDK

    v 2.0.0 (released 02-04-2026)

    Support

    • The LandmarksID SDK LOD supports Android 8.0 Oreo (API 26) and above.
    • Compile SDK: 36
    • Target SDK: 36
    • Java 17

    User Permissions

    Normal permissions (such as INTERNET, FOREGROUND_SERVICE, and FOREGROUND_SERVICE_LOCATION) are declared in the SDK manifest and will be merged automatically.

    Your app must declare the following dangerous permissions in its AndroidManifest.xml and request them at runtime:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    
    • ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION — Required for location services. Must be requested at runtime.
    • ACCESS_BACKGROUND_LOCATION — Required for location updates while the app is in the background. On Android 10+ this must be requested separately from foreground location permissions.

    The SDK does not request permissions itself. The host application is responsible for requesting location permissions and forwarding the results to the SDK.

    Setup Instructions

    Installation

    1. Add the credentials provided by LANDMARKSID to ~/.gradle/gradle.properties:
    gpr.key=YOUR_ACCESS_TOKEN
    

    The access token will be provided by LANDMARKSID.

    1. Open your root build.gradle file and add the GitHub Packages repository:
    allprojects {
      repositories {
        ...
        maven {
            name = "GitHubPackages-LOD"
            url = uri("https://maven.pkg.github.com/LANDMARKSID/sdk-android-lod")
            credentials {
                username = "LANDMARKS-ID"
                password = project.findProperty("gpr.key")
            }
        }
      }
    }
    
    1. Add the dependency in your app-level build.gradle:
    dependencies {
      implementation 'com.landmarksid:landmarks-android-sdk-lod:2.0.0'
    }
    

    Initialisation

    Application Class

    Add the following line inside the Application class's onCreate() method:

    LandmarksID.getInstance().initMetaData(getApplicationContext());
    

    Starting the SDK

    In your main activity's onCreate() method, initialise and start the LandmarksID SDK:

    landmarksId = LandmarksID.getInstance().start(this, options);
    

    .start() accepts two arguments — a context and an Options object (described in detail below) — and returns an instance of the LandmarksID SDK.

    Configuration

    A typical Options builder would look something like this:

    Options options = new Options()
                    .setApiKey(API_KEY)
                    .setAppMetadata(APP_ID, APP_SECRET)
                    .setCustomerId("sample-id")
                    .setCustomData(customData);
    

    All constants in upper case are to be obtained/clarified with LandmarksID, and are not part of the SDK itself.

    Permission Handling (Mandatory)

    The host app must request location permissions and forward the results to the SDK. The SDK automatically detects when location permissions are granted and starts location services. No additional calls are needed — just forward the result.

    The SDK processes any permission result that includes ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION, regardless of the request code used by the application.

    Option A: AndroidX Activity Result API (Recommended)

    private final ActivityResultLauncher<String[]> locationPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), results -> {
                landmarksId.onRequestPermissionsResult(this, results);
            });
    
    // To request permissions:
    locationPermissionLauncher.launch(new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION
    });
    

    Option B: Legacy onRequestPermissionsResult

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        landmarksId.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }
    

    Background Location Permission

    The LOD SDK requires ACCESS_BACKGROUND_LOCATION for geofencing and location services to work while the app is in the background. On Android 10+, background location must be requested separately from foreground location permissions.

    Recommended flow:

    1. Request foreground location permissions first (ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION).
    2. After foreground permission is granted, prompt the user and request ACCESS_BACKGROUND_LOCATION.
    3. On Android 10 (Q), the background permission can be requested via the system dialog.
    4. On Android 11+, the user must be directed to the app settings page to grant "Allow all the time".
    private final ActivityResultLauncher<String> backgroundPermissionLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
                // Background permission result handled
            });
    
    private void requestBackgroundPermission() {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            // Android 10: can request via system dialog
            backgroundPermissionLauncher.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            // Android 11+: must redirect to app settings
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.setData(Uri.fromParts("package", getPackageName(), null));
            startActivity(intent);
        }
    }
    

    Additional Controls

    Custom Data (Optional)

    .setCustomData(CustomData)

    User data that is collected by, or made available to, the application can be passed into the LandmarksID SDK, as custom values. Use this method to pass along a set of key-value pairs constructed using the provided CustomData class. These will be recorded by the LandmarksID SDK with each location event. Multiple custom values can be passed into the method.

    CustomData customData = new CustomData();
    customData.addString("country", "Germany");
    customData.addInt("code", 49);
    customData.addFloat("score", 23.58f);
    

    At the moment, the supported types are String, int, and float. CustomData is an extension of HashSet, and exhibits the same behavior with one notable difference: in case an entry with a duplicate key is added, only the one added last would be kept.

    Putting It All Together

    public class LocationAwareApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            LandmarksID.getInstance().initMetaData(getApplicationContext());
        }
    }
    
    public class MainActivity extends AppCompatActivity {
        private static final String API_KEY = "<YOUR_API_KEY>";
        private static final String APP_ID = "<YOUR_APP_ID>";
        private static final String APP_SECRET = "<YOUR_APP_SECRET>";
    
        private LandmarksID landmarksId;
    
        private final ActivityResultLauncher<String[]> locationPermissionLauncher =
                registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), results -> {
                    landmarksId.onRequestPermissionsResult(this, results);
    
                    boolean hasFine = ContextCompat.checkSelfPermission(this,
                            Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
                    boolean hasBackground = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q ||
                            ContextCompat.checkSelfPermission(this,
                                    Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
    
                    if (hasFine && !hasBackground) {
                        requestBackgroundPermission();
                    }
                });
    
        private final ActivityResultLauncher<String> backgroundPermissionLauncher =
                registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
                    // Background permission result handled
                });
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            CustomData customData = new CustomData();
            customData.addString("country", "Germany");
            customData.addInt("code", 49);
            customData.addFloat("score", 23.58f);
    
            Options options = new Options()
                    .setApiKey(API_KEY)
                    .setAppMetadata(APP_ID, APP_SECRET)
                    .setCustomerId("sample-id")
                    .setCustomData(customData);
    
            landmarksId = LandmarksID.getInstance().start(this, options);
    
            // Request foreground location permissions
            locationPermissionLauncher.launch(new String[] {
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION
            });
        }
    
        private void requestBackgroundPermission() {
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
                backgroundPermissionLauncher.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                intent.setData(Uri.fromParts("package", getPackageName(), null));
                startActivity(intent);
            }
        }
    }
    

    Upgrading from 1.x

    Breaking Changes

    1. SDK distribution moved from JitPack to GitHub Packages — Remove JitPack from your repository configuration and replace with GitHub Packages as described in the Installation section above.

      // Before (remove this)
      maven {
          url "https://jitpack.io"
          credentials { username "<accessToken>" }
      }
      
      // Before (remove this)
      implementation 'com.gitlab.landmarksid:sdk-android-lod:1.6.x'
      
      // After
      implementation 'com.landmarksid:landmarks-android-sdk-lod:2.0.0'
      
    2. LandmarksID.Options is now a standalone Options class — Previously LandmarksID.Options, now com.landmarksid.android.Options.

      // Before
      LandmarksID.Options options = new LandmarksID.Options()
              .setApiKey(API_KEY);
      
      // After
      Options options = new Options()
              .setApiKey(API_KEY);
      
    3. setLocationUsable(Activity) is deprecated — The SDK now handles permission state automatically when you call onRequestPermissionsResult(). Remove all calls to setLocationUsable().

      // Before
      @Override
      public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
          landmarksId.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
          if (permissionGranted) {
              landmarksId.setLocationUsable(this);  // REMOVE THIS
          }
      }
      
      // After — Option A: AndroidX Activity Result API (recommended)
      private final ActivityResultLauncher<String[]> locationPermissionLauncher =
              registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), results -> {
                  landmarksId.onRequestPermissionsResult(this, results);
              });
      
      // After — Option B: Legacy callback
      @Override
      public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
          landmarksId.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
          // That's it — the SDK handles the rest
      }
      
    4. setLocationUsable() should not be called at startup — Previously some apps called setLocationUsable() immediately after start() to bootstrap location services. This is no longer needed.

      // Before
      landmarksId = LandmarksID.getInstance().start(this, options);
      landmarksId.setLocationUsable(this);  // REMOVE THIS
      
      // After
      landmarksId = LandmarksID.getInstance().start(this, options);
      
    5. CustomData import changed — Import changed to com.landmarksid.lo.types.CustomData.

    6. EventListener interface updated — If your app implements EventListener, it now extends com.landmarksid.lo.logging.EventLogListener. You may need to implement additional methods from the parent interface.

    7. Background location requires separate handling — ACCESS_BACKGROUND_LOCATION must be requested separately from foreground permissions on Android 10+. See the Background Location Permission section above for the recommended flow.

    Contact Details

    If you have any further questions please do not hesitate to contact our friendly team at;

    developers@landmarksid.com

    ← LOD - iOS SDK
    • v 2.0.0 (released 02-04-2026)
    • Support
    • User Permissions
    • Setup Instructions
      • Installation
      • Initialisation
    • Permission Handling (Mandatory)
      • Option A: AndroidX Activity Result API (Recommended)
      • Option B: Legacy onRequestPermissionsResult
      • Background Location Permission
    • Additional Controls
      • Custom Data (Optional)
    • Putting It All Together
    • Upgrading from 1.x
      • Breaking Changes
    • Contact Details
    Docs
    LandmarksID SDK overviewLocation Optimised SDK with DiscoveryLocation Optimised SDK
    LandmarksID
    Copyright © 2026 LandmarksID