8年前のMacBook Air(Intel)で全テスト済み。7本のMacアプリをソロ開発した実体験から書いています。案件でも広告でもありません。
HiyokoAutoSyncはAndroidとMac間の双方向同期を行う。双方向同期には難しい問題がある:同じファイルが両方で変更されたらどうするか?その対処法を紹介する。
コンフリクトのケース
- 前回の同期以降、両方で同じファイルが変更された——どちらが勝つか?
- 片方で削除、もう片方で変更された——削除するか残すか?
- 片方でファイルが移動された——もう片方でも移動するか、削除+新規作成として扱うか?
ほとんどの同期アプリはケース1と3を放置している。私のアプローチを紹介する。
コンフリクトの検出
最後の同期状態をSQLiteで追跡する:
CREATE TABLE sync_state (
file_path TEXT PRIMARY KEY,
mac_hash TEXT,
android_hash TEXT,
mac_modified INTEGER,
android_modified INTEGER,
last_synced INTEGER
);
同期チェック時:
fn classify_file(record: &SyncRecord, mac_stat: &FileStat, android_stat: &FileStat) -> SyncAction {
let mac_changed = mac_stat.hash != record.mac_hash;
let android_changed = android_stat.hash != record.android_hash;
match (mac_changed, android_changed) {
(true, false) => SyncAction::CopyToAndroid,
(false, true) => SyncAction::CopyToMac,
(false, false) => SyncAction::NoOp,
(true, true) => SyncAction::Conflict,
}
}
コンフリクト解決戦略
ユーザーが設定できる3つの戦略を用意している:
新しい方が勝つ:更新タイムスタンプを比較して新しいファイルを残す。
SyncAction::Conflict => {
if mac_stat.modified > android_stat.modified {
SyncAction::CopyToAndroid
} else {
SyncAction::CopyToMac
}
}
Macが常に勝つ:Macをソースオブトゥルースとして扱うユーザー向け。
両方残す:片方のファイルにコンフリクトサフィックスを付けて両方のバージョンを保持する。
// Androidバージョンを "file.conflict-2026-05-01.ext" にリネーム
let conflict_name = add_conflict_suffix(&file_path);
copy_to_mac_as(&android_file, &conflict_name)?;
copy_to_android(&mac_file)?;
削除 vs 変更のコンフリクト
Macで削除、Androidで変更された場合:
(Deleted, Modified) => {
// デフォルト:変更されたファイルを残してMacに復元
// 代替案:両方から削除
// ユーザーが設定可能
SyncAction::RestoreToMac
}
安全なデフォルトはデータを残すことだ。コンフリクト時に両方から削除すると、ユーザーが意図しないデータロスを引き起こす可能性がある。
まとめ
コンフリクト解決のない双方向同期は、発生待ちのバグだ。「新しい方が勝つ」戦略で現実のケースの90%をカバーできる。「両方残す」で残りをカバーする。パワーユーザー向けに設定できるようにしよう。
記事が参考になったら ❤️ もらえると励みになります!
HiyokoAutoSync | X → @hiyoyok