Getting Started
IntroductionVision and MissionFor Users
Nodle IoTNodle AppNodle ClientNodle on zkSync EraNodle PortalNODL TokenNFT Minting ToolNodle ExplorerParticipateFor Developers
SubQuery IndexerNodle APIsNodle ParachainParachain ModulesNodle SDKNodle Android SDKNodle iOS SDKSmart MissionsMore Info
AppendixGlossaryAndroid SDK Integration
Integrating the Nodle SDK into your android app is easy and straightforward. You can use our NodleSDK Quickstart application or just follow the steps below and you should be ready to go in no time.
- 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
- 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: - 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)
- Without Google Play Services
- 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
- Java | Kotlin
- 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
- 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
- Run the Nodle SDK
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.
// 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:d6440e52ec'
// additional dependencies may be required when using getEvents
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
}
// Module Gradle
dependencies {
implementation 'io.nodle:nodlesdk-rc-lg:d6440e52ec'
// 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 d6440e52ec
<?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>
In the onCreate
method of your application class you should initialize Nodle like this:
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.
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:
// 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)
}
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.
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.
In the onCreate
method of your launcher activity start Nodle by giving it the ss58:public_key
generated in Step 1:
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.
import static io.nodle.sdk.android.Nodle.Nodle;INodle nodle = Nodle();
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:
Nodle.init(this);
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:
Nodle().start("ss58:public_key");
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:
Boolean sdkStarted = Nodle().isStarted()
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:
Boolean sdkScanning = Nodle().isScanning()
val sdkScanning = Nodle().isScanning()
stop
public fun stop()
Immediately stops the Nodle SDK
Example:
Nodle().stop();
Nodle().stop()
clear
public fun clear()
Clear any configs by Nodle SDK
Example:
Nodle().clear();
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:
String nodleSdkVersion = Nodle().getVersion();
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:
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:
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;
}
}
Example: Nodle Continuation for Java
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} ")
}
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:
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);
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 |
Nodle.Nodle().h3?.h3ToGeo("8a1eebbb461ffff")
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.
- Please make sure to follow all steps carefully and ensure have done all that's requested from you for the integration.
- Make sure you have selected the right version of the SDK with Google Play services or without depending on your usage.
- Make sure you have your public key in the following format ss58:public_key.
- Make sure you have all permissions in your Android manifest file and you have added your application class inside the android tag.
- Make sure you have initialized the NodleSDK.
- 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.
- Please disable your Bluetooth, Wifi, Mobile Data and proceed to next step.
- 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.
- After you have done the above, restart your phone.
- 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:
- Make sure you have Location enabled on your phone.
- Make sure you followed all steps on our documentation for the integration and you are requesting all the permissions in your Manifest.
- 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.
- 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.
- If you are still having issues, disable your Location, Wifi, Mobile data.
- After you have done the above, restart your phone.
- If you still having Location related problems, contact your manufacturer or update your software.
Network Troubleshooting
Here are the steps to follow to troubleshoot issues with the network.
- Make sure you have Wifi or Mobile data enabled on your phone. We need this to be able to process data in our SDK.
- 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.
- 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.
- Go ahead and disable your Wifi, Mobile data.
- After you have done the above, restart your phone. If you’re still having internet related problems, contact your manufacturer or update your software.
- Once you have the internet connection, you can proceed.
Network Security Layers Troubleshooting
- If there are issues with our security layers, make sure you aren't using custom certificates and trust anchors for the system or user.
- 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>
- And update the following setup in your AndroidManifest.xml:
android:networkSecurityConfig="@xml/network_security_config"
Copy - 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/
- 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:
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** { *; }
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.
- Make sure you have the right ProGuard rules to keep all the files, classes, interfaces that your application would need.
- 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.
- 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.
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:
- Run the following in your terminal:
rm -rf ~/.gradle/caches/
- Clean and build the project once more:
./gradlew clean build
- You can refresh the dependencies as well:
./gradlew --refresh-dependencies
- 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/
- 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.
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.24 (14.08.2024) - Android SDK - d6440e52ec
- Security patches to ensure stability and false positives
- Security updates to latest version
Version 0.0.18 (17.07.2023) - Android SDK - 57f6eec4c0
- 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 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
- 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
- 00574bbf5ac50a0043f5aed7e0eaa8fc81d2db67 - LP
- eae0238019c694f2d43dd23f64bd6b99497a57f1 - LG
Version 0.0.15 (03.03.2023) - Android SDK - 6a50b7b008
- 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
- c70f2d9babd9d616d8817e0591cce19c5e4bc9c8 - LP
- aaa1c11a5eb5ee3ab33b1c79742352ca1b5b065a - LG
Version 0.0.14 (10.10.2022) - Android SDK - e61c593b4d
- Fixed compile time issues causing issues with some client dependencies
- 8d7d75b3896bfde842962d64964ca3aa00460488 - LP
- 7b74974d55f228506d5641691688fb9c500b62be - LG
Version 0.0.13 (26.09.2022) - Android SDK - 95a5b4f577
- Performance improvements and optimizations
- Updated internal libraries
- Updated consumer rules
Version 0.0.12 (19.07.2022) - Android SDK - 5b978643ad
- Issues when generating release builds requiring additional rules
- 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
- Security updates
- Issues with config
- Issues with network
- Updated internal libraries
- Updated Maven repository - http://maven.nodle.io
Version 0.0.10 (12.04.2022) - Android SDK - 381d19b7b5
- Config features
- Issues with config
- Issues with telemetry
- Internal changes
← Previous
Next →
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