Nodle Documentation
  • Introduction
  • Vision and Mission
  • Nodle IoT
  • Nodle App
  • Nodle Client
  • Nodle Portal
  • NODL Token
  • NFT Minting Tool
  • Nodle Explorer
  • Participate
  • Subquery Indexer
  • Nodle APIs
  • Nodle Parachain
  • Parachain Modules
  • Nodle SDK
  • Nodle Android SDK
  • Nodle iOS SDK
  • Smart Missions
  • Appendix
  • Glossary
Nodle Documentation
Nodle Documentation
Nodle Android SDK

Nodle Android SDK

Getting Started

IntroductionIntroductionVision and MissionVision and Mission

For Users

Nodle IoTNodle IoTNodle AppNodle AppNodle ClientNodle ClientNodle on zkSync EraNodle on zkSync EraNodle PortalNodle PortalNODL TokenNODL TokenNodle ExplorerNodle ExplorerParticipateParticipate

For Developers

SubQuery IndexerSubQuery IndexerNodle APIsNodle APIsNodle SDKNodle SDKNodle Android SDKNodle Android SDKNodle iOS SDKNodle iOS SDKSmart MissionsSmart Missions

More Info

AppendixAppendixGlossaryGlossary

Android SDK Integration

Integrating the Nodle SDK into your android app is easy and straightforward.

  1. Generate Developer Key
    • Create a Nodle account
    • Make sure you save your private key!
    • Copy your public_key from the extension
    • Proceed with the next steps
  2. Add the Maven Repository: Add the code below in your project's build.gradle to add the Nodle repository. We will be migrating our SDKs to a new maven repository. Please make sure to use that one from now on:
  3. buildscript {
    repositories {
    google()
    maven {
    url "http://maven.nodle.io"
    allowInsecureProtocol = true
    }
    }
    }
    allprojects {
    repositories {
    google()
    maven {
    url "http://maven.nodle.io"
    allowInsecureProtocol = true
    }
    }
    }

    If you are using Android Studio Bumblebee and newer AGP 7.0.2+ and GP 7.0.2+ please use the following in your settings.gradle

    dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
    maven {
    url "http://maven.nodle.io"
    allowInsecureProtocol = true
    }
    }
    }

    If you are using Java as your language of choice please make sure to use the default Java Library version which is JDK 11 as of Android Studio. Like that you can make sure your project works as expected between the Kotlin-Java and vice-versa compatibility. You can do that by following this path: Project Structure -> SDK Location -> Gradle Settings -> Gradle Projects -> Gradle JDK -> Select 11 or later.

  4. Add the NodleSDK dependency: In your app module's build.gradle simply add the Nodle SDK dependency in gradle. Please note that nodlesdk depends by default on google play service. If your app runs on devices that doesn't have google play service, you can use a different flavour of the nodlesdk that doesn't depend on google play services.
    • Default (depends on Google Play services)
    • // Top level gradle
      	buildscript {
      dependencies {
      classpath 'com.google.gms:google-services:4.3.10'    // Google Services plugin
      }
      }
      // Module Gradle
      dependencies {
      implementation 'io.nodle:nodlesdk-rc-lp:94207dd00f'
      // additional dependencies may be required when using getEvents
      implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
      }
    • Without Google Play Services
    • // Module Gradle
      dependencies {
      implementation 'io.nodle:nodlesdk-rc-lg:94207dd00f'
      // additional dependencies may be required when using getEvents
      implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
      }

      If you are using the Google Play Services version please make sure to add the plugin. You can use the libraries we are using or the newest ones. We would try to support always the latest libraries. The minAPI:19 and maxAPI:31. We are also on the latest version of AGP 7.1.3+ and Kotlin 1.6.21+. The latest version of the SDK - GP is 94207dd00f 

  5. Initialize the Nodle SDK: You must declare your application class in your ApplicationManifest.xml. And, declare the required permissions for Nodle to be able to run:
    • Android Manifest
    • In the onCreate method of your application class you should initialize Nodle like this:

    • Java | Kotlin
    • import io.nodle.sdk.android.Nodle
      class App : Application() {
      override fun onCreate() {
      super.onCreate()
      Nodle.init(this)
      }
      }

      After you have verified that you have the required permissions in the manifest and you are initializing Nodle, then you can proceed with the next steps. When passing (this) to Nodle, you will pass your application Context. This way, Nodle will be able to stay alive in your global application state.

  6. Check Permission: The SDK expects a certain number of permission to be set. You must make sure that to request the following permissions from the user:
    • INTERNET
    • BLUETOOTH - API 30 and BELOW
    • BLUETOOTH_ADMIN - API 30 and BELOW
    • ACCESS_FINE_LOCATION
    • ACCESS_COARSE_LOCATION
    • ACCESS_BACKGROUND_LOCATION - API 29 and ABOVE
    • BLUETOOTH_SCAN - API 31 (ANDROID 12)
    • BLUETOOTH_ADVERTISE - API 31 (ANDROID 12)
    • BLUETOOTH_CONNECT - API 31 (ANDROID 12)
    • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS - required for extended background capabilities
    • SCHEDULE_EXACT_ALARM - required for extended background capabilities
    • In order for NodleSDK to be able to work while in the background we require the ACCESS_BACKGROUND_LOCATION, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, SCHEDULE_EXACT_ALARM which Google Play Store has updated it's policy and require extra steps for verification in Google Play Stores requiring the application developer to submit a video of the permissions usage. If you can't provide the requested usage description you can always strip the permission's like this:

      <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:node="remove" />
      <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" tools:node="remove" />
      <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" tools:node="remove" />

      Below you can find a simple solution to request all the mandatory permissions that the SDK require to operate. You aren't limited to using our permissions request and you can use any other third party provider that you like:

      If you decide to use a third party please follow their guide on how to install and setup the request. After permissions are requested and given the NodleSDK should work as expected.

  7. Allow the NodleSDK extended background capabilities: We have provided/extended the SDK capabilities for developers to keep our SDK in the background even further. To allow the SDK extended capabilities, we do require the following permissions: ACCESS_BACKGROUND_LOCATION, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, SCHEDULE_EXACT_ALARM. Additionally the capabilities for the SDK can be enabled/disabled dependening on what the developer would like to do. To enable the capabilities you can do the following:
    • Java | Kotlin
    • Nodle.Nodle().config("heartbeat.background-mode", true)
      Nodle.Nodle().config("ble.background-mode", true)

      The first capability will extend the SDK lifecycle to be able to operate when in the background and even when the phone is in Doze mode. The second capability will enable the SDK to perform additional BLE scanning when in the background.

  8. Run the Nodle SDK

In the onCreate method of your launcher activity start Nodle by giving it the ss58:public_key generated in Step 1:

  • Java | Kotlin
Nodle().start("ss58:public_key")

And there you have it! You’re good to go!

Checking Your SDK rewards

Currently we have our dashboard under development and rewards are not available. If you want see your rewards please go to our Nodle Subscan please follow the steps:

  • Copy your public_key and paste it in the search bar
  • Scroll down the page after it loads and navigate to allocations
  • You should see you rewards which are allocated every 2 hours

Make sure to add all permissions to the SDK in order to see your rewards. We have a lot of traffic so please bear with us since rewards might take a bit of time. But if you allow all the rules in SDK you should see the packets coming to the dashboard. Then rewards should be visible.

SDK Configuration

The SDK receives configuration remotely from Nodle servers as well as statically using API calls. The static configuration always takes precedence over the remote configuration.

Nodle SDK API

To interact with the SDK you need to call the Nodle() method that will give you an Instance of the INodle class. The following are all the public methods for the Nodle API.

Java

import static io.nodle.sdk.android.Nodle.Nodle;INodle nodle = Nodle();

Kotlin

import io.nodle.sdk.android.Nodle.Nodleval nodle = Nodle()

init

public fun init(context: Context)

Initialize the Nodle SDK

Parameters
context
A Context of the application. This value must never be null.

Example:

Java

Nodle.init(this);

Kotlin

Nodle.init(this)

start

public fun start(public_key: String)

Immediately starts the Nodle SDK

Parameters
public_key
The application public_key created in Step 1

Example:

Java

Nodle().start("ss58:public_key");

Kotlin

Nodle().start("ss58:public_key")

isStarted

public fun isStarted(): Boolean

Checks if the Nodle SDK is started

Parameters
boolean
true if the Nodle SDK is started, false otherwise

Example:

Java

Boolean sdkStarted = Nodle().isStarted()

Kotlin

val sdkStarted = Nodle().isStarted()

isScanning

public fun isScanning(): Boolean

Checks if the Nodle SDK is currently scanning the BLE neighborhood. This is useful if you want to show that the SDK is working.

Parameters
boolean
true if the Nodle SDK is scanning, false otherwise

Example:

Java

Boolean sdkScanning = Nodle().isScanning()

Kotlin

val sdkScanning = Nodle().isScanning()

stop

public fun stop()

Immediately stops the Nodle SDK

Example:

Java

Nodle().stop();

Kotlin

Nodle().stop()

clear

public fun clear()

Clear any configs by Nodle SDK

Example:

Java

Nodle().clear();

Kotlin

Nodle().clear()

getVersion

public fun getVersion(): String

Get the version identifier of the Nodle SDK.

Parameters
String
the current version of the Nodle SDK

Example:

Java

String nodleSdkVersion = Nodle().getVersion();

Kotlin

val nodleSdkVersion = Nodle().getVersion()

getEvents

public fun getEvents(): NodleEvent

Get the raw bluetooth events from the Nodle SDK with the following type:

Returns
NodleEventType.BlePayloadEvent
Returns NodleBluetoothScanRecord
NodleEventType.BleStartSearching
Returns NodleBluetoothEvent
NodleEventType.BleStopSearching
Returns NodleBluetoothEvent

Example of available return event classes below:

Returns
NodleBluetoothScanRecord
Raw Bluetooth Record from Nodle SDK
NodleBluetoothEvent
Bluetooth Event when the SDK start/stop

Example:

Java

BuildersKt.launch(GlobalScope.INSTANCE, (CoroutineContext) Dispatchers.getMain(), CoroutineStart.DEFAULT,
(Function2<CoroutineScope, Continuation<? super Unit>, Unit>) (coroutineScope, continuation) -> {
// start collecting events
nodle.getEvents().collect(new NodleCollector(), new NodleContinuation());
return Unit.INSTANCE;
}
);

Example: Nodle Collector for Java:

Example: Nodle Continuation for Java

Kotlin

The following data can be collected from the NodleEventType:

Key
Description
Default Value
type
returns nodle bluetooth event type
NodleEventType

The following data can be collected from the NodleBluetoothScanRecord:

Key
Description
Default Value
device
returns device unique identifier
String
rssi
returns received signal strength indicator
Int
bytes
returns raw bytes of the record
ByteArray
manufacturerSpecificData
returns the manufacturer specific data associated with the manufacturer id
Map<Int, ByteArray>
servicesUuids
returns an array of services UUID's within the advertisement
List<UUID>

The following data can be collected from the NodleBluetoothEvent:

Key
Description
Default Value
scanning
returns bluetooth scanning state
Boolean

config

public fun config(resourceId: AndroidNodleResourceId)

public fun <T> config(key: String, value: T)

Configure the SDK either by supplying a json file located in res/raw/config.json or by directly configuring a key. An example of a json configuration look like this:

{
"ble": {
"scan": {
"duration-msec": 10000,
"interval-msec": 90000,
"interval-x-factor": 1
}
},
"dtn": {
"use-cellular": false
}
}

The following are the table of all the keys available and their description:

Key
Description
Default Value
ble.scan.duration-msec
duration of a single ble pass in milliseconds. Longer scan increase battery consumption but gives more reward.
10000
ble.scan.interval-msec
wait time between two ble pass in milliseconds. Longer period reduce battery consumption but gives less reward
90000
ble.scan.interval-x-factor
multiplier for the ble scan interval above.
1
dtn.use-cellular
if true, the cellular connection will be used. if false, only wifi connection will be used.
true
heartbeat.background-mode
if true, the SDK will be able to continue to operate when in the background. If false the SDK will eventually stop after a while.
false
ble.background-mode
if true, the SDK will perform additional BLE scanning even when in the background. If false the SDK won't perform additional BLE scannning.
false

Example:

Java

import io.nodle.sdk.android.common.config.AndroidNodleResourceId;
// load the json config located in res/raw/config.json
Nodle().config(AndroidNodleResourceId(R.raw.sdk_config));
// or you can manually set the entries, for instance
Nodle().config("dtn.use-cellular", false);

Kotlin

import io.nodle.sdk.android.common.config.AndroidNodleResourceId
// load the json config located in res/raw/config.json
Nodle().config(AndroidNodleResourceId(R.raw.sdk_config))
// or you can manually set the entries, for instance
Nodle().config("dtn.use-cellular", false)
// then proceed to start Nodle
Nodle().start()

Debug Logs API

This API enable the debug logs for the SDK and allows developer to debug on their own and have better visiblity on their application. The default value will be false which will output PRODUCTION level logs going forward. Here is a sample how to enable/disable the API:

Nodle.Nodle().config("core.debug-log.enable", true)

Production Logs

  • Init of the SDK
  • Coroutine event logs from the API
  • SDKCore logs
    • init of the core
    • SDK ID
  • Feature logs
    • Bluetooth Scanner lifecycle logs
      • enabled/disabled
      • success scan log
      • failed scan log
    • Cell Scanner lifecycle logs
      • enabled/disabled
      • scan started
      • scan failed
    • Heartbeat feature logs
      • enabled/disabled

Debug Logs

  • Init of the SDK
  • Coroutine event logs from the API
  • SDKCore logs
    • init of the core
    • current SDK setup dump
    • bundles in the DB
    • SDK ID
  • Feature logs
    • Bluetooth Scanner lifecycle logs
      • enabled/disabled
      • success scan log
      • each scan item found
      • transmission for bundle
      • failed scan log
    • Cell Scanner lifecycle logs
      • enabled/disabled
      • scan started
      • scan failed
      • transmission for bundle
    • Network feature logs
      • network status log
      • resume bundles logs
      • networking logs over CLA Http
      • networking bundle transmission logs
    • Heartbeat feature logs
      • enabled/disabled
      • transmission log
      • error logs
    • Location Provider logs
      • waiting for location log
      • saved location fetch log
      • timeout on location log
      • fresh location fetch log
      • error logs

Heartbeat API

public fun getHeartbeats(): List<NodleHeartbeatRecord?>?

The following data can be collected from the NodleHeartbeatRecord. Each parameter is optional:

Key
Description
Default Value
id
returns hb unique identifier
Long?
timestamp
returns the generated timestamp when created
Int?
timezone
returns the device timezone
String?
locationH3
returns the device last known location in h3 format string
String?
geoHash
returns the device last known location in geohash format
String?
isBlePermissionsGranted
returns the device ble permissions granted
Boolean?
isLocPermissionsGranted
returns the device location permissions granted
Boolean?
isWifiEnabled
returns the device wifi module status
Boolean?
isCellEnabled
returns the device cell module status
Boolean?
isBluetoothEnabled
returns the device bluetooth module status
Boolean?
sdkVersion
returns the sdk version
String?
configVersion
returns the sdk config version
String?
os
returns the device os
String?
phone
returns the device model
String?
release
returns the device release
String?
api
returns the device api level
String?
hardware
returns the device hardware name
String?
appName
returns the app name
String?
battery
returns the device battery
Int?
charging
returns the device charging status
Boolean?
appInForeground
returns the app current status
Boolean?
phoneStorageTotal
returns the device total storage
String?
phoneStorageAvailable
returns the device storage available
String?
sdkStorage
returns the device storage consumed
String?
httpIn
returns the sdk http input
String?
httpOut
returns the sdk http output
String?
bundleRxCount
returns the DTN RX
Int?
bundleTxCount
returns the DTN TX
Int?
bleScanSuccess
returns the BLE Scan success count
Int?
bleScanFailed
returns the BLE Failed count
Int?
blePayloadCount
returns the BLE payload found
Int?
developerMode
returns the device developer mode status
Boolean?

The HB API will provide a history of the heartbeats being generated by the SDK. It will always add the latest HB on top of the list being sorted by the timestamp. When there is a new heartbeat it will take the 0 element in the array. Here is a sample how to increase/decrease the storage size and be able to fetch all the heartbeats:

Nodle.Nodle().config("core.heartbeat.history", 100f)

Java

Nodle.Nodle().getHeartbeats()?.forEach {
println("Nodle HB:  $it")
}

Kotlin

Nodle.Nodle().heartbeats?.forEach {
println("Nodle HB:  $it")
}

H3 API

public fun fun getH3(): H3?

Return the H3 instance exposing the H3 library methods to be used by the developer:

Returns
H3
Returns H3Core

The H3 interface with all the methods that the developer can take advantage is defined below:

Method
Description
Return Value
h3IsValid(h3: Long)
Returns true if the h3 index is valid
Boolean
h3IsValid(h3Address: String)
Returns true if the h3 index is valid
Boolean
h3GetBaseCell(h3: Long)
Returns the base cell number for the index
Int
h3GetBaseCell(h3Address: String)
Returns the base cell number for the index
Int
h3IsPentagon(h3: Long)
Returns true if this index is one of the twelve pentagons per resolution
Boolean
h3IsPentagon(h3Address: String)
Returns true if this index is one of the twelve pentagons per resolution
Boolean
geoToH3(lat: Double, lng: Double, res: Int)
Find the H3 index of the resolution res cell containing the lat/lon (in degrees) returns h3 index
Long
geoToH3Address(lat: Double, lng: Double, res: Int)
Find the H3 index of the resolution res cell containing the lat/lon (in degrees) returns H3 index
String
h3ToGeo(h3: Long)
Find the latitude, longitude (both in degrees) center point of the cell.
Pair<NodleLat, NodleLng>
h3ToGeo(h3Address: String)
Find the latitude, longitude (degrees) center point of the cell.
Pair<NodleLat, NodleLng>
h3ToGeoBoundary(h3: Long)
Find the cell boundary in latitude, longitude (degrees) coordinates for the cell
List<Pair<NodleLat, NodleLng>>
h3ToGeoBoundary(h3Address: String)
Find the cell boundary in latitude, longitude (degrees) coordinates for the cell
List<Pair<NodleLat, NodleLng>>
kRing(h3Address: String?, k: Int)
Neighboring indexes in all directions h3Address – Origin index k – Number of rings around the origin
List<String?>?
kRing(h3: Long, k: Int)
Neighboring indexes in all directions h3Address – Origin index k – Number of rings around the origin
List<Long>
kRings(h3Address: String, k: Int)
Neighboring indexes in all directions h3Address – Origin index k – Number of rings around the origin
List<List<String?>?>?
h3Distance(a: String?, b: String?)
Returns the distance between a and b. This is the grid distance, or distance expressed in number of H3 cells.
Int
h3Distance(a: Long, b: Long)
Returns the distance between a and b. This is the grid distance, or distance expressed in number of H3 cells.
Int
h3Line(startAddress: String?, endAddress: String?)
Given two H3 indexes, return the line of indexes between them (inclusive of endpoints).
List<String?>?
h3Line(start: Long, end: Long)
Given two H3 indexes, return the line of indexes between them (inclusive of endpoints).
List<Long>
h3GetResolution(h3Address: String?)
Returns the resolution of the provided index
Int
h3GetResolution(h3: Long)
Returns the resolution of the provided index
Int
h3ToString(h3: Long)
Converts from long representation of an index to String representation.
String?
stringToH3(h3Address: String?)
Converts from String representation of an index to long representation.
Long
numHexagons(res: Int)
Returns the number of unique H3 indexes at resolution res.
Long

Java

Nodle.Nodle().h3?.h3ToGeo("8a1eebbb461ffff")

Kotlin

Nodle.Nodle().h3?.h3ToGeo("8a1eebbb461ffff")

SDK Troubleshooting

In this section, we will try to explain some of the common issues you may face on Android and how to troubleshoot them.

General Guidelines

Here are some of the common steps to take in case of issues in general.

  1. Please make sure to follow all steps carefully and ensure have done all that's requested from you for the integration.
  2. Make sure you have selected the right version of the SDK with Google Play services or without depending on your usage.
  3. Make sure you have your public key in the following format ss58:public_key.
  4. Make sure you have all permissions in your Android manifest file and you have added your application class inside the android tag.
  5. Make sure you have initialized the NodleSDK.
  6. Make sure to start the NodleSDK.

If you are still having issues, proceed with the next steps below.

Bluetooth Troubleshooting

Follow these steps to troubleshoot issues with your Bluetooth.

  1. Please disable your Bluetooth, Wifi, Mobile Data and proceed to next step.
  2. Go to your phone Settings-> Apps -> Bluetooth. Clear the cache and data for the system application. Some manufacturers hide that so you might need to enable it to find it.
  3. After you have done the above, restart your phone.
  4. If you still having Bluetooth related problems, contact your manufacturer or update your software. If the issue persists, try with another phone from a different manufacturer.

Location Troubleshooting

To troubleshoot issues with location, do the following:

  1. Make sure you have Location enabled on your phone.
  2. Make sure you followed all steps on our documentation for the integration and you are requesting all the permissions in your Manifest.
  3. Make sure you are requesting all runtime permissions for the user and that you have permissions for them to be used. You can verify that on the next step.
  4. Go to your phone Settings-> Apps -> Your Application and make sure you have Location permission enabled. Location can be enabled either Always or While in Use.
  5. If you are still having issues, disable your Location, Wifi, Mobile data.
  6. After you have done the above, restart your phone.
  7. If you still having Location related problems, contact your manufacturer or update your software.
⚠️
Important: Please make sure you are using the right version of the SDK. If the issue persists, try with another phone from a different manufacturer.

Network Troubleshooting

Here are the steps to follow to troubleshoot issues with the network.

  1. Make sure you have Wifi or Mobile data enabled on your phone. We need this to be able to process data in our SDK.
  2. Make sure you have an internet connection (double check this). Also, check for weak connections. Our SDK will still keep any generated data on your phone until your connection is stable, so you aren't missing out.
  3. If you are having issues with either Wifi or Mobile data, go to your phone Settings → Wifi / Mobile Data and make sure you have them enabled. If you have them enabled but still there’s no connection, follow the steps below.
    1. Go ahead and disable your Wifi, Mobile data.
    2. After you have done the above, restart your phone. If you’re still having internet related problems, contact your manufacturer or update your software.
  4. Once you have the internet connection, you can proceed.

Network Security Layers Troubleshooting

  1. If there are issues with our security layers, make sure you aren't using custom certificates and trust anchors for the system or user.
  2. Try the following code for your network_security_config.xml depending on your needs. <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> <certificates src="user" /> </trust-anchors> </base-config> </network-security-config> <?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="false"> <trust-anchors> <certificates src="system" /> <certificates src="user" /> </trust-anchors> </base-config> </network-security-config>
  3. And update the following setup in your AndroidManifest.xml: android:networkSecurityConfig="@xml/network_security_config"Copy
  4. If you are using a VPN, make sure you have the correct VPN settings. Ensure you have a proper connection to outside servers and you can access our website  https://www.nodle.com/
  5. If you are still having issues, try without a VPN connection (since some of them may not work as needed or may have issues).

ProGuard Troubleshooting

For common issues with ProGuard shrinking and obfuscation, we recommend adding the following ProGuard rules when generating a release build using R8:

There might be need for adding some additional configuration on your end depending if you are using R8 which might strip some .so files. You have to add the following to your android section to prevent stripping:

packagingOptions {
    pickFirst '**/*.so'  
    doNotStrip '**/*.so' 
}

Start by generating a release build with no ProGuard shrinking or obfuscation enabled. Check if your application is working correctly. If not, follow these steps.

  1. Make sure you have the right ProGuard rules to keep all the files, classes, interfaces that your application would need.
  2. If your problem is related to shrinking, disable it or make sure you have the correct rules for the files and lines for classes in your ProGuard configuration. Note that these rules are dependent on the type of configuration you use, ProGuard or DexGuard.
  3. If your problem is related to obfuscation, start by increasing or decreasing the obfuscation levels and setup. Or, use the default configuration in your project (check the ProGuard config file) to be able to debug the problem.
⚠️
Important: If you are still having issues with ProGuard, refer to the official documentation: https://developer.android.com/studio/build/shrink-code.
💡
Note: Developers are responsible for their own rules and setup. Nodle is responsible for the SDK only. The latest versions of the SDK require almost no additional configuration on the client end. They also encapsulate all dependencies completely.

Gradle Troubleshooting

To troubleshoot Gradle issues, we recommend that you always invalidate caches and restart the Android Studio.

You can do the following File -> Invalidate Cache-> Select both options-> Invalidate and Restart.

If you are still facing issues, follow these steps:

  1. Run the following in your terminal: rm -rf ~/.gradle/caches/
  2. Clean and build the project once more: ./gradlew clean build
  3. You can refresh the dependencies as well: ./gradlew --refresh-dependencies
  4. Check our release SHA and validate the one that Gradle has downloaded by going to the following path ./gradle/caches/modules-2/files-2.1/io.nodle/nodlesdk-lp or lg/version/ 
  5. Compare the release SHA and make sure it matches one of the folders in that location. If you don't want to depend on the automatic Gradle manager to manage your dependencies, you can build your own dependency validation.
⚠️
Important: If you are still having issues with Gradle, refer to the official documentation: https://developer.android.com/studio/troubleshoot.

Changelog

Here, you can find the latest releases and changes that are being done in the new and old versions of the SDKs for Android.

Version 0.0.25 (30.09.2025) - Android SDK - 94207dd00f

Updated

  • Updates to dependencies to latest version
  • Fixed minor issues

Version 0.0.24 (14.08.2024) - Android SDK - d6440e52ec

Updated

  • Security patches to ensure stability and false positives
  • Security updates to latest version

Version 0.0.18 (17.07.2023) - Android SDK - 57f6eec4c0

Added

  • HB API which can be used by developers to retrieve the last heartbeats that have been produced by their SDK:
    • Nodle.Nodle().config("core.heartbeat.history", 100f)
  • H3 API which can be used by developers to use the Uber H3 Library features safely
  • Debug Logs API that will allow the developers to debug their own SDK with two log levels PRODUCTION/DEBUG:
    • Nodle.Nodle().config("core.debug-log.enable", false)
  • Improved and extented capabilities for background mode scanning which will improve the overall capabilities of the SDK and the network
  • Added further configuration to allow developers to improve the background lifecycle and enable/disable the SDK to always be active:
    • Nodle.Nodle().config("heartbeat.background-mode", false)
  • Added further configuration to allow developers to improve their background scanning process even while in Doze mode:
    • Nodle.Nodle().config("ble.background-mode", false)

Fixed

  • Fixed a issue where the SDK won't update the last known location all the time
  • Fixed a issue where network configuration for the developer could cause issues and prevent the SDK to send payloads because of false positives
  • Fixed a issue where some Android 8 phone GPS stack is broken when trying to retrive location - LG build only

Updated

  • Google Play Services Location minimum version to 21 - LP build only
  • Prevent the SDK from running two instances in multiple applications on the same phone
  • Security patches and adjustments to ensure latest protection mechanisms are added
  • Security patches to ensure stability and false positives
  • Security updates to latest version

SHA

  • 00574bbf5ac50a0043f5aed7e0eaa8fc81d2db67 - LP
  • eae0238019c694f2d43dd23f64bd6b99497a57f1 - LG

Version 0.0.15 (03.03.2023) - Android SDK - 6a50b7b008

Updated

  • Updated BLE permissions checks with latest recommendations from Android Developer team
  • Updated BLE manifest changes required from the Android Developer team to handle maxSDK 30
  • Google Play Services Location minimum version to 19 - LP build only

SHA

  • c70f2d9babd9d616d8817e0591cce19c5e4bc9c8 - LP
  • aaa1c11a5eb5ee3ab33b1c79742352ca1b5b065a - LG

Version 0.0.14 (10.10.2022) - Android SDK - e61c593b4d

Fixed

  • Fixed compile time issues causing issues with some client dependencies

SHA

  • 8d7d75b3896bfde842962d64964ca3aa00460488 - LP
  • 7b74974d55f228506d5641691688fb9c500b62be - LG

Version 0.0.13 (26.09.2022) - Android SDK - 95a5b4f577

Fixed

  • Performance improvements and optimizations

Updated

  • Updated internal libraries
  • Updated consumer rules

Version 0.0.12 (19.07.2022) - Android SDK - 5b978643ad

Fixed

  • Issues when generating release builds requiring additional rules

Updated

  • Updated internal libraries to latest versions
  • Updated kotlin and dependencies to 1.6.21
  • Updated gradle to latest versions 7.1.3+

Version 0.0.11 (11.07.2022) - Android SDK - a790f76ea5

Added

  • Security updates

Fixed

  • Issues with config
  • Issues with network

Updated

  • Updated internal libraries
  • Updated Maven repository - http://maven.nodle.io

Version 0.0.10 (12.04.2022) - Android SDK - 381d19b7b5

Added

  • Config features

Fixed

  • Issues with config
  • Issues with telemetry

Updated

  • Internal changes

← Previous

Nodle SDK

Next →

Nodle iOS SDK

On this page

  • Android SDK Integration
  • Checking Your SDK rewards
  • SDK Configuration
  • Nodle SDK API
  • init
  • start
  • isStarted
  • isScanning
  • stop
  • clear
  • getVersion
  • getEvents
  • config
  • Debug Logs API
  • Production Logs
  • Debug Logs
  • Heartbeat API
  • H3 API
  • SDK Troubleshooting
  • General Guidelines
  • Bluetooth Troubleshooting
  • Location Troubleshooting
  • Network Troubleshooting
  • Network Security Layers Troubleshooting
  • ProGuard Troubleshooting
  • Gradle Troubleshooting
  • Changelog
Logo

Nodle Website

Network Explorer

Chain Explorer

© Nodle, 2024

DiscordTelegramXYouTube
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nodle.dummy">
<!-- Required permissions NodleSDK -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<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" />

<!-- Required permissions NodleSDK extended background capabilities -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

<!-- Required permissions NodleSDK Android 12  -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

 <!-- Put your application class name below -->
<application
    android:name="App">
</application>
</manifest>
// required permissions for the SDK to run
private val foregroundPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
arrayOf(
Manifest.permission.INTERNET,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
} else {
arrayOf(
Manifest.permission.INTERNET,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
}
@RequiresApi(Build.VERSION_CODES.Q)
private val backgroundPermission = Manifest.permission.ACCESS_BACKGROUND_LOCATION
// handle background permissions
val requestBackgroundPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) {
println("Background location permission granted")
 // start Nodle SDK
    Nodle.Nodle().start("ss58:public_key", "tag1", "tag2")
} else {
    println("Background location permission denied")
}
}
// handle permissions request
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()) { isGranted ->
if (isGranted.containsKey(Manifest.permission.ACCESS_FINE_LOCATION)) {
println("Foreground permissions granted")
 // request background permissions if possible
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        requestBackgroundPermissionLauncher.launch(backgroundPermission)
    } else {
        // start Nodle SDK
        Nodle.Nodle().start("ss58:public_key", "tag1", "tag2")
    }
} else {
    println("Foreground permissions weren't granted")
}
}
// start nodle
binding.start.setOnClickListener {
// request foreground permissions
requestPermissionLauncher.launch(foregroundPermissions)
}
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.nodle.sdk.NodleEvent;
import io.nodle.sdk.core.actions.events.NodleBluetoothRecord;
import kotlin.Unit;
import kotlin.coroutines.Continuation;
import kotlinx.coroutines.flow.FlowCollector;
public class NodleCollector implements FlowCollector<NodleEvent> {
@Nullable
@Override
public Object emit(NodleEvent nodleEvent, @NonNull Continuation<? super Unit> continuation) {
switch (nodleEvent.getType()) {
case BlePayloadEvent:
NodleBluetoothRecord payload = (NodleBluetoothRecord) nodleEvent;
System.out.println("Bluetooth payload available: " + payload.getDevice());
break;
case BleStartSearching:
System.out.println("Bluetooth started searching");
break;
case BleStopSearching:
System.out.println("Bluetooth stop searching");
break;
}
return nodleEvent;
}
}
import androidx.annotation.NonNull;
import kotlin.coroutines.Continuation;
import kotlin.coroutines.CoroutineContext;
import kotlin.coroutines.EmptyCoroutineContext;
public class NodleContinuation implements Continuation {
@NonNull
@Override
public CoroutineContext getContext() {
// pass an empty instance or one that you need
return EmptyCoroutineContext.INSTANCE;
}
@Override
public void resumeWith(@NonNull Object o) {
    // provide a base implementation if you need
}
Nodle().getEvents().collect { event ->
// collect the NodleEvents events here by chosing a type
when (event.type) {
NodleEventType.BlePayloadEvent -> handlePayload(it)
NodleEventType.BleStartSearching -> println("Bluetooth started searching")
NodleEventType.BleStopSearching -> println("Bluetooth stopped searching")
}
}
fun handlePayload(payload: NodleEvent) {
val data = payload as NodleBluetoothScanRecord
println("Bluetooth payload available ${data.device} ")
}
Nodle
keep,includecode class io.nodle.** { *; }
Jackson - Nodle dependency
keep class com.fasterxml.jackson.databind.ObjectMapper {
public <methods>;
protected <methods>;
}
Jackson - Nodle dependency
keep class com.fasterxml.jackson.databind.ObjectWriter {
public ** writeValueAsString(**);
}
Jackson - Nodle dependency
keepnames class com.fasterxml.jackson.** { ; }
-dontwarn com.fasterxml.jackson.databind.

Kotlin - Internal dependency
keep class kotlin.jvm.internal** { *; }

Uber
-keep,includecode class com.uber.h3core.H3Core {
    <fields>;    <methods>;
}

Protobuf
-keepclassmembers class * extends com.google.protobuf.GeneratedMessageLite {
    <fields>;    <methods>;
}