Migrowanie danych śledzenia wersji z aplikacji platformy Xamarin.Forms do aplikacji .NET MAUI
Interfejs użytkownika aplikacji wieloplatformowej platformy Xamarin.Essentials i .NET (.NET MAUI) mają klasę VersionTracking
, która umożliwia sprawdzanie wersji i numerów kompilacji aplikacji oraz dodatkowych informacji, takich jak to, czy po raz pierwszy aplikacja została uruchomiona. Jednak w środowisku Xamarin.Essentials dane śledzenia wersji są przechowywane w kontenerze preferencji specyficznych dla platformy o nazwie {your-app-package-id}.xamarinessentials.versiontracking
, podczas gdy w programie .NET MAUI dane śledzenia wersji są przechowywane w kontenerze preferencji specyficznych dla platformy o nazwie {your-app-package-id}.microsoft.maui.essentials.versiontracking
.
Podczas migrowania aplikacji platformy Xamarin.Forms korzystającej z klasy do interfejsu VersionTracking
MAUI platformy .NET należy radzić sobie z różnicą nazewnictwa kontenerów preferencji, aby zapewnić użytkownikom bezproblemowe środowisko uaktualniania. W tym artykule opisano sposób użycia LegacyVersionTracking
klas i klas pomocników do obsługi kontenera preferencji. Klasa LegacyVersionTracking
umożliwia aplikacji .NET MAUI w systemach Android, iOS i Windows odczytywanie danych śledzenia wersji utworzonych przy użyciu poprzedniej wersji aplikacji Xamarin.Forms.
Ważne
LegacyVersionTracking
Aby klasa działała poprawnie, aplikacja .NET MAUI musi mieć wyższy numer wersji niż numer wersji aplikacji Xamarin.Forms. Numer wersji można ustawić w pliku projektu aplikacji .NET MAUI z właściwościami $(ApplicationVersion)
i $(ApplicationDisplayVersion)
kompilacji.
Aby uzyskać więcej informacji na temat VersionTracking
klasy na platformie Xamarin.Essentials, zobacz Xamarin.Essentials: Śledzenie wersji. Aby uzyskać więcej informacji na temat VersionTracking klasy w programie .NET MAUI, zobacz Śledzenie wersji.
Uzyskiwanie dostępu do starszych danych śledzenia wersji
Poniższy kod przedstawia klasę LegacyVersionTracking
, która zapewnia dostęp do danych śledzenia wersji utworzonych przez aplikację platformy Xamarin.Forms:
Uwaga
Aby użyć tego kodu, dodaj go do klasy o nazwie LegacyVersionTracking
w projekcie aplikacji .NET MAUI.
namespace MigrationHelpers;
public static class LegacyVersionTracking
{
const string versionsKey = "VersionTracking.Versions";
const string buildsKey = "VersionTracking.Builds";
static readonly string sharedName = LegacyPreferences.GetPrivatePreferencesSharedName("versiontracking");
static Dictionary<string, List<string>> versionTrail;
static string LastInstalledVersion => versionTrail[versionsKey].LastOrDefault();
static string LastInstalledBuild => versionTrail[buildsKey].LastOrDefault();
public static string VersionsKey => versionsKey;
public static string BuildsKey => buildsKey;
public static string SharedName => sharedName;
public static bool IsFirstLaunchEver { get; private set; }
public static bool IsFirstLaunchForCurrentVersion { get; private set; }
public static bool IsFirstLaunchForCurrentBuild { get; private set; }
public static string CurrentVersion => AppInfo.VersionString;
public static string CurrentBuild => AppInfo.BuildString;
public static string PreviousVersion => GetPrevious(versionsKey);
public static string PreviousBuild => GetPrevious(buildsKey);
public static string FirstInstalledVersion => versionTrail[versionsKey].FirstOrDefault();
public static string FirstInstalledBuild => versionTrail[buildsKey].FirstOrDefault();
public static IEnumerable<string> VersionHistory => versionTrail[versionsKey].ToArray();
public static IEnumerable<string> BuildHistory => versionTrail[buildsKey].ToArray();
public static bool IsFirstLaunchForVersion(string version) => CurrentVersion == version && IsFirstLaunchForCurrentVersion;
public static bool IsFirstLaunchForBuild(string build) => CurrentBuild == build && IsFirstLaunchForCurrentBuild;
static LegacyVersionTracking()
{
InitVersionTracking();
}
internal static void InitVersionTracking()
{
IsFirstLaunchEver = !LegacyPreferences.ContainsKey(versionsKey, sharedName) || !LegacyPreferences.ContainsKey(buildsKey, sharedName);
if (IsFirstLaunchEver)
{
versionTrail = new Dictionary<string, List<string>>
{
{ versionsKey, new List<string>() },
{ buildsKey, new List<string>() }
};
}
else
{
versionTrail = new Dictionary<string, List<string>>
{
{ versionsKey, ReadHistory(versionsKey).ToList() },
{ buildsKey, ReadHistory(buildsKey).ToList() }
};
}
IsFirstLaunchForCurrentVersion = !versionTrail[versionsKey].Contains(CurrentVersion) || CurrentVersion != LastInstalledVersion;
if (IsFirstLaunchForCurrentVersion)
{
// Avoid duplicates and move current version to end of list if already present
versionTrail[versionsKey].RemoveAll(v => v == CurrentVersion);
versionTrail[versionsKey].Add(CurrentVersion);
}
IsFirstLaunchForCurrentBuild = !versionTrail[buildsKey].Contains(CurrentBuild) || CurrentBuild != LastInstalledBuild;
if (IsFirstLaunchForCurrentBuild)
{
// Avoid duplicates and move current build to end of list if already present
versionTrail[buildsKey].RemoveAll(b => b == CurrentBuild);
versionTrail[buildsKey].Add(CurrentBuild);
}
}
static string GetPrevious(string key)
{
var trail = versionTrail[key];
return (trail.Count >= 2) ? trail[trail.Count - 2] : null;
}
static string[] ReadHistory(string key) => LegacyPreferences.Get(key, null, sharedName)?.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) ?? new string[0];
}
Klasa LegacyVersionTracking
używa LegacyPreferences
klasy , która zapewnia dostęp do danych śledzenia wersji przechowywanych przez klasę Xamarin.Essentials Preferences
z aplikacji Xamarin.Forms:
Uwaga
Aby użyć tego kodu, dodaj go do klasy o nazwie LegacyPreferences
w projekcie aplikacji .NET MAUI.
#if ANDROID || IOS || WINDOWS
namespace MigrationHelpers;
public static partial class LegacyPreferences
{
internal static string GetPrivatePreferencesSharedName(string feature) => $"{AppInfo.PackageName}.xamarinessentials.{feature}";
public static bool ContainsKey(string key, string sharedName) => PlatformContainsKey(key, sharedName);
public static void Remove(string key, string sharedName) => PlatformRemove(key, sharedName);
public static string Get(string key, string defaultValue, string sharedName) => PlatformGet<string>(key, defaultValue, sharedName);
}
#endif
Klasa LegacyPreferences
jest klasą partial
, której pozostała implementacja jest specyficzna dla platformy.
Android
W systemie Android LegacyPreferences
klasa udostępnia implementację kontenera preferencji, która pobiera dane z udostępnionych preferencji. Poniższy kod przedstawia klasę LegacyPreferences
:
Uwaga
Aby użyć tego kodu, dodaj go do klasy o nazwie LegacyPreferences
w folderze Platforms\Android projektu aplikacji .NET MAUI.
using System.Globalization;
using Android.Content;
using Android.Preferences;
using Application = Android.App.Application;
namespace MigrationHelpers;
public static partial class LegacyPreferences
{
static readonly object locker = new object();
static bool PlatformContainsKey(string key, string sharedName)
{
lock (locker)
{
using (var sharedPreferences = GetSharedPreferences(sharedName))
{
return sharedPreferences.Contains(key);
}
}
}
static void PlatformRemove(string key, string sharedName)
{
lock (locker)
{
using (var sharedPreferences = GetSharedPreferences(sharedName))
using (var editor = sharedPreferences.Edit())
{
editor.Remove(key).Apply();
}
}
}
static T PlatformGet<T>(string key, T defaultValue, string sharedName)
{
lock (locker)
{
object value = null;
using (var sharedPreferences = GetSharedPreferences(sharedName))
{
if (defaultValue == null)
{
value = sharedPreferences.GetString(key, null);
}
else
{
switch (defaultValue)
{
case int i:
value = sharedPreferences.GetInt(key, i);
break;
case bool b:
value = sharedPreferences.GetBoolean(key, b);
break;
case long l:
value = sharedPreferences.GetLong(key, l);
break;
case double d:
var savedDouble = sharedPreferences.GetString(key, null);
if (string.IsNullOrWhiteSpace(savedDouble))
{
value = defaultValue;
}
else
{
if (!double.TryParse(savedDouble, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var outDouble))
{
var maxString = Convert.ToString(double.MaxValue, CultureInfo.InvariantCulture);
outDouble = savedDouble.Equals(maxString) ? double.MaxValue : double.MinValue;
}
value = outDouble;
}
break;
case float f:
value = sharedPreferences.GetFloat(key, f);
break;
case string s:
// the case when the string is not null
value = sharedPreferences.GetString(key, s);
break;
}
}
}
return (T)value;
}
}
static ISharedPreferences GetSharedPreferences(string sharedName)
{
var context = Application.Context;
return string.IsNullOrWhiteSpace(sharedName) ?
#pragma warning disable CS0618 // Type or member is obsolete
PreferenceManager.GetDefaultSharedPreferences(context) :
#pragma warning restore CS0618 // Type or member is obsolete
context.GetSharedPreferences(sharedName, FileCreationMode.Private);
}
}
iOS
W systemie iOS LegacyPreferences
klasa udostępnia implementację kontenera preferencji, która pobiera dane z NSUserDefaults
klasy . Poniższy kod przedstawia klasę LegacyPreferences
:
Uwaga
Aby użyć tego kodu, dodaj go do klasy o nazwie LegacyPreferences
w folderze Platforms\iOS projektu aplikacji .NET MAUI.
using Foundation;
using System.Globalization;
namespace MigrationHelpers;
public static partial class LegacyPreferences
{
static readonly object locker = new object();
static bool PlatformContainsKey(string key, string sharedName)
{
lock (locker)
{
return GetUserDefaults(sharedName)[key] != null;
}
}
static void PlatformRemove(string key, string sharedName)
{
lock (locker)
{
using (var userDefaults = GetUserDefaults(sharedName))
{
if (userDefaults[key] != null)
userDefaults.RemoveObject(key);
}
}
}
static T PlatformGet<T>(string key, T defaultValue, string sharedName)
{
object value = null;
lock (locker)
{
using (var userDefaults = GetUserDefaults(sharedName))
{
if (userDefaults[key] == null)
return defaultValue;
switch (defaultValue)
{
case int i:
value = (int)(nint)userDefaults.IntForKey(key);
break;
case bool b:
value = userDefaults.BoolForKey(key);
break;
case long l:
var savedLong = userDefaults.StringForKey(key);
value = Convert.ToInt64(savedLong, CultureInfo.InvariantCulture);
break;
case double d:
value = userDefaults.DoubleForKey(key);
break;
case float f:
value = userDefaults.FloatForKey(key);
break;
case string s:
// the case when the string is not null
value = userDefaults.StringForKey(key);
break;
default:
// the case when the string is null
if (typeof(T) == typeof(string))
value = userDefaults.StringForKey(key);
break;
}
}
}
return (T)value;
}
static NSUserDefaults GetUserDefaults(string sharedName)
{
if (!string.IsNullOrWhiteSpace(sharedName))
return new NSUserDefaults(sharedName, NSUserDefaultsType.SuiteName);
else
return NSUserDefaults.StandardUserDefaults;
}
}
Windows
W systemie Windows LegacyVersionTracking
klasa udostępnia implementację kontenera preferencji, która pobiera dane z ApplicationDataContainerklasy . Poniższy kod przedstawia klasę LegacyPreferences
:
Uwaga
Aby użyć tego kodu, dodaj go do klasy o nazwie LegacyPreferences
w folderze Platformy\Windows projektu aplikacji .NET MAUI.
using Windows.Storage;
namespace MigrationHelpers;
public static partial class LegacyPreferences
{
static readonly object locker = new object();
static bool PlatformContainsKey(string key, string sharedName)
{
lock (locker)
{
var appDataContainer = GetApplicationDataContainer(sharedName);
return appDataContainer.Values.ContainsKey(key);
}
}
static void PlatformRemove(string key, string sharedName)
{
lock (locker)
{
var appDataContainer = GetApplicationDataContainer(sharedName);
if (appDataContainer.Values.ContainsKey(key))
appDataContainer.Values.Remove(key);
}
}
static T PlatformGet<T>(string key, T defaultValue, string sharedName)
{
lock (locker)
{
var appDataContainer = GetApplicationDataContainer(sharedName);
if (appDataContainer.Values.ContainsKey(key))
{
var tempValue = appDataContainer.Values[key];
if (tempValue != null)
return (T)tempValue;
}
}
return defaultValue;
}
static ApplicationDataContainer GetApplicationDataContainer(string sharedName)
{
var localSettings = ApplicationData.Current.LocalSettings;
if (string.IsNullOrWhiteSpace(sharedName))
return localSettings;
if (!localSettings.Containers.ContainsKey(sharedName))
localSettings.CreateContainer(sharedName, ApplicationDataCreateDisposition.Always);
return localSettings.Containers[sharedName];
}
}
Korzystanie ze starszych danych śledzenia wersji
Klasa LegacyVersionTracking
może służyć do pobierania danych śledzenia wersji w systemach Android, iOS i Windows utworzonych przy użyciu poprzedniej wersji platformy Xamarin.Forms aplikacji:
#if ANDROID || IOS || WINDOWS
using MigrationHelpers;
...
string isFirstLaunchEver = LegacyVersionTracking.IsFirstLaunchEver.ToString();
string currentVersionIsFirst = LegacyVersionTracking.IsFirstLaunchForCurrentVersion.ToString();
string currentBuildIsFirst = LegacyVersionTracking.IsFirstLaunchForCurrentBuild.ToString();
string currentVersion = LegacyVersionTracking.CurrentVersion.ToString();
string currentBuild = LegacyVersionTracking.CurrentBuild.ToString();
string firstInstalledVer = LegacyVersionTracking.FirstInstalledVersion.ToString();
string firstInstalledBuild = LegacyVersionTracking.FirstInstalledBuild.ToString();
string versionHistory = String.Join(',', LegacyVersionTracking.VersionHistory);
string buildHistory = String.Join(',', LegacyVersionTracking.BuildHistory);
string previousVersion = LegacyVersionTracking.PreviousVersion?.ToString() ?? "none";
string previousBuild = LegacyVersionTracking.PreviousBuild?.ToString() ?? "none";
#endif
W tym przykładzie LegacyVersionTracking
pokazano użycie klasy do odczytywania starszych danych śledzenia wersji. Nie można jednak przypisać tych danych do klasy .NET MAUI VersionTracking , ponieważ nie można ustawić jej właściwości. Zamiast tego dane można zapisywać w preferencjach programu .NET MAUI za pomocą WriteHistory
metody :
void WriteHistory(string key, IEnumerable<string> history)
{
Preferences.Default.Set(key, string.Join("|", history), $"{AppInfo.Current.PackageName}.microsoft.maui.essentials.versiontracking");
}
#if ANDROID || IOS || WINDOWS
WriteHistory(LegacyVersionTracking.VersionsKey, LegacyVersionTracking.VersionHistory);
WriteHistory(LegacyVersionTracking.BuildsKey, LegacyVersionTracking.BuildHistory);
#endif
Gdy starsze dane śledzenia wersji zostały zapisane w preferencjach programu .NET MAUI, mogą być używane przez klasę .NET MAUI VersionTracking :
var mauiVersionHistory = VersionTracking.Default.VersionHistory;
var mauiBuildHistory = VersionTracking.Default.BuildHistory;
Starsze dane śledzenia wersji można następnie usunąć z urządzenia:
#if ANDROID || IOS || WINDOWS
LegacyPreferences.Remove(LegacyVersionTracking.VersionsKey, LegacyVersionTracking.SharedName);
LegacyPreferences.Remove(LegacyVersionTracking.BuildsKey, LegacyVersionTracking.SharedName);
#endif