Xamarin.iOS 中的社交框架

社交框架提供统一的 API,用于与 Twitter、Facebook 以及中国用户的新浪微博等社交网络交互。

使用社交框架,应用程序可以通过单个 API 与社交网络交互,而无需管理身份验证。 它包括一个系统提供的用于撰写帖子的视图控制器,以及允许通过 HTTP 使用每个社交网络的 API 的抽象层。

连接到 Twitter

Twitter 帐户设置

要使用社交框架连接到 Twitter,需要在设备设置中配置帐户,如下所示:

Twitter 帐户设置

使用 Twitter 输入并验证帐户后,使用社交框架类访问 Twitter 的设备上的任何应用程序都将使用此帐户。

发送推文

社交框架包括一个名为 SLComposeViewController 的控制器,可提供系统提供的视图来编辑和发送推文。 以下屏幕截图显示了此视图的示例:

此屏幕截图显示了 SLComposeViewController 的示例

要将 SLComposeViewController 与 Twitter 一起使用,必须通过使用 SLServiceType.Twitter 调用 FromService 方法来创建控制器实例,如下所示:

var slComposer = SLComposeViewController.FromService (SLServiceType.Twitter);

返回 SLComposeViewController 实例后,它可用于显示要发布到 Twitter 的 UI。 但首先请通过调用 IsAvailable 来检查社交网络(在本例中为 Twitter)的可用性:

if (SLComposeViewController.IsAvailable (SLServiceKind.Twitter)) {
  ...
}

SLComposeViewController 无需用户交互即可直接发送推文。 但可以使用以下方法对它进行初始化处理:

  • SetInitialText - 添加要在推文中显示的初始文本。
  • AddUrl - 向推文添加 URL。
  • AddImage - 将图像添加到推文中。

初始化后,调用 PresentVIewController 将会显示由 SLComposeViewController 创建的视图。 然后,用户可以选择性编辑和发送推文,或取消发送推文。 在任一情况下,控制器都应在 CompletionHandler 中被关闭,并且在此处还可以检查结果,以查看是否发送推文或取消了推文,如下所示:

slComposer.CompletionHandler += (result) => {
  InvokeOnMainThread (() => {
    DismissViewController (true, null);
    resultsTextView.Text = result.ToString ();
  });
};

推文示例

以下代码演示如何使用 SLComposeViewController 显示用于发送推文的视图:

using System;
using Social;
using UIKit;

namespace SocialFrameworkDemo
{
    public partial class ViewController : UIViewController
    {
        #region Private Variables
        private SLComposeViewController _twitterComposer = SLComposeViewController.FromService (SLServiceType.Twitter);
        #endregion

        #region Computed Properties
        public bool isTwitterAvailable {
            get { return SLComposeViewController.IsAvailable (SLServiceKind.Twitter); }
        }

        public SLComposeViewController TwitterComposer {
            get { return _twitterComposer; }
        }
        #endregion

        #region Constructors
        protected ViewController (IntPtr handle) : base (handle)
        {

        }
        #endregion

        #region Override Methods
        public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);

            // Update UI based on state
            SendTweet.Enabled = isTwitterAvailable;
        }
        #endregion

        #region Actions
        partial void SendTweet_TouchUpInside (UIButton sender)
        {
            // Set initial message
            TwitterComposer.SetInitialText ("Hello Twitter!");
            TwitterComposer.AddImage (UIImage.FromFile ("Icon.png"));
            TwitterComposer.CompletionHandler += (result) => {
                InvokeOnMainThread (() => {
                    DismissViewController (true, null);
                    Console.WriteLine ("Results: {0}", result);
                });
            };

            // Display controller
            PresentViewController (TwitterComposer, true, null);
        }
        #endregion
    }
}

调用 Twitter API

社交框架还包括对于向社交网络发出 HTTP 请求的支持。 它将请求封装在用于面向特定社交网络 API 的 SLRequest 类中。

例如,以下代码会向 Twitter 发出获取公共时间线的请求(通过扩展上述代码):

using Accounts;
...

#region Private Variables
private ACAccount _twitterAccount;
#endregion

#region Computed Properties
public ACAccount TwitterAccount {
    get { return _twitterAccount; }
}
#endregion

#region Override Methods
public override void ViewWillAppear (bool animated)
{
    base.ViewWillAppear (animated);

    // Update UI based on state
    SendTweet.Enabled = isTwitterAvailable;
    RequestTwitterTimeline.Enabled = false;

    // Initialize Twitter Account access
    var accountStore = new ACAccountStore ();
    var accountType = accountStore.FindAccountType (ACAccountType.Twitter);

    // Request access to Twitter account
    accountStore.RequestAccess (accountType, (granted, error) => {
        // Allowed by user?
        if (granted) {
            // Get account
            _twitterAccount = accountStore.Accounts [accountStore.Accounts.Length - 1];
            InvokeOnMainThread (() => {
                // Update UI
                RequestTwitterTimeline.Enabled = true;
            });
        }
    });
}
#endregion

#region Actions
partial void RequestTwitterTimeline_TouchUpInside (UIButton sender)
{
    // Initialize request
    var parameters = new NSDictionary ();
    var url = new NSUrl("https://api.twitter.com/1.1/statuses/user_timeline.json?count=10");
    var request = SLRequest.Create (SLServiceKind.Twitter, SLRequestMethod.Get, url, parameters);

    // Request data
    request.Account = TwitterAccount;
    request.PerformRequest ((data, response, error) => {
        // Was there an error?
        if (error == null) {
            // Was the request successful?
            if (response.StatusCode == 200) {
                // Yes, display it
                InvokeOnMainThread (() => {
                    Results.Text = data.ToString ();
                });
            } else {
                // No, display error
                InvokeOnMainThread (() => {
                    Results.Text = string.Format ("Error: {0}", response.StatusCode);
                });
            }
        } else {
            // No, display error
            InvokeOnMainThread (() => {
                Results.Text = string.Format ("Error: {0}", error);
            });
        }
    });
}
#endregion

我们来仔细查看此代码。 首先,它会获取对帐户存储的访问权限,并获取 Twitter 帐户的类型:

var accountStore = new ACAccountStore ();
var accountType = accountStore.FindAccountType (ACAccountType.Twitter);

接下来,它会询问用户其应用是否可以访问其 Twitter 帐户,如果已授予访问权限,该帐户将会加载到内存中并更新 UI:

// Request access to Twitter account
accountStore.RequestAccess (accountType, (granted, error) => {
    // Allowed by user?
    if (granted) {
        // Get account
        _twitterAccount = accountStore.Accounts [accountStore.Accounts.Length - 1];
        InvokeOnMainThread (() => {
            // Update UI
            RequestTwitterTimeline.Enabled = true;
        });
    }
});

当用户请求时间线数据(通过点击 UI 中的按钮)时,应用会首先形成从 Twitter 访问数据的请求:

// Initialize request
var parameters = new NSDictionary ();
var url = new NSUrl("https://api.twitter.com/1.1/statuses/user_timeline.json?count=10");
var request = SLRequest.Create (SLServiceKind.Twitter, SLRequestMethod.Get, url, parameters);

此示例通过在 URL 中包含 ?count=10 将返回的结果限制为最后 10 个条目。 最后,它将请求附加到 Twitter 帐户(已在上面加载)并执行对 Twitter 的调用来提取数据:

// Request data
request.Account = TwitterAccount;
request.PerformRequest ((data, response, error) => {
    // Was there an error?
    if (error == null) {
        // Was the request successful?
        if (response.StatusCode == 200) {
            // Yes, display it
            InvokeOnMainThread (() => {
                Results.Text = data.ToString ();
            });
        } else {
            // No, display error
            InvokeOnMainThread (() => {
                Results.Text = string.Format ("Error: {0}", response.StatusCode);
            });
        }
    } else {
        // No, display error
        InvokeOnMainThread (() => {
            Results.Text = string.Format ("Error: {0}", error);
        });
    }
});

如果成功加载数据,将会显示原始 JSON 数据(如以下示例输出所示):

原始 JSON 数据显示的示例

在实际应用中,可以按正常方式分析 JSON 结果,并将结果呈现给用户。 有关如何分析 JSON 的信息,请参阅 Web 服务简介

连接到 Facebook

Facebook 帐户设置

使用社交框架连接到 Facebook 与上文所述的用于 Twitter 的过程几乎相同。 必须在设备设置中配置 Facebook 用户帐户,如下所示:

Facebook 帐户设置

配置后,使用社交框架的设备上的任何应用程序都将使用此帐户连接到 Facebook。

发布到 Facebook

由于社交框架是一个旨在访问多个社交网络的统一的 API,,因此无论使用哪个社交网络,该代码都几乎完全相同。

例如,可以像前面所示的 Twitter 示例中一样使用 SLComposeViewController,唯一不同的是切换到特定于 Facebook 的设置和选项。 例如:

using System;
using Foundation;
using Social;
using UIKit;

namespace SocialFrameworkDemo
{
    public partial class ViewController : UIViewController
    {
        #region Private Variables
        private SLComposeViewController _facebookComposer = SLComposeViewController.FromService (SLServiceType.Facebook);
        #endregion

        #region Computed Properties
        public bool isFacebookAvailable {
            get { return SLComposeViewController.IsAvailable (SLServiceKind.Facebook); }
        }

        public SLComposeViewController FacebookComposer {
            get { return _facebookComposer; }
        }
        #endregion

        #region Constructors
        protected ViewController (IntPtr handle) : base (handle)
        {

        }
        #endregion

        #region Override Methods
        public override void ViewWillAppear (bool animated)
        {
            base.ViewWillAppear (animated);

            // Update UI based on state
            PostToFacebook.Enabled = isFacebookAvailable;
        }
        #endregion

        #region Actions
        partial void PostToFacebook_TouchUpInside (UIButton sender)
        {
            // Set initial message
            FacebookComposer.SetInitialText ("Hello Facebook!");
            FacebookComposer.AddImage (UIImage.FromFile ("Icon.png"));
            FacebookComposer.CompletionHandler += (result) => {
                InvokeOnMainThread (() => {
                    DismissViewController (true, null);
                    Console.WriteLine ("Results: {0}", result);
                });
            };

            // Display controller
            PresentViewController (FacebookComposer, true, null);
        }
        #endregion
    }
}

在用于 Facebook 时,SLComposeViewController 将显示与 Twitter 示例外观几乎完全相同的视图,在本例中会显示 Facebook 作为标题:

SLComposeViewController 显示

调用 Facebook 图形 API

与 Twitter 示例类似,社交网络的 SLRequest 对象也可与 Facebook 的图形 API 一起使用。 例如,以下代码会从图形 API 中返回有关 Xamarin 帐户的信息(通过扩展上述代码):

using Accounts;
...

#region Private Variables
private ACAccount _facebookAccount;
#endregion

#region Computed Properties
public ACAccount FacebookAccount {
    get { return _facebookAccount; }
}
#endregion

#region Override Methods
public override void ViewWillAppear (bool animated)
{
    base.ViewWillAppear (animated);

    // Update UI based on state
    PostToFacebook.Enabled = isFacebookAvailable;
    RequestFacebookTimeline.Enabled = false;

    // Initialize Facebook Account access
    var accountStore = new ACAccountStore ();
    var options = new AccountStoreOptions ();
    var options.FacebookAppId = ""; // Enter your specific Facebook App ID here
    accountType = accountStore.FindAccountType (ACAccountType.Facebook);

    // Request access to Facebook account
    accountStore.RequestAccess (accountType, options, (granted, error) => {
        // Allowed by user?
        if (granted) {
            // Get account
            _facebookAccount = accountStore.Accounts [accountStore.Accounts.Length - 1];
            InvokeOnMainThread (() => {
                // Update UI
                RequestFacebookTimeline.Enabled = true;
            });
        }
    });

}
#endregion

#region Actions
partial void RequestFacebookTimeline_TouchUpInside (UIButton sender)
{
    // Initialize request
    var parameters = new NSDictionary ();
    var url = new NSUrl ("https://graph.facebook.com/283148898401104");
    var request = SLRequest.Create (SLServiceKind.Facebook, SLRequestMethod.Get, url, parameters);

    // Request data
    request.Account = FacebookAccount;
    request.PerformRequest ((data, response, error) => {
        // Was there an error?
        if (error == null) {
            // Was the request successful?
            if (response.StatusCode == 200) {
                // Yes, display it
                InvokeOnMainThread (() => {
                    Results.Text = data.ToString ();
                });
            } else {
                // No, display error
                InvokeOnMainThread (() => {
                    Results.Text = string.Format ("Error: {0}", response.StatusCode);
                });
            }
        } else {
            // No, display error
            InvokeOnMainThread (() => {
                Results.Text = string.Format ("Error: {0}", error);
            });
        }
    });
}
#endregion

此代码与上面显示的 Twitter 版本的唯一真正的区别在于 Facebook 要求获取开发人员/应用特定的 ID(可以从 Facebook 的开发人员门户生成),并且必须在发出请求时将其设置为选项:

var options = new AccountStoreOptions ();
var options.FacebookAppId = ""; // Enter your specific Facebook App ID here
...

// Request access to Facebook account
accountStore.RequestAccess (accountType, options, (granted, error) => {
    ...
});

未能设置此选项(或使用无效密钥)将导致错误或不会返回任何数据。

总结

本文介绍了如何使用社交框架与 Twitter 和 Facebook 进行交互。 其中显示了在设备设置中为每个社交网络配置帐户的位置。 此外,还讨论了如何使用 SLComposeViewController 来呈现发布到社交网络的统一视图。 此外,它还介绍了用于调用每个社交网络 API 的 SLRequest 类。