Apple iCloud访问uwp应用程序中的联系人

时间:2018-08-08 03:46:38

标签: c# .net uwp icloud

我正在尝试在UWP应用程序中访问我的iCloud联系人。 我知道我可以通过Google's People API访问我的Gmail联系人,并可以通过Microsoft的Graph apiOutook people api访问Outlook联系人。

Apple是否提供可用于获取,更新,添加,删除联系人的API(Rest或其他方式)?如果是,是否有一个教程可以逐步介绍如何设置访问iCloud api?

2 个答案:

答案 0 :(得分:0)

花了很多天试图弄清楚这一点之后,我认为我开始对此进行破解。我不确定(也许是)苹果是否有意使这一过程变得困难,但这比原本应该的困难。 这是我什至需要获取联系人的方法(根本不知道如何添加,更新或删除它们):

  

步骤1>使用Apple ID和密码请求令牌。如果激活了2FA,则在响应标头中将不会收到auth令牌和auth用户cookie。但这没关系,我们将在下一步中解决。请注意,最有可能暂时无法提取AUTH-TOKEN和AUTH-USER。另外,我们将在以后的回复中接收语言环境信息和联系链接。

public sealed partial class MainPage : Page
{
    String contactLink = "";
    String authToken = "";
    String authUser = "";

    public MainPage()
    {
        this.InitializeComponent();
    }

    private async void IcloudBtn_Click(object sender, RoutedEventArgs e)
    {
        HttpResponseHeaderCollection respHeaders = await ContactApple();
        ContactsBlock.Text += "CONTACT LINK: " + contactLink + "\n";
        ContactsBlock.Text += authToken + "\n";
        ContactsBlock.Text += authUser + "\n";
    }

    private async void GetToken_Click(object sender, RoutedEventArgs e)
    {
        HttpResponseHeaderCollection respHeaders = await ContactApple(AuthenticationCode.Text);
        ContactsBlock.Text += "CONTACT LINK: " + contactLink + "\n";
        ContactsBlock.Text += authToken + "\n";
        ContactsBlock.Text += authUser + "\n";
    }

    private async void GetContacts_Click(object sender, RoutedEventArgs e)
    {
        Uri contactUri = new Uri(contactLink + "/co/startup?locale=en_US&order=last%2Cfirst");
        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("Origin", "https://www.icloud.com");
        client.DefaultRequestHeaders.Add("Cookie", authToken + ";" + authUser + ";");

        HttpResponseMessage hrm = await client.GetAsync(contactUri);
        JObject contactJson = JObject.Parse(await hrm.Content.ReadAsStringAsync());
        ContactsBlock.Text += contactJson["contacts"];
    }


    private async Task<HttpResponseHeaderCollection> ContactApple(String authentication = "")
    {
        // The apple id and the password
        String appleId = "AppleID";
        String password = "Password" + authentication;

        // https://stackoverflow.com/questions/31457068/get-icloud-contact-list-in-c-sharp?noredirect=1&lq=1
        // Post request will have this in the content
        String data = "{\"apple_id\":" + appleId + ", \"password\":" + password + ", \"extended_login\":true}";
        HttpStringContent content = new HttpStringContent(data, UnicodeEncoding.Utf8);

        // The URI to get the tokens from:
        Uri requestUri = new Uri("https://setup.icloud.com/setup/ws/1/accountLogin");

        // Create an instance of the HttpClient (Windows.Web.Http)
        HttpClient client = new HttpClient();

        // Add Origin = https://www.icloud.com in the header.
        client.DefaultRequestHeaders.Add("Origin", "https://www.icloud.com");

        // Post request and read response as JSON object (NewtonSoft)
        HttpResponseMessage hrm = await client.PostAsync(requestUri, content);
        JObject resp = JObject.Parse(await hrm.Content.ReadAsStringAsync());

        // Get the URL to the contacts
        contactLink = (String)resp["webservices"]["contacts"]["url"];

        // Read the headers for AUTH-TOKEN and AUTH-USER Cookies,
        HttpResponseHeaderCollection headers = hrm.Headers;
        if (headers.ContainsKey("Set-Cookie"))
        {
            String cookie = headers["Set-Cookie"];
            char[] separators = { ';', ',' };
            String[] tokens = cookie.Split(separators);
            foreach (String token in tokens)
            {
                int length = token.Length;
                if (token.Contains("X-APPLE-WEBAUTH-TOKEN"))
                {
                    authToken = token;
                }
                if (token.Contains("X-APPLE-WEBAUTH-USER"))
                {
                    authUser = token;
                }
            }
        }
        return headers;
    }
}
  

第2步>如果2FA已激活,您将在Apple设备上收到请求以授权登录并使用提供的代码进行登录。获得代码后,请重复上述步骤,仅附加通过在授权码文本字段中提供密码来输入密码。

请注意,您将需要输入授权码。

  

第3步>希望您现在已收到获取联系人所需的令牌。现在,您可以通过使用在响应正文中获得的联系链接来获取联系人,同时获取令牌并附加“ / co / startup?locale = XXXXX&order = last%2Cfirst”

请注意,您将必须使用适合您需要的语言环境。我需要使用“ en_US”,因为这就是我在响应中所使用的语言环境。您将需要使用请求中返回的语言环境。

XAML:

<Page
    x:Class="AddressBook.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:AddressBook"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <StackPanel x:Name="MainStack">
        <Button x:Name="IcloudBtn" Content="Request Code" Click="IcloudBtn_Click"/>
        <TextBox x:Name="AuthenticationCode" Text="Authentication Code here." TextWrapping="Wrap"/>
        <Button x:Name="GetToken" Content="Get Token" Click="GetToken_Click"/>
        <Button x:Name="GetContacts" Content="Get Contacts" Click="GetContacts_Click"/>
        <TextBox x:Name="ContactsBlock" TextWrapping="Wrap"/>
    </StackPanel>
</Page>

Screenshot of demo app.

但是,我仍然不知道如何实际操作联系人列表。我想如果我发现了,我会在这里更新。

答案 1 :(得分:0)

因此,如果您只想获取联系人(并以JSON格式),则我以前的答案可能是解决方法。 但是,由于我希望能够对Apple帐户执行CRUD操作,因此更好的方法是使用icloud / apple支持的CARDDAV协议。

  
      
  1. 通过在here上发出带有请求内容的PROPFIND请求,以使用基本身份验证获取主要用户(此基本身份验证中使用的密码必须作为应用程序密码https://contacts.icloud.com生成):< / li>   
<propfind
xmlns="DAV:">
<prop>
    <current-user-principal/>
</prop>
</propfind> 
  
      
  1. 上一步将使您可以检索格式为/ 1437425399 / principal /的原理。现在,您可以在链接https://contacts.icloud.com/1437425399/principal上使用以下请求内容来触发对此用户的家庭设置的PROPFIND查询:
  2.   
<propfind
    xmlns="DAV:"
    xmlns:c="urn:ietf:params:xml:ns:carddav">
    <prop>
        <c:addressbook-home-set/>
    </prop>
</propfind>
  
      
  1. 从上一个请求中,您将获得格式为https://p48-contacts.icloud.com:443/1437425399/carddavhome/的家庭链接。您可以在首页链接上使用以下PROPFIND请求查询用户的vcard的位置:
  2.   
<propfind
xmlns="DAV:">
<prop>
    <resourcetype/>
</prop>
</propfind>
  
      
  1. 您将收到放置所有卡的位置(例如/ 1437425399 / carddavhome / card /)。使用地址簿查询,现在您可以在上一个链接中收到的端点上发起REPORT请求:
  2.   
<c:addressbook-query
    xmlns="DAV:"
    xmlns:c="urn:ietf:params:xml:ns:carddav">
    <prop>
    </prop>
</c:addressbook-query>
  
      
  1. 这将为您提供标签中的所有卡片。然后,您可以使用地址簿多报告请求来获取多张卡片:
  2.   
<c:addressbook-multiget
    xmlns="DAV:"
    xmlns:c="urn:ietf:params:xml:ns:carddav">
    <prop>
        <getetag />
        <c:address-data />
    </prop>
    <href>/1437425399/carddavhome/card/somecard.vcf</href>
    <href>/1437425399/carddavhome/card/anothercard.vcf</href>
</c:addressbook-multiget>

对于更新,创建和删除卡,您可以使用我们先前在将Content-Type设置为“ text / vcard”之后讨论的基本身份验证,在“ /1437425399/carddavhome/card/cardtobemanipulated.vcf”端点上触发PUT请求。并发送内容中的VCard以进行更新和创建请求。