Migrace dat sledování verzí z aplikace Xamarin.Forms do aplikace .NET MAUI
Xamarin.Essentials a uživatelské rozhraní multiplatformních aplikací .NET MAUI (.NET MAUI) mají VersionTracking
třídu, která umožňuje zkontrolovat verzi a čísla buildů aplikace spolu s dalšími informacemi, jako je například první spuštění aplikace. V Xamarin.Essentials je však data sledování verzí uložena v kontejneru předvoleb specifických pro platformu s názvem {your-app-package-id}.xamarinessentials.versiontracking
, zatímco v .NET MAUI jsou data sledování verzí uložena v kontejneru předvoleb specifických pro platformu s názvem {your-app-package-id}.microsoft.maui.essentials.versiontracking
.
Při migraci aplikace Xamarin.Forms, která používá VersionTracking
třídu na .NET MAUI, je nutné vyřešit tento rozdíl v pojmenování kontejnerů předvoleb, abyste uživatelům poskytli bezproblémové prostředí upgradu. Tento článek popisuje, jak můžete pomocí LegacyVersionTracking
tříd a pomocných tříd pracovat s kontejnerem předvoleb. Tato LegacyVersionTracking
třída umožňuje aplikaci .NET MAUI v androidu, iOSu a Windows číst data sledování verzí vytvořená s předchozí verzí vaší aplikace Xamarin.Forms.
Důležité
LegacyVersionTracking
Aby třída správně fungovala, musí mít aplikace .NET MAUI vyšší číslo verze než číslo verze aplikace Xamarin.Forms. Číslo verze je možné nastavit v souboru projektu aplikace .NET MAUI s vlastnostmi a $(ApplicationDisplayVersion)
vlastnostmi $(ApplicationVersion)
sestavení.
Další informace o VersionTracking
třídě v Xamarin.Essentials naleznete v tématu Xamarin.Essentials: Sledování verzí. Další informace o VersionTracking třídě v .NET MAUI naleznete v tématu Sledování verzí.
Přístup ke starším datům sledování verzí
Následující kód ukazuje LegacyVersionTracking
třídu, která poskytuje přístup k datům sledování verzí vytvořeným vaší aplikací Xamarin.Forms:
Poznámka:
Pokud chcete tento kód použít, přidejte ho do třídy pojmenované LegacyVersionTracking
v projektu aplikace .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];
}
Třída LegacyVersionTracking
používá LegacyPreferences
třídu, která poskytuje přístup k datům sledování verzí uloženým třídou Xamarin.Essentials Preferences
z vaší aplikace Xamarin.Forms:
Poznámka:
Pokud chcete tento kód použít, přidejte ho do třídy pojmenované LegacyPreferences
v projektu aplikace .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
Třída LegacyPreferences
je partial
třída, jejíž zbývající implementace je specifická pro platformu.
Android
Třída v Androidu LegacyPreferences
poskytuje implementaci kontejneru předvoleb, která načítá data ze sdílených předvoleb. Následující kód ukazuje LegacyPreferences
třídu:
Poznámka:
Pokud chcete tento kód použít, přidejte ho do třídy pojmenované LegacyPreferences
ve složce Platforms\Android projektu aplikace .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
V iOSu LegacyPreferences
třída poskytuje předvolby implementace kontejneru, která načítá data z NSUserDefaults
. Následující kód ukazuje LegacyPreferences
třídu:
Poznámka:
Pokud chcete tento kód použít, přidejte ho do třídy pojmenované LegacyPreferences
ve složce Platforms\iOS projektu aplikace .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
Ve Windows LegacyVersionTracking
třída poskytuje předvolby implementace kontejneru, která načítá data z ApplicationDataContainer. Následující kód ukazuje LegacyPreferences
třídu:
Poznámka:
Pokud chcete tento kód použít, přidejte ho do třídy pojmenované LegacyPreferences
ve složce Platforms\Windows projektu aplikace .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];
}
}
Využívání dat sledování starších verzí
Třídu LegacyVersionTracking
lze použít k načtení dat sledování verzí v androidu, iOSu a Windows vytvořeném pomocí předchozí verze Xamarin.Forms vaší aplikace:
#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
Tento příklad ukazuje použití LegacyVersionTracking
třídy ke čtení starších dat sledování verzí. Tato data ale nelze přiřadit ke třídě .NET MAUI VersionTracking , protože její vlastnosti nelze nastavit. Místo toho je možné data zapsat do předvoleb .NET MAUI metodou WriteHistory
:
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
Po zápisu starších dat sledování verzí do předvoleb .NET MAUI je možné je využívat ve třídě .NET MAUI VersionTracking :
var mauiVersionHistory = VersionTracking.Default.VersionHistory;
var mauiBuildHistory = VersionTracking.Default.BuildHistory;
Data sledování starší verze je pak možné ze zařízení odebrat:
#if ANDROID || IOS || WINDOWS
LegacyPreferences.Remove(LegacyVersionTracking.VersionsKey, LegacyVersionTracking.SharedName);
LegacyPreferences.Remove(LegacyVersionTracking.BuildsKey, LegacyVersionTracking.SharedName);
#endif