protected override IPreferenceStore CreatePreferenceStore() { const string preferencesVersionKey = "preferencesVersion"; const string inspectorBundleId = "com.xamarin.Inspector"; var preferenceStore = new NSUserDefaultsPreferenceStore(synchronizeOnSet: true); // Check for, and if necessary, perform a one-time preferences migration from // com.xamarin.Inspector to com.xamarin.Workbooks, allowing the two client // applications to more fully split (they no longer share CFBundleIdentifier) if (ClientInfo.Flavor == ClientFlavor.Inspector || preferenceStore.GetInt64(preferencesVersionKey) >= 2) { return(preferenceStore); } var migratedPrefs = 0; using (var inspectorDefaults = new NSUserDefaults()) { inspectorDefaults.AddSuite(inspectorBundleId); foreach (var item in inspectorDefaults.ToDictionary()) { if (item.Key is NSString nsKey && item.Value != null) { var key = nsKey.ToString(); switch (key) { // preserve some Cocoa/WebKit preferences case "WebKitDeveloperExtras": case "NSNavLastRootDirectory": case "NSNavRecentPlaces": break; default: // preserve all nav panel (open/save) prefs if (key.StartsWith("NSNavPanel", StringComparison.Ordinal)) { break; } // lastly, preserve our own explicit preferences if (key.StartsWith(inspectorBundleId + ".", StringComparison.Ordinal)) { key = preferenceStore.BundleId + key.Substring(inspectorBundleId.Length); break; } // there are tons of "junk" preferences/state stored by various // controls (e.g. frame dimensions) that I'd rather just discard continue; } preferenceStore.UserDefaults.SetValueForKey(item.Value, new NSString(key)); migratedPrefs++; } } preferenceStore.Set(preferencesVersionKey, 2); preferenceStore.UserDefaults.Synchronize(); Log.Info(TAG, $"Migrated {migratedPrefs} preferences from " + $"{inspectorBundleId} to {preferenceStore.BundleId}"); } return(preferenceStore); }