{"id":44844487,"url":"https://github.com/easyhooon/dari","last_synced_at":"2026-05-13T09:01:21.171Z","repository":{"id":337931121,"uuid":"1155220063","full_name":"easyhooon/dari","owner":"easyhooon","description":"Android library for inspecting WebView bridge messages in real time, inspired by Chucker.","archived":false,"fork":false,"pushed_at":"2026-05-13T07:06:25.000Z","size":5586,"stargazers_count":17,"open_issues_count":6,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-13T07:35:33.473Z","etag":null,"topics":["android","android-library","bridge","debugger","kotlin","webview"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","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/easyhooon.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-11T09:06:33.000Z","updated_at":"2026-05-13T06:09:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/easyhooon/dari","commit_stats":null,"previous_names":["easyhooon/dari"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/easyhooon/dari","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyhooon%2Fdari","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyhooon%2Fdari/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyhooon%2Fdari/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyhooon%2Fdari/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/easyhooon","download_url":"https://codeload.github.com/easyhooon/dari/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/easyhooon%2Fdari/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32975183,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T06:31:55.726Z","status":"ssl_error","status_checked_at":"2026-05-13T06:31:51.336Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","android-library","bridge","debugger","kotlin","webview"],"created_at":"2026-02-17T04:16:39.494Z","updated_at":"2026-05-13T09:01:21.157Z","avatar_url":"https://github.com/easyhooon.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dari\n\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.easyhooon/dari)](https://central.sonatype.com/artifact/io.github.easyhooon/dari)\n\n**Dari** (다리) means **\"bridge\"** in Korean. Dari is an Android library for inspecting WebView bridge communication in real time, inspired by [Chucker](https://github.com/ChuckerTeam/chucker).\n\nJust as Chucker intercepts and displays HTTP traffic, Dari captures and visualizes **WebView JavaScript bridge messages** between your web content and native Android code.\n\n## Screenshots\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eLauncher Shortcut\u003c/b\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eNotification\u003c/b\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eMessage List\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/shortcut_v3.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/notification.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/list_v2.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eOverview\u003c/b\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eRequest\u003c/b\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eResponse\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/overview_v2.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/request_v2.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/response_v2.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eTag Filter\u003c/b\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eSettings\u003c/b\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cb\u003eDark Mode\u003c/b\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/tag_filter.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/share_bottom_sheet.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\"screenshots/dark_mode.jpeg\" width=\"270\" /\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Features\n\n- Intercepts Web-to-App and App-to-Web bridge messages\n- **Tag support** for identifying message sources in multi-WebView/Activity environments\n- **Message status tracking** — `IN_PROGRESS`, `SUCCESS`, `ERROR` with color-coded indicators\n- **Status filtering** — filter messages by status via chips\n- Chucker-style persistent notification showing recent bridge activity\n- Message list UI with search, filter by handler name, and **tag-based filtering**\n- Detail view with Overview / Request / Response tabs\n- JSON pretty-printing for request and response payloads\n- Export messages as text or JSON\n- **Shake-to-open** — shake device to launch Dari UI (with haptic feedback)\n- **Dark mode** — System / Light / Dark theme toggle\n- **Settings bottom sheet** — shake toggle, theme selector, clear data, and version info\n- Dynamic launcher shortcut for quick access\n- Zero overhead in release builds via no-op module\n- Auto-initialization via `androidx.startup`\n\n## Setup\n\n### Gradle\n\nAdd the `dari` (debug) and `dari-noop` (release) dependencies to your app's `build.gradle.kts`:\n\n```kotlin\ndependencies {\n    debugImplementation(\"io.github.easyhooon:dari:\u003clatest-version\u003e\")\n    releaseImplementation(\"io.github.easyhooon:dari-noop:\u003clatest-version\u003e\")\n}\n```\n\nThat's it for initialization. Dari auto-initializes via `androidx.startup` when your app starts.\n\n### Interceptor Integration\n\nDari requires **manual injection** of the interceptor into your WebView bridge layer. Create an interceptor instance and call its methods at the appropriate points in your bridge communication code.\n\n#### 1. Create the interceptor\n\n```kotlin\nimport com.easyhooon.dari.Dari\nimport com.easyhooon.dari.interceptor.DariInterceptor\n\n// Basic usage (no tag)\nval interceptor: DariInterceptor? = Dari.createInterceptor()\n\n// With tag — identifies the source in multi-WebView/Activity environments\nval paymentInterceptor: DariInterceptor? = Dari.createInterceptor(tag = \"PaymentWebView\")\nval mainInterceptor: DariInterceptor? = Dari.createInterceptor(tag = \"MainWebView\")\n```\n\nWhen a `tag` is provided, all messages captured by that interceptor are automatically tagged. Tags appear as chips in the message list and can be used to filter messages by source.\n\n#### 2. Intercept Web-to-App messages\n\nCall the interceptor in your `@JavascriptInterface` method when a request arrives and after the response is ready:\n\n```kotlin\n// When a request is received from JavaScript\ninterceptor?.onWebToAppRequest(handlerName, requestId, data)\n\n// After processing, log the response\ninterceptor?.onWebToAppResponse(handlerName, requestId, responseData, isSuccess)\n```\n\n#### 3. Intercept App-to-Web messages\n\nCall the interceptor when your native code sends a message to JavaScript and when the response comes back:\n\n```kotlin\n// When sending a message to JavaScript\ninterceptor?.onAppToWebMessage(handlerName, requestId, data)\n\n// When the web response is received\ninterceptor?.onAppToWebResponse(requestId, isSuccess, responseData)\n```\n\n#### 4. Fire-and-Forget messages (optional requestId)\n\nFor messages that don't require a response (e.g., analytics events, screen tracking), you can pass `null` as the `requestId`:\n\n```kotlin\n// Fire-and-forget: no response expected\ninterceptor?.onWebToAppRequest(handlerName, null, data)\n// No need to call onWebToAppResponse\n```\n\nWhen `requestId` is `null`, the message is treated as standalone and won't be matched with a response.\n\n### Custom Configuration\n\nYou can customize Dari by calling `init` with a config before auto-initialization occurs, or in your `Application.onCreate()`:\n\n```kotlin\nclass MyApp : Application() {\n    override fun onCreate() {\n        super.onCreate()\n        Dari.init(\n            context = this,\n            config = DariConfig(\n                maxEntries = 1000,              // Default: 500\n                showNotification = true,        // Default: true\n                maxContentLength = 500_000,     // Default: 500,000 (truncate large payloads)\n                shakeToOpen = true,             // Default: false\n                retentionPeriod = 1.days,       // Default: null (disabled)\n            )\n        )\n    }\n}\n```\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `maxEntries` | `Int` | `500` | Maximum number of stored messages |\n| `showNotification` | `Boolean` | `true` | Show persistent notification |\n| `maxContentLength` | `Int` | `500,000` | Truncate request/response payloads exceeding this length |\n| `shakeToOpen` | `Boolean` | `false` | Enable shake gesture to open Dari UI |\n| `retentionPeriod` | `Duration?` | `null` | TTL-based message cleanup (e.g., `1.hours`, `3.days`). `null` disables it |\n\n## Module Structure\n\n```\ndari/\n├── dari-core/     ← Shared types (DariConfig, MessageEntry, DariInterceptor, etc.)\n├── dari/          ← Debug library (interceptor, UI, notifications)\n├── dari-noop/     ← Release no-op (same API surface, zero overhead)\n└── sample/        ← Sample app with WebView bridge demo\n```\n\n## Sample App\n\nThe `sample/` module contains a working WebView demo with realistic bridge scenarios: fetching app/device info, showing toast messages, haptic feedback, sharing via native share sheet, clipboard access, opening app settings, and requesting camera permission. Run the sample app, tap the buttons, and observe:\n\n1. A notification appears showing recent bridge messages\n2. Tap the notification to open the message list\n3. Tap any message to see its details (overview, request payload, response payload)\n\n## API Reference\n\n### Dari\n\n| Method | Description |\n|--------|-------------|\n| `init(context, config)` | Initialize with custom configuration |\n| `createInterceptor(tag?)` | Create a `DariInterceptor` with an optional tag (returns `null` in noop) |\n| `setShakeToOpenEnabled(enabled)` | Enable/disable shake-to-open at runtime (persisted) |\n| `setDarkMode(value)` | Override dark mode: `true` / `false` / `null` (system default). Persisted |\n| `showNotification()` | Show the notification (e.g., after permission grant) |\n| `clear()` | Clear all stored messages and dismiss notification |\n\n### DariInterceptor\n\n| Method | Description |\n|--------|-------------|\n| `onWebToAppRequest()` | Log a Web-to-App request. `requestId` is optional for fire-and-forget messages. |\n| `onWebToAppResponse()` | Log the response to a Web-to-App request. Skipped if `requestId` is null. |\n| `onAppToWebMessage()` | Log an App-to-Web message. `requestId` is optional for fire-and-forget messages. |\n| `onAppToWebResponse()` | Log the response to an App-to-Web message. Skipped if `requestId` is null. |\n\n```kotlin\n/**\n * Interface for intercepting WebView bridge communication.\n * Injected into WebViewBridge to capture all bridge messages.\n */\ninterface DariInterceptor {\n    /** Called when a Web -\u003e App request is received */\n    fun onWebToAppRequest(\n        handlerName: String,\n        requestId: String?,\n        requestData: String?,\n    )\n\n    /** Called when a response is sent for a Web -\u003e App request */\n    fun onWebToAppResponse(\n        handlerName: String,\n        requestId: String?,\n        responseData: String?,\n        isSuccess: Boolean,\n    )\n\n    /** Called when an App -\u003e Web message is sent */\n    fun onAppToWebMessage(\n        handlerName: String,\n        requestId: String?,\n        data: String?,\n    )\n\n    /** Called when a web response is received for an App -\u003e Web request */\n    fun onAppToWebResponse(\n        requestId: String?,\n        isSuccess: Boolean,\n        responseData: String?,\n    )\n}\n```\n\n## License\n\n```\nCopyright 2026 easyhooon\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasyhooon%2Fdari","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasyhooon%2Fdari","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasyhooon%2Fdari/lists"}