在Xamarin.Forms中编写特定于设备平台的代码

32

我有以下Xamarin.Forms.ContentPage类的结构。

public class MyPage : ContentPage
{
    public MyPage()
    {
        //do work to initialize MyPage 
    }

    public void LogIn(object sender, EventArgs eventArgs)
    {
        bool isAuthenticated = false;
        string accessToken = string.Empty;

        //do work to use authentication API to validate users

        if(isAuthenticated)
        {
            //I would to write device specific code to write to the access token to the device
            //Example of saving the access token to iOS device
            NSUserDefaults.StandardUserDefaults.SetString(accessToken, "AccessToken");

            //Example of saving the access token to Android device
            var prefs = Application.Context.GetSharedPreferences("MySharedPrefs", FileCreationMode.Private);
            var prefsEditor = prefs.Edit();

            prefEditor.PutString("AccessToken", accessToken);
            prefEditor.Commit();
        }
    }
}

我希望在MyPageLogIn方法中编写特定于平台的代码,根据用户在我的应用上使用的设备操作系统保存访问令牌。

当用户在其设备上使用我的应用程序时,如何只运行特定于设备的代码?

5个回答

65

这是一个可以通过依赖注入轻松解决的场景。

在您的共享或PCL代码中,使用所需方法的接口,例如:

public interface IUserPreferences 
{
    void SetString(string key, string value);
    string GetString(string key);
}

在您的App类上拥有该接口的一个属性:

public class App 
{
    public static IUserPreferences UserPreferences { get; private set; }

    public static void Init(IUserPreferences userPreferencesImpl) 
    {
        App.UserPreferences = userPreferencesImpl;
    }

    (...)
}

在您的目标项目上创建特定于平台的实现:

iOS:

public class iOSUserPreferences : IUserPreferences 
{
    public void SetString(string key, string value)
    {
        NSUserDefaults.StandardUserDefaults.SetString(value, key);
    }

    public string GetString(string key)
    {
        return NSUserDefaults.StandardUserDefaults.StringForKey(key);
    }
}

安卓:

public class AndroidUserPreferences : IUserPreferences
{
    public void SetString(string key, string value)
    {
        var prefs = Application.Context.GetSharedPreferences("MySharedPrefs", FileCreationMode.Private);
        var prefsEditor = prefs.Edit();

        prefEditor.PutString(key, value);
        prefEditor.Commit();
    }

    public string GetString(string key)
    {
        (...)
    }
}

然后在每个特定平台的项目中创建一个 IUserPreferences 的实现,并使用 App.Init(new iOSUserPrefernces())App.Init(new AndroidUserPrefernces()) 方法来设置它。

最后,您可以将您的代码更改为:

public class MyPage : ContentPage
{
    public MyPage()
    {
        //do work to initialize MyPage 
    }

    public void LogIn(object sender, EventArgs eventArgs)
    {
        bool isAuthenticated = false;
        string accessToken = string.Empty;

        //do work to use authentication API to validate users

        if(isAuthenticated)
        {
            App.UserPreferences.SetString("AccessToken", accessToken);
        }
    }
}

App类的代码片段中,我尝试编写代码时遇到了“方法必须具有返回类型”的提示。它是否应该具有void的返回类型? - Michael Kniskern
init方法的返回类型应该是void - valdetero
这是一个非常好的解决方案,将代码组织到每个特定平台的项目中。谢谢。 - Michael Kniskern
感谢Michael和valdetero指出并修复了这个问题。很高兴这个答案对你有用,我使用这种方法来访问几个不同的平台特定功能。还值得一提的是,Stephane Delcroix提到的DependencyService也值得一看。 - Pedro

16

Xamarin.Forms 2.3.4 引入了一种新的方法:

if (Device.RuntimePlatform == Device.Android)
{
    // Android specific code
}
else if (Device.RuntimePlatform == Device.iOS)
{
    // iOS specific code
}
else if (Device.RuntimePlatform == Device.UWP)
{
    // UWP specific code
}

还有其他平台可供选择,您可以在Visual Studio中键入 Device.,它将显示您的选项。


9

根据您想要实现的目标和项目类型,有多种答案:

在不同平台上执行不同的Xamarin.Forms代码。
例如,如果您希望在不同平台上使用不同的字体大小,请使用此选项:

label.Font = Device.OnPlatform<int> (12, 14, 14);

在共享(PCL)项目中执行平台特定的代码 通常的模式是使用DI(依赖注入)。 Xamarin.Forms 提供了一个简单的 DependencyService,但您可以使用任何您想要的东西。

在共享(Shared Asset Project)项目中执行平台特定的代码 由于代码针对每个平台进行编译,因此您可以将平台特定的代码包装在 #if __PLATFORM__ #endif 中,并将所有代码放在同一个文件中。平台项目应定义__IOS____ANDROID____WINDOWS_PHONE__。请注意,包含 Xaml 和代码的共享资源项目在 Xamarin.Studio 上无法很好地为 iOS 工作,并且具有编译器指令使得你的代码更难以阅读和测试。


我目前正在使用第三个选项“在共享资产项目中执行特定于平台的代码”,并且采用了__IOS____ANDROID__语法,但是安卓特定的代码在Intellisense中没有显示出来。iOS特定的代码在Intellisense中已经显示出来了。 - Michael Kniskern
1
@MichaelKniskern:将你的构建目标更改为安卓,以便拥有它的智能感知功能。并确保(在项目首选项中)该符号已导出。顺便说一句,我觉得很有趣,你使用了这个答案,并接受了另一个答案:) - Stephane Delcroix
我决定选择不依赖Xamarin功能的答案,因为我在使用空白应用程序(Xamarin.Forms共享)项目类型时遇到了其他问题。此外,每次想要使用特定于平台的代码时都必须切换启动项目,这并不理想。 - Michael Kniskern

2
这似乎与Xamarin.Forms关系不大,更多的是关于在PCL中使用默认值。请查看James Montemagno的github仓库以进行跨平台默认值设置。然后只需调用他的静态方法进行设置/检索即可。该Nuget包名为Xam.Plugins.Settings
可以像这样使用它:
using Refractored.Xam.Settings;

...

CrossSettings.Current.AddOrUpdateValue("AccessToken", accessToken);
var value = CrossSettings.Current.GetValueOrDefault<string>("AccessToken");

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接