{"id":21437516,"url":"https://github.com/appspector/android-sdk","last_synced_at":"2025-10-05T00:54:46.216Z","repository":{"id":111392432,"uuid":"130043417","full_name":"appspector/android-sdk","owner":"appspector","description":"AppSpector is a debugging service for mobile apps","archived":false,"fork":false,"pushed_at":"2024-10-16T21:03:41.000Z","size":12730,"stargazers_count":43,"open_issues_count":2,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-06T05:50:41.167Z","etag":null,"topics":["android","debug","debugger-visualizer","debugging-tool","http","http-proxy","introspection","java","logger","logging","logs","mobile-development","monitoring","networking","remote","remote-logging","sqlite","sqlite-android"],"latest_commit_sha":null,"homepage":"https://appspector.com","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appspector.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-18T10:07:39.000Z","updated_at":"2024-10-16T21:03:45.000Z","dependencies_parsed_at":"2024-10-18T18:00:03.843Z","dependency_job_id":"a619eea2-889f-44aa-906c-83a6ed0ea0f9","html_url":"https://github.com/appspector/android-sdk","commit_stats":null,"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appspector%2Fandroid-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appspector%2Fandroid-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appspector%2Fandroid-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appspector%2Fandroid-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appspector","download_url":"https://codeload.github.com/appspector/android-sdk/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230507051,"owners_count":18236944,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","debug","debugger-visualizer","debugging-tool","http","http-proxy","introspection","java","logger","logging","logs","mobile-development","monitoring","networking","remote","remote-logging","sqlite","sqlite-android"],"created_at":"2024-11-23T00:20:44.241Z","updated_at":"2025-10-05T00:54:41.193Z","avatar_url":"https://github.com/appspector.png","language":null,"readme":"# [![AppSpector](images/github-cover.png)](https://appspector.com?utm_source=android_readme)\n\nWith AppSpector you can remotely debug your app running in the same room or on another continent.\nYou can measure app performance, view database content, logs, network requests and many more in realtime.\nThis is the instrument that you've been looking for. Don't limit yourself only to simple logs.\nDebugging doesn't have to be painful!\n\n* [Installation](#installation)\n  * [Gradle dependency](#add-appspector-sdk-to-your-project)\n  * [Initialize AppSpector](#initialize-appspector-sdk)\n  * [Use End-To-End Encryption to protect your data](#use-end-to-end-encryption-to-protect-your-data)\n  * [Build and Run](#build-and-run)\n* [Upgrading the AppSpector SDK from older versions](#upgrading-the-appspector-sdk-from-older-versions)\n* [Configure](#configure)\n  * [SDK start/stop](#sdk-startstop)\n  * [Custom device name](#custom-device-name)\n  * [Support SQLCipher](#support-sqlcipher)\n  * [Filtering your data](#filtering-your-data)\n    * [Filtering HTTP requests and responses](#filtering-http-requests-and-responses)\n    * [Filtering SharedPreferences values and files](#filtering-sharedpreferences-values-and-files)\n    * [Filtering Logs](#filtering-logs)\n    * [Applying filters](#applying-filters)\n  * [Getting session URL](#getting-session-url)\n  * [Disable background data collection](#disable-background-data-collection)\n  * [Network Monitor configuration](#network-monitor-configuration)\n* [Features](#features)\n\n# Installation\n\nEach app you want to use with AppSpector SDK you have to register on our\nservice through the web ([https://app.appspector.com](https://app.appspector.com?utm_source=android_readme))\nor the [desktop app](https://appspector.com/download/?utm_source=android_readme).\nAfter adding the application navigate to app settings and copy API key.\n\n## Add AppSpector SDK to your project\n\u003c!-- integration-manual-start --\u003e\n[![GitHub release](https://img.shields.io/github/release/appspector/android-sdk.svg)](https://github.com/appspector/android-sdk/releases)\n\n#### Modify your app-level build.gradle\n```kotlin\napply plugin: 'com.android.application'\n\n// Add AppSpector maven repository\nrepositories {\n    maven { url \"https://maven.appspector.com/artifactory/android-sdk\" }\n}\n\ndependencies {\n    implementation \"com.appspector:android-sdk:1.+\"\n}\n```\n\nIn case when you don't want to have AppSpector SDK in your release APK use AppSpector NO-OP artifact\n```groovy\ndependencies {\n    debugImplementation \"com.appspector:android-sdk:1.6.+\"\n    releaseImplementation(\"com.appspector:android-sdk:1.6.+\") {\n      exclude group: 'com.appspector', module: 'android-core'\n    }\n}\n```\n\u003c!-- integration-manual-end --\u003e\n\n\n## Initialize AppSpector SDK\n\u003c!-- initialization-manual-start --\u003e\n```java\nimport android.app.Application;\n\nimport com.appspector.sdk.AppSpector;\n\npublic class AmazingApp extends Application {\n\n   @Override\n   public void onCreate() {\n      super.onCreate();\n      \n      // We recommend to start AppSpector from Application#onCreate method\n      \n      // You can start all monitors\n      AppSpector\n            .build(this)\n            .withDefaultMonitors()            \n            .run(\"API_KEY\");\n            \n      // Or you can select monitors that you want to use\n      AppSpector\n            .build(this)\n            .addPerformanceMonitor()\n            .addLogMonitor()\n            // Next line disables added monitor above. In our case, Log and Performace monitors.\n            .disableProvidedMonitors() // Disabled monitors can be enabled from Dashboard.\n            .addHttpMonitor()\n            .addScreenshotMonitor()\n            .addSQLMonitor()\n            // Monitors that were not added to config will be ignored till declared here.\n            .run(\"API_KEY\");\n   }\n\n}\n```\n\u003c!-- initialization-manual-end --\u003e\n\n\n## Use End-To-End encryption to protect your data\n\nAppSpector SDK collects and stores user data including logs, database content\nand network traffic. All of this can contain sensitive data so to protect\nyour privacy we offer an additional module with E2EE feature. It allows\nyou to encrypt all data AppSpector sends from or to your device and be sure\nonly you can decrypt it. Due to security reasons encrypted sessions are only\navailable in [desktop application](https://appspector.com/download/?utm_source=android_readme).\n\nTo use encryption you must select the `Enable End-To-End encryption` option\nduring the registration of your app using [desktop application](https://appspector.com/download/?utm_source=android_readme)\n(previously registered application can't be updated to support encryption).\n\nAfter that, you need to add the `android-sdk-encryption` module to your\ndependencies declaration. So, your app-level `build.gradle` should contain the next lines:\n\n```groovy\napply plugin: 'com.android.application'\n\n// Add AppSpector maven repository\nrepositories {\n    maven { url \"https://maven.appspector.com/artifactory/android-sdk\" }\n}\n\ndependencies {\n    implementation \"com.appspector:android-sdk:1.+\"\n    implementation 'com.appspector:android-sdk-encryption:1.+'\n}\n```\n\nFinally, enable encryption by putting the `enableEncryption` to SDK\nconfiguration. The client `Public Key` you can find on the application settings screen.\n\n\u003c!-- e2e-start --\u003e\n```java\nAppSpector\n            .build(this)\n            .withDefaultMonitors() \n            .enableEncryption(\"CLIENT_PUBLIC_KEY\")\n            .run(\"API_KEY\");\n```\n\n\u003c!-- e2e-end --\u003e\n\n\n## Build and Run\n\nBuild your project and see everything work! When your app is up and running you can go to [https://app.appspector.com](https://app.appspector.com?utm_source=android_readme) and connect to your application session.\n\n\n# Upgrading the AppSpector SDK from older versions\n\n\u003c!--upgrade-manual-start --\u003e\n\n**Important:** Old SDK versions (pre v1.5.0) included a Gradle Plugin which is no longer available. Please follow these steps to migrate your project to the new integration method:\n\n### Step 1: Remove the plugin from your app-level `build.gradle` file\n\n**For Groovy DSL (`build.gradle`):**\n```groovy\napply plugin: 'com.android.application'\n// TODO: Remove the next line\napply plugin: 'com.appspector.sdk'\n```\n\n**For Kotlin DSL (`build.gradle.kts`):**\n```kotlin\nplugins {\n    id(\"com.android.application\")\n    // TODO: Remove the next line\n    id(\"com.appspector.sdk\")\n}\n```\n\n### Step 2: Clean up your project-level `build.gradle` file\n\nRemove the AppSpector plugin from your project-level build file:\n\n**For Groovy DSL (`build.gradle`):**\n```groovy\nbuildscript {\n    dependencies {\n        classpath 'com.android.tools.build:gradle:8.0.0'\n        // TODO: Remove the next line\n        classpath 'com.appspector:android-sdk-plugin:1.4.0'\n    }\n}\n```\n\n**For Kotlin DSL (`build.gradle.kts`):**\n```kotlin\nbuildscript {\n    dependencies {\n        classpath(\"com.android.tools.build:gradle:8.0.0\")\n        // TODO: Remove the next line\n        classpath(\"com.appspector:android-sdk-plugin:1.4.0\")\n    }\n}\n```\n\n### Step 3: Add the new dependency\n\nAdd the AppSpector SDK as a regular dependency in your app-level `build.gradle` file:\n\n**For Groovy DSL (`build.gradle`):**\n```groovy\ndependencies {\n    implementation 'com.appspector:android-sdk:1.6.0'\n}\n```\n\n**For Kotlin DSL (`build.gradle.kts`):**\n```kotlin\ndependencies {\n    implementation(\"com.appspector:android-sdk:1.6.0\")\n}\n```\n\n### Step 4: Update monitor configuration\n\nSince the plugin handled network monitoring automatically, you now need to manually configure network monitors. See the [Network Monitor configuration](#network-monitor-configuration) section below for details on setting up OkHttp interceptors or URLConnection instrumentation.\n\n### Step 5: Clean and rebuild\n\nAfter making these changes:\n1. Clean your project: `./gradlew clean`\n2. Rebuild your project: `./gradlew build`\n\n\u003c!--upgrade-manual-end --\u003e\n\n\n# Configure\n\n## SDK start/stop\n\nAfter calling the `run` method the SDK starts data collection and\ndata transferring to the web service. From that point you can see\nyour session in the AppSpector client.\n\nSince we recommend to keep SDK initialization in the `onCreate()` method\nof your [Application](https://developer.android.com/reference/android/app/Application),\nthe SDK provides methods to help you control AppSpector state by\ncalling `stopSdk()` and `startSdk()` static methods.\n**You are able to use these methods only after AppSpector was initialized.**\n\nThe `stop()` tells AppSpector to disable all data collection and close current session.\n\n```java\nAppSpector.stopSdk();\n```\n\nThe `startSdk()` starts it again using config you provided at initialization.\n\n```java\nAppSpector.startSdk();\n```\n\n**As the result new session will be created and all activity between\n`stop()` and `start()` calls will not be tracked.**\n\nTo check AppSpector state you can use `isStarted()` method.\n\n```java\nAppSpector.shared().isStarted();\n```\n\n## Custom device name\n\nYou can assign a custom name to your device to easily find needed sessions\nin the sessions list. To do this you should add the desired name as a value\nfor `AppSpector.METADATA_KEY_DEVICE_NAME` key to the `metadata` dictionary:\n\n```java\nAppSpector\n            .build(this)\n            .withDefaultMonitors()\n            .addMetadata(AppSpector.METADATA_KEY_DEVICE_NAME, \"YOUR_DEVICE_NAME\")\n            .run(\"YOUR_API_KEY\");\n```\n\nAlso, the SDK allows managing the device name during application lifetime using\n\nthe `setMetadataValue` method to change device name\n\n```java\nAppSpector.shared().setMetadataValue(AppSpector.METADATA_KEY_DEVICE_NAME, \"NEW_DEVICE_NAME\");\n```\n\nor the `removeMetadataValue` to remove your custom device name\n\n```java\nAppSpector.shared().removeMetadataValue(AppSpector.METADATA_KEY_DEVICE_NAME);\n```\n\n## Support SQLCipher\nFor browsing and running SQL queries in the SQLCipher database you need to perform a couple of additional steps.\nFirst of all, add the `sqlcipher-extension` module to your `app/build.gradle` file under the main sdk module. So, it'll look like that:\n\n```groovy\ndependencies {\n    implementation 'com.appspector:android-sdk:1.+'\n    implementation 'com.appspector:sqlcipher-extension:1.+'\n}\n```\n\nAfter that, create DatabaseConnectionFactory and pass it as an argument of the `addSQLMonitor` method.\n\nLet's imagine your project contains SQLCipher database with \"my_encrypted_db\" name and other SQLite ones:\n\n```java\nAppSpector\n            .build(this)\n            .withDefaultMonitors()\n            .addSQLMonitor(new SQLiteMonitor.DatabaseConnectionFactory() {\n                @NonNull\n                @Override\n                public DatabaseConnection createDatabaseConnection(@NonNull Database database) {\n                    if (\"my_encrypted_db\".equals(database.name)) {\n                        return new SQLCipherDatabaseConnection(database, \"password\");\n                    }\n                    return new SQLiteDatabaseConnection(database);\n                }\n            })\n            .run(\"YOUR_API_KEY\");\n```\n\n\n## Filtering your data\nSometimes you may want to adjust or completely skip some pieces of data AppSpector gather. \n\n### Filtering HTTP requests and responses\nFor this aim, the HTTP monitor provides the interface `HTTPFilter` which can be pass to `addHttpMonitor(HTTPFilter)` method.\n\nLet's say we want to skip our auth token from requests headers. Here is a sample of this filter:\n```java\npublic class TokenFilter implements HTTPFilter {\n    @Nullable\n    @Override\n    public HttpRequest filter(HttpRequest request) {\n        if (request.getHeaders().containsKey(\"YOUR-AUTH-HEADER\")) {\n             request.getHeaders().remove(\"YOUR-AUTH-HEADER\");\n        }\n        return request;\n    }\n\n    @Nullable\n    @Override\n    public HttpResponse filter(HttpResponse response) {\n        return response;\n    }\n}\n```\n\n### Filtering SharedPreferences values and files\nThe SharedPreferences monitor allows specifying files you want to observe by using `SharedPreferencesSourceFactory`.\n1. To observe all SharedPreferences files it provides `SharedPreferencesSourceFactory.all()` method. By default, the monitor uses this value.\n2. To ignore some files it provides `SharedPreferencesSourceFactory.excludeFiles(\"preferences_name\")` method, where \"preferences_name\" is a name of ignored file. You may pass as many file names as you want.\n3. To observe only specified file it provides `SharedPreferencesSourceFactory.only(\"preferences_name\")` method, where \"preferences_name\" is a name of file for observing. This method also receives as many argumens as you want. \n\nIn additinal, the monitor allows to provide `SharedPreferencesMonitor.Filter` for removing or modifying some values before sending data on client.\n\nLet's say you want to remove `key_1` and modify `key_2` preferences in the file `preferences_name`. So, your filter will look like that: \n```java\npublic class SimpleSharedPreferencesFilter implements SharedPreferencesMonitor.Filter {\n    @NonNull\n    @Override\n    public Map\u003cString, PreferenceValue\u003e filter(@NonNull String fileName, @NonNull Map\u003cString, PreferenceValue\u003e values) {\n        if (fileName.equals(\"preferences_name\")) {\n            values.remove(\"key_1\");\n            if (values.containsKey(\"key_2\")) {\n                values.put(\"key_2\", PreferenceValue.stringValue(\"modified value\"));\n            }\n        }\n        return values;\n    }\n}\n```\nFor applying these customizations, you need to use one of these methods: `addSharedPreferenceMonitor(SharedPreferencesMonitor.Filter)`, `addSharedPreferenceMonitor(SharedPreferencesSourceFactory)`, `addSharedPreferenceMonitor(SharedPreferencesSourceFactory, SharedPreferencesMonitor.Filter)`.\n\n### Filtering Logs\nTo filter logs you need to implement `LogMonitor.Filter` and pass it to `addLogMonitor(LogMonitor.Filter)` method.\n\nLet's consider an example where we want to change a log level to WARN for all messages with word *token*:\n```java\npublic class LogFilter implements LogMonitor.Filter {\n  \n    @Nullable\n    @Override\n    public LogEvent filter(LogEvent event) {\n        if (event.message.contains(\"token\")) {\n             event.level = LogLevel.WARN;\n        }\n        return request;\n    }\n}\n```\n### Applying filters\nLet's provide the created filtes to monitors:\n```java\nAppSpector\n            .build(this)\n            .withDefaultMonitors()\n            .addHttpMonitor(new TokenFilter())\n            .addSharedPreferenceMonitor(new SimpleSharedPreferencesFilter()) \n            .addLogMonitor(new LogFilter())\n            .run(\"YOUR_API_KEY\");\n```\n\n## Getting session URL\n\nSometimes you may need to get URL pointing to current session from code. Say you want link crash in your crash reporter with it, write it to logs or display in your debug UI. To get this URL you have to add a session start callback:\n\n```java\nAppSpector.shared().setSessionUrlListener(new SessionUrlListener() {\n    @Override\n    public void onReceived(@NonNull String sessionUrl) {\n        // Save url for future use...\n    }\n});\n```\n\n## Disable background data collection\nBy default, AppSpector SDK is active until the application is killed by Android OS, even if no activities left.\nIt may lead to unnecessary data collection and long sessions for inactive apps.\nWe provide API to disable data collection for a case when the app has no started activities.\n\n```java\nAppSpector\n        .build(this)\n        .collectDataInBackground(false) // Set this flag to disable data collection if no activities left\n        .withDefaultMonitors()\n        .run(\"YOUR_API_KEY\");\n```\n\n\n## Network Monitor configuration\n\n\u003c!-- network-monitor-config-start --\u003e\n### Using OkHttp interceptor for network monitoring\n\nYou can manually add `AppSpectorOkHttp3Interceptor` to your OkHttpClient (or `AppSpectorOkHttp2Interceptor` for older versions of OkHttpClient) to intercept HTTP requests and responses:\n\n```java\nnew OkHttpClient.Builder()\n  .addInterceptor(new AuthenticationInterceptor()) // for example, it adds auth token to your request\n  .addInterceptor(new AppSpectorOkHttp3Interceptor()) // it will track your requests and responses\n  .build()\n```\n\n### Experimental support for URLConnection requests\n\nThe SDK provides API for manual setup in your codebase for URLConnection requests.\n\nTo use it in the project, first add the `urlconnection-extension` dependency:\n\n```groovy\ndependencies {\n    implementation 'com.appspector:android-sdk:1.+'\n    implementation 'com.appspector:urlconnection-extension:1.+'\n}\n```\n\nAfter that, replace the `url.openConnection()` calls with `UrlInstrument.openConnection(url)`. Let's say we have a method to get google page and we want to track this request:\n\n**Before:**\n```java \nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic void getGooglePage() {\n    HttpURLConnection connection = null;\n    try {\n        connection = (HttpURLConnection) new URL(\"https://google.com\").openConnection();\n        if (connection.getResponseCode() == 200) {\n            //Read data from connection.inputStream\n        }\n    } catch (IOException ex) {\n        Log.d(\"UrlConnectionSample\", \"Request was failed\", ex);\n    } finally {\n        if (connection != null) {\n            connection.disconnect();\n        }\n    }\n}\n```\n\n**After integration:**\n```java\nimport com.appspector.sdk.urlconnection.instrumentation.UrlInstrument;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic void getGooglePage() {\n    HttpURLConnection connection = null;\n    try {\n        connection = (HttpURLConnection) UrlInstrument.openConnection(new URL(\"https://google.com\"));\n        if (connection.getResponseCode() == 200) {\n            //Read data from connection.inputStream\n        }\n    } catch (IOException ex) {\n        Log.d(\"UrlConnectionSample\", \"Request was failed\", ex);\n    } finally {\n        if (connection != null) {\n            connection.disconnect();\n        }\n    }\n}\n```\n\n**Note:** Calling the `disconnect` method is important for us. It's a marker that the request was completed.\n\u003c!-- network-monitor-config-start --\u003e\n\n\n## Logger integration with Timber\nIf Timber has been integrated into your project you can easily use it with AppSpector:\n```java\nTimber.plant(new Timber.DebugTree() {\n    @Override\n    void log(int priority, String tag, @NotNull String message, Throwable t) {\n        Logger.log(priority, tag, message, t)\n    }\n})\n```\n\n# Features\nAppSpector provides many monitors that tracks different activities inside your app:\n\n#### SQLite monitor\nProvides browser for sqlite databases found in your app. Allows to track all queries, shows DB scheme and data in DB. You can issue custom SQL query on any DB and see results in browser immediately.\n\n![SQLite monitor](images/sqlite-monitor.png)\n\n#### HTTP monitor\nShows all HTTP traffic in your app. You can examine any request, see request/response headers and body.\nWe provide XML and JSON highliting for request/responses with formatting and folding options so even huge responses are easy to look through.\n\n![Http monitor](images/http-monitor.png)\n\n#### Logs monitor\nDisplays all logs generated by your app.\n\n![Logs](images/logs-monitor.png)\n\n##### AppSpector Logger\nAppSpector Logger allows you to collect log message only into AppSpector service. It is useful when you log some internal data witch can be leaked via Logcat. AppSpector Logger has the same API with `android.util.Log` class.\n\n```java\nLogger.d(\"MyTAG\", \"It won't be printed to the Logcat\");\n```\n\n#### Location monitor\nMost of the apps are location-aware. Testing it requires changing locations yourself. In this case, location mocking is a real time saver. Just point to the location on the map and your app will change its geodata right away.\n\n![Location](images/location-monitor.png)\n\n#### Performance monitor\nDisplays real-time graphs of the CPU / Memory / Network / Disk / Battery usage.\n\n![Performance](images/performance-monitor.png)\n\n#### Screenshot monitor\nSimply captures screenshot from the device.\n\n![Screenshots](images/screenshot-monitor.png)\n\n#### SharedPreferences monitor\nProvides browser and editor for SharedPreferences.\n\n![SharedPreferences](images/shared-preferences-monitor.png)\n\n#### File System monitor\nProvides access to the application internal folder. So, using this monitor you're able to download, remove or upload files, create folders and just walk through app's folders.\n\n![File System](images/fs-monitor.png)\n\n#### Custom Events monitor\nThe monitor allows you to send any data that you want to see. \nThe SDK provides a simple API to send your events. Here is an example:\n\n```java\nCustomEventsSender.send(new MyCustomEvent())\n```\n\nIn the example, the `MyCustomEvent` class implements the `CustomEventPayload` interface like here:\n\n```java\npublic class MyCustomEvent implements CustomEventPayload {\n    @NonNull\n    @Override\n    public String getName() {\n        return \"Custom Event\";\n    }\n\n    @NonNull\n    @Override\n    public String getCategory() {\n        return \"Application\";\n    }\n\n    @NonNull\n    @Override\n    public Map\u003cString, Object\u003e getPayload() {\n        final  Map\u003cString, Object\u003e payload = new HashMap\u003c\u003e();\n        payload.put(\"sampleDate\", new Date());\n        payload.put(\"sampleBool\", false);\n        payload.put(\"sampleInt\", 42);\n        payload.put(\"sampleString\", \"Test\");\n        return payload;\n    }\n}\n```\n\n#### Commands Monitor\nThe monitor provides an opportunity to trigger your code remotely from AppSpector dashboard. The triggered code should be wrapped in AppSpector's CommandCallback and registered to SDK. The command allows you to pass params to your code and declare the result type.\n\nLet's say you need to show the Toast with the specified text and return an int value.\n\nHere is the declaration of your command which requires a message argument and has an Integer result.\n\n```java\n@Command(value = \"Show message\", category = \"Application\")\npublic class ShowToastCommand extends BaseCommand\u003cInteger\u003e {\n    @Argument(isRequired = true)\n    public String message;\n}\n```\n\nAnd here is the registration of your command and the implementation of CommandCallback.\n\n```java\nAppSpector.shared().commands().register(ShowToastCommand.class, new CommandCallback\u003cInteger, ShowToastCommand\u003e() {\n    @Override\n    public void exec(@NonNull final ShowToastCommand command, @NonNull final Responder\u003cInteger\u003e responder) {\n        new Handler(Looper.getMainLooper()).post(new Runnable() {\n            @Override\n            public void run() {\n                Toast.makeText(getContext(), command.message, Toast.LENGTH_SHORT).show();\n                responder.ok(42);\n            }\n        });\n    }\n});\n```\n\nThis command will appear under the `Application` category and will have `Show message` name on the dashboard. You can use your own categories for grouping commands on the dashboard.\n\n__Commands can be registered only after running the SDK.__\n\n\n# Feedback\nLet us know what do you think or what would you like to be improved: [info@appspector.com](mailto:info@appspector.com).\n\n[Join our slack to discuss setup process and features](https://slack.appspector.com)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappspector%2Fandroid-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappspector%2Fandroid-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappspector%2Fandroid-sdk/lists"}