Note: This app was built with Claude (AI) and only briefly tested. There may still be bugs. PRs and issue reports welcome.
A no-root Android app to merge, deduplicate, and clean contact lists. Import from VCF files, Android DB backups, or the device's own contacts — then export a clean VCF or write directly back to the phone. Supports combining multiple sources in one session.
| Multi-source merge | Import any combination of VCF files, DB backups, and device contacts in one session — all merged and deduped together |
| Configurable dedup | Three strictness modes: exact match, shared phone number, or same name |
| Duplicate review | See a list of every removed duplicate before committing the export |
| Country code fix | Adds country prefix to bare local numbers (US, Israel, UK, Australia + more) |
| Export VCF 3.0 | Clean UTF-8 VCF via the system file picker — you choose the location |
| Write to device | Imports contacts directly to the phone via WRITE_CONTACTS |
| No root needed | Live contacts accessed via ContactsContract; files via SAF picker |
| D-pad friendly | Full keyboard/remote navigation with visible focus indicators |
- Tap an import source (VCF, DB, or Device). Repeat to add more sources — each import merges into the current session.
- Tap Export VCF or Add to Device. You'll first see a list of all removed duplicates and can go back if something looks wrong.
- Choose where to save the VCF (or confirm the device import).
- Tap Clear All to start a new session.
Settings (⚙) let you choose the country code prefix and dedup strictness. Changes take effect on the next import.
| Mode | A duplicate is... |
|---|---|
| Exact match (default) | Same name + same phones + same emails + same org |
| Same phone | Shares any normalised phone number |
| Same name | Same display name (case-insensitive) |
Numbers with + are never touched. Numbers not matching the selected country's local pattern are left as-is.
US/Canada (+1), Israel (+972), UK (+44), Australia (+61), Germany (+49), France (+33), India (+91), Brazil (+55), Mexico (+52), Japan (+81), South Korea (+82).
pkg install aapt2 ecj d8 apksigner openjdk-17android.jar is a compile-time stub — not bundled in the APK. Fetch it once:
# Option A — direct zip (faster, no sdkmanager needed)
wget https://dl.google.com/android/repository/platform-35_r01.zip
unzip -j platform-35_r01.zip "android-35/android.jar" -d ~/.android/
rm platform-35_r01.zip# Option B — via sdkmanager
mkdir -p ~/android-sdk/cmdline-tools && cd ~/android-sdk/cmdline-tools
wget https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip
unzip commandlinetools-linux-11076708_latest.zip && mv cmdline-tools latest
~/android-sdk/cmdline-tools/latest/bin/sdkmanager \
--sdk_root="$HOME/android-sdk" "platforms;android-35"
cp ~/android-sdk/platforms/android-35/android.jar ~/.android/Required by aapt2 for resource linking:
cp /system/framework/framework-res.apk ~/.android/build.sh expects ~/.android/debug.keystore with alias androiddebugkey. To create one:
keytool -genkey -v \
-keystore ~/.android/debug.keystore \
-storepass android -alias androiddebugkey -keypass android \
-keyalg RSA -keysize 2048 -validity 10000 \
-dname "CN=Android Debug,O=Android,C=US"chmod +x build.sh
./build.sh
adb install -r ContactFix.apk
# or: cp ContactFix.apk /sdcard/Keep the same keystore for future updates — a different key requires uninstalling first.
| Permission | Trigger | Purpose |
|---|---|---|
READ_CONTACTS |
"Device contacts" button | Read live contacts |
WRITE_CONTACTS |
"Add to Device" button | Write contacts back |
No internet permission. No broad storage permission — all file access is through the SAF picker (per-URI grants).
- Min: Android 5.0 (API 21)
- Target: Android 15/16 (API 35)
- On Android 5.x, permissions are granted at install time. Runtime prompts appear on Android 6+.
- The live
contacts2.dbon-device file is still root-only; the DB import is for offline backups of that file (e.g. from an ADB or Titanium backup).