{"id":36417953,"url":"https://github.com/pablobaxter/harmony","last_synced_at":"2026-01-11T17:01:17.421Z","repository":{"id":43225965,"uuid":"257517336","full_name":"pablobaxter/Harmony","owner":"pablobaxter","description":"Multi-process SharedPreference implementation without ContentProvider","archived":false,"fork":false,"pushed_at":"2025-11-22T08:09:46.000Z","size":775,"stargazers_count":98,"open_issues_count":7,"forks_count":9,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-11-22T08:28:07.382Z","etag":null,"topics":["android","encrypted-preferences","encryptedsharedpreferences","multi-process","multiprocess","sharedpreferences"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pablobaxter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","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},"funding":{"github":"pablobaxter"}},"created_at":"2020-04-21T07:40:54.000Z","updated_at":"2025-11-22T08:09:49.000Z","dependencies_parsed_at":"2022-08-26T10:10:52.806Z","dependency_job_id":"5744a03a-8bda-4754-b2db-2541377b3be1","html_url":"https://github.com/pablobaxter/Harmony","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/pablobaxter/Harmony","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablobaxter%2FHarmony","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablobaxter%2FHarmony/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablobaxter%2FHarmony/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablobaxter%2FHarmony/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pablobaxter","download_url":"https://codeload.github.com/pablobaxter/Harmony/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pablobaxter%2FHarmony/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28314259,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-11T14:58:17.114Z","status":"ssl_error","status_checked_at":"2026-01-11T14:55:53.580Z","response_time":60,"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","encrypted-preferences","encryptedsharedpreferences","multi-process","multiprocess","sharedpreferences"],"created_at":"2026-01-11T17:00:35.388Z","updated_at":"2026-01-11T17:01:17.393Z","avatar_url":"https://github.com/pablobaxter.png","language":"Kotlin","funding_links":["https://github.com/sponsors/pablobaxter"],"categories":[],"sub_categories":[],"readme":"# [Harmony — Multiprocess SharedPreferences](https://medium.com/@pablobaxter/harmony-sharedpreferences-4d0fb500907e?source=friends_link\u0026sk=22b45fe99fe66a085dc8d455d0d90178)\n\n[![CircleCI](https://circleci.com/gh/pablobaxter/Harmony/tree/main.svg?style=shield)](https://circleci.com/gh/pablobaxter/Harmony/tree/main)\n[![GitHub](https://img.shields.io/github/license/pablobaxter/harmony)](https://github.com/pablobaxter/Harmony/blob/main/LICENSE)\n[![Maven Central](https://img.shields.io/maven-central/v/com.frybits.harmony/harmony?label=Harmony)](https://search.maven.org/artifact/com.frybits.harmony/harmony/1.2.6/aar) [![Harmony API](https://img.shields.io/badge/API-23%2B-brightgreen.svg?style=flat\u0026label=Harmony%20API)](https://android-arsenal.com/api?level=23) [![Maven Central](https://img.shields.io/maven-central/v/com.frybits.harmony/harmony-crypto?label=Harmony-Crypto)](https://search.maven.org/artifact/com.frybits.harmony/harmony-crypto/1.2.6/aar) [![Crypto API](https://img.shields.io/badge/API-23%2B-purple.svg?style=flat\u0026label=Crypto%20API)](https://android-arsenal.com/api?level=23)\n\nWorking on multiprocess Android apps is a complex undertaking. One of the biggest challenges is managing shared data between the multiple processes. Most solutions rely on one process to be available for another to read the data, which can be quite slow and could potentially lead to ANRs.\n\nHarmony is a thread-safe, process-safe, full [`SharedPreferences`](https://developer.android.com/reference/android/content/SharedPreferences) implementation. It can be used in place of [`SharedPreferences`](https://developer.android.com/reference/android/content/SharedPreferences) everywhere.\n\n## Features\n- Built to support multiprocess apps\n- Each process can open a Harmony `SharedPreference` object, without requiring another process to start\n- Full [`SharedPreferences`](https://developer.android.com/reference/android/content/SharedPreferences) implementation\n- [`OnSharedPreferenceChangeListener`](https://developer.android.com/reference/android/content/SharedPreferences.OnSharedPreferenceChangeListener) emits changes made by other processes\n- Uses no native code (NDK) or any IPC classes such as [`ContentProvider`](https://developer.android.com/reference/android/content/ContentProvider), [`Service`](https://developer.android.com/reference/android/app/Service), [`BroadcastReceiver`](https://developer.android.com/reference/android/content/BroadcastReceiver), or [AIDL](https://developer.android.com/guide/components/aidl)\n- Built-in failed-write recovery similar to the default [`SharedPreferences`](https://developer.android.com/reference/android/content/SharedPreferences)\n- Supports Android API 23+\n\n## Download\nThe latest release is available on [Maven Central](https://search.maven.org/artifact/com.frybits.harmony/harmony/1.2.6/aar).\n### Gradle\n```\nimplementation 'com.frybits.harmony:harmony:1.2.6'\n// implementation 'com.frybits.harmony:harmony-crypto:1.2.6' // For Encrypted SharedPreferences\n```\n\n## Usage\n### Creating Harmony SharedPreferences\n#### Kotlin\n```kotlin\n// Getting Harmony SharedPreferences\nval prefs: SharedPreferences = context.getHarmonySharedPreferences(\"PREF_NAME\")\n```\n\n#### Java\n```java\n// Getting Harmony SharedPreferences\nSharedPreferences prefs = Harmony.getSharedPreferences(context, \"PREF_NAME\")\n```\n\nOR\n\n### Creating Encrypted Harmony SharedPreferences (Requires `harmony-crypto` library)\n#### Kotlin\n```kotlin\n// Getting Encrypted Harmony SharedPreferences\nval prefs: SharedPreferences = context.getEncryptedHarmonySharedPreferences(\n            \"PREF_NAME\",\n            MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),\n            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,\n            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM\n        )\n```\n\n#### Java\n```java\n// Getting Encrypted Harmony SharedPreferences\nSharedPreferences prefs = EncryptedHarmony.getSharedPreferences(\n            context, \n            \"PREF_NAME\",\n            MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),\n            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,\n            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM\n          )\n```\n\nOnce you have this `SharedPreferences` object, it can be used just like any other `SharedPreferences`. The main difference with Harmony is that any change made to `\"PREF_NAME\"` using `apply()` or `commit()` is reflected across all processes.\n\n**NOTE: Changes in Harmony do not reflect in Android SharedPreferences and vice-versa!** \n\n## Performance\n\nThe following are comparison performance tests of some popular multiprocess preference libraries. Each test measures the time it takes to insert 1000 items individually into the preference library (Write), the time it takes to read each 1000 items individually (Read), and how long it took for each item to be available in an alternate process (IPC). Each test was run 10 times. All values in the table below are the average time for a single item to be inserted, read, and available in the alternate process.\n\nTests were broken into two separate categories:\n- Asynchronous writing (if applicable)\n- Synchronous writing\n\nLogic for tests can been seen in the [`TestRunner.kt`](app/src/main/java/com/frybits/harmony/app/test/TestRunner.kt) file.\n\n**Notes** \n- All tests were performed on a Google Pixel 6 Pro running Android 14\n- Times are for single item operation.\n\n#### Asynchronous Tests\n\n|Library                                             | Read (avg) | Write (avg) | IPC (avg) \u003csup\u003e1\u003c/sup\u003e  |\n|----------------------------------------------------|------------|-------------|-------------------------|\n|SharedPreferences                                   | 0.0004 ms  | 0.029ms     | N/A                     |\n|Harmony                                             | 0.001 ms   | 0.026 ms    | 113.417 ms              |\n|[MMKV](https://github.com/Tencent/MMKV) \u003csup\u003e2\u003c/sup\u003e| 0.012 ms   | 0.051 ms    | 152.887 ms \u003csup\u003e3\u003c/sup\u003e |\n|[Tray](https://github.com/GCX-HCI/tray) \u003csup\u003e2\u003c/sup\u003e| 1.501 ms   | 1.917 ms    | 1.294 s                 |\n\n\n#### Synchronous Tests\n\n|Library                                             | Read (avg) | Write (avg) | IPC (avg) \u003csup\u003e1\u003c/sup\u003e  |\n|----------------------------------------------------|------------|-------------|-------------------------|\n|SharedPreferences                                   | 0.0002 ms  | 0.429 ms    | N/A                     |\n|Harmony                                             | 0.002 ms   | 6.466 ms    | 11.692 ms               |\n|[MMKV](https://github.com/Tencent/MMKV) \u003csup\u003e2\u003c/sup\u003e| 0.013 ms   | 0.046 ms    | 168.328 ms \u003csup\u003e3\u003c/sup\u003e |\n|[Tray](https://github.com/GCX-HCI/tray) \u003csup\u003e2\u003c/sup\u003e| 1.589 ms   | 1.956 ms    | 1.384 s                 |\n\n\u003csup\u003e1\u003c/sup\u003e IPC is the time it took for the item to be available in a secondary process. SharedPreferences doesn't support IPC.\n\n\u003csup\u003e2\u003c/sup\u003e These libraries don't support asynchronous writes. All tests were synchronous writes by default.\n\n\u003csup\u003e3\u003c/sup\u003e MMKV doesn't support a change listener, so a while-loop in a separate thread was used to determine how soon the data was available in the separate process. See [`MMKVRemoteTestRunnerService.kt`](app/src/main/java/com/frybits/harmony/app/test/MMKVRemoteTestRunnerService.kt) for implementation details.\n\n## Special thanks\n\nThis section is to give a special thanks to individuals that helped with getting this project where it is today.\n- JD - For the batching idea, reviewing the code, and all around bouncing of ideas to improve this project. \n- [@orrinLife360](https://github.com/orrinLife360) - For helping review some of the more critical improvements.\n- [@imminent](https://github.com/imminent) - For all the Kotlin insight and helping review many of the changes on this project.\n- [@bipin360](https://github.com/bipin360) - For pushing me on this project when I was unsure about it.\n\nFinally, a very special thank you to [@life360](https://github.com/life360) for integrating this project and providing incredibly valuable feedback that I was able to use to improve Harmony.\n\n## License\n```\n   Copyright 2020 Pablo Baxter\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpablobaxter%2Fharmony","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpablobaxter%2Fharmony","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpablobaxter%2Fharmony/lists"}